Compare commits

...
564 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
AndrewandGitHub 8c209f5a9e Merge pull request #280 from OpenSignLabs/all-contributors/add-VikramNagwal 2023-12-17 10:22:59 +05:30
allcontributors[bot]andGitHub 995a2a5cef docs: update .all-contributorsrc 2023-12-17 04:52:20 +00:00
allcontributors[bot]andGitHub 71fd7b20a6 docs: update README.md 2023-12-17 04:52:19 +00:00
AndrewandGitHub d8e73eef72 Merge pull request #279 from VikramNagwal/staging 2023-12-17 10:21:54 +05:30
prafull-opensignlabs ca6b4e7d82 add createDocument from template functionality 2023-12-16 22:19:12 +05:30
prafull-opensignlabs cb4a94d036 add createDocument from template functionality 2023-12-16 22:19:01 +05:30
prafull-opensignlabsandGitHub 300ddb810f Update LoginFacebook.js 2023-12-16 17:03:35 +05:30
prafull-opensignlabsandGitHub 0b687310fd Update LoginGoogle.js 2023-12-16 17:03:04 +05:30
jeremyito07 61209f4c6c fix: Removed "/test" Route with comments 2023-12-16 10:23:48 +05:30
prafull-opensignlabs 3e741ac2f9 add functionality of add placholder in template 2023-12-15 19:01:05 +05:30
jeremyito07 c4507dd06b fix: removed "/test" route from application 2023-12-15 18:35:18 +05:30
prafull-opensignlabsandGitHub f65b23ca26 Merge pull request #278 from OpenSignLabs/staging
Sync fork
2023-12-15 16:37:32 +05:30
prafull-opensignlabsandGitHub 773e8b8dbb Merge pull request #260 from OpenSignLabs/placeholder-block
fix: placeholder block issue for select multisigners
2023-12-15 16:32:49 +05:30
AmolandGitHub 91976d2355 chore: add dependabot dependency update check 2023-12-15 13:47:21 +05:30
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
RaktimaNXG 77042224a1 fix: opensign-drive drop-down issue 2023-12-15 13:19:26 +05:30
RaktimaNXG 0b64908eab increase zIndex of header and footer 2023-12-15 10:59:41 +05:30
RaktimaNXG fc3f134bd5 fix: zIndex of placeholder-block and added signyourself & request signature form in openSign drive 2023-12-15 10:22:00 +05:30
RaktimaNXG d6c2c66fdd fix: image-upload issue in mobile view 2023-12-13 18:12:47 +05:30
prafull-opensignlabsandGitHub db9b8d2ba1 Merge pull request #261 from OpenSignLabs/staging
sync fork
2023-12-12 19:57:56 +05:30
prafull-opensignlabs 4866447f33 add api for template, createDocument 2023-12-12 19:37:59 +05:30
RaktimaNXG d5853e6fc3 fix: placeholder block issue for select multisigners 2023-12-12 19:23:21 +05:30
AmolandGitHub 765c3c19fa Merge pull request #259 from OpenSignLabs/placeholder-resize 2023-12-12 18:27:54 +05:30
prafull-opensignlabs 2b345ff840 add new template form 2023-12-12 17:57:11 +05:30
RaktimaNXG f13991b88b fix: upload large size image overflow in placeholder 2023-12-12 15:15:19 +05:30
RaktimaNXG 47ddac3529 fix: multisign signature issue in mobile view 2023-12-11 17:50:36 +05:30
RaktimaNXG e51feaa1fe Refactor code 2023-12-08 17:11:01 +05:30
RaktimaNXG d224a44e54 fix: mobile to desktop and desktop to mobile view placeholder location issue 2023-12-07 20:01:15 +05:30
AmolandGitHub f5c0694e32 Merge pull request #249 from OpenSignLabs/placeholder-resize 2023-12-06 18:52:47 +05:30
RaktimaNXG dec13e8b5f fix: image resize placeholder location issue in mobile to mobile and desktop to desktop view 2023-12-06 16:37:59 +05:30
RaktimaandGitHub dd536dc7d0 Merge branch 'staging' into placeholder-resize 2023-12-06 10:13:03 +05:30
AmolandGitHub b6ce00519f Merge pull request #257 from OpenSignLabs/send-mail 2023-12-06 09:33:24 +05:30
RaktimaNXG 7495955420 fix: design of email sent toast message 2023-12-05 14:12:12 +05:30
AndrewandGitHub d17951af30 Merge pull request #258 from OpenSignLabs/profile_ui 2023-12-05 14:11:00 +05:30
prafull-opensignlabs 42c6f03f28 remove outline of buttons in profile ui 2023-12-05 13:47:46 +05:30
prafull-opensignlabs a9d6bc2246 update user profile ui 2023-12-05 13:32:14 +05:30
RaktimaNXG 428bb3b7c3 fix: design of sent mail message,change variable name emailCount to emailList 2023-12-05 13:08:42 +05:30
RaktimaNXG ac0cdd28cf feat: mail button on header after sign document in signyourself flow 2023-12-05 12:07:25 +05:30
RaktimaNXG 37250f8a11 fix multiple signature location issue after complete signature in signyourself flow 2023-12-05 10:51:58 +05:30
AmolandGitHub 0102480954 Merge pull request #255 from OpenSignLabs/main
Merge pull request #229 from OpenSignLabs/staging
2023-12-04 18:23:02 +05:30
AmolandGitHub f3a1c74a45 Merge pull request #254 from OpenSignLabs/fix_action_btn
fix: continuous loader on action btn in report
2023-12-04 18:14:39 +05:30
prafull-opensignlabsandGitHub 2544651ff1 fix: continuous loader on action btn in report 2023-12-04 18:13:35 +05:30
AmolandGitHub 93297b972a Merge pull request #253 from OpenSignLabs/update_appname
Update app name
2023-12-04 17:56:14 +05:30
prafull-opensignlabsandGitHub 7165ed82f5 Update_appname 2023-12-04 17:55:16 +05:30
prafull-opensignlabsandGitHub 17422427a8 Update index.html 2023-12-04 17:33:33 +05:30
AmolandGitHub 9ef2bc9ee2 Merge pull request #238 from OpenSignLabs/feat-dropbox-fileupload
feat: add dropbox fileupload
2023-12-04 17:31:10 +05:30
AmolandGitHub 12ec1bad0f Merge pull request #248 from OpenSignLabs/contactbook-validation
update query for contact
2023-12-04 17:07:53 +05:30
AmolandGitHub fd552cedec Merge pull request #251 from OpenSignLabs/folder-update
update folder component
2023-12-04 17:06:36 +05:30
prafull-opensignlabsandGitHub 5784378073 Update TreeWidget.js 2023-12-04 16:17:28 +05:30
prafull-opensignlabsandGitHub e0448cd4fa Merge pull request #252 from OpenSignLabs/staging
Merge pull request #250 from OpenSignLabs/folder-update
2023-12-04 16:10:55 +05:30
RaktimaNXG 9a4bd79d75 Merge branch 'staging' of https://github.com/OpenSignLabs/OpenSign into placeholder-resize 2023-12-04 16:08:31 +05:30
RaktimaNXG 9ae0334249 update folder component 2023-12-04 16:06:00 +05:30
AndrewandGitHub eb355f562b Merge pull request #250 from OpenSignLabs/folder-update 2023-12-04 13:13:27 +05:30
RaktimaNXG 92dc13185b update folder creation query 2023-12-04 12:16:06 +05:30
RaktimaNXG 65ec4e78ad update folder creation 2023-12-04 11:56:56 +05:30
RaktimaNXG 0c4b8143b2 fix: placeholder and signyourself location issue in mobille view 2023-12-04 11:34:51 +05:30
prafull-opensignlabs b47bf437a9 created generateapitoken, getapitoken cloud function & generatetoken route 2023-12-02 21:16:56 +05:30
RaktimaNXG 1cc4cf93cb fix: resize placeholder design and adding resize option for recipients, added signers's name on placeholder 2023-12-01 20:09:22 +05:30
prafull-opensignlabs 944370134a add validation for contactbook 2023-12-01 19:14:36 +05:30
prafull-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
prafull-opensignlabsandGitHub c1621f64e6 Merge pull request #247 from OpenSignLabs/feat-password-validation
add password validation
2023-12-01 10:50:24 +05:30
prafull-opensignlabsandGitHub e8c06d0836 Merge pull request #246 from OpenSignLabs/guest-signers-download
fix:  #227 download button throws error in guest signer flow issue
2023-12-01 10:50:08 +05:30
prafull-opensignlabs a6295a6e56 add password validation 2023-11-30 18:08:32 +05:30
RaktimaNXG 47ae52c881 fix: download button throws error in guest signer flow 2023-11-30 18:01:37 +05:30
prafull-opensignlabsandGitHub f2f0b55596 Merge pull request #245 from raktima-opensignlabs/horizontal-pdf-issue
fix: horizontal pdf or large size pdf's scrollbar issue in signyourself & placeholder flow
2023-11-30 15:43:09 +05:30
RaktimaNXG 0c415de598 remove unecessary times call getDocumentsDetails function 2023-11-30 14:15:50 +05:30
RaktimaNXG 411941d9f7 fix: horizontal pdf or large size pdf's scrollbar issue in signyourself and placeholder flow 2023-11-30 14:12:25 +05:30
RaktimaandGitHub 3c54f2287c Merge pull request #28 from OpenSignLabs/staging
update
2023-11-30 13:37:28 +05:30
AndrewandGitHub dfa121fe57 Merge pull request #234 from raktima-opensignlabs/default-signature 2023-11-30 13:17:52 +05:30
prafull-opensignlabsandGitHub 52b17730ef feat: migration of contactbook report (#243) 2023-11-30 13:17:35 +05:30
AndrewandGitHub 346d69124c chore: Add issue and feature request template (#244) 2023-11-29 16:34:26 +05:30
AndrewandGitHub 7f35074acd Merge pull request #241 from OpenSignLabs/all-contributors/add-crediblebilal 2023-11-28 19:49:19 +05:30
allcontributors[bot]andGitHub b9e9694d61 docs: update .all-contributorsrc 2023-11-28 14:19:00 +00:00
allcontributors[bot]andGitHub ee4a787b81 docs: update README.md 2023-11-28 14:18:59 +00:00
AndrewandGitHub d801680846 Merge pull request #239 from crediblebilal/fix-automatic-sidebar-opening 2023-11-28 19:47:59 +05:30
prafull-opensignlabsandAndrew d84ab89a9b fix: smtp mail issue resolve 2023-11-28 19:40:08 +05:30
prafull-opensignlabs 26d38f4ca2 change color of cancel btn test in file-upload 2023-11-28 15:52:26 +05:30
Bilal Ahmad Bhat 745e519eec fix automatic sidebar opening on window resize 2023-11-28 14:04:51 +05:30
prafull-opensignlabs 45b3e739d7 make changes UI in file upload 2023-11-28 12:22:13 +05:30
prafull-opensignlabs 5ce50db001 add dropbox in file upload field 2023-11-28 10:14:41 +05:30
AndrewandGitHub a8c7b60c1b Docs: Add SMTP config 2023-11-28 04:17:05 +05:30
AndrewandGitHub 16860bc7b8 Docs: Add SMTP CONFIG 2023-11-28 04:15:26 +05:30
AndrewandGitHub 57f20ae1c0 Docs: Add USE_LOCAL variable 2023-11-28 03:45:22 +05:30
allcontributors[bot]andAndrew d3b0c614ff docs: update .all-contributorsrc 2023-11-27 23:55:22 +05:30
allcontributors[bot]andAndrew e28f929ffc docs: update README.md 2023-11-27 23:55:22 +05:30
AndrewandGitHub 9f8f9a0992 Merge pull request #235 from Govinda04/feature/fix-delete-btn
fix: Delete button issue
2023-11-27 23:53:58 +05:30
Govinda KocharekarandGitHub 60857638ba Proper style for the delete button(cross) on "email documents" popup 2023-11-27 23:14:31 +05:30
Govinda KocharekarandGitHub 8041151243 show cursor pointer for select email list cancel button/img 2023-11-27 23:13:12 +05:30
AmolandGitHub 7faed512b8 Merge pull request #226 from prafull-opensignlabs/auth_user
feat:add contactbook report & updated version of app in footer
2023-11-27 17:01:23 +05:30
RaktimaNXG 5d99a4a9c8 fix: multiple default signature error,sign-yourself placeholder location issue in mobile view 2023-11-27 16:29:19 +05:30
prafull-opensignlabs 25c50d5387 change subscipiton urls 2023-11-27 12:48:20 +05:30
prafull-opensignlabsandGitHub 5719dcca79 Merge pull request #51 from OpenSignLabs/staging
sync fork
2023-11-27 11:01:53 +05:30
RaktimaandGitHub db1e81a249 Merge pull request #27 from OpenSignLabs/staging
update
2023-11-26 15:04:58 +05:30
AndrewandGitHub ecd3395453 Docs: fix duplicate values in INSTALLATION.md 2023-11-26 11:15:41 +05:30
AmolandGitHub 4327b2e348 Merge pull request #229 from OpenSignLabs/staging
patch: typo fix
2023-11-24 19:25:47 +05:30
AmolandGitHub 06e8140be4 Merge pull request #228 from OpenSignLabs/fix-additionalinfo-popup
fix: correct typo
2023-11-24 19:24:38 +05:30
prafull-opensignlabsandGitHub 14e9330651 replace destination to Jobtitle in additional info popup 2023-11-24 19:21:51 +05:30
prafull-opensignlabs 636910a78e feat:add contactbook report & updated version of app in footer 2023-11-24 17:12:38 +05:30
prafull-opensignlabsandGitHub e4f9152de8 Merge pull request #49 from OpenSignLabs/staging
sync fork
2023-11-24 16:56:41 +05:30
RaktimaandGitHub e0b9df9ba5 Merge pull request #26 from OpenSignLabs/staging
update
2023-11-24 10:54:28 +05:30
AmolandGitHub a20bd407a8 Merge pull request #224 from prafull-opensignlabs/auth_user
chore:code refactor
2023-11-23 19:25:11 +05:30
prafull-opensignlabs 5630dd45a7 chore:code refactor 2023-11-23 19:23:35 +05:30
AmolandGitHub 20220dd8c9 Merge pull request #223 from raktima-opensignlabs/horizontal-pdf2
fix: two modal overlap at a time in signyourself flow
2023-11-23 19:23:17 +05:30
RaktimaNXG db4b8ec0ee fix two modal overlap during signyourself flow 2023-11-23 19:19:57 +05:30
RaktimaandGitHub 2ee9ae16fb Merge pull request #25 from OpenSignLabs/staging
update
2023-11-23 18:18:24 +05:30
prafull-opensignlabsandGitHub e50a55403d Merge pull request #48 from OpenSignLabs/staging
sync fork
2023-11-23 18:10:28 +05:30
AmolandGitHub 23ae72738d chore: syntax issue 2023-11-23 18:07:22 +05:30
AmolandGitHub 8619021f30 chore: syntax issue 2023-11-23 17:57:00 +05:30
AmolandGitHub 6c579178c0 chore: syntax issue 2023-11-23 17:51:10 +05:30
AmolandGitHub 01e19632a9 fix: syntax issue 2023-11-23 17:49:43 +05:30
AmolandGitHub 79ff8fd71d Merge pull request #191 from raktima-opensignlabs/transparent-img
fix:  #165 - transparent PNG signature issue
2023-11-23 17:36:30 +05:30
AmolandGitHub 8700fd837d Merge branch 'staging' into transparent-img 2023-11-23 17:36:10 +05:30
AmolandGitHub cdc8eb5bf6 Merge pull request #189 from rishabjasrotia/issue/126
#126 - Fix UI layout issue after signing a document from mobile
2023-11-23 17:27:43 +05:30
AmolandGitHub 95200e234f Merge pull request #216 from rishabjasrotia/issue/204
#204 - Fix issue due to Signature URL validation
2023-11-23 17:26:44 +05:30
AmolandGitHub d94527e31a Merge branch 'staging' into issue/204 2023-11-23 17:26:35 +05:30
prafull-opensignlabsandGitHub 903066e6fa Merge pull request #47 from OpenSignLabs/staging
sync fork
2023-11-23 17:25:16 +05:30
AmolandGitHub 8c8015fe4a Merge pull request #188 from rishabjasrotia/issue/168
#168 - Align Modal to Center of PDF if Signed
2023-11-23 17:19:01 +05:30
AmolandGitHub a002ac779c Merge pull request #222 from prafull-opensignlabs/auth_user 2023-11-23 13:47:12 +05:30
prafull-opensignlabs 5c9bfbbdfe fix: signature slighty move from top and bottom 2023-11-23 13:36:35 +05:30
RishabandGitHub 4a1e6d1318 Merge branch 'OpenSignLabs:staging' into issue/168 2023-11-23 12:56:50 +05:30
RaktimaandGitHub 90dc7c738a Merge pull request #24 from OpenSignLabs/staging
update
2023-11-23 11:14:50 +05:30
prafull-opensignlabsandGitHub 777028f3a7 Merge pull request #46 from OpenSignLabs/staging
Merge pull request #221 from prafull-opensignlabs/auth_user
2023-11-22 20:46:57 +05:30
AmolandGitHub c5a0ff4021 Merge pull request #221 from prafull-opensignlabs/auth_user
change sequence in add signer form
2023-11-22 20:42:58 +05:30
prafull-opensignlabs bf9f42e94d change sequence in add signer form 2023-11-22 20:41:55 +05:30
prafull-opensignlabsandGitHub 5556de2ef5 Merge pull request #45 from OpenSignLabs/staging
sync fork
2023-11-22 20:32:28 +05:30
rishabjasrotia 1b3508a9ef Replace npm package with manual valiadation 2023-11-22 18:57:18 +05:30
RishabandGitHub 3992a9be94 Merge branch 'OpenSignLabs:staging' into issue/204 2023-11-22 18:54:53 +05:30
AmolandGitHub eaf875be06 Merge pull request #220 from OpenSignLabs/add-verificaiton-branding
Add "OpenSign" branding to verification email
2023-11-22 17:27:53 +05:30
AmolandGitHub e62897e729 Add "OpenSign" branding to verification email 2023-11-22 16:57:44 +05:30
AmolandGitHub 4c58fe2040 Merge pull request #219 from prafull-opensignlabs/auth_user
add parameter verifyUserEmails in server
2023-11-22 16:34:26 +05:30
prafull-opensignlabs 298068207e add parameter verifyUserEmails in server 2023-11-22 16:33:18 +05:30
prafull-opensignlabsandGitHub d0abe615cb Merge pull request #44 from OpenSignLabs/staging
Merge pull request #215 from prafull-opensignlabs/auth_user
2023-11-22 16:32:06 +05:30
Rishab 87c65e4bea #204 - Fix issue due to Signature URL validation 2023-11-22 06:20:02 +00:00
RishabandGitHub be49cb9d6d Merge branch 'staging' into issue/168 2023-11-22 08:52:17 +05:30
AmolandGitHub 2b73087b7e Merge pull request #215 from prafull-opensignlabs/auth_user 2023-11-22 00:13:04 +05:30
prafull-opensignlabs d11dff2987 fix: google sign in mobile & add progress in profile pic upload 2023-11-22 00:09:28 +05:30
prafull-opensignlabsandGitHub 8ac82b1214 Merge pull request #43 from OpenSignLabs/staging
Merge pull request #214 from prafull-opensignlabs/auth_user
2023-11-21 23:07:08 +05:30
RaktimaandGitHub c46fa19bbb Merge pull request #23 from OpenSignLabs/staging
update
2023-11-21 20:56:29 +05:30
AmolandGitHub 2fa2f56bac Merge pull request #214 from prafull-opensignlabs/auth_user 2023-11-21 19:35:42 +05:30
prafull-opensignlabs ef50aaa417 fix google sign in 2023-11-21 19:34:11 +05:30
prafull-opensignlabsandGitHub a1d7275fcd Merge pull request #42 from OpenSignLabs/staging
sync fork
2023-11-21 19:17:55 +05:30
AmolandGitHub 080acc9ed6 Merge pull request #213 from raktima-opensignlabs/signer-login
fix:  no data found issue on signers login page
2023-11-21 16:36:10 +05:30
prafull-opensignlabsandGitHub 30b888f3a0 Merge pull request #41 from OpenSignLabs/staging
sync fork
2023-11-21 15:35:30 +05:30
prafull-opensignlabs df11a77971 Merge branch 'auth_user' of https://github.com/prafull-opensignlabs/OpenSign into auth_user 2023-11-21 15:28:41 +05:30
prafull-opensignlabs 03e660527d security improvement 2023-11-21 15:23:26 +05:30
RaktimaNXG f7bd439df5 remove contracts_contactbook class query from placeholderSign.js 2023-11-21 14:14:01 +05:30
RaktimaNXG 2a55c03788 fix no data found on signers login page 2023-11-21 13:36:42 +05:30
RaktimaandGitHub f712532793 Merge pull request #22 from OpenSignLabs/staging
update
2023-11-21 10:27:00 +05:30
AmolandGitHub cbdeaf8cc9 Merge pull request #212 from raktima-opensignlabs/email-message 2023-11-21 10:24:29 +05:30
RaktimaNXG 6bb353fd1f fix spelling mistake of email message beeen to been after signed by all parties 2023-11-21 10:22:16 +05:30
RaktimaandGitHub 523dd43b4d Merge pull request #21 from OpenSignLabs/staging
update
2023-11-21 09:55:49 +05:30
AmolandGitHub bd0216fc39 Merge pull request #197 from rishabjasrotia/issue/170 2023-11-21 03:09:16 +05:30
prafull-opensignlabsandGitHub 50c40bfec1 Merge pull request #40 from OpenSignLabs/staging
Merge pull request #211 from prafull-opensignlabs/auth_user
2023-11-20 23:03:35 +05:30
AmolandGitHub 0e2b6ee180 Merge pull request #211 from prafull-opensignlabs/auth_user 2023-11-20 23:01:49 +05:30
prafull-opensignlabs 359d86e17b fix: sendmail functionality not working 2023-11-20 23:00:07 +05:30
prafull-opensignlabsandGitHub 0b19c87a50 Merge pull request #37 from OpenSignLabs/staging
sync fork
2023-11-20 22:25:28 +05:30
AmolandGitHub 4a35eab7c6 Merge pull request #209 from raktima-opensignlabs/cloud-function 2023-11-20 22:14:20 +05:30
RaktimaNXG b178a3c91e handle condition of no data for contracts_Document and contracts_ContactBook classes 2023-11-20 21:57:26 +05:30
prafull-opensignlabsandGitHub 9fb0fecba4 Merge pull request #36 from OpenSignLabs/staging
sync fork
2023-11-20 20:18:32 +05:30
AmolandGitHub cfc7408a52 Merge pull request #210 from prafull-opensignlabs/auth_user
add getReport cloud function
2023-11-20 19:21:19 +05:30
prafull-opensignlabs aed0b8a3db add getReport cloud function 2023-11-20 19:11:46 +05:30
RaktimaNXG 910bd801ac remove contracts_Document & contracts_Users query from frontend and call cloud function 2023-11-20 16:46:27 +05:30
AmolandGitHub 22dad33b2e Merge pull request #208 from prafull-opensignlabs/auth_user
security changes in getDocument function & add getDrive cloud function
2023-11-20 14:14:31 +05:30
prafull-opensignlabs 4d3ed0232e security changes in getDocument function & add getDrive function 2023-11-20 14:11:32 +05:30
prafull-opensignlabsandGitHub 6d83f05b13 Merge pull request #34 from OpenSignLabs/staging
sync fork
2023-11-20 12:51:41 +05:30
AmolandGitHub 66cc2e1f2f Merge pull request #203 from rishabjasrotia/feature/certificate_update 2023-11-20 12:36:32 +05:30
AmolandGitHub f773fc6e3c Merge pull request #207 from prafull-opensignlabs/auth_user 2023-11-20 12:33:34 +05:30
prafull-opensignlabs dc83f21f5e Merge branch 'auth_user' of https://github.com/prafull-opensignlabs/OpenSign into auth_user 2023-11-20 12:04:06 +05:30
prafull-opensignlabsandGitHub 0186c48d59 Update getDocument.js 2023-11-20 12:00:41 +05:30
prafull-opensignlabs 43f20508ae Merge branch 'auth_user' of https://github.com/prafull-opensignlabs/OpenSign into auth_user 2023-11-20 11:54:18 +05:30
prafull-opensignlabs f678dd02cb change in getDoucment cloud function 2023-11-20 11:54:04 +05:30
prafull-opensignlabsandGitHub 5c2d6cddcb Merge pull request #33 from OpenSignLabs/staging
Merge pull request #205 from prafull-opensignlabs/auth_user
2023-11-20 11:53:02 +05:30
AmolandGitHub 1bbf64fe83 Merge pull request #205 from prafull-opensignlabs/auth_user
create getDocument cloud function & minor UI changes
2023-11-20 11:14:21 +05:30
prafull-opensignlabs 296f43101e comment getinProgessReport 2023-11-20 11:13:24 +05:30
prafull-opensignlabs ed6f44fd62 create getDocument cloud function & minor UI changes 2023-11-20 10:42:20 +05:30
prafull-opensignlabsandGitHub 776b1a7b43 Merge pull request #32 from OpenSignLabs/staging
sync fork
2023-11-20 10:25:08 +05:30
RaktimaandGitHub 06cdb660b3 Merge pull request #20 from OpenSignLabs/staging
update
2023-11-20 10:22:25 +05:30
rishabjasrotia db9268e1af Include the Signer Email Address 2023-11-18 20:21:17 +05:30
nxglabs 83ce3a1c21 update local cert setup 2023-11-18 01:52:20 +05:30
prafull-opensignlabsandGitHub bda31de345 add parse-dbtool package (#201) 2023-11-17 20:12:51 +05:30
prafull-opensignlabs cdfc952a3f add parse-dbtool package 2023-11-17 20:00:43 +05:30
prafull-opensignlabsandGitHub 9434315775 migration db changes (#200) 2023-11-17 19:58:01 +05:30
prafull-opensignlabsandGitHub 47bb4cac38 migration db changes (#200) 2023-11-17 19:37:44 +05:30
prafull-opensignlabs 11d3e6c696 migration db changes 2023-11-17 19:36:11 +05:30
prafull-opensignlabsandGitHub 0173727bc5 Merge branch 'OpenSignLabs:staging' into auth_user 2023-11-17 19:35:13 +05:30
prafull-opensignlabsandGitHub 3cfa2639e5 migrate db changes (#199) 2023-11-17 18:29:41 +05:30
prafull-opensignlabs 502400ee56 rename file from create_setclp to update_setclp 2023-11-17 18:27:34 +05:30
prafull-opensignlabs 4a3276f4e3 check migration functionality in staging app 2023-11-17 18:07:26 +05:30
prafull-opensignlabsandGitHub 750e48ca2e Merge pull request #27 from OpenSignLabs/staging
sync fork
2023-11-17 16:21:37 +05:30
prafull-opensignlabsandGitHub 823e6a9e2f update schema of contracts_users (#196) 2023-11-17 15:39:18 +05:30
Rishab 642ef334f6 #170 - Fix While dragging sign placeholder in mobile view the drawbox pops up unexpectedly 2023-11-17 09:21:31 +00:00
prafull-opensignlabsandGitHub 939a67b2c5 fix: resolve user not able to login/signup (#195) 2023-11-17 14:03:33 +05:30
prafull-opensignlabsandGitHub e1f8481aa2 Merge pull request #24 from prafull-opensignlabs/staging
sync fork'
2023-11-17 10:08:55 +05:30
rishabjasrotia b8e8cd127a Remove duplicate code 2023-11-16 20:14:32 +05:30
rishabjasrotia 876a2d78d5 enhancement 2023-11-16 20:06:57 +05:30
rishabjasrotia 16f287fdc0 Added backdrop to modal 2023-11-16 20:03:59 +05:30
prafull-opensignlabsandGitHub d396a4f71d Merge pull request #22 from OpenSignLabs/staging
fix: sendmail cloud function is not working (#194)
2023-11-16 19:57:02 +05:30
prafull-opensignlabsandGitHub 6bee566d8d fix: sendmail cloud function is not working (#194) 2023-11-16 19:25:57 +05:30
RaktimaandGitHub 79acd8ae13 Merge pull request #19 from OpenSignLabs/staging
update
2023-11-16 17:04:03 +05:30
prafull-opensignlabsandGitHub 01666b49cf Merge pull request #21 from OpenSignLabs/staging
change in in class level permission of contracts_User class (#192)
2023-11-16 11:24:18 +05:30
prafull-opensignlabsandGitHub a20ebbf08f change in in class level permission of contracts_User class (#192) 2023-11-16 11:19:34 +05:30
prafull-opensignlabsandGitHub 26cf9c5310 Merge pull request #20 from OpenSignLabs/staging
security improvement (#190)
2023-11-16 11:18:44 +05:30
prafull-opensignlabs 3ad58ee52b update url of migrate 2023-11-16 11:16:28 +05:30
prafull-opensignlabs 2b67af6097 change create, update clp of contracts_Users class 2023-11-16 11:09:56 +05:30
prafull-opensignlabsandGitHub f61dae35ff Merge pull request #19 from OpenSignLabs/staging
security improvement (#190)
2023-11-16 11:08:57 +05:30
prafull-opensignlabsandGitHub dead3088d6 security improvement (#190) 2023-11-16 11:02:38 +05:30
prafull-opensignlabs 45d65cfbe2 change cloud function name getContractUser to getUserDetails 2023-11-16 11:00:49 +05:30
RaktimaNXG 6d2010facb fix transparent PNG signature issue 2023-11-16 10:59:26 +05:30
prafull-opensignlabsandGitHub 48d3166049 Merge pull request #18 from prafull-opensignlabs/staging
sync fork
2023-11-16 10:52:47 +05:30
prafull-opensignlabsandGitHub 82992d324d Merge pull request #17 from OpenSignLabs/staging
sync fork
2023-11-16 10:51:50 +05:30
prafull-opensignlabs 9a549fa35d Merge branch 'auth_user' of https://github.com/prafull-opensignlabs/OpenSign into auth_user 2023-11-16 10:50:01 +05:30
prafull-opensignlabs 93a891c8b6 feat: add migration code for contracts_users class 2023-11-16 10:47:11 +05:30
RaktimaandGitHub 2ede742b10 Merge pull request #18 from OpenSignLabs/staging
update
2023-11-16 10:32:15 +05:30
Rishab c43690faa8 #126 - Fix UI layout issue after signing a document from mobile 2023-11-16 04:08:12 +00:00
Rishab a482a92d34 #168 - Align Modal to Center of PDF if Signed 2023-11-16 04:02:34 +00:00
prafull-opensignlabsandGitHub 1d429cbe36 Merge pull request #16 from OpenSignLabs/staging
sync fork
2023-11-15 17:14:46 +05:30
AmolandGitHub 0a36550907 Update README.md 2023-11-15 02:21:26 +05:30
Mathieu VigneandGitHub 09610112fc Feature/use smtp to send email (#182) 2023-11-14 20:55:45 +05:30
RaktimaandGitHub a14454227c fix Completion certificate issues (#184) 2023-11-14 20:31:19 +05:30
AmolandGitHub 0d8767ee98 Revert "fix: #172 - Location of requested signature placeholders shift to slight right on mobile view in "Request Signatures" flow (#185)" (#186)
This reverts commit f463dc7af7.
2023-11-14 20:30:40 +05:30
RaktimaandGitHub f463dc7af7 fix: #172 - Location of requested signature placeholders shift to slight right on mobile view in "Request Signatures" flow (#185) 2023-11-14 20:09:51 +05:30
RaktimaandGitHub 407b01565a Merge pull request #17 from OpenSignLabs/staging
Update main
2023-11-14 15:50:20 +05:30
RaktimaandGitHub 6c565a144a fix need your sign report document signature issue (#183) 2023-11-14 15:29:00 +05:30
RaktimaandGitHub 141351de49 Merge pull request #16 from OpenSignLabs/staging
update main branch
2023-11-14 10:14:48 +05:30
nxglabs edecf3ea23 chore: configure husky & prettier 2023-11-13 18:21:49 +05:30
prafull-opensignlabsandGitHub e708dad596 add shipping country code param in subscriptions url (#181) 2023-11-13 16:17:40 +05:30
prafull-opensignlabsandGitHub 48012c9343 Merge pull request #13 from OpenSignLabs/staging
sync fork
2023-11-13 16:00:03 +05:30
prafull-opensignlabsandGitHub 009a24e943 Merge pull request #15 from OpenSignLabs/staging
sync fork
2023-11-13 15:59:51 +05:30
RaktimaandGitHub 04a3251968 fix issue of mulitple annotation in signyourself (#174) 2023-11-13 14:29:14 +05:30
prafull-opensignlabsandGitHub 82694a24f2 replace modal title login with additional info and verification mail alert (#179) 2023-11-13 13:22:10 +05:30
prafull-opensignlabsandGitHub 748cc042dd Merge pull request #14 from OpenSignLabs/staging
sync fork
2023-11-13 10:59:43 +05:30
RishabandGitHub 6b8bca0802 #167 - Sanitize Output filename (#176) 2023-11-11 13:25:04 +05:30
AmolandGitHub fed1cff0cb Update features in README.md 2023-11-11 02:45:53 +05:30
AmolandGitHub b2eba6409f Main (#175) 2023-11-10 20:12:35 +05:30
RaktimaandGitHub 81af6a6c61 Merge pull request #15 from OpenSignLabs/staging
update
2023-11-10 10:28:02 +05:30
AmolandGitHub c326849b8d Merge pull request #162 from rishabjasrotia/issue/146 2023-11-09 21:18:53 +05:30
prafull-opensignlabsandGitHub a92188d8e2 change variable name 2023-11-09 21:18:36 +05:30
prafull-opensignlabsandGitHub b5dbc69188 Merge pull request #12 from OpenSignLabs/staging
sync fork
2023-11-09 20:54:17 +05:30
prafull-opensignlabsandGitHub 4055574785 sanitize File Name in upload file 2023-11-09 20:48:53 +05:30
AmolandGitHub 9b295f784a Merge pull request #158 from raktima-opensignlabs/placeholder-mobile-view2 2023-11-09 20:37:49 +05:30
prafull-opensignlabsandGitHub bfae7f236c Merge branch 'staging' into placeholder-mobile-view2 2023-11-09 20:36:33 +05:30
AmolandGitHub fe907116e2 Merge pull request #156 from raktima-opensignlabs/login-header3 2023-11-09 20:27:04 +05:30
rishabjasrotia ade39c2f46 Doc Updated 2023-11-09 18:36:18 +05:30
AndrewandGitHub 31baefcce3 Merge pull request #161 from rishabjasrotia/issue/32 2023-11-09 18:32:23 +05:30
RishabandGitHub 59eb4eb9c7 #32 - Change the title of popup that appears after sending out emails from "Request signatures" flow
#32 - Change the title of popup that appears after sending out emails from "Request signatures" flow
2023-11-09 18:30:37 +05:30
rishabjasrotia 3b93f96479 Fix makefile 2023-11-09 18:05:34 +05:30
rishabjasrotia dbff436bc2 #146 - Fix issue of build & Add local File upload support 2023-11-09 17:53:34 +05:30
AmolandGitHub c3cf9c891e Merge pull request #160 from maoo/patch-1 2023-11-09 17:47:54 +05:30
Maurizio PillituandGitHub 4e7c8c63bb CORS configuration instructions
See https://github.com/OpenSignLabs/OpenSign/issues/159
2023-11-09 12:57:58 +01:00
prafull-opensignlabs db4494c463 security improvment 2023-11-09 17:08:57 +05:30
RaktimaandGitHub d208a90107 Merge pull request #14 from OpenSignLabs/staging
update
2023-11-09 15:48:38 +05:30
RaktimaNXG 450a971ca9 remove isSigner exist checking from local storage 2023-11-09 14:30:17 +05:30
RaktimaNXG 5ba1f79f3b replce isSigner variable name to isGuestSigner 2023-11-09 14:23:56 +05:30
prafull-opensignlabsandGitHub f81f72a147 Merge pull request #11 from OpenSignLabs/staging
sync fork
2023-11-09 12:28:51 +05:30
AndrewandGitHub d255d5bfb2 Merge pull request #151 from prafull-opensignlabs/mf_header 2023-11-09 12:01:41 +05:30
AndrewandGitHub f5e835cbc4 Merge pull request #148 from prafull-opensignlabs/fix_signup 2023-11-09 12:01:20 +05:30
AmolandGitHub b40eb7119d Merge branch 'issue/119' into staging 2023-11-08 22:36:01 +05:30
RaktimaNXG f56faf3afd handle placeholder block position and size on mobile view 2023-11-08 21:01:09 +05:30
RaktimaNXG 5fa60d8135 solved overflow header on logiin page 2023-11-08 20:42:35 +05:30
AmolandGitHub 695345d911 Merge pull request #144 from raktima-opensignlabs/main
fix: blocking popup on view expired and declined document screens
2023-11-08 20:11:16 +05:30
prafull-opensignlabs 3f60509254 remove header from report microapp 2023-11-08 16:55:30 +05:30
RaktimaandGitHub 6bd9ac0b8f Merge pull request #12 from OpenSignLabs/staging
Update
2023-11-08 16:55:09 +05:30
prafull-opensignlabs 2022df000e fix: user sign up issue for user existing in contact list 2023-11-08 13:56:28 +05:30
prafull-opensignlabsandGitHub ec6e037422 Merge pull request #10 from OpenSignLabs/staging
sync fork
2023-11-07 18:35:15 +05:30
prafull-opensignlabsandGitHub 4b11fe77e0 Merge pull request #9 from OpenSignLabs/staging
sync fork
2023-11-07 17:40:34 +05:30
RaktimaNXG d42e11c5c1 fix: blocking screen by warning for expired and decline document 2023-11-07 11:32:25 +05:30
RaktimaNXG fe37f3e021 fix: expired and decline document block whole screeen 2023-11-06 14:51:33 +05:30
RaktimaandGitHub 95558d1407 Merge pull request #11 from OpenSignLabs/staging
update
2023-11-06 14:48:05 +05:30
rishabjasrotia 73978ebce4 Fix issue 2023-11-05 19:20:34 +05:30
rishabjasrotia 96ae95a97c Fix the generation of remoteentry.js for docker development 2023-11-05 19:13:54 +05:30
rishabjasrotia 356d2e81c5 Update Document & Self Signed Cert added 2023-11-05 19:09:15 +05:30
213 changed files with 26733 additions and 19351 deletions
+27
View File
@@ -178,6 +178,33 @@
"contributions": [
"a11y"
]
},
{
"login": "Govinda04",
"name": "Govinda Kocharekar",
"avatar_url": "https://avatars.githubusercontent.com/u/50038172?v=4",
"profile": "https://github.com/Govinda04",
"contributions": [
"code"
]
},
{
"login": "crediblebilal",
"name": "Bilal Ahmad Bhat",
"avatar_url": "https://avatars.githubusercontent.com/u/55330484?v=4",
"profile": "https://bilal.cc",
"contributions": [
"code"
]
},
{
"login": "VikramNagwal",
"name": "Vikram",
"avatar_url": "https://avatars.githubusercontent.com/u/123088024?v=4",
"profile": "https://github.com/VikramNagwal",
"contributions": [
"code"
]
}
]
}
+9 -2
View File
@@ -39,11 +39,18 @@ DO_ACCESS_KEY_ID=
DO_SECRET_ACCESS_KEY=
# Digital ocean spaces region or AWS s3 region
DO_REGION=us-west
# Set this to true id you are using local storage instead of s3 compatible storage
# USE_LOCAL=TRUE
# Email mailgun config (The app will not initialize if any of these 3 variables are not set) *********************************************************************************************************************
MAILGUN_API_KEY=
# Email mailgun or set SMTP_ENABLE true to use SMTP config (The app will not initialize if any of these 3 variables are not set) *********************************************************************************************************************
MAILGUN_API_KEY=XXXXX
MAILGUN_DOMAIN=mail.yourdomain.com
MAILGUN_SENDER=postmaster@mail.yourdomain.com
SMTP_ENABLE=
SMTP_HOST=
SMTP_PORT=
SMTP_USER_EMAIL=
SMTP_PASS=
# Base64 encoded PFX or p12 document signing certificate file *********************************************************************************************************************
PFX_BASE64=
+63 -4
View File
@@ -44,13 +44,72 @@ DO_REGION=us-west
# local storage
USE_LOCAL=TRUE
# Email mailgun config (The app will not initialize if any of these 3 variables are not set) *********************************************************************************************************************
MAILGUN_API_KEY=XXXXX
# Email mailgun or set SMTP_ENABLE true to use SMTP config (The app will not initialize if any of these 3 variables are not set) *********************************************************************************************************************
MAILGUN_API_KEY=
MAILGUN_DOMAIN=mail.yourdomain.com
MAILGUN_SENDER=postmaster@mail.yourdomain.com
SMTP_ENABLE=
SMTP_HOST=smtp.yourhost.com
SMTP_PORT=443
SMTP_USER_EMAIL=mailer@yourdomain.com
SMTP_PASS=password # if your password includes spaces then write password in single quotes ('asdf pasd asdf bgds').
# Base64 encoded PFX or p12 document signing certificate file *********************************************************************************************************************
PFX_BASE64=
PFX_BASE64='MIIKCQIBAzCCCc8GCSqGSIb3DQEHAaCCCcAEggm8MIIJuDCCBG8GCSqGSIb3DQEH
BqCCBGAwggRcAgEAMIIEVQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQIpumu
bFabBWACAggAgIIEKDqHS7Icd5MzIBk1dBokGK2s+5a2fA4308WA1QzEWmczqVYI
z6lYmW8qsiZIw4PFkRzdIx1+zCmP8jgWiiqh5RKnbHYmh1JPNyx9SqmUDILDXmjg
KxO9agRw9LXge4hgRL7YW0TxYZYw4EeXV9Yr7kcOq9DoO2MoRikJ+2Tuvvq/hfuV
9zFHsz4jpf7W95k1IeH6bZ92klz5R1e/EK8JuHy592i/u+BxxW1vTkiPpTaHD6s9
1lDSkT1j0LIDU6l9gVvJvFBV8j88vet/Z4QkTbHPMYvBnKNRstKuOvDasEJE4RkA
PV4TfBwFF6uvREZI1vBboM/18pzeyjoRX+mlJNfcH3kh1tkck+Jg+M2bLXAH1EdD
GRwENvnTNW1CFIn37VVja7SFBQNXA+E6rejmqtUmZ5XktSINDBUyjow9XuYTUtI/
sgcRSC0aB0EKKpphbFPp1niKCLm1ef33e+bWyWbtR2L2Kc3ETmhjNADpyapAGmzc
LP2BafGaKj18KiLAG4GL6+kXk0GUz7Fw5q8H8RY1T33o+xjWvC0+aJgvr65qWdKw
+ug6wuu4Cr2kFEuXxPKsnYqmE5NT/x+lfunlZ5iEQN3w2XO5J2u2eMXVRUsPH2T6
0sJKomjY0RB1JsqZBnyleWm+tYo0RpVAyJ3NGBp9dVb7a3Qw6jNZBG/xMW+gvtUJ
q6hfK/cD3cagD0NQFVD5STMOuGOSqq/bbwAKjZ/lrPmCCYATKwkjAFybYfHJVrrW
Y2tQgCQ/zrZLIxQjp7F17hU0+gT54x0MpF6AoqIM/qqNnHrQ0fi50ECmLvx3SqYa
nvjvt/HZhMZfqRXiXjeicIwpnNoG7+uQknySk+7cc9GNhHZR7cfPfkTpgvuuebrQ
l5YW+k9tG+xrX8g72nvtFMnammlBixlFwECJaEszEQk5tc2ti8uG2z+kGnFoDoBV
M6ZVMpKDJzXPxLdzT6ChIPyatjIkqOKe6vDpnmzcoEhbBhmtkVjWFA2dfX846ugV
y1QiecWgk8pMNWhh3IDd05v/wzbFwNcq+Gi+1dZsPmFH+egIcrQKZu2r3jCJtGHh
DNG/nyf/anqvKXF90bi4hRT3vdDXXuWgY7EUwfn9h5jYabCO6HsQxQOBjFYNmBrh
MfaiBZe72E8fzNAfIlwDcJ4AWY1SOM7hi8bqfRWw1NtNxuMUiRFoR31O6XkQauye
9hAmpdlZHZXtJ6LM0QaWkPJmG3058GMtIn/qS60V9nINh+zXhwza/1pnFB+e9MWc
hAPgo0nn55FusM//g1nM31PKe+nOm3Jyp0nEQ4m8aDtJS63o2fvp3e2KJbPWQMHE
a83W975diWg4NTdevV9lFpNllHclVoPoavUHIzHd7HF9TcPpjbXJSUZ7cITHHefr
kQTa/2G9cWuRhN9GKIHBdr13nfEvMIIFQQYJKoZIhvcNAQcBoIIFMgSCBS4wggUq
MIIFJgYLKoZIhvcNAQwKAQKgggTuMIIE6jAcBgoqhkiG9w0BDAEDMA4ECDgnjfOf
AjArAgIIAASCBMgkbVuptroBdyMY5gl/eBQj5+iAV02YSaF969ihStLSWI4x5FAf
HuDgqCyEMSl4RHG8ZvNaO9JoNfIpMK/TPQBoQRCzE2Vjf66VTERaQtU6h7tZrbQt
K96n9eqvohm/vXbXe08fsodYp2s79kAvKgpuGG5iX77qYVzJHBPed87cvczo4ToP
CpurDpByt8fGEmjtcikal8o+H9uoHjcFwqMigX1Q7IEjuKXrb5e6wTvxMRob8yfv
LVl6ahteKSkWCMb6rLZ5f12jDoCGX/YXRrSsU9t/lXe0Nxv5i7c8flb2EsNtwygD
fexVvn5u6ble6RDYNpuQkPgF41HyZh+JvGAF6i1r4tJPL9Pf4HnjEB8Y8IHgon+w
T5I+8LTgcrWyhptzblXMjKySTEp9OEa2cCVwZkl4z43PWJ5oIAQ2IDTOQ603/5o/
d9KA76/zMPQ5O0gv17OA7kwFv98v6sTcR4vgkQZqnyDpJSEPHyNxhw2MSBqS3jq3
YPhRz+3Ei1oFp9uYFhzn39f9gzNi++X9pOjSrDb8v3mcDXZKNrxQLuoRMSf0eQNI
dgJRqj/fuqNZ5ac3kd4P5BALCsnA1tM27zYrgUdpOnrc2D9FBthEjpRlQKMMzhQf
cNMFWmoNjakDilvvLcsQeQ3P6cXbN1ODoNnjgK3VzcmeKyzW2PrTXEPHARUM3j4V
sZzGaUOVKLqaaDrXWQKC0vrTvxP2WMfjQ1dTdXQP/kSZTXRC5rtB9tky38flBor0
N9rhUDIGMs5qBvyrkV2hKXiW39G69p1KWY+Cw28AzY+CNSjePRi60TsnUxgcOS7i
0AT25Gx3A4YqxmTY38MPB4wPcBPcw4hjNoQamaC9mqs+KVHcP5YHUlqykMeH0YVi
J+ehytJE9xuDcfBOjxjadxp3/q/Lku4rky89gdJGFQWuuz75VulDywPRZRwmQTel
sjEGMHR1zTOlPJdTDWhqaKmWvL4GhbCgEPIKwmqd1QKRTl/3Baa1nYllJeYVwiTT
qLCkbA6qXrLGj1ENZxrKn9yqr8HwOoApjwhARu4LF/BRMgdkzelK2kOXHnZ26sZ2
NY/MMtVmq4c59y6iQwmsbHr9tWGz3ahyXcZZufjNXU/AVnO1c92g7umAWZF4RohL
gMmh57cAhN9PEbEv6j/6BT3XXp8jB0ywcRriYxfxwidviCKH/76Q4sytYJQaDFI1
fnzmv0aDotbG2BdpWSiYPDOPm+3cmfjlULsn1FYWL4NDCX1f+C4lNtKVX9LU8c5M
m8dA1DUlDfnuNO5/BShuoGXG2z4O/XwxIaRFizMxWS2sWurbAEFJ6oNw3kC7WSah
NIe8aUC1umpc1Gk3X2f4Ytzj9OEqn0y55qoqLINJuejXMffF/gjopxHWadLVaVaj
Q1SewrECuEXdSbBR/a10po24wmRtkmlvRJXJl7sG95xE5ZCqp+m6sRPWGdf1yKbV
vyWNUe4Qvkxe4a0VAJpTyIGr980CKz/jkvtNQMobGl7AfhxKJ450wg454WcexMct
BYXvZMSdUDCgMLlh0nHJHl5btrFWqE0Z/fqWmIknZL2jZ4J+2hdVl/xB/sUt6kcu
txw+RfL+vNE8PxhTNaOdJFwD8yeN1mJ3yMUA8HHYpw9yljgxJTAjBgkqhkiG9w0B
CRUxFgQUDYlgGVxSxuOknhQc256x3++7BDwwMTAhMAkGBSsOAwIaBQAEFFjASdYl
3pXAXxZuvVvv9tsb4bdrBAhyb+KCIjp/gAICCAA='
# Provide Pass pharse of above PFX or p12 document
PASS_PHRASE=
PASS_PHRASE=opensign
+73
View File
@@ -0,0 +1,73 @@
name: "Bug Report"
labels: ["bug","up-for-grabs"]
title: "[Bug]: "
assignees:
- andrew-opensignlabs
description: Create a bug report to help us make OpenSign™ the world's best document e-signature platform
body:
- type: textarea
attributes:
label: Issue Description
description: Please provide a clear & concise description of the problem.
- type: textarea
attributes:
label: Expected Behavior
description: Describe what you expected to happen.
- type: textarea
attributes:
label: Current Behavior
description: Describe what is happening instead.
- type: textarea
attributes:
label: Steps to reproduce
description: Please provide step-by-step instructions to reproduce the issue. Include code snippets, URLs, error messages and any other relevant information.
- type: textarea
attributes:
label: Screenshots of the issue(optional)
description: Add screenshots to better explain the issue.
- type: input
attributes:
label: Operating System [e.g. MacOS Sonoma 14.1, Windows 11]
- type: dropdown
id: browsers
attributes:
label: What browsers are you seeing the problem on?
multiple: true
options:
- Chrome
- Firefox
- Safari
- Microsoft Edge
default: 0
- type: input
attributes:
label: What version of OpenSign™ are you seeing this issue on? [e.g. 1.0.6]
validations:
required: true
- type: dropdown
id: environment
attributes:
label: What environment are you seeing the problem on?
multiple: true
options:
- Production (app.opensignlabs.com)
- Staging (staging-app.opensignlabs.com)
- Hosted (app.yourdomain.com)
- Dev (localhost or vercel)
- type: checkboxes
attributes:
label: Please check the boxes that apply to this issue report.
options:
- label: I have searched the existing issues & discussions to make sure that this is not a duplicate.
validations:
required: true
- type: checkboxes
id: terms
attributes:
label: Code of Conduct
description: By submitting this issue, you agree to follow our [Code of Conduct](https://www.opensignlabs.com)
options:
- label: I agree to follow this project's Code of Conduct
required: true
- label: I have searched the existing issues & discussions to make sure that this is not a duplicate.
required: true
@@ -0,0 +1,70 @@
name: Feature Request
description: Suggest an idea for OpenSign™
title: "Feature Request: [Short Description]"
labels: [feature request, needs triage]
body:
- type: markdown
attributes:
value: |
## Thanks for taking the time to fill out this feature request!
- type: input
id: title
attributes:
label: Feature Title
description: What would you call this feature?
placeholder: e.g., Advanced Signature Verification
validations:
required: true
- type: textarea
id: feature-description
attributes:
label: Feature Description
description: |
Please provide a detailed description of the feature you're proposing.
placeholder: |
e.g., I'm proposing an advanced signature verification feature that...
validations:
required: true
- type: dropdown
id: featuretype
attributes:
label: What type of feature are you requesting?
multiple: true
options:
- UI/UX Improvement
- Security / Compliance
- Performance / Optimization
- 3rd party integration
- Other
- type: dropdown
id: importance
attributes:
label: Importance
description: How important is this feature to you?
options:
- Critical
- High
- Medium
- Low
validations:
required: true
- type: textarea
id: additional-context
attributes:
label: Additional Context
description: Any other context or screenshots about the feature request here.
placeholder: Additional details, examples, or screenshots...
- type: checkboxes
id: terms
attributes:
label: Code of Conduct
description: By submitting this issue, you agree to follow our [Code of Conduct](https://www.opensignlabs.com)
options:
- label: I agree to follow this project's Code of Conduct
required: true
- label: I have searched the existing issues & discussions to make sure that this is not a duplicate.
required: true
+22
View File
@@ -0,0 +1,22 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
# maintain dependencies for frontend
- package-ecosystem: "npm" # See documentation for possible values
directory: "/apps/OpenSign" # Location of package manifests
schedule:
interval: "weekly"
# maintain dependencies for server
- package-ecosystem: "npm" # See documentation for possible values
directory: "/apps/OpenSignServer" # Location of package manifests
schedule:
interval: "weekly"
# maintain dependencies for microfrontends
- package-ecosystem: "npm" # See documentation for possible values
directory: "microfrontends/SignDocuments" # Location of package manifests
schedule:
interval: "weekly"
+7 -4
View File
@@ -2,7 +2,7 @@ name: ci
on:
push:
branches:
- 'main'
- 'staging'
jobs:
docker:
@@ -11,9 +11,9 @@ jobs:
matrix:
include:
- image: amolshejole/OpenSign
dockerfile: apps/OpenSign/Dockerfile
dockerfile: apps/OpenSign/Dockerhubfile
- image: amolshejole/OpenSignServer
dockerfile: apps/OpenSignServer/Dockerfile
dockerfile: apps/OpenSignServer/Dockerhubfile
steps:
-
name: Checkout
@@ -31,8 +31,11 @@ jobs:
with:
images: ${{ matrix.image }}
-
name: Debug - List files
name: Debug - List files opensign
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
uses: docker/build-push-action@v4
+3
View File
@@ -22,3 +22,6 @@
npm-debug.log*
yarn-debug.log*
yarn-error.log*
apps/OpenSign/public/mfbuild/*
microfrontends/SignDocuments/build/*
apps/OpenSignServer/files/files/*
+3 -4
View File
@@ -1,5 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx eslint '**/*.{js,jsx}'
npx pretty-quick --staged '**/*.{js,jsx}'
npm run lint-staged-changes
+3
View File
@@ -0,0 +1,3 @@
{
"*.js": "prettier --write"
}
+16 -79
View File
@@ -1,92 +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)
- Digital Ocean
- Localhost(Docker)
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.
## 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 -
- [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.
- **Access Contributor Instructions:** [Contributors Guide](https://docs.opensignlabs.com/docs/contribute/INSTALLATION)
## 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 -
- ReactJS frontend
- NodeJS API
- MongoDB database
- **Twitter:** [OpenSignHQ on Twitter](https://twitter.com/OpenSignHQ)
- **Facebook:** [OpenSign on Facebook](https://www.facebook.com/profile.php?id=61551030403669)
- **LinkedIn:** [OpenSign™ on LinkedIn](https://www.linkedin.com/company/opensign%E2%84%A2/)
- **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)
Below are the steps to follow -
- Execute `make build`
+6
View File
@@ -1,3 +1,9 @@
build:
cp .env.local_dev .env
rm -rf apps/OpenSign/public/mfbuild
cd microfrontends/SignDocuments && npm install && npm run build
docker compose up --build --force-recreate
run:
cp .env.local_dev .env
docker compose up -d
+23 -14
View File
@@ -1,8 +1,7 @@
<h1 align="center"><a href='https://www.opensignlabs.com'>OpenSign™</a></h1>
<div align="center">
<h1 align="center"><a href='https://www.opensignlabs.com'><img src=https://github.com/OpenSignLabs/OpenSign/assets/5486116/e518cc9c-5de3-47da-950b-f93336b9f14e></a>
</h1><div align="center">
The free and open source alternative to DocuSign
[The free and open source alternative to DocuSign](https://www.opensignlabs.com)
[![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/opensignlabs/opensign.svg)](http://isitmaintained.com/project/opensignlabs/opensign "Average time to resolve an issue")
[![All Contributors](https://img.shields.io/github/all-contributors/opensignlabs/opensign?color=ee8449&style=flat-square)](#contributors)
@@ -23,7 +22,7 @@ The free and open source alternative to DocuSign
<a href="https://www.linkedin.com/company/opensign%E2%84%A2/about/">LinkedIn</a>
## An open-source document e-signing solution
## The open-source document e-signing solution
---
</div>
@@ -39,23 +38,28 @@ The free and open source alternative to DocuSign
7. [Acknowledgments](#acknowledgments)
---
Please star ⭐ the repo to support us! 😀
### 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.
---
### Features
- **Secure Signing**: Utilizes state-of-the-art cryptographic algorithms to ensure the security & integrity of your documents.
- **User-Friendly Interface**: Designed with usability in mind, making it easy for both technical and non-technical users.
- **Multi-Platform Support**: Compatible with various browsers and devices.
- **Invite & collaborate users**: Bring multiple people from your team into the signing process, all within your own infrastructure.
- **Secure**: Allows for the easy, secure and seamless organization of your documents using 'OpenSigDrive'.
- **Audit Trails**: Keeps a detailed log of all activities related to the document signing process including IP addresses and access timings.
- **Completion Certificate**: Generate secure completion certificate as soon as a document is signed by all participants.
- **API Support**: Provides a robust API for integration into other software and services.
- **Secure PDF E-Signing:** With the help of Robust encryption algorithms, OpenSign™ ensures maximum security, privacy & compatibility.
- **Annotate Documents:** OpenSign™ allows you to annotate PDF documents with an advanced signing pad that comes with hand drawn signatures support as well as uploaded images & saved signatures for the simplest signing experience.
- **User-Friendly Interface:** OpenSign™ was built while keeping Intuitive design in mind for ease of use. Features like "Sign yourself", "One click signatures" and "OpenSign Drive" makes it stand out of the crowd and even makes it better than a lot of so-called industry leaders.
- **Multi-signer Support:** OpenSign's ability to invite multiple signers for signing along with the ability to invite witnesses & being able to enforce signing in a sequence makes it the only open source solution that is fully loaded and allows it to compete head-to-head with established players.
- **Email Unique Code(OTP) verification support for guest signers:** With OpenSign™, your documents are fully secure even when being signed by guest users. Guest signers can only sign the document after entering a unique code sent to their email address. 
- **"Expiring Docs" & "Rejection":** You can set documents to expire after certain number of days after which nobody will be able to sign it. Not just this, OpenSign also allows signers to reject signing a document.
- **Beautiful email templates:** All document signing invitations, completion notifications & reminders are formatted using great looking email templates.
- **PDF Template Creation(coming soon):** OpenSign™ allows you to create and store PDF document templates for repeated use thereby saving you a lot of time.
- **OpenSign™ Drive:** It is a centralised secure vault for your signed documents that makes storing, signing, organizing, sharing & achieving your docs a breeze.
- **Audit Trails & completion certificate:** Being a security focused solution, OpenSign™ makes it a top priority to save detailed logs for tracking document activities along with time-stamps, IP addresses, email IDs & phone numbers. A completion certificate is generated as soon as document is completed which contains all the document related logs for added safety.
- **API Support(coming soon):** OpenSign™ API allows seamless integration into existing systems and software. APIs will soon be available as a cloud hosted solution.
- **Integrations:** Seamless integrations with various Cloud storage systems, CRMs & enterprise platforms is coming soon.
<img src=https://github.com/OpenSignLabs/OpenSign/assets/5486116/b37ff443-7099-4273-9aeb-21c46d7154cf height='200'>
<img src=https://github.com/OpenSignLabs/OpenSign/assets/5486116/86db91b7-6c2f-4885-a33c-58f4fd35ec89 height='200'>
@@ -125,6 +129,11 @@ We would like to thank all our contributors and users for their support and feed
<td align="center" valign="top" width="14.28%"><a href="https://github.com/rishabjasrotia"><img src="https://avatars.githubusercontent.com/u/33950743?v=4?s=100" width="100px;" alt="Rishab"/><br /><sub><b>Rishab</b></sub></a><br /><a href="#code-rishabjasrotia" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://session.it"><img src="https://avatars.githubusercontent.com/u/327285?v=4?s=100" width="100px;" alt="Maurizio Pillitu"/><br /><sub><b>Maurizio Pillitu</b></sub></a><br /><a href="#bug-maoo" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://luisparra.dev"><img src="https://avatars.githubusercontent.com/u/16653744?v=4?s=100" width="100px;" alt="Luis Parra"/><br /><sub><b>Luis Parra</b></sub></a><br /><a href="#a11y-lsprr" title="Accessibility">️♿️</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Govinda04"><img src="https://avatars.githubusercontent.com/u/50038172?v=4?s=100" width="100px;" alt="Govinda Kocharekar"/><br /><sub><b>Govinda Kocharekar</b></sub></a><br /><a href="#code-Govinda04" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://bilal.cc"><img src="https://avatars.githubusercontent.com/u/55330484?v=4?s=100" width="100px;" alt="Bilal Ahmad Bhat"/><br /><sub><b>Bilal Ahmad Bhat</b></sub></a><br /><a href="#code-crediblebilal" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/VikramNagwal"><img src="https://avatars.githubusercontent.com/u/123088024?v=4?s=100" width="100px;" alt="Vikram"/><br /><sub><b>Vikram</b></sub></a><br /><a href="#code-VikramNagwal" title="Code">💻</a></td>
</tr>
</tbody>
</table>
+1
View File
@@ -10,6 +10,7 @@
# production
/build
/mfbuild
# misc
.env
+2 -2
View File
@@ -1,5 +1,5 @@
# Use an official Node runtime as the base image
FROM node:16
FROM node:18
# Set the working directory inside the container
WORKDIR /usr/src/app
@@ -21,5 +21,5 @@ EXPOSE 3000
# ENV NODE_ENV production
# Run the application
CMD ["npm", "start"]
ENTRYPOINT npm run start-dev
+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": {
singleton: true,
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",
"dependencies": {
"@reduxjs/toolkit": "^1.9.7",
"@rjsf/core": "^5.13.0",
"@rjsf/utils": "^5.13.0",
"@rjsf/validator-ajv8": "^5.13.0",
"axios": "^1.5.1",
"axios": "^1.6.0",
"daisyui": "^3.9.2",
"file-saver": "^2.0.5",
"html-react-parser": "^4.2.2",
"json-rules-engine-simplified": "^0.1.17",
"jwt-decode": "^3.1.2",
"jwt-decode": "^4.0.0",
"mf-cra": "^0.0.5",
"moment": "^2.29.4",
"parse": "^4.2.0",
"parse": "^4.3.1",
"react": "^18.2.0",
"react-bootstrap": "^2.9.0",
"react-dnd": "^16.0.1",
@@ -39,20 +36,19 @@
"reactour": "^1.19.2",
"redux": "^4.2.1",
"redux-thunk": "^2.4.2",
"rjsf-conditionals": "github:prafullnavkar-nxg/rjsf-conditionals",
"serve": "^14.2.1",
"styled-components": "^4.4.1",
"web-vitals": "^2.1.4"
},
"devDependencies": {
"@babel/runtime-corejs2": "^7.23.2",
"@babel/runtime-corejs2": "^7.23.9",
"autoprefixer": "^10.4.16",
"commitizen": "^4.3.0",
"eslint": "^8.51.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.33.2",
"lint-staged": "^15.0.1",
"postcss": "^8.4.31",
"lint-staged": "^15.2.2",
"postcss": "^8.4.35",
"prettier": "^2.8.0",
"pretty-quick": "^3.1.3",
"tailwindcss": "^3.3.3"
@@ -90,11 +86,11 @@
}
},
"node_modules/@babel/code-frame": {
"version": "7.22.13",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
"integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
"version": "7.23.5",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz",
"integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==",
"dependencies": {
"@babel/highlight": "^7.22.13",
"@babel/highlight": "^7.23.4",
"chalk": "^2.4.2"
},
"engines": {
@@ -180,11 +176,11 @@
}
},
"node_modules/@babel/generator": {
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
"integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
"version": "7.23.6",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz",
"integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==",
"dependencies": {
"@babel/types": "^7.23.0",
"@babel/types": "^7.23.6",
"@jridgewell/gen-mapping": "^0.3.2",
"@jridgewell/trace-mapping": "^0.3.17",
"jsesc": "^2.5.1"
@@ -463,9 +459,9 @@
}
},
"node_modules/@babel/helper-string-parser": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz",
"integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==",
"version": "7.23.4",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz",
"integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==",
"engines": {
"node": ">=6.9.0"
}
@@ -513,9 +509,9 @@
}
},
"node_modules/@babel/highlight": {
"version": "7.22.20",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz",
"integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==",
"version": "7.23.4",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz",
"integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==",
"dependencies": {
"@babel/helper-validator-identifier": "^7.22.20",
"chalk": "^2.4.2",
@@ -526,9 +522,9 @@
}
},
"node_modules/@babel/parser": {
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
"integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
"version": "7.23.9",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz",
"integrity": "sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==",
"bin": {
"parser": "bin/babel-parser.js"
},
@@ -1986,9 +1982,9 @@
}
},
"node_modules/@babel/runtime-corejs2": {
"version": "7.23.2",
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs2/-/runtime-corejs2-7.23.2.tgz",
"integrity": "sha512-lTwRWGcAUBANnxD0A4c5/wKQ0eLhgdAy9kdY2rzTmmliumBQ8u8awykMnaQAnZR3PC47jLRjGoj+hozZqy9Bww==",
"version": "7.23.9",
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs2/-/runtime-corejs2-7.23.9.tgz",
"integrity": "sha512-lwwDy5QfMkO2rmSz9AvLj6j2kWt5a4ulMi1t21vWQEO0kNCFslHoszat8reU/uigIQSUDF31zraZG/qMkcqAlw==",
"dev": true,
"dependencies": {
"core-js": "^2.6.12",
@@ -1999,22 +1995,17 @@
}
},
"node_modules/@babel/runtime-corejs3": {
"version": "7.21.0",
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.21.0.tgz",
"integrity": "sha512-TDD4UJzos3JJtM+tHX+w2Uc+KWj7GV+VKKFdMVd2Rx8sdA19hcc3P3AHFYd5LVOw+pYuSd5lICC3gm52B6Rwxw==",
"version": "7.23.2",
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.23.2.tgz",
"integrity": "sha512-54cIh74Z1rp4oIjsHjqN+WM4fMyCBYe+LpZ9jWm51CZ1fbH3SkAzQD/3XLoNkjbJ7YEmjobLXyvQrFypRHOrXw==",
"dependencies": {
"core-js-pure": "^3.25.1",
"regenerator-runtime": "^0.13.11"
"core-js-pure": "^3.30.2",
"regenerator-runtime": "^0.14.0"
},
"engines": {
"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": {
"version": "7.22.15",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
@@ -2029,19 +2020,19 @@
}
},
"node_modules/@babel/traverse": {
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.0.tgz",
"integrity": "sha512-t/QaEvyIoIkwzpiZ7aoSKK8kObQYeF7T2v+dazAYCb8SXtp58zEVkWW7zAnju8FNKNdr4ScAOEDmMItbyOmEYw==",
"version": "7.23.9",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.9.tgz",
"integrity": "sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==",
"dependencies": {
"@babel/code-frame": "^7.22.13",
"@babel/generator": "^7.23.0",
"@babel/code-frame": "^7.23.5",
"@babel/generator": "^7.23.6",
"@babel/helper-environment-visitor": "^7.22.20",
"@babel/helper-function-name": "^7.23.0",
"@babel/helper-hoist-variables": "^7.22.5",
"@babel/helper-split-export-declaration": "^7.22.6",
"@babel/parser": "^7.23.0",
"@babel/types": "^7.23.0",
"debug": "^4.1.0",
"@babel/parser": "^7.23.9",
"@babel/types": "^7.23.9",
"debug": "^4.3.1",
"globals": "^11.1.0"
},
"engines": {
@@ -2049,11 +2040,11 @@
}
},
"node_modules/@babel/types": {
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
"integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
"version": "7.23.9",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz",
"integrity": "sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==",
"dependencies": {
"@babel/helper-string-parser": "^7.22.5",
"@babel/helper-string-parser": "^7.23.4",
"@babel/helper-validator-identifier": "^7.22.20",
"to-fast-properties": "^2.0.0"
},
@@ -3921,85 +3912,6 @@
"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": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
@@ -5612,9 +5524,9 @@
}
},
"node_modules/axios": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.5.1.tgz",
"integrity": "sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==",
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.0.tgz",
"integrity": "sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg==",
"dependencies": {
"follow-redirects": "^1.15.0",
"form-data": "^4.0.0",
@@ -6675,16 +6587,16 @@
}
},
"node_modules/cli-truncate": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz",
"integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==",
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz",
"integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==",
"dev": true,
"dependencies": {
"slice-ansi": "^5.0.0",
"string-width": "^5.0.0"
"string-width": "^7.0.0"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -6702,18 +6614,24 @@
"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": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz",
"integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==",
"dev": true,
"dependencies": {
"eastasianwidth": "^0.2.0",
"emoji-regex": "^9.2.2",
"strip-ansi": "^7.0.1"
"emoji-regex": "^10.3.0",
"get-east-asian-width": "^1.0.0",
"strip-ansi": "^7.1.0"
},
"engines": {
"node": ">=12"
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -6965,27 +6883,6 @@
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"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": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -7132,9 +7029,9 @@
}
},
"node_modules/crypto-js": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz",
"integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==",
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==",
"optional": true
},
"node_modules/crypto-random-string": {
@@ -7676,14 +7573,6 @@
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
"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": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
@@ -9505,9 +9394,9 @@
"integrity": "sha512-bHWEmjLsTjGP9gVs7P3Hyl+oY5NlMW8aTSPdTJ+X2GKt6glDctt9fUCLbRV+d/l8NDC40+FxMjp9WlTQXaQALw=="
},
"node_modules/follow-redirects": {
"version": "1.15.3",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz",
"integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==",
"version": "1.15.5",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz",
"integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==",
"funding": [
{
"type": "individual",
@@ -9810,6 +9699,18 @@
"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": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz",
@@ -10506,12 +10407,9 @@
"integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ=="
},
"node_modules/idb-keyval": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.0.tgz",
"integrity": "sha512-uw+MIyQn2jl3+hroD7hF8J7PUviBU7BPKWw4f/ISf32D4LoGu98yHjrzWWJDASu9QNrX10tCJqk9YY0ClWm8Ng==",
"dependencies": {
"safari-14-idb-fix": "^3.0.0"
}
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.1.tgz",
"integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg=="
},
"node_modules/identity-obj-proxy": {
"version": "3.0.0",
@@ -13418,27 +13316,6 @@
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
"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": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@@ -13516,9 +13393,12 @@
}
},
"node_modules/jwt-decode": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz",
"integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A=="
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz",
"integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==",
"engines": {
"node": ">=18"
}
},
"node_modules/keyv": {
"version": "4.5.4",
@@ -13608,21 +13488,21 @@
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
},
"node_modules/lint-staged": {
"version": "15.0.1",
"resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.0.1.tgz",
"integrity": "sha512-2IU5OWmCaxch0X0+IBF4/v7sutpB+F3qoXbro43pYjQTOo5wumckjxoxn47pQBqqBsCWrD5HnI2uG/zJA7isew==",
"version": "15.2.2",
"resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.2.tgz",
"integrity": "sha512-TiTt93OPh1OZOsb5B7k96A/ATl2AjIZo+vnzFZ6oHK5FuTk63ByDtxGQpHm+kFETjEWqgkF95M8FRXKR/LEBcw==",
"dev": true,
"dependencies": {
"chalk": "5.3.0",
"commander": "11.1.0",
"debug": "4.3.4",
"execa": "8.0.1",
"lilconfig": "2.1.0",
"listr2": "7.0.1",
"lilconfig": "3.0.0",
"listr2": "8.0.1",
"micromatch": "4.0.5",
"pidtree": "0.6.0",
"string-argv": "0.3.2",
"yaml": "2.3.2"
"yaml": "2.3.4"
},
"bin": {
"lint-staged": "bin/lint-staged.js"
@@ -13711,6 +13591,15 @@
"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": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
@@ -13790,29 +13679,29 @@
}
},
"node_modules/lint-staged/node_modules/yaml": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.2.tgz",
"integrity": "sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg==",
"version": "2.3.4",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz",
"integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==",
"dev": true,
"engines": {
"node": ">= 14"
}
},
"node_modules/listr2": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/listr2/-/listr2-7.0.1.tgz",
"integrity": "sha512-nz+7hwgbDp8eWNoDgzdl4hA/xDSLrNRzPu1TLgOYs6l5Y+Ma6zVWWy9Oyt9TQFONwKoSPoka3H50D3vD5EuNwg==",
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/listr2/-/listr2-8.0.1.tgz",
"integrity": "sha512-ovJXBXkKGfq+CwmKTjluEqFi3p4h8xvkxGQQAQan22YCgef4KZ1mKGjzfGh6PL6AW5Csw0QiQPNuQyH+6Xk3hA==",
"dev": true,
"dependencies": {
"cli-truncate": "^3.1.0",
"cli-truncate": "^4.0.0",
"colorette": "^2.0.20",
"eventemitter3": "^5.0.1",
"log-update": "^5.0.1",
"log-update": "^6.0.0",
"rfdc": "^1.3.0",
"wrap-ansi": "^8.1.0"
"wrap-ansi": "^9.0.0"
},
"engines": {
"node": ">=16.0.0"
"node": ">=18.0.0"
}
},
"node_modules/listr2/node_modules/ansi-regex": {
@@ -13839,6 +13728,12 @@
"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": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
@@ -13846,17 +13741,17 @@
"dev": true
},
"node_modules/listr2/node_modules/string-width": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz",
"integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==",
"dev": true,
"dependencies": {
"eastasianwidth": "^0.2.0",
"emoji-regex": "^9.2.2",
"strip-ansi": "^7.0.1"
"emoji-regex": "^10.3.0",
"get-east-asian-width": "^1.0.0",
"strip-ansi": "^7.1.0"
},
"engines": {
"node": ">=12"
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -13878,17 +13773,17 @@
}
},
"node_modules/listr2/node_modules/wrap-ansi": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
"integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz",
"integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==",
"dev": true,
"dependencies": {
"ansi-styles": "^6.1.0",
"string-width": "^5.0.1",
"strip-ansi": "^7.0.1"
"ansi-styles": "^6.2.1",
"string-width": "^7.0.0",
"strip-ansi": "^7.1.0"
},
"engines": {
"node": ">=12"
"node": ">=18"
},
"funding": {
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
@@ -13934,21 +13829,11 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"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": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
"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": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
@@ -14081,34 +13966,34 @@
}
},
"node_modules/log-update": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/log-update/-/log-update-5.0.1.tgz",
"integrity": "sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==",
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/log-update/-/log-update-6.0.0.tgz",
"integrity": "sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==",
"dev": true,
"dependencies": {
"ansi-escapes": "^5.0.0",
"ansi-escapes": "^6.2.0",
"cli-cursor": "^4.0.0",
"slice-ansi": "^5.0.0",
"strip-ansi": "^7.0.1",
"wrap-ansi": "^8.0.1"
"slice-ansi": "^7.0.0",
"strip-ansi": "^7.1.0",
"wrap-ansi": "^9.0.0"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/log-update/node_modules/ansi-escapes": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-5.0.0.tgz",
"integrity": "sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==",
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.0.tgz",
"integrity": "sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==",
"dev": true,
"dependencies": {
"type-fest": "^1.0.2"
"type-fest": "^3.0.0"
},
"engines": {
"node": ">=12"
"node": ">=14.16"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -14153,6 +14038,27 @@
"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": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz",
@@ -14169,18 +14075,34 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/log-update/node_modules/string-width": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
"node_modules/log-update/node_modules/slice-ansi": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz",
"integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==",
"dev": true,
"dependencies": {
"eastasianwidth": "^0.2.0",
"emoji-regex": "^9.2.2",
"strip-ansi": "^7.0.1"
"ansi-styles": "^6.2.1",
"is-fullwidth-code-point": "^5.0.0"
},
"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": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -14202,29 +14124,29 @@
}
},
"node_modules/log-update/node_modules/type-fest": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz",
"integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==",
"version": "3.13.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz",
"integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==",
"dev": true,
"engines": {
"node": ">=10"
"node": ">=14.16"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/log-update/node_modules/wrap-ansi": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
"integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz",
"integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==",
"dev": true,
"dependencies": {
"ansi-styles": "^6.1.0",
"string-width": "^5.0.1",
"strip-ansi": "^7.0.1"
"ansi-styles": "^6.2.1",
"string-width": "^7.0.0",
"strip-ansi": "^7.1.0"
},
"engines": {
"node": ">=12"
"node": ">=18"
},
"funding": {
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
@@ -14310,17 +14232,6 @@
"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": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz",
@@ -14624,9 +14535,9 @@
}
},
"node_modules/nanoid": {
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
"version": "3.3.7",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
"funding": [
{
"type": "github",
@@ -15128,14 +15039,14 @@
}
},
"node_modules/parse": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/parse/-/parse-4.2.0.tgz",
"integrity": "sha512-K8bWs0wM2qRhkSr6N16j8OvsF6Uallrynqng9e+tzR3RdKuB09vaJh48qrf9MbiJ1Ya4JZI7AfEHYF+ywEKs7Q==",
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/parse/-/parse-4.3.1.tgz",
"integrity": "sha512-ypLPhMPFsJY+C2MXg6HdrVu6ielsL+kUjcSqh7J01lPC5oBuLh70F9YMQSw51QBocEeMSVgB7eUorFOH+MkVpA==",
"dependencies": {
"@babel/runtime-corejs3": "7.21.0",
"idb-keyval": "6.2.0",
"@babel/runtime-corejs3": "7.23.2",
"idb-keyval": "6.2.1",
"react-native-crypto-js": "1.0.0",
"uuid": "9.0.0",
"uuid": "9.0.1",
"ws": "8.13.0",
"xmlhttprequest": "1.8.0"
},
@@ -15143,7 +15054,7 @@
"node": ">=14.21.0 <17 || >=18 <20"
},
"optionalDependencies": {
"crypto-js": "4.1.1"
"crypto-js": "4.2.0"
}
},
"node_modules/parse-json": {
@@ -15173,9 +15084,13 @@
}
},
"node_modules/parse/node_modules/uuid": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
"integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==",
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
"funding": [
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
],
"bin": {
"uuid": "dist/bin/uuid"
}
@@ -15445,9 +15360,9 @@
}
},
"node_modules/postcss": {
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
"version": "8.4.35",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz",
"integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==",
"funding": [
{
"type": "opencollective",
@@ -15463,7 +15378,7 @@
}
],
"dependencies": {
"nanoid": "^3.3.6",
"nanoid": "^3.3.7",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
},
@@ -18183,9 +18098,9 @@
}
},
"node_modules/rfdc": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz",
"integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==",
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz",
"integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==",
"dev": true
},
"node_modules/rimraf": {
@@ -18202,26 +18117,6 @@
"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": {
"version": "2.79.1",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz",
@@ -18331,11 +18226,6 @@
"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": {
"version": "1.0.1",
"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",
"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": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+11 -12
View File
@@ -4,18 +4,15 @@
"private": true,
"dependencies": {
"@reduxjs/toolkit": "^1.9.7",
"@rjsf/core": "^5.13.0",
"@rjsf/utils": "^5.13.0",
"@rjsf/validator-ajv8": "^5.13.0",
"axios": "^1.5.1",
"axios": "^1.6.0",
"daisyui": "^3.9.2",
"file-saver": "^2.0.5",
"html-react-parser": "^4.2.2",
"json-rules-engine-simplified": "^0.1.17",
"jwt-decode": "^3.1.2",
"jwt-decode": "^4.0.0",
"mf-cra": "^0.0.5",
"moment": "^2.29.4",
"parse": "^4.2.0",
"parse": "^4.3.1",
"react": "^18.2.0",
"react-bootstrap": "^2.9.0",
"react-dnd": "^16.0.1",
@@ -34,7 +31,6 @@
"reactour": "^1.19.2",
"redux": "^4.2.1",
"redux-thunk": "^2.4.2",
"rjsf-conditionals": "github:prafullnavkar-nxg/rjsf-conditionals",
"serve": "^14.2.1",
"styled-components": "^4.4.1",
"web-vitals": "^2.1.4"
@@ -42,8 +38,11 @@
"scripts": {
"start": "serve -s build",
"start-dev": "mf-cra start",
"build": "rm -rf public/mfbuild && npm run micro && CI=false && mf-cra build",
"version": "curl -s https://api.github.com/repos/opensignlabs/opensign/releases/latest | grep '\"tag_name\":' | awk -F '\"' '{print $4}' > ./public/version.txt",
"build": "npm run version && rm -rf public/mfbuild && npm run micro && CI=false && mf-cra build",
"micro": "cd ../../microfrontends/SignDocuments && npm install && npm run build",
"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",
"eject": "react-scripts eject",
"release": "standard-version",
@@ -73,16 +72,16 @@
}
},
"devDependencies": {
"@babel/runtime-corejs2": "^7.23.2",
"@babel/runtime-corejs2": "^7.23.9",
"autoprefixer": "^10.4.16",
"commitizen": "^4.3.0",
"eslint": "^8.51.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.33.2",
"lint-staged": "^15.0.1",
"postcss": "^8.4.31",
"lint-staged": "^15.2.2",
"postcss": "^8.4.35",
"prettier": "^2.8.0",
"pretty-quick": "^3.1.3",
"tailwindcss": "^3.3.3"
}
}
}
+2 -2
View File
@@ -31,7 +31,7 @@
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous" />
<title>Open sign</title>
<title>OpenSign</title>
</head>
<body>
@@ -50,4 +50,4 @@
-->
</body>
</html>
</html>
+1
View File
@@ -0,0 +1 @@
v1.1.1-beta
+25 -75
View File
@@ -7,7 +7,7 @@ import Signup from "./routes/Signup";
import Form from "./routes/Form";
import Report from "./routes/Report";
import Dashboard from "./routes/Dashboard";
import PlanSubscriptions from "./routes/PlanSubscriptions";
import Subscriptions from "./routes/PlanSubscriptions";
import HomeLayout from "./layout/HomeLayout";
import UserProfile from "./routes/UserProfile";
import PageNotFound from "./routes/PageNotFound";
@@ -15,6 +15,10 @@ import ForgetPassword from "./routes/ForgetPassword";
import ChangePassword from "./routes/ChangePassword";
import ReportMicroapp from "./components/ReportMicroapp";
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() {
const [isloading, setIsLoading] = useState(true);
@@ -58,88 +62,34 @@ function App() {
) : (
<BrowserRouter>
<Routes>
<Route exact path="/" element={<Login />} />
<Route exact path="/signup" element={<Signup />} />
<Route element={<ValidateRoute />}>
<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="/forgetpassword" element={<ForgetPassword />} />
{process.env.REACT_APP_ENABLE_SUBSCRIPTION && (
<>
<Route exact path="/pgsignup" element={<Pgsignup />} />
<Route
exact
path="/subscription"
element={<PlanSubscriptions />}
/>
<Route exact path="/subscription" element={<Subscriptions />} />
</>
)}
<Route
exact
path="/changepassword"
element={
<HomeLayout>
<ChangePassword />
</HomeLayout>
}
/>
<Route
path="/mf/:remoteApp/*"
element={
<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 element={<HomeLayout />}>
<Route path="/changepassword" element={<ChangePassword />} />
<Route path="/mf/:remoteApp/*" element={<Microapp />} />
<Route path="/asmf/:remoteApp/*" element={<Microapp />} />
<Route path="/rpmf/:remoteApp/*" element={<ReportMicroapp />} />
<Route path="/form/:id" element={<Form />} />
<Route path="/report/:id" element={<Report />} />
<Route path="/dashboard/:id" element={<Dashboard />} />
<Route path="/profile" element={<UserProfile />} />
<Route path="/generatetoken" element={<GenerateToken />} />
<Route path="/webhook" element={<Webhook />} />
</Route>
<Route path="*" element={<PageNotFound />} />
{/* <Route exact path="/ForgotPassword" element={<ForgotPassword />} /> */}
</Routes>
</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 Parse from "parse";
import axios from "axios";
import { modalCancelBtnColor, modalSubmitBtnColor } from "../constant/const";
const AppendFormInForm = (props) => {
const [name, setName] = useState("");
@@ -32,6 +33,7 @@ const AppendFormInForm = (props) => {
try {
const query = new Parse.Query("contracts_Contactbook");
query.equalTo("CreatedBy", user);
query.notEqualTo("IsDeleted", true);
query.equalTo("Email", user.getEmail());
const res = await query.first();
// console.log(res);
@@ -45,6 +47,7 @@ const AppendFormInForm = (props) => {
// Define a function to handle form submission
const handleSubmit = async (e) => {
e.preventDefault();
e.stopPropagation();
setIsLoader(true);
Parse.serverURL = parseBaseUrl;
Parse.initialize(parseAppId);
@@ -104,13 +107,18 @@ const AppendFormInForm = (props) => {
const res = await contactQuery.save();
const parseData = JSON.parse(JSON.stringify(res));
props.details({
value: parseData[props.valueKey],
label: parseData[props.displayKey]
});
if (props.details) {
props.details({
value: parseData[props.valueKey],
label: parseData[props.displayKey]
});
}
if (props.closePopup) {
props.closePopup();
}
if (props.handleUserData) {
props.handleUserData(parseData);
}
setIsLoader(false);
// Reset the form fields
@@ -157,13 +165,18 @@ const AppendFormInForm = (props) => {
const res = await contactQuery.save();
const parseData = JSON.parse(JSON.stringify(res));
props.details({
value: parseData[props.valueKey],
label: parseData[props.displayKey]
});
if (props.details) {
props.details({
value: parseData[props.valueKey],
label: parseData[props.displayKey]
});
}
if (props.closePopup) {
props.closePopup();
}
if (props.handleUserData) {
props.handleUserData(parseData);
}
setIsLoader(false);
// Reset the form fields
setAddYourself(false);
@@ -241,7 +254,24 @@ const AppendFormInForm = (props) => {
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
disabled={addYourself}
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"
@@ -261,36 +291,19 @@ const AppendFormInForm = (props) => {
/>
</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
disabled={addYourself}
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
/>
</div>
<div className="mt-4 flex justify-start">
<button
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
</button>
<button
type="button"
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
</button>
+22 -7
View File
@@ -1,8 +1,21 @@
import React, { useEffect, useState } from "react";
import Package from "../../package.json";
import axios from "axios";
import { openInNewTab } from "../constant/Utils";
const Footer = () => {
const [showButton, setShowButton] = useState(false);
const [version, setVersion] = useState("");
useEffect(() => {
axios
.get("/version.txt")
.then((response) => {
setVersion(response.data); // Set the retrieved data to the state variable
})
.catch((error) => {
console.error("Error reading the file:", error);
});
}, []);
const handleScroll = () => {
if (window.pageYOffset >= 50) {
setShowButton(true);
@@ -25,16 +38,18 @@ const Footer = () => {
}, []);
const appName = "OpenSign™";
const openUrl = () => {
openInNewTab(
"https://github.com/OpenSignLabs/OpenSign/releases/tag/" + version
);
};
return (
<>
<div className="bg-[#222c3c] text-[#98a6ba] text-center text-[13px] py-3">
All Rights Reserved &copy; {new Date().getFullYear()} &nbsp;
{appName}{" "}
(version:{" "}
{localStorage.getItem("appVersion") &&
`${Package.version}.${localStorage.getItem("appVersion")}`}
)
<span onClick={openUrl} className="hover:underline cursor-pointer">
{appName} ( version: {version ? version : `${Package.version} `})
</span>
</div>
<button
className={`${
+7
View File
@@ -4,6 +4,7 @@ import FullScreenButton from "./FullScreenButton";
import { useNavigate } from "react-router-dom";
import Parse from "parse";
import { useWindowSize } from "../hook/useWindowSize";
import { openInNewTab } from "../constant/Utils";
const Header = ({ showSidebar }) => {
const navigation = useNavigate();
const { width } = useWindowSize();
@@ -118,6 +119,12 @@ const Header = ({ showSidebar }) => {
<ul>
<li
className="hover:bg-gray-100 rounded-t-lg py-1 px-2 cursor-pointer font-normal"
onClick={() => openInNewTab("https://docs.opensignlabs.com")}
>
<i className="fa-solid fa-book"></i> Docs
</li>
<li
className="hover:bg-gray-100 py-1 px-2 cursor-pointer font-normal"
onClick={() => {
setIsOpen(false);
navigation("/profile");
+16 -13
View File
@@ -27,14 +27,14 @@ const LoginFacebook = ({
setThirdpartyLoader(true);
const details = {
Email: response.email,
Name: response.name,
Name: response.name
};
setUserDetails({ ...userDetails, ...details });
const fDetails = {
Id: response.userID,
AccessToken: response.accessToken,
Name: response.name,
Email: response.email,
Email: response.email
};
setFBDetails({ ...fBDetails, ...fDetails });
const res = await checkExtUser(fDetails);
@@ -42,9 +42,11 @@ const LoginFacebook = ({
};
const checkExtUser = async (details) => {
const extUser = new Parse.Query("contracts_Users");
extUser.equalTo("Email", details.Email);
const extRes = await extUser.first();
// const extUser = new Parse.Query("contracts_Users");
// extUser.equalTo("Email", details.Email);
// const extRes = await extUser.first();
const params = { email: details.Email };
const extRes = await Parse.Cloud.run("getUserDetails", params);
// console.log("extRes ", extRes);
if (extRes) {
const params = { ...details, Phone: extRes.get("Phone") };
@@ -84,7 +86,7 @@ const LoginFacebook = ({
email: userDetails.Email,
// "passsword":userDetails.Phone,
phone: userDetails.Phone,
role: "contracts_Admin",
role: "contracts_User",
company: userDetails.Company
}
};
@@ -209,18 +211,19 @@ const LoginFacebook = ({
<div>
<button
type="button"
className="btn btn-secondary"
onClick={() => setIsModal(false)}
style={{ marginRight: 10, width: 90 }}
onClick={() => handleSubmitbtn()}
className="btn btn-info"
style={{ marginRight: 10 }}
>
Cancel
Sign up
</button>
<button
type="button"
onClick={() => handleSubmitbtn()}
className="btn btn-info"
className="btn btn-secondary"
onClick={() => setIsModal(false)}
style={{ width: 90 }}
>
Sign up
Cancel
</button>
</div>
</form>
+157 -115
View File
@@ -1,7 +1,9 @@
import React, { useState, useRef } from "react";
import Parse from "parse";
import jwtDecode from "jwt-decode";
import { jwtDecode } from "jwt-decode";
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
@@ -42,7 +44,42 @@ const GoogleSignInBtn = ({
width: "187px"
});
});
const clearStorage = async () => {
if (Parse.User.current()) {
await Parse.User.logOut();
}
let baseUrl = localStorage.getItem("BaseUrl12");
let appid = localStorage.getItem("AppID12");
let applogo = localStorage.getItem("appLogo");
let domain = localStorage.getItem("domain");
let appversion = localStorage.getItem("appVersion");
let appTitle = localStorage.getItem("appTitle");
let defaultmenuid = localStorage.getItem("defaultmenuid");
let PageLanding = localStorage.getItem("PageLanding");
let _appName = localStorage.getItem("_appName");
let _app_objectId = localStorage.getItem("_app_objectId");
let appName = localStorage.getItem("appName");
let userSettings = localStorage.getItem("userSettings");
localStorage.clear();
localStorage.setItem("BaseUrl12", baseUrl);
localStorage.setItem("AppID12", appid);
localStorage.setItem("appLogo", applogo);
localStorage.setItem("domain", domain);
localStorage.setItem("appversion", appversion);
localStorage.setItem("appTitle", appTitle);
localStorage.setItem("defaultmenuid", defaultmenuid);
localStorage.setItem("PageLanding", PageLanding);
localStorage.setItem("_appName", _appName);
localStorage.setItem("_app_objectId", _app_objectId);
localStorage.setItem("appName", appName);
localStorage.setItem("userSettings", userSettings);
localStorage.setItem("baseUrl", baseUrl);
localStorage.setItem("parseAppId", appid);
};
const responseGoogle = async (response) => {
clearStorage();
setThirdpartyLoader(true);
// console.log("response ", response);
if (response.credential) {
@@ -66,9 +103,11 @@ const GoogleSignInBtn = ({
}
};
const checkExtUser = async (details) => {
const extUser = new Parse.Query("contracts_Users");
extUser.equalTo("Email", details.Gmail);
const extRes = await extUser.first();
// const extUser = new Parse.Query("contracts_Users");
// extUser.equalTo("Email", details.Gmail);
// const extRes = await extUser.first();
const params = { email: details.Gmail };
const extRes = await Parse.Cloud.run("getUserDetails", params);
// console.log("extRes ", extRes);
if (extRes) {
const params = { ...details, Phone: extRes.get("Phone") };
@@ -111,7 +150,7 @@ const GoogleSignInBtn = ({
email: userDetails.Email,
// "passsword":userDetails.Phone,
phone: userDetails.Phone,
role: "contracts_Admin",
role: "contracts_User",
company: userDetails.Company,
jobTitle: userDetails.Destination
}
@@ -141,6 +180,32 @@ const GoogleSignInBtn = ({
alert("Please fill required details!");
}
};
const handleCloseModal = () => {
setIsModal(false);
Parse.User.logOut();
let appdata = localStorage.getItem("userSettings");
let applogo = localStorage.getItem("appLogo");
let appName = localStorage.getItem("appName");
let defaultmenuid = localStorage.getItem("defaultmenuid");
let PageLanding = localStorage.getItem("PageLanding");
let domain = localStorage.getItem("domain");
let _appName = localStorage.getItem("_appName");
let baseUrl = localStorage.getItem("BaseUrl12");
let appid = localStorage.getItem("AppID12");
localStorage.clear();
localStorage.setItem("appLogo", applogo);
localStorage.setItem("appName", appName);
localStorage.setItem("_appName", _appName);
localStorage.setItem("defaultmenuid", defaultmenuid);
localStorage.setItem("PageLanding", PageLanding);
localStorage.setItem("domain", domain);
localStorage.setItem("userSettings", appdata);
localStorage.setItem("BaseUrl12", baseUrl);
localStorage.setItem("AppID12", appid);
};
return (
<div style={{ position: "relative" }}>
{thirdpartyLoader && (
@@ -168,117 +233,94 @@ const GoogleSignInBtn = ({
</div>
)}
<div ref={googleBtn} className="text-sm"></div>
{isModal && (
<div
className="modal fade show"
id="exampleModal"
tabIndex="-1"
role="dialog"
style={{ display: "block", zIndex: 1 }}
>
<div className="modal-dialog" role="document">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title">Sign up form</h5>
<span>
<span></span>
</span>
</div>
<div className="modal-body">
<form>
<div className="form-group">
<label
htmlFor="Phone"
style={{ display: "flex" }}
className="col-form-label"
>
Phone{" "}
<span style={{ fontSize: 13, color: "red" }}>*</span>
</label>
<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="Destination"
style={{ display: "flex" }}
className="col-form-label"
>
Destination{" "}
<span style={{ fontSize: 13, color: "red" }}>*</span>
</label>
<input
type="text"
className="form-control"
id="Destination"
value={userDetails.Destination}
onChange={(e) =>
setUserDetails({
...userDetails,
Destination: e.target.value
})
}
required
/>
</div>
<div>
<button
type="button"
className="btn btn-secondary"
onClick={() => setIsModal(false)}
style={{ marginRight: 10, width: 90 }}
>
Cancel
</button>
<button
type="button"
onClick={() => handleSubmitbtn()}
className="btn btn-info"
>
Sign up
</button>
</div>
</form>
</div>
</div>
<ModalUi showClose={false} isOpen={isModal} title="Sign up form">
<form className="px-4 py-3">
<div className="mb-3">
<label
htmlFor="Phone"
style={{ display: "flex" }}
className="block text-xs text-gray-700 font-semibold"
>
Phone <span style={{ fontSize: 13, color: "red" }}>*</span>
</label>
<input
type="tel"
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
id="Phone"
value={userDetails.Phone}
onChange={(e) =>
setUserDetails({
...userDetails,
Phone: e.target.value
})
}
required
/>
</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>
);
};
+26 -50
View File
@@ -1,6 +1,6 @@
import useFederatedComponent from "mf-cra";
import React, { Suspense, useEffect } from "react";
import { useNavigate, useParams } from "react-router-dom";
import { useParams } from "react-router-dom";
const MicroappModal = () => {
const { remoteApp } = useParams();
@@ -28,60 +28,36 @@ const MicroappModal = () => {
}
// console.log("app ", remoteApp);
const { Component: RemoteComponent } = useFederatedComponent(obj);
const navigate = useNavigate();
// console.log("RemoteComponent ", RemoteComponent);
return (
<div className="w-full h-full flex items-center justify-center ">
{/* <!-- Modal Container --> */}
<div className="bg-white rounded-lg shadow-lg w-full">
{/* <!-- Modal Header --> */}
<div className="flex w-full items-center border-b-2 mb-2 p-2">
<button
className="focus:outline-none bg-blue-500 text-white text-sm shadow px-2.5 py-1 rounded"
id="closeModal"
onClick={(e) => {
e.preventDefault();
// setIsModal(false);
navigate(-1);
<div className="w-full">
<Suspense
fallback={
<div style={{ height: "300px" }}>
<div
style={{
marginLeft: "45%",
marginTop: "150px",
fontSize: "45px",
color: "#3dd3e0"
}}
className="loader-37"
></div>
</div>
}
>
<div
style={{
backgroundColor: "#ffffff",
width: "100%",
overflow: "hidden",
minHeight: "50vh"
}}
>
Back
</button>
{localStorage.getItem("domain") && (
<p className="flex-1 w-full text-sm md:text-base text-black text-center">
{localStorage.getItem("domain") === "contracts" ? "Document" : ""}
</p>
)}
</div>
{/* <!-- Modal Body --> */}
<div className="w-full">
<Suspense
fallback={
<div style={{ height: "300px" }}>
<div
style={{
marginLeft: "45%",
marginTop: "150px",
fontSize: "45px",
color: "#3dd3e0"
}}
className="loader-37"
></div>
</div>
}
>
<div
style={{
backgroundColor: "#ffffff",
width: "100%",
overflow: "hidden",
minHeight: "50vh"
}}
>
{RemoteComponent && <RemoteComponent />}
</div>
</Suspense>
</div>
{RemoteComponent && <RemoteComponent />}
</div>
</Suspense>
</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;
-894
View File
@@ -1,894 +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 {
var emp = Parse.Object.extend(
localStorage.getItem("extended_class")
);
var q = new Parse.Query(emp);
q.equalTo("UserId", currentUser);
res = await q.first();
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 {
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();
}
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();
}
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
);
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);
@@ -1,7 +1,6 @@
import React, { useState, useEffect } from "react";
import axios from "axios";
import Parse from "parse";
import onSearchFilter from "../../constant/searchQuery";
import getReplacedHashQuery from "../../constant/getReplacedHashQuery";
import "../../styles/loader.css";
import { useNavigate } from "react-router-dom";
@@ -35,14 +34,9 @@ const DashboardCard = (props) => {
let data = JSON.parse(localStorage.getItem("Extand_Class"));
res = data[0];
} else {
var emp = Parse.Object.extend(localStorage.getItem("extended_class"));
var q = new Parse.Query(emp);
q.equalTo("UserId", {
__type: "Pointer",
className: "_User",
objectId: currentUser
res = await Parse.Cloud.run("getUserDetails", {
email: currentUser.get("email")
});
res = await q.first();
if (res) res = res.toJSON();
}
if (res) {
@@ -50,12 +44,7 @@ const DashboardCard = (props) => {
var reg = /(\#.*?\#)/gi; // eslint-disable-line
var str = props.Data.query;
var test = "";
if (str.includes("#filterCondition#")) {
str = str.replace(
"#filterCondition#",
onSearchFilter(props.DefaultQuery)
);
}
if (props.Data.extendkey) {
let a = props.Data.extendkey.split(".");
if (a.length > 0) {
@@ -110,13 +99,10 @@ const DashboardCard = (props) => {
let data = JSON.parse(localStorage.getItem("Extand_Class"));
resr = data[0];
} else {
let emp = Parse.Object.extend(
localStorage.getItem("extended_class")
);
let q = new Parse.Query(emp);
q.equalTo("UserId", currentUser);
let t = await q.first();
resr = t.toJSON();
resr = await Parse.Cloud.run("getUserDetails", {
email: currentUser.get("email")
});
if (resr) resr = resr.toJSON();
}
let json = resr;
@@ -150,47 +136,65 @@ const DashboardCard = (props) => {
"X-Parse-Application-Id": parseAppId,
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
};
await axios.get(url, { headers: headers }).then((res) => {
if (res.data.results.length > 0) {
setLoading(false);
if (props.Data.key !== "count") {
setresponse(res.data.results[0][props.Data.key]);
} else {
if (props.Label === "Need your Signature") {
const listData = res.data?.results.filter(
(x) => x.Signers.length > 0
// handle need your sign report count
if (props.Data.Redirect_id === "4Hhwbp482K") {
const params = {
reportId: props.Data.Redirect_id,
skip: 0,
limit: 200
};
const url = `${parseBaseUrl}/functions/getReport`;
await axios
.post(url, params, {
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": parseAppId,
sessiontoken: localStorage.getItem("accesstoken")
}
})
.then((res) => {
const listData = res.data?.result.filter(
(x) => x.Signers.length > 0
);
let arr = [];
for (const obj of listData) {
const isSigner = obj.Signers.some(
(item) => item.UserId.objectId === currentUser.id
);
let arr = [];
for (const obj of listData) {
const isSigner = obj.Signers.some(
(item) => item.UserId.objectId === currentUser.id
);
if (isSigner) {
let isRecord;
if (obj?.AuditTrail && obj?.AuditTrail.length > 0) {
isRecord = obj?.AuditTrail.some(
(item) =>
item?.UserPtr?.UserId?.objectId === currentUser.id &&
item.Activity === "Signed"
);
} else {
isRecord = false;
}
if (isRecord === false) {
arr.push(obj);
}
if (isSigner) {
let isRecord;
if (obj?.AuditTrail && obj?.AuditTrail.length > 0) {
isRecord = obj?.AuditTrail.some(
(item) =>
item?.UserPtr?.UserId?.objectId === currentUser.id &&
item.Activity === "Signed"
);
} else {
isRecord = false;
}
if (isRecord === false) {
arr.push(obj);
}
}
setresponse(arr.length);
}
setresponse(arr.length);
setLoading(false);
});
} else {
await axios.get(url, { headers: headers }).then((res) => {
if (res.data.results.length > 0) {
setLoading(false);
if (props.Data.key !== "count") {
setresponse(res.data.results[0][props.Data.key]);
} else {
setresponse(res.data[props.Data.key]);
}
} else {
setresponse(0);
setLoading(false);
}
} else {
setresponse(0);
setLoading(false);
}
});
});
}
} catch (e) {
console.error("Problem", e);
setLoading(false);
@@ -227,13 +231,10 @@ const DashboardCard = (props) => {
let data = JSON.parse(localStorage.getItem("Extand_Class"));
res = data[0];
} else {
var emp = Parse.Object.extend(
localStorage.getItem("extended_class")
);
var q = new Parse.Query(emp);
q.equalTo("UserId", currentUser);
let resr = await q.first();
res = resr.toJSON();
let resr = await Parse.Cloud.run("getUserDetails", {
email: currentUser.get("email")
});
if (res) res = resr.toJSON();
}
let json = res;
@@ -9,39 +9,60 @@ function DashboardReport(props) {
const [isLoader, setIsLoader] = useState(true);
const [reportName, setReportName] = useState("");
const [actions, setActions] = useState([]);
const [heading, setHeading] = useState([]);
const [isNextRecord, setIsNextRecord] = useState(false);
const [isMoreDocs, setIsMoreDocs] = useState(true);
const abortController = new AbortController();
const docPerPage = 5;
useEffect(() => {
setReportName("");
getReportData(props.Record.reportId);
// Function returned from useEffect is called on unmount
return () => {
setIsLoader(true);
setList([]);
setIsNextRecord(false);
// Here it'll abort the fetch
abortController.abort();
};
// eslint-disable-next-line
}, [props.Record.reportId]);
const getReportData = async (id) => {
// below useEffect call when isNextRecord state is true and fetch next record
useEffect(() => {
if (isNextRecord) {
getReportData(props.Record.reportId, List.length, 200);
}
// eslint-disable-next-line
}, [isNextRecord]);
const getReportData = async (id, skipUserRecord = 0, limit = 200) => {
setIsLoader(true);
const json = reportJson(id);
if (json) {
setActions(json.actions);
setReportName(json.reportName);
const { className, params, keys, orderBy } = json;
setHeading(json.heading);
Parse.serverURL = localStorage.getItem("BaseUrl12");
Parse.initialize(localStorage.getItem("AppID12"));
const serverURL =
localStorage.getItem("BaseUrl12") + "classes/" + className;
const currentUser = Parse.User.current().id;
const strParams = JSON.stringify(params);
const strKeys = keys.join();
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("AppID12"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
sessiontoken: localStorage.getItem("accesstoken")
};
try {
const url = `${serverURL}?where=${strParams}&keys=${strKeys}&order=${orderBy}&include=AuditTrail.UserPtr`;
const res = await axios.get(url, { headers: headers });
// console.log("res ", res.data?.results);
const params = { reportId: id, skip: skipUserRecord, limit: limit };
const url = `${localStorage.getItem("BaseUrl12")}/functions/getReport`;
const res = await axios.post(url, params, {
headers: headers,
signal: abortController.signal // is used to cancel fetch query
});
if (id === "5Go51Q7T8r") {
const currentUser = Parse.User.current().id;
const listData = res.data?.results.filter(
(x) => x.Signers.length > 0
);
const listData = res.data?.result.filter((x) => x.Signers.length > 0);
let arr = [];
for (const obj of listData) {
const isSigner = obj.Signers.some(
@@ -63,14 +84,34 @@ function DashboardReport(props) {
}
}
}
setList(arr);
if (arr.length === docPerPage) {
setIsMoreDocs(true);
} else {
setIsMoreDocs(false);
}
setList((prevRecord) =>
prevRecord.length > 0 ? [...prevRecord, ...arr] : arr
);
} else {
setList(res.data?.results);
if (res.data.result.length === docPerPage) {
setIsMoreDocs(true);
} else {
setIsMoreDocs(false);
}
setIsNextRecord(false);
setList((prevRecord) =>
prevRecord.length > 0
? [...prevRecord, ...res.data.result]
: res.data.result
);
}
setIsLoader(false);
} catch (err) {
console.log("err ", err);
setIsLoader(false);
const isCancel = axios.isCancel(err);
if (!isCancel) {
console.log("err ", err);
setIsLoader(false);
}
}
} else {
setIsLoader(false);
@@ -101,8 +142,12 @@ function DashboardReport(props) {
<ReportTable
ReportName={reportName}
List={List}
act={"Sign"}
setList={setList}
actions={actions}
heading={heading}
setIsNextRecord={setIsNextRecord}
isMoreDocs={isMoreDocs}
docPerPage={docPerPage}
/>
) : (
<div className="flex items-center justify-center h-[100px] w-full bg-white rounded">
@@ -1,5 +1,4 @@
import React, { useState, Suspense, lazy } from "react";
import moment from "moment";
import React, { Suspense, lazy } from "react";
import ErrorBoundary from "../ErrorBoundary";
const DashboardCard = lazy(() => import("./DashboardCard"));
@@ -7,258 +6,6 @@ const DashboardCard = lazy(() => import("./DashboardCard"));
const DashboardReport = lazy(() => import("./DashboardReport"));
const GetDashboard = (props) => {
const [filter, setfilter] = useState("");
const [option, setoption] = useState("");
const onSearchFilter = (e) => {
let _search = e.target.value;
localStorage.setItem("DashboardDefaultFilter", _search);
switch (_search) {
case "Today": {
let d = new Date();
let formDate = new Date(
Date.UTC(d.getFullYear(), d.getMonth(), d.getDate(), 0, 0, 0)
).toISOString();
let Todate = new Date(
Date.UTC(d.getFullYear(), d.getMonth(), d.getDate(), 23, 59, 59)
).toISOString();
let Query = `'$gte':'${formDate}','$lte':'${Todate}'`;
setfilter(Query);
setoption(_search);
break;
}
case "Yesterday": {
let d1 = new Date();
d1.setDate(d1.getDate() - 1);
let yesFrDate = new Date(
Date.UTC(d1.getFullYear(), d1.getMonth(), d1.getDate(), 0, 0, 0)
).toISOString();
let YesTodate = new Date(
Date.UTC(d1.getFullYear(), d1.getMonth(), d1.getDate(), 23, 59, 59)
).toISOString();
let Query1 = `'$gte':'${yesFrDate}','$lte':'${YesTodate}'`;
setfilter(Query1);
setoption(_search);
break;
}
case "This week": {
let oneDay = 24 * 60 * 60 * 1000;
let curr = new Date(); // get current date
let first = curr.getDate() - curr.getDay(); // First day is the day of the month - the day of the week
let firstday = new Date(
new Date(
Date.UTC(
curr.getFullYear(),
curr.getMonth(),
curr.getDate(),
0,
0,
0
)
).setDate(first)
).toISOString();
let diffDays = Math.round(
Math.abs(
(new Date(
Date.UTC(
curr.getFullYear(),
curr.getMonth(),
curr.getDate(),
23,
59,
59
)
) -
new Date(firstday)) /
oneDay
)
); //Days since last week
let last = first + diffDays;
let lastday = new Date(
new Date(
Date.UTC(
curr.getFullYear(),
curr.getMonth(),
curr.getDate(),
23,
59,
59
)
).setDate(last)
).toISOString();
let Query2 = `'$gte':'${firstday}','$lte':'${lastday}'`;
setfilter(Query2);
setoption(_search);
break;
}
case "Last 7 days": {
let d7 = new Date();
let d7l = new Date();
d7.setDate(d7.getDate() - 7);
let l7t = new Date(
Date.UTC(d7l.getFullYear(), d7l.getMonth(), d7l.getDate(), 23, 59, 59)
).toISOString();
let date7 = new Date(
Date.UTC(d7.getFullYear(), d7.getMonth(), d7.getDate(), 0, 0, 0)
).toISOString();
let Query7 = `'$gte':'${date7}','$lte':'${l7t}'`;
setfilter(Query7);
setoption(_search);
break;
}
case "Last 14 days": {
let d14 = new Date();
let d14l = new Date();
let l14t = new Date(
Date.UTC(
d14l.getFullYear(),
d14l.getMonth(),
d14l.getDate(),
23,
59,
59
)
).toISOString();
d14.setDate(d14.getDate() - 14);
let date14 = new Date(
Date.UTC(d14.getFullYear(), d14.getMonth(), d14.getDate(), 0, 0, 0)
).toISOString();
let Query14 = `'$gte':'${date14}','$lte':'${l14t}'`;
setfilter(Query14);
setoption(_search);
break;
}
case "Last 30 days": {
let d30 = new Date();
let d30l = new Date();
let l30t = new Date(
Date.UTC(
d30l.getFullYear(),
d30l.getMonth(),
d30l.getDate(),
23,
59,
59
)
).toISOString();
d30.setDate(d30.getDate() - 30);
let date30 = new Date(
Date.UTC(d30.getFullYear(), d30.getMonth(), d30.getDate(), 0, 0, 0)
).toISOString();
let Query30 = `'$gte':'${date30}','$lte':'${l30t}'`;
setfilter(Query30);
setoption(_search);
break;
}
case "Last week": {
const from_date = moment().startOf("week").subtract(7, "days");
const to_date = moment().endOf("week").subtract(7, "days");
let Queryl = `'$gte':'${from_date.toISOString()}','$lte':'${to_date.toISOString()}'`;
setfilter(Queryl);
setoption(_search);
break;
}
case "This month": {
const tdate = new Date();
let tfirstDay = new Date(
tdate.getFullYear(),
tdate.getMonth(),
1
).toISOString();
let tlastDay = new Date(
tdate.getFullYear(),
tdate.getMonth() + 1,
0
).toISOString();
let Querylt = `'$gte':'${tfirstDay}','$lte':'${tlastDay}'`;
setfilter(Querylt);
setoption(_search);
break;
}
case "Last month": {
const ldate = new Date();
var lfirstDay = new Date(
ldate.getFullYear(),
ldate.getMonth() - 1,
2
).toISOString();
var llastDay = new Date(
ldate.getFullYear(),
ldate.getMonth(),
1
).toISOString();
let Queryltl = `'$gte':'${lfirstDay}','$lte':'${llastDay}'`;
setfilter(Queryltl);
setoption(_search);
break;
}
case "All": {
let fall = new Date(
new Date().getFullYear() - 100,
0,
1,
0,
0,
0
).toISOString();
let fall_year = `'$gte':'${fall}'`;
setfilter(fall_year);
setoption(_search);
break;
}
case "This year": {
let fcy = new Date(
new Date().getFullYear(),
0,
1,
0,
0,
0
).toISOString();
let lcy = new Date(
new Date().getFullYear(),
11,
31,
23,
59,
59
).toISOString();
let cur_year = `'$gte':'${fcy}','$lte':'${lcy}'`;
setfilter(cur_year);
setoption(_search);
break;
}
case "Last year": {
let fly = new Date(
new Date().getFullYear() - 1,
0,
1,
0,
0,
0
).toISOString();
let lly = new Date(
new Date().getFullYear() - 1,
11,
31,
23,
59,
59
).toISOString();
let last_year = `'$gte':'${fly}','$lte':'${lly}'`;
setfilter(last_year);
setoption(_search);
break;
}
default: {
setoption(_search);
break;
}
}
};
const renderSwitchWithTour = (col) => {
switch (col.widget.type) {
case "Card":
@@ -272,7 +19,6 @@ const GetDashboard = (props) => {
<DashboardCard
Icon={col.widget.icon}
Label={col.widget.label}
Filter={filter}
Format={col.widget.format && col.widget.format}
Data={col.widget.data}
FilterData={col.widget.filter}
@@ -281,50 +27,12 @@ const GetDashboard = (props) => {
</Suspense>
</div>
);
case "customeHtml":
return (
<div data-tut={col.widget.data.tourSection}>
<select
id="searchFiltr"
className="form-control"
value={
option ||
localStorage.getItem("DashboardDefaultFilter") ||
col.widget.data[0].default
}
onChange={onSearchFilter}
>
{col.widget.data[0].options.map((opt) => (
<option key={opt} value={opt}>
{opt}
</option>
))}
</select>
<br />
</div>
);
case "customeTag":
return (
<h3
data-tut={col.widget.data.tourSection}
style={{
marginBottom: "4px",
color: "currentColor",
marginLeft: "4px"
}}
>
{col.widget.label}
</h3>
);
case "report": {
let _filter = `${col.widget.filterKey}:${filter}`;
return (
<div data-tut={col.widget.data.tourSection}>
<Suspense fallback={<div>please wait</div>}>
<div className="mb-4 md:mb-0">
<DashboardReport Filter={_filter} Record={col.widget} />
<DashboardReport Record={col.widget} />
</div>
</Suspense>
</div>
@@ -346,7 +54,6 @@ const GetDashboard = (props) => {
<DashboardCard
Icon={col.widget.icon}
Label={col.widget.label}
Filter={filter}
Format={col.widget.format && col.widget.format}
Data={col.widget.data}
FilterData={col.widget.filter}
@@ -355,48 +62,11 @@ const GetDashboard = (props) => {
</Suspense>
</div>
);
case "customeHtml":
return (
<div>
<select
id="searchFiltr"
className="form-control"
value={
option ||
localStorage.getItem("DashboardDefaultFilter") ||
col.widget.data[0].default
}
onChange={onSearchFilter}
>
{col.widget.data[0].options.map((opt) => (
<option key={opt} value={opt}>
{opt}
</option>
))}
</select>
<br />
</div>
);
case "customeTag":
return (
<h3
style={{
marginBottom: "4px",
color: "currentColor",
marginLeft: "4px"
}}
>
{col.widget.label}
</h3>
);
case "report": {
let _filter = `${col.widget.filterKey}:${filter}`;
return (
<Suspense fallback={<div>please wait</div>}>
<div className="mb-4 md:mb-0">
<DashboardReport Filter={_filter} Record={col.widget} />
<DashboardReport Record={col.widget} />
</div>
</Suspense>
);
@@ -0,0 +1,147 @@
import React, { useEffect, useState } from "react";
import Parse from "parse";
import Alert from "../../primitives/Alert";
const CreateFolder = ({ parentFolderId, onSuccess, folderCls }) => {
const folderPtr = {
__type: "Pointer",
className: folderCls,
objectId: parentFolderId
};
const [name, setName] = useState("");
const [folderList, setFolderList] = useState([]);
const [isAlert, setIsAlert] = useState(false);
const [selectedParent, setSelectedParent] = useState();
const [alert, setAlert] = useState({ type: "info", message: "" });
useEffect(() => {
fetchFolder();
// eslint-disable-next-line
}, []);
const fetchFolder = async () => {
try {
const FolderQuery = new Parse.Query(folderCls);
if (parentFolderId) {
FolderQuery.equalTo("Folder", folderPtr);
FolderQuery.equalTo("Type", "Folder");
} else {
FolderQuery.doesNotExist("Folder");
FolderQuery.equalTo("Type", "Folder");
}
const res = await FolderQuery.find();
if (res) {
const result = JSON.parse(JSON.stringify(res));
if (result) {
setFolderList(result);
}
}
} catch (error) {
console.log("Err ", error);
}
};
const handleCreateFolder = async (event) => {
event.preventDefault();
if (name) {
const currentUser = Parse.User.current();
const exsitQuery = new Parse.Query(folderCls);
exsitQuery.equalTo("Name", name);
exsitQuery.equalTo("Type", "Folder");
if (parentFolderId) {
exsitQuery.equalTo("Folder", folderPtr);
}
const templExist = await exsitQuery.first();
if (templExist) {
setAlert({ type: "dange", message: "Folder already exist!" });
setIsAlert(true);
setTimeout(() => {
setIsAlert(false);
}, 1000);
} else {
const template = new Parse.Object(folderCls);
template.set("Name", name);
template.set("Type", "Folder");
if (selectedParent) {
template.set("Folder", {
__type: "Pointer",
className: folderCls,
objectId: selectedParent
});
} else if (parentFolderId) {
template.set("Folder", folderPtr);
}
template.set("CreatedBy", Parse.User.createWithoutData(currentUser.id));
const res = await template.save();
if (res) {
setAlert({
type: "success",
message: "Folder created successfully!"
});
setIsAlert(true);
setTimeout(() => {
setIsAlert(false);
}, 1000);
if (onSuccess) {
onSuccess(res);
}
}
}
} else {
setAlert({ type: "info", message: "Please fill folder name" });
setIsAlert(true);
setTimeout(() => {
setIsAlert(false);
}, 1000);
}
};
const handleOptions = (e) => {
setSelectedParent(e.target.value);
};
return (
<div>
{isAlert && <Alert type={alert.type}>{alert.message}</Alert>}
<div id="createFolder">
<h1 className="text-base font-semibold">Create Folder</h1>
<div className="text-xs mt-2">
<label className="block">
Name<span className="text-red-500 text-[13px]">*</span>
</label>
<input
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
value={name}
onChange={(e) => setName(e.target.value)}
required
/>
</div>
<div className="text-xs mt-2">
<label className="block">Parent Folder</label>
<select
value={selectedParent}
onChange={handleOptions}
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
>
<option>select</option>
{folderList.length > 0 &&
folderList.map((x) => (
<option key={x.objectId} value={x.objectId}>
{x.Name}
</option>
))}
</select>
</div>
<div>
<button
onClick={handleCreateFolder}
className="flex items-center rounded p-2 bg-[#32a3ac] text-white mt-3"
>
<i className="fa-solid fa-plus mr-1"></i>
<span>Create</span>
</button>
</div>
</div>
</div>
);
};
export default CreateFolder;
@@ -0,0 +1,60 @@
import React, { useCallback, useMemo } from "react";
import { useDropScript } from "../../hook/useScript";
const DROPBOX_APP_KEY = process.env.REACT_APP_DROPBOX_API_KEY; // App key
const DROPBOX_SDK_URL = "https://www.dropbox.com/static/api/2/dropins.js";
const DROPBOX_SCRIPT_ID = "dropboxjs";
export default function DropboxChooser({ children, onSuccess, onCancel }) {
useDropScript(DROPBOX_SDK_URL, {
attrs: {
id: DROPBOX_SCRIPT_ID,
"data-app-key": DROPBOX_APP_KEY
}
});
const options = useMemo(
() => ({
// Required. Called when a user selects an item in the Chooser.
success: (files) => {
// console.log("success", files);
onSuccess && onSuccess(files);
},
// Optional. Called when the user closes the dialog without selecting a file
// and does not include any parameters.
cancel: () => {
console.log("cancel");
onCancel && onCancel();
},
// Optional. "preview" (default) is a preview link to the document for sharing,
// "direct" is an expiring link to download the contents of the file. For more
linkType: "direct", // or "preview"
multiselect: false, // 是否支持多选
extensions: [".pdf"],
// Optional. A value of false (default) limits selection to files,
// while true allows the user to select both folders and files.
// You cannot specify `linkType: "direct"` when using `folderselect: true`.
folderselect: false // or true
}),
[onSuccess, onCancel]
);
const handleChoose = useCallback((e) => {
e.preventDefault()
if (window.Dropbox) {
window.Dropbox.choose(options);
}
}, [options]);
return (
<div onClick={handleChoose}>
{children || (
<button className="px-2 py-[2px] text-2xl rounded border-[1px] text-blue-400 border-gray-300 w-full">
<i className="fa-brands fa-dropbox"></i>
</button>
)}
</div>
);
}
@@ -1,265 +0,0 @@
import React, { useState, useEffect } from "react";
import { SaveFileSize } from "../../constant/saveFileSize";
import Parse from "parse";
import sanitizeFileName from "../../primitives/sanitizeFileName";
const FileUpload = (props) => {
const [parseBaseUrl] = useState(localStorage.getItem("baseUrl"));
const [parseAppId] = useState(localStorage.getItem("parseAppId"));
const [_fileupload, setFileUpload] = useState("");
const [fileload, setfileload] = useState(false);
const [localValue, setLocalValue] = useState("");
const [Message] = useState(false);
const [percentage, setpercentage] = useState(0);
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;
setLocalValue(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);
}
};
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>
<>
{localValue ? (
<input
type="file"
id="hashfile"
style={{
border: "1px solid #ccc",
color: "gray",
backgroundColor: "white",
padding: "5px 10px",
borderRadius: "4px",
fontSize: "13px",
width: "100%",
fontWeight: "bold"
}}
accept="application/pdf,application/vnd.ms-excel"
onChange={onChange}
/>
) : props.formData ? (
<div
style={{
border: "1px solid #ccc",
color: "gray",
backgroundColor: "white",
padding: "5px 10px",
borderRadius: "4px",
fontSize: "13px",
width: "100%",
fontWeight: "bold"
}}
>
file selected : {props.formData.split("/")[3]}
</div>
) : (
<input
type="file"
id="hashfile"
style={{
border: "1px solid #ccc",
color: "gray",
backgroundColor: "white",
padding: "5px 10px",
borderRadius: "4px",
fontSize: "13px",
width: "100%",
fontWeight: "bold"
}}
accept="application/pdf,application/vnd.ms-excel"
onChange={onChange}
/>
)}
</>
</React.Fragment>
);
};
export default FileUpload;
@@ -1,83 +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 });
});
}
}
} 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,484 +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 {
var emp = Parse.Object.extend(
localStorage.getItem("extended_class")
);
var q = new Parse.Query(emp);
q.equalTo("UserId", currentUser);
res = await q.first();
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;
@@ -42,9 +42,8 @@ const Sidebar = ({ isOpen, closeSidebar }) => {
return (
<aside
className={`${isOpen ? "block" : "hidden"
} bg-white text-[#444] h-screen w-full md:w-[300px] overflow-y-auto transform transition-transform z-40 ${isOpen ? "translate-x-0" : "-translate-x-full"
}`}
className={`bg-white text-[#444] h-screen w-full md:w-[300px] overflow-y-auto transform transition-transform z-40 md:translate-x-0
${isOpen ? "translate-x-0 block" : "-translate-x-full hidden"}`}
>
<div className="flex px-2 py-3 gap-2 items-center shadow-md">
<div className="w-[75px] h-[75px] rounded-full ring-[2px] ring-offset-2 ring-gray-400 overflow-hidden">
+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";
-210
View File
@@ -1,210 +0,0 @@
import moment from "moment";
export default function onSearchFilter(_search) {
switch (_search) {
case "Today": {
let d = new Date();
let formDate = new Date(
Date.UTC(d.getFullYear(), d.getMonth(), d.getDate(), 0, 0, 0)
).toISOString();
let Todate = new Date(
Date.UTC(d.getFullYear(), d.getMonth(), d.getDate(), 23, 59, 59)
).toISOString();
let Query = `'$gte':'${formDate}','$lte':'${Todate}'`;
return Query;
}
case "Yesterday": {
let d1 = new Date();
d1.setDate(d1.getDate() - 1);
let yesFrDate = new Date(
Date.UTC(d1.getFullYear(), d1.getMonth(), d1.getDate(), 0, 0, 0)
).toISOString();
let YesTodate = new Date(
Date.UTC(d1.getFullYear(), d1.getMonth(), d1.getDate(), 23, 59, 59)
).toISOString();
let Query1 = `'$gte':'${yesFrDate}','$lte':'${YesTodate}'`;
return Query1;
}
case "This week": {
let oneDay = 24 * 60 * 60 * 1000;
let curr = new Date(); // get current date
let first = curr.getDate() - curr.getDay(); // First day is the day of the month - the day of the week
let firstday = new Date(
new Date(
Date.UTC(curr.getFullYear(), curr.getMonth(), curr.getDate(), 0, 0, 0)
).setDate(first)
).toISOString();
let diffDays = Math.round(
Math.abs(
(new Date(
Date.UTC(
curr.getFullYear(),
curr.getMonth(),
curr.getDate(),
23,
59,
59
)
) -
new Date(firstday)) /
oneDay
)
); //Days since last week
let last = first + diffDays;
let lastday = new Date(
new Date(
Date.UTC(
curr.getFullYear(),
curr.getMonth(),
curr.getDate(),
23,
59,
59
)
).setDate(last)
).toISOString();
let Query2 = `'$gte':'${firstday}','$lte':'${lastday}'`;
return Query2;
}
case "Last 7 days": {
let d7 = new Date();
let d7l = new Date();
d7.setDate(d7.getDate() - 7);
let l7t = new Date(
Date.UTC(d7l.getFullYear(), d7l.getMonth(), d7l.getDate(), 23, 59, 59)
).toISOString();
let date7 = new Date(
Date.UTC(d7.getFullYear(), d7.getMonth(), d7.getDate(), 0, 0, 0)
).toISOString();
let Query7 = `'$gte':'${date7}','$lte':'${l7t}'`;
return Query7;
}
case "Last 14 days": {
let d14 = new Date();
let d14l = new Date();
let l14t = new Date(
Date.UTC(
d14l.getFullYear(),
d14l.getMonth(),
d14l.getDate(),
23,
59,
59
)
).toISOString();
d14.setDate(d14.getDate() - 14);
let date14 = new Date(
Date.UTC(d14.getFullYear(), d14.getMonth(), d14.getDate(), 0, 0, 0)
).toISOString();
let Query14 = `'$gte':'${date14}','$lte':'${l14t}'`;
return Query14;
}
case "Last 30 days": {
let d30 = new Date();
let d30l = new Date();
let l30t = new Date(
Date.UTC(
d30l.getFullYear(),
d30l.getMonth(),
d30l.getDate(),
23,
59,
59
)
).toISOString();
d30.setDate(d30.getDate() - 30);
let date30 = new Date(
Date.UTC(d30.getFullYear(), d30.getMonth(), d30.getDate(), 0, 0, 0)
).toISOString();
return `'$gte':'${date30}','$lte':'${l30t}'`;
}
case "Last week": {
const from_date = moment().startOf("week").subtract(7, "days");
const to_date = moment().endOf("week").subtract(7, "days");
return `'$gte':'${from_date.toISOString()}','$lte':'${to_date.toISOString()}'`;
}
case "This month": {
var tdate = new Date();
var tfirstDay = new Date(
tdate.getFullYear(),
tdate.getMonth(),
1
).toISOString();
var tlastDay = new Date(
tdate.getFullYear(),
tdate.getMonth() + 1,
0
).toISOString();
let Querylt = `'$gte':'${tfirstDay}','$lte':'${tlastDay}'`;
return Querylt;
}
case "Last month": {
var ldate = new Date();
var lfirstDay = new Date(
ldate.getFullYear(),
ldate.getMonth() - 1,
2
).toISOString();
var llastDay = new Date(
ldate.getFullYear(),
ldate.getMonth(),
1
).toISOString();
let Queryltl = `'$gte':'${lfirstDay}','$lte':'${llastDay}'`;
return Queryltl;
}
case "All": {
let fall = new Date(
new Date().getFullYear() - 100,
0,
1,
0,
0,
0
).toISOString();
let fall_year = `'$gte':'${fall}'`;
return fall_year;
}
case "This year": {
let fcy = new Date(new Date().getFullYear(), 0, 1, 0, 0, 0).toISOString();
let lcy = new Date(
new Date().getFullYear(),
11,
31,
23,
59,
59
).toISOString();
let cur_year = `'$gte':'${fcy}','$lte':'${lcy}'`;
return cur_year;
}
case "Last year": {
let fly = new Date(
new Date().getFullYear() - 1,
0,
1,
0,
0,
0
).toISOString();
let lly = new Date(
new Date().getFullYear() - 1,
11,
31,
23,
59,
59
).toISOString();
let last_year = `'$gte':'${fly}','$lte':'${lly}'`;
return last_year;
}
default:
return "";
}
}
+17
View File
@@ -15,3 +15,20 @@ export const useScript = (url, onload) => {
};
}, [url, onload]);
};
/**`useScript` hook is generated scripte for google sign in button */
export const useDropScript = (url, onload) => {
useEffect(() => {
const script = document.createElement("script");
//add url parameter to the script src, for load and it will remove after load in return
script.src = url;
script.async = true;
script.defer = true;
script.id = "dropboxjs";
script.setAttribute("data-app-key", "8k0thg9r1t7asqg");
document.head.appendChild(script);
return () => {
document.head.removeChild(script);
};
}, [url, onload]);
};
+12 -1
View File
@@ -4,4 +4,15 @@
body{
background-color: white;
}
}
/* Custom CSS to hide scrollbar */
.hide-scrollbar::-webkit-scrollbar {
display: none;
}
.hide-scrollbar {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
+22 -581
View File
@@ -1,585 +1,26 @@
import Parse from "parse";
export const formJson = (id) => {
let formData;
import { documentCls, templateCls } from "../constant/const";
export const formJson = {
//json form for signYourself
if (id === "sHAnZphf69") {
formData = {
jsonSchema: {
title: "Sign Yourself",
description: "",
type: "object",
required: ["URL", "Name"],
properties: {
URL: {
type: "string",
title: "Select Document",
filetypes: [],
maxfilesizeKB: "5000",
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=="
};
sHAnZphf69: {
title: "Sign Yourself",
redirectRoute: "signaturePdf",
msgVar: "Document",
Cls: documentCls
},
return formData;
}
//json form for request signature
else if (id === "8mZzFxbG1z") {
const user = Parse.User.current();
const userPtr = JSON.stringify({
__type: "Pointer",
className: "_User",
objectId: user.id
});
formData = {
jsonSchema: {
title: "New Document",
description: "",
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}}&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;
//json form for request signatures
"8mZzFxbG1z": {
title: "Request Signatures",
msgVar: "Document",
redirectRoute: "placeHolderSign",
Cls: documentCls,
signers: true
},
//json form for template
template: {
title: "New Template",
redirectRoute: "template",
msgVar: "Template",
Cls: templateCls
}
};
+51 -245
View File
@@ -1,35 +1,15 @@
import Parse from "parse";
export default function reportJson(id) {
const currentUserId = Parse.User.current().id;
// console.log("json ", json);
const head = ["Sr.No", "Title", "Note", "Folder", "File", "Owner", "Signers"];
const contactbook = ["Sr.No", "Title", "Email", "Phone"];
const dashboardReportHead = ["Title", "File", "Owner", "Signers"];
switch (id) {
// draft documents report
case "ByHuevtCFY":
return {
reportName: "Draft Documents",
className: "contracts_Document",
params: {
Type: null,
$or: [
{ Signers: null, SignedUrl: null },
{ Signers: { $exists: true }, Placeholders: null }
],
CreatedBy: {
__type: "Pointer",
className: "_User",
objectId: currentUserId
}
},
keys: [
"Name",
"Note",
"Folder.Name",
"URL",
"ExtUserPtr.Name",
"Signers.Name"
],
orderBy: "-updatedAt",
heading: head,
actions: [
{
btnLabel: "sign",
@@ -45,27 +25,7 @@ export default function reportJson(id) {
case "4Hhwbp482K":
return {
reportName: "Need your sign",
className: "contracts_Document",
params: {
Type: { $ne: "Folder" },
IsCompleted: { $ne: true },
IsDeclined: { $ne: true },
ExpiryDate: {
$gt: { __type: "Date", iso: new Date().toISOString() }
},
Placeholders: { $ne: null }
},
keys: [
"Name",
"Note",
"Folder.Name",
"URL",
"ExtUserPtr.Name",
"Signers.Name",
"Signers.UserId",
"AuditTrail"
],
orderBy: "-updatedAt",
heading: head,
actions: [
{
btnLabel: "sign",
@@ -81,31 +41,7 @@ export default function reportJson(id) {
case "1MwEuxLEkF":
return {
reportName: "In-progress documents",
className: "contracts_Document",
params: {
Type: { $ne: "Folder" },
Signers: { $ne: null },
Placeholders: { $ne: null },
IsCompleted: { $ne: true },
IsDeclined: { $ne: true },
CreatedBy: {
__type: "Pointer",
className: "_User",
objectId: currentUserId
},
ExpiryDate: {
$gt: { __type: "Date", iso: new Date().toISOString() }
}
},
keys: [
"Name",
"Note",
"Folder.Name",
"URL",
"ExtUserPtr.Name",
"Signers.Name"
],
orderBy: "-updatedAt",
heading: head,
actions: [
{
btnLabel: "View",
@@ -121,27 +57,7 @@ export default function reportJson(id) {
case "kQUoW4hUXz":
return {
reportName: "Completed Documents",
className: "contracts_Document",
params: {
Type: null,
IsCompleted: true,
CreatedBy: {
__type: "Pointer",
className: "_User",
objectId: currentUserId
},
IsDeclined: { $ne: true }
},
keys: [
"Name",
"Note",
"Folder.Name",
"URL",
"ExtUserPtr.Name",
"Signers.Name",
"TimeToCompleteDays"
],
orderBy: "-updatedAt",
heading: head,
actions: [
{
btnLabel: "View",
@@ -153,63 +69,11 @@ export default function reportJson(id) {
}
]
};
// OpenSignDrive™ documents Drafts
case "VRFDmUmw5B":
return {
reportName: "OpenSignDrive™ Drafts",
className: "contracts_Document",
params: {
Type: "AIDoc",
$or: [
{ Signers: null, SignedUrl: null },
{ Signers: { $exists: true }, Placeholders: null }
],
CreatedBy: {
__type: "Pointer",
className: "_User",
objectId: currentUserId
}
},
keys: [
"Name",
"Note",
"Folder.Name",
"URL",
"ExtUserPtr.Name",
"Signers.Name"
],
orderBy: "-updatedAt",
actions: [
{
btnLabel: "edit",
btnColor: "#3ac9d6",
textColor: "white",
btnIcon: "fa fa-plus",
redirectUrl:
"remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9MZWdhR2VuaWUtTWljcm9hcHBWMi9yZW1vdGVFbnRyeS5qcw==&moduleToLoad=AppRoutes&remoteName=legageniemicroapp/legagenie"
}
]
};
// declined documents report
case "UPr2Fm5WY3":
return {
reportName: "Declined Documents",
className: "contracts_Document",
params: { Type: null, IsDeclined: true },
CreatedBy: {
__type: "Pointer",
className: "_User",
objectId: currentUserId
},
keys: [
"Name",
"Note",
"Folder.Name",
"URL",
"ExtUserPtr.Name",
"Signers.Name"
],
orderBy: "-updatedAt",
heading: head,
actions: [
{
btnLabel: "View",
@@ -225,39 +89,7 @@ export default function reportJson(id) {
case "zNqBHXHsYH":
return {
reportName: "Expired Documents",
className: "contracts_Document",
params: {
IsCompleted: { $ne: true },
IsDeclined: { $ne: true },
Type: { $ne: "Folder" },
$and: [
{
$or: [
{ Signers: { $ne: null }, SignedUrl: { $ne: null } },
{ Placeholders: { $ne: null } }
]
},
{
ExpiryDate: {
$lt: { __type: "Date", iso: new Date().toISOString() }
}
}
],
CreatedBy: {
__type: "Pointer",
className: "_User",
objectId: currentUserId
}
},
keys: [
"Name",
"Note",
"Folder.Name",
"URL",
"ExtUserPtr.Name",
"Signers.Name"
],
orderBy: "-updatedAt",
heading: head,
actions: [
{
btnLabel: "View",
@@ -273,31 +105,7 @@ export default function reportJson(id) {
case "d9k3UfYHBc":
return {
reportName: "Recently sent for signatures",
className: "contracts_Document",
params: {
Type: { $ne: "Folder" },
Signers: { $ne: null },
Placeholders: { $ne: null },
IsCompleted: { $ne: true },
IsDeclined: { $ne: true },
CreatedBy: {
__type: "Pointer",
className: "_User",
objectId: currentUserId
},
ExpiryDate: {
$gt: { __type: "Date", iso: new Date().toISOString() }
}
},
keys: [
"Name",
"Note",
"Folder.Name",
"URL",
"ExtUserPtr.Name",
"Signers.Name"
],
orderBy: "-updatedAt",
heading: dashboardReportHead,
actions: [
{
btnLabel: "View",
@@ -313,27 +121,7 @@ export default function reportJson(id) {
case "5Go51Q7T8r":
return {
reportName: "Recent signature requests",
className: "contracts_Document",
params: {
Type: { $ne: "Folder" },
IsCompleted: { $ne: true },
IsDeclined: { $ne: true },
ExpiryDate: {
$gt: { __type: "Date", iso: new Date().toISOString() }
},
Placeholders: { $ne: null }
},
keys: [
"Name",
"Note",
"Folder.Name",
"URL",
"ExtUserPtr.Name",
"Signers.Name",
"Signers.UserId",
"AuditTrail"
],
orderBy: "-updatedAt",
heading: dashboardReportHead,
actions: [
{
btnLabel: "Sign",
@@ -349,28 +137,7 @@ export default function reportJson(id) {
case "kC5mfynCi4":
return {
reportName: "Drafts",
className: "contracts_Document",
params: {
Type: null,
$or: [
{ Signers: null, SignedUrl: null },
{ Signers: { $exists: true }, Placeholders: null }
],
CreatedBy: {
__type: "Pointer",
className: "_User",
objectId: currentUserId
}
},
keys: [
"Name",
"Note",
"Folder.Name",
"URL",
"ExtUserPtr.Name",
"Signers.Name"
],
orderBy: "-updatedAt",
heading: ["Title", "Note", "Folder", "File", "Owner", "Signers"],
actions: [
{
btnLabel: "sign",
@@ -382,6 +149,45 @@ export default function reportJson(id) {
}
]
};
// contactbook report
case "5KhaPr482K":
return {
reportName: "Contactbook",
heading: contactbook,
actions: [
{
btnLabel: "",
btnColor: "#f55a42",
textColor: "white",
btnIcon: "fa-solid fa-trash"
}
],
form: "ContactBook"
};
// template report
case "6TeaPr321t":
return {
reportName: "Templates",
heading: head,
actions: [
{
btnLabel: "Use",
btnColor: "#4bd396",
textColor: "white",
btnIcon: "fa fa-plus",
redirectUrl:
"remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/placeHolderSign"
},
{
btnLabel: "Edit",
btnColor: "#00c9d5",
textColor: "white",
btnIcon: "fa fa-plus",
redirectUrl:
"remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/template"
}
]
};
default:
return null;
}
+5 -2
View File
@@ -6,6 +6,7 @@
"subtitle": "Free for life One click install.",
"btnText": "Visit github",
"url": "https://github.com/opensignlabs/opensign",
"target": "_blank",
"benefits": [
"Sign Unlimited Documents",
"S3 Doc Storage",
@@ -26,12 +27,13 @@
"planName": "THANKS PLAN",
"currency": "$",
"price": "29.99",
"subtitle": "Use code 'FREEBETA' to get this for free(First 100 users)",
"subtitle": "Use code <span style='background-color: yellow;'>'FREEBETA'</span> to get this for free(First 1000 users)",
"btnText": "Subscribe",
"url": "https://subscriptions.zoho.in/subscribe/ef798486e6a0a11ea65f2bae8f2af901dbadf3175d495584fd25b9af5d2f2b9e/thanks",
"target": "_self",
"benefits": [
"Sign Unlimited Documents",
"Unlimited Secure Doc Storage with OpenSignDrive",
"Unlimited Secure Doc Storage with OpenSignDrive",
"Unlimited Guest Signers",
"Unlimited completion certificates",
"Unique Code(OTP) verification for guest signers",
@@ -50,6 +52,7 @@
"subtitle": "Customization available Priority support.",
"btnText": "Contact us",
"url": "https://www.opensignlabs.com/contact-us",
"target": "_blank",
"benefits": [
"All features",
"Custom domain",
+103 -41
View File
@@ -6,11 +6,38 @@ import { useWindowSize } from "../hook/useWindowSize";
import Tour from "reactour";
import axios from "axios";
import { useSelector } from "react-redux";
import Parse from "parse";
import ModalUi from "../primitives/ModalUi";
import { useNavigate, useLocation, Outlet } from "react-router-dom";
const HomeLayout = ({ children }) => {
const HomeLayout = () => {
const navigate = useNavigate();
const location = useLocation();
const { width } = useWindowSize();
const [isOpen, setIsOpen] = useState(false);
const [isOpen, setIsOpen] = useState(true);
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
const [isCloseBtn, setIsCloseBtn] = useState(true);
@@ -19,20 +46,16 @@ const HomeLayout = ({ children }) => {
const [tourConfigs, setTourConfigs] = useState([]);
const showSidebar = () => {
setIsOpen(!isOpen);
setIsOpen((value) => !value);
};
useEffect(() => {
if (width && width <= 768) {
setIsOpen(false);
} else {
setIsOpen(true);
}
}, [width]);
useEffect(() => {
if (localStorage.getItem("domain") === "sign" && arr && arr.length > 0) {
handleDynamicSteps();
} else if (
if (
localStorage.getItem("domain") === "contracts" &&
arr &&
arr.length > 0
@@ -124,20 +147,11 @@ const HomeLayout = ({ children }) => {
};
async function checkTourStatus() {
const serverUrl = localStorage.getItem("baseUrl");
const appId = localStorage.getItem("AppID12");
const extUserClass = localStorage.getItem("extended_class");
const json = JSON.parse(localStorage.getItem("Extand_Class"));
const extUserId = json && json.length > 0 && json[0].objectId;
// console.log("extUserId ", extUserId);
const res = await axios.get(
serverUrl + "classes/" + extUserClass + "/" + extUserId,
{
headers: {
"X-Parse-Application-Id": appId
}
}
);
const currentUser = Parse.User.current();
const cloudRes = await Parse.Cloud.run("getUserDetails", {
email: currentUser.get("email")
});
const res = { data: cloudRes.toJSON() };
if (res.data && res.data.TourStatus && res.data.TourStatus.length > 0) {
const tourStatus = res.data.TourStatus;
// console.log("res ", res.data.TourStatus);
@@ -164,32 +178,80 @@ const HomeLayout = ({ children }) => {
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 (
<div>
<div className="sticky top-0 z-50">
<Header showSidebar={showSidebar} />
</div>
<div className="flex md:flex-row flex-col z-50">
<Sidebar isOpen={isOpen} closeSidebar={closeSidebar} />
{isUserValid ? (
<>
{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="bg-[#eef1f5] p-3">{children}</div>
<div className="z-30">
<Footer />
<div className="relative h-screen flex flex-col justify-between w-full overflow-y-auto">
<div className="bg-[#eef1f5] p-3">{<Outlet />}</div>
<div className="z-30">
<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>
<Tour
onRequestClose={closeTour}
steps={tourConfigs}
isOpen={isTour}
closeWithMask={false}
disableKeyboardNavigation={["esc"]}
// disableInteraction={true}
scrollOffset={-100}
rounded={5}
showCloseButton={isCloseBtn}
/>
</ModalUi>
)}
</div>
);
};
+30
View File
@@ -0,0 +1,30 @@
import React from "react";
const Alert = ({ children, type }) => {
const textcolor = type ? theme(type) : theme();
function theme(color) {
switch (color) {
case "success":
return "border-[#c3e6cb] bg-[#d4edda] text-[#155724]";
case "info":
return "border-[#adcdeb] bg-[#c1daf0] text-[#153756]";
case "danger":
return "border-[#f0a8a8] bg-[#f4bebe] text-[#c42121]";
default:
return "border-[#d6d6d6] bg-[#d9d9d9] text-[#575757]";
}
}
return (
<>
{children && (
<div
className={`z-40 fixed top-20 left-1/2 transform -translate-x-1/2 border-[1px] text-sm ${textcolor} rounded py-[.75rem] px-[1.25rem] `}
>
{children}
</div>
)}
</>
);
};
export default Alert;
+386 -75
View File
@@ -1,18 +1,31 @@
import React, { useState, useEffect, useMemo } from "react";
import pad from "../assets/images/pad.svg";
import { useNavigate } from "react-router-dom";
import axios from "axios";
import "../styles/report.css";
import ModalUi from "./ModalUi";
import AppendFormInForm from "../components/AppendFormInForm";
import { modalSubmitBtnColor, modalCancelBtnColor } from "../constant/const";
const ReportTable = ({
ReportName,
List,
setList,
actions,
heading,
setIsNextRecord,
isMoreDocs
isMoreDocs,
docPerPage,
form
}) => {
const navigate = useNavigate();
const [currentPage, setCurrentPage] = useState(1);
const docPerPage = 10;
// const pageNumbers = [];
const [actLoader, setActLoader] = useState({});
const [isAlert, setIsAlert] = useState(false);
const [isErr, setIsErr] = useState(false);
const [isDocErr, setIsDocErr] = useState(false);
const [isContactform, setIsContactform] = useState(false);
const [isDeleteModal, setIsDeleteModal] = useState({});
const startIndex = (currentPage - 1) * docPerPage;
// For loop is used to calculate page numbers visible below table
// Initialize pageNumbers using useMemo to avoid unnecessary re-creation
@@ -22,7 +35,7 @@ const ReportTable = ({
calculatedPageNumbers.push(i);
}
return calculatedPageNumbers;
}, [List]);
}, [List, docPerPage]);
// below useEffect reset currenpage to 1 if user change route
useEffect(() => {
return () => setCurrentPage(1);
@@ -51,14 +64,129 @@ const ReportTable = ({
}, [isMoreDocs, pageNumbers, currentPage, setIsNextRecord]);
// `handlemicroapp` is used to open microapp
const handlemicroapp = (item, url) => {
localStorage.removeItem("rowlevel");
navigate("/rpmf/" + url);
localStorage.setItem("rowlevel", JSON.stringify(item));
const handlemicroapp = async (item, url, btnLabel) => {
if (ReportName === "Templates") {
if (btnLabel === "Edit") {
navigate(`/asmf/${url}/${item.objectId}`);
} else {
setActLoader({ [`${item.objectId}_${btnLabel}`]: true });
try {
const params = {
templateId: item.objectId
};
const templateDeatils = await axios.post(
`${localStorage.getItem("baseUrl")}functions/getTemplate`,
params,
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
sessionToken: localStorage.getItem("accesstoken")
}
}
);
// console.log("templateDeatils.data ", templateDeatils.data);
const templateData =
templateDeatils.data && templateDeatils.data.result;
if (!templateData.error) {
const Doc = templateData;
let signers = [];
if (Doc.Signers?.length > 0) {
Doc.Signers?.forEach((x) => {
if (x.objectId) {
const obj = {
__type: "Pointer",
className: "contracts_Contactbook",
objectId: x.objectId
};
signers.push(obj);
}
});
}
let placeholdersArr = [];
if (Doc.Placeholders?.length > 0) {
placeholdersArr = Doc.Placeholders;
const data = {
Name: Doc.Name,
URL: Doc.URL,
SignedUrl: Doc.SignedUrl,
Description: Doc.Description,
Note: Doc.Note,
Placeholders: placeholdersArr,
ExtUserPtr: {
__type: "Pointer",
className: "contracts_Users",
objectId: Doc.ExtUserPtr.objectId
},
CreatedBy: {
__type: "Pointer",
className: "_User",
objectId: Doc.CreatedBy.objectId
},
Signers: signers
};
try {
const res = await axios.post(
`${localStorage.getItem(
"baseUrl"
)}classes/${localStorage.getItem("_appName")}_Document`,
data,
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id":
localStorage.getItem("parseAppId"),
"X-Parse-Session-Token":
localStorage.getItem("accesstoken")
}
}
);
// console.log("Res ", res.data);
if (res.data && res.data.objectId) {
setActLoader({});
setIsAlert(true);
navigate(`/asmf/${url}/${res.data.objectId}`, {
state: { title: "Use Template" }
});
}
} catch (err) {
console.log("Err", err);
setIsAlert(true);
setIsErr(true);
setActLoader({});
}
} else {
setIsDocErr(true);
setActLoader({});
}
} else {
setIsAlert(true);
setIsErr(true);
setActLoader({});
}
} catch (err) {
console.log("err", err);
setIsAlert(true);
setIsErr(true);
setActLoader({});
}
}
} else {
localStorage.removeItem("rowlevel");
navigate("/rpmf/" + url);
localStorage.setItem("rowlevel", JSON.stringify(item));
}
// localStorage.setItem("rowlevelMicro");
};
const handlebtn = () => {
console.log("clicked");
const handlebtn = async (item) => {
if (ReportName === "Contactbook") {
setIsDeleteModal({ [item.objectId]: true });
}
};
// Get current list
@@ -71,19 +199,83 @@ const ReportTable = ({
const paginateFront = () => setCurrentPage(currentPage + 1);
const paginateBack = () => setCurrentPage(currentPage - 1);
const handleContactFormModal = () => {
setIsContactform(!isContactform);
};
const handleUserData = (data) => {
setList((prevData) => [data, ...prevData]);
};
const handleDelete = async (item) => {
setIsDeleteModal({});
setActLoader({ [item.objectId]: true });
try {
const url =
process.env.REACT_APP_SERVERURL + "/classes/contracts_Contactbook/";
const body = { IsDeleted: true };
const res = await axios.put(url + item.objectId, body, {
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("AppID12"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
}
});
// console.log("Res ", res.data);
if (res.data && res.data.updatedAt) {
setActLoader({});
setIsAlert(true);
const upldatedList = List.filter((x) => x.objectId !== item.objectId);
setList(upldatedList);
}
} catch (err) {
console.log("err", err);
setIsAlert(true);
setIsErr(true);
setActLoader({});
}
};
const handleCloseDeleteModal = () => setIsDeleteModal({});
return (
<div className="p-2 overflow-x-scroll w-full bg-white rounded-md">
<h2 className="text-[23px] font-light my-2">{ReportName}</h2>
{isAlert && (
<div
className={`alert alert-${isErr ? "danger" : "success"} alertBox`}
role="alert"
onAnimationEnd={() => setIsAlert(false)}
>
{isErr
? "Something went wrong, Please try again later!"
: "Record deleted successfully!"}
</div>
)}
<div className="flex flex-row items-center justify-between my-2 mx-3 text-[20px] md:text-[23px]">
<div className="font-light">{ReportName}</div>
{ReportName === "Templates" && (
<i
onClick={() => navigate("/form/template")}
className="fa-solid fa-square-plus text-sky-400 text-[25px]"
></i>
)}
{form && (
<div
className="cursor-pointer"
onClick={() => handleContactFormModal()}
>
<i className="fa-solid fa-square-plus text-sky-400 text-[25px]"></i>
</div>
)}
</div>
<table className="table-auto w-full border-collapse">
<thead className="text-[14px]">
<tr className="border-y-[1px]">
<th className="px-4 py-2 font-thin">Sr.No</th>
<th className="px-4 py-2 font-thin">Name</th>
<th className="px-4 py-2 font-thin">Note</th>
<th className="px-4 py-2 font-thin">Folder</th>
<th className="px-4 py-2 font-thin">File</th>
<th className="px-4 py-2 font-thin">Owner</th>
<th className="px-4 py-2 font-thin">Signers</th>
{heading?.map((item, index) => (
<React.Fragment key={index}>
<th className="px-4 py-2 font-thin">{item}</th>
</React.Fragment>
))}
{actions?.length > 0 && (
<th className="px-4 py-2 font-thin">Action</th>
)}
@@ -92,61 +284,160 @@ const ReportTable = ({
<tbody className="text-[12px]">
{List?.length > 0 ? (
<>
{currentLists.map((item, index) => (
<tr className="border-y-[1px]" key={index}>
<td className="px-4 py-2">{index + 1}</td>
<td className="px-4 py-2 font-semibold">{item?.Name} </td>
<td className="px-4 py-2">{item?.Note || "-"}</td>
<td className="px-4 py-2">
{item?.Folder?.Name || "OpenSignDrive"}
</td>
<td className="px-4 py-2">
<a
target="_blank"
rel="noopener noreferrer"
title={item?.URL}
href={item?.URL}
download={item?.URL}
className="text-[blue] hover:text-[blue] hover:underline"
>
{item?.URL ? "Download" : "-"}
</a>
</td>
<td className="px-4 py-2">{formatRow(item?.ExtUserPtr)}</td>
<td className="px-4 py-2">
{item?.Signers ? formatRow(item?.Signers) : "-"}
</td>
<td className="px-4 py-2 flex flex-col justify-center items-center gap-2 text-white">
{actions?.length > 0 &&
actions.map((act, index) => (
<button
key={index}
onClick={() =>
act?.redirectUrl
? handlemicroapp(item, act.redirectUrl)
: handlebtn(item)
}
className={`flex justify-center items-center w-full gap-1 px-2 py-1 rounded shadow`}
style={{
backgroundColor: act.btnColor
? act.btnColor
: "#3ac9d6",
color: act?.textColor ? act?.textColor : "white"
}}
{currentLists.map((item, index) =>
ReportName === "Contactbook" ? (
<tr className="border-y-[1px]" key={index}>
{heading.includes("Sr.No") && (
<td className="px-4 py-2">{startIndex + index + 1}</td>
)}
<td className="px-4 py-2 font-semibold">{item?.Name} </td>
<td className="px-4 py-2">{item?.Email || "-"}</td>
<td className="px-4 py-2">{item?.Phone || "-"}</td>
<td className="px-3 py-2 text-white">
{actions?.length > 0 &&
actions.map((act, index) => (
<button
key={index}
onClick={() =>
act?.redirectUrl
? handlemicroapp(item, act.redirectUrl)
: handlebtn(item)
}
className={`mb-1 flex justify-center items-center gap-1 px-2 py-1 rounded shadow`}
style={{
backgroundColor: act.btnColor
? act.btnColor
: "#3ac9d6",
color: act?.textColor ? act?.textColor : "white"
}}
>
<span>
{act?.btnIcon && (
<i
className={
actLoader[item.objectId]
? "fa-solid fa-spinner fa-spin-pulse"
: act.btnIcon
}
></i>
)}
</span>
{act?.btnLabel && (
<span className="uppercase">
{act?.btnLabel ? act.btnLabel : "View"}
</span>
)}
</button>
))}
{isDeleteModal[item.objectId] && (
<ModalUi
isOpen
title={"Delete Contact"}
handleClose={handleCloseDeleteModal}
>
<span>
{act?.btnIcon && <i className={act.btnIcon}></i>}
</span>
<span className="uppercase">
{act?.btnLabel ? act.btnLabel : "view"}
</span>
</button>
// )
))}
</td>
</tr>
))}
<div className="m-[20px]">
<div className="text-lg font-normal text-black">
Are you sure you want to delete this contact?
</div>
<hr className="bg-[#ccc] mt-4 " />
<div className="flex items-center mt-3 gap-2 text-white">
<button
onClick={() => handleDelete(item)}
className="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>
</tr>
) : (
<tr className="border-y-[1px]" key={index}>
{heading.includes("Sr.No") && (
<td className="px-4 py-2">{startIndex + index + 1}</td>
)}
<td className="px-4 py-2 font-semibold w-56">
{item?.Name}{" "}
</td>
{heading.includes("Note") && (
<td className="px-4 py-2">{item?.Note || "-"}</td>
)}
{heading.includes("Folder") && (
<td className="px-4 py-2">
{item?.Folder?.Name || "OpenSign™ Drive"}
</td>
)}
<td className="px-4 py-2">
<a
target="_blank"
rel="noopener noreferrer"
title={item?.URL}
href={item?.URL}
download={item?.URL}
className="text-[blue] hover:text-[blue] hover:underline"
>
{item?.URL ? "Download" : "-"}
</a>
</td>
<td className="px-4 py-2">{formatRow(item?.ExtUserPtr)}</td>
<td className="px-4 py-2">
{item?.Signers ? formatRow(item?.Signers) : "-"}
</td>
<td className="px-3 py-2 text-white">
{actions?.length > 0 &&
actions.map((act, index) => (
<button
key={index}
onClick={() =>
act?.redirectUrl
? handlemicroapp(
item,
act.redirectUrl,
act.btnLabel
)
: handlebtn(item)
}
className={`mb-1 flex justify-center items-center gap-1 px-2 py-1 rounded shadow`}
style={{
backgroundColor: act.btnColor
? act.btnColor
: "#3ac9d6",
color: act?.textColor ? act?.textColor : "white"
}}
>
<span>
{act?.btnIcon && (
<i
className={
actLoader[
`${item.objectId}_${act.btnLabel}`
]
? "fa-solid fa-spinner fa-spin-pulse"
: act.btnIcon
}
></i>
)}
</span>
<span className="uppercase">
{act?.btnLabel ? act.btnLabel : "view"}
</span>
</button>
))}
</td>
</tr>
)
)}
</>
) : (
<></>
@@ -154,7 +445,7 @@ const ReportTable = ({
</tbody>
</table>
<div className="flex flex-wrap items-center gap-2 p-2 ">
{List.length > 10 && (
{List.length > docPerPage && (
<>
{currentPage > 1 && (
<button
@@ -178,7 +469,7 @@ const ReportTable = ({
{isMoreDocs && (
<button className="text-black rounded px-1 py-2">...</button>
)}
{List.length > 10 && (
{List.length > docPerPage && (
<>
{pageNumbers.includes(currentPage + 1) && (
<button
@@ -199,6 +490,26 @@ const ReportTable = ({
<div className="text-sm font-semibold">No Data Available</div>
</div>
)}
<ModalUi
title={"Add Contact"}
isOpen={isContactform}
handleClose={handleContactFormModal}
>
<AppendFormInForm
handleUserData={handleUserData}
closePopup={handleContactFormModal}
/>
</ModalUi>
<ModalUi
headColor={"#dc3545"}
isOpen={isDocErr}
title={"Receipent required"}
handleClose={() => setIsDocErr(false)}
>
<div style={{ height: "100%", padding: 20 }}>
<p>Please add receipent in template!</p>
</div>
</ModalUi>
</div>
);
};
+28
View File
@@ -0,0 +1,28 @@
import React, { useState } from "react";
const Modal = ({ children, Title }) => {
const [isOpen, SetIsOpen] = useState(false);
return (
<>
{children && (
<div
className={`fixed top-20 left-1/2 transform -translate-x-1/2 border-[1px] text-sm bg-white rounded `}
>
<div className="flex justify-between items-center py-[.75rem] px-[1.25rem] ">
<div className="font-semibold text-xl text-black">{Title}</div>
<div
onClick={() => SetIsOpen()}
className="px-2 py-1 bg-gray-400 rounded cursor-pointer"
>
<i className="fa-solid fa-xmark"></i>
</div>
</div>
<hr />
{isOpen && <div>{children}</div>}
</div>
)}
</>
);
};
export default Modal;
+40
View File
@@ -0,0 +1,40 @@
import React from "react";
const ModalUi = ({
children,
title,
isOpen,
headColor,
handleClose,
showHeader = true,
showClose = true
}) => {
return (
<>
{isOpen && (
<div className="fixed z-[999] top-0 left-0 w-[100%] h-[100%] bg-black bg-opacity-[75%]">
<div className="fixed z-[1000] top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 text-sm bg-white rounded shadow-md max-h-90 min-w-[90%] md:min-w-[500px] overflow-y-auto hide-scrollbar">
{showHeader && (
<div
className="flex justify-between rounded-t items-center py-[15px] px-[20px] text-white"
style={{ background: headColor ? headColor : "#32a3ac" }}
>
<div className="text-[1.2rem] font-normal">{title}</div>
{showClose && (
<div
className="text-[1.5rem] cursor-pointer"
onClick={() => handleClose && handleClose()}
>
&times;
</div>
)}
</div>
)}
<div>{children}</div>
</div>
</div>
)}
</>
);
};
export default ModalUi;
+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) {
// 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;
+7 -97
View File
@@ -11,7 +11,8 @@ export const fetchAppInfo = (str, burl, app_id) => async (dispatch) => {
let _base = ""; // Define _base here and initialize it to an empty string
if (response && response.baseurl) {
_base = response.baseurl.charAt(response.baseurl.length - 1);
} localStorage.removeItem("baseUrl");
}
localStorage.removeItem("baseUrl");
localStorage.setItem("_appName", response.appname);
localStorage.setItem("_app_objectId", response.objectId);
if (_base === "/") {
@@ -120,16 +121,10 @@ export const login = (username, password) => async (dispatch) => {
localStorage.setItem("_user_role", _role);
}
try {
const tour = Parse.Object.extend(
localStorage.getItem("extended_class")
);
let _tour = new Parse.Query(tour);
_tour.equalTo("UserId", {
__type: "Pointer",
className: "_User",
objectId: resultjson.objectId
});
await _tour.first().then(
const currentUser = Parse.User.current();
await Parse.Cloud.run("getUserDetails", {
email: currentUser.get("email")
}).then(
(results) => {
let userinfo = results.toJSON();
if (userinfo.TenantId) {
@@ -142,7 +137,7 @@ export const login = (username, password) => async (dispatch) => {
}
);
} catch (error) {
console.log("err ", error)
console.log("err ", error);
}
}
});
@@ -219,95 +214,10 @@ export const fetchRoleEnum = (name) => async (dispatch) => {
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) => {
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) => {
dispatch({ type: "SAVE_TOURSTEPS", payload: steps });
};
+15 -15
View File
@@ -2,11 +2,12 @@ import React, { useState, useEffect } from "react";
import Parse from "parse";
import "../styles/loader.css";
import GetDashboard from "../components/dashboard/GetDashboard";
import { Navigate, useParams } from "react-router-dom";
import { useNavigate, useParams } from "react-router-dom";
import Title from "../components/Title";
import { save_tourSteps } from "../redux/actions";
import { connect } from "react-redux";
const Dashboard = (props) => {
const navigate = useNavigate();
const { id } = useParams();
const [dashboard, setdashboard] = useState([]);
const [classnameArray, setclassnameArray] = useState([]);
@@ -15,6 +16,19 @@ const Dashboard = (props) => {
const [parseAppId] = useState(localStorage.getItem("parseAppId"));
const [defaultQuery, setDefaultQuery] = useState("");
useEffect(() => {
if (localStorage.getItem("accesstoken")) {
if (id !== undefined) {
getDashboard(id);
} else {
getDashboard(localStorage.getItem("PageLanding"));
}
} else {
navigate("/", { replace: true, state: { from: location } });
}
// eslint-disable-next-line
}, [id]);
const getDashboard = async (id) => {
setloading(true);
try {
@@ -93,20 +107,6 @@ const Dashboard = (props) => {
}
};
useEffect(() => {
if (id !== undefined) {
getDashboard(id);
} else {
getDashboard(localStorage.getItem("PageLanding"));
}
// eslint-disable-next-line
}, [id]);
if (localStorage.getItem("accesstoken") === "" || null) {
return <Navigate to="/" />;
}
let _dash = (
<GetDashboard
dashboard={dashboard}
+26 -4
View File
@@ -4,13 +4,15 @@ import { fetchAppInfo, forgetPassword } from "../redux/actions";
import Title from "../components/Title";
import { NavLink } from "react-router-dom";
import login_img from "../assets/images/login_img.svg";
import Parse from "parse";
import Alert from "../primitives/Alert";
function ForgotPassword(props) {
const [state, setState] = useState({
email: "",
password: "",
hideNav: ""
});
const [sentStatus, setSentStatus] = useState("");
const handleChange = (event) => {
const { name, value } = event.target;
setState({ ...state, [name]: value });
@@ -23,7 +25,7 @@ function ForgotPassword(props) {
}
};
const handleSubmit = (event) => {
const handleSubmit = async (event) => {
event.preventDefault();
localStorage.setItem("appLogo", props.appInfo.applogo);
localStorage.setItem("appName", props.appInfo.appname);
@@ -33,9 +35,21 @@ function ForgotPassword(props) {
"userSettings",
JSON.stringify(props.appInfo.settings)
);
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 (
<div className="bg-white">
<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 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">
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)",
backgroundColor: "#ffffff",
width: "100%",
overflow: "hidden",
borderRadius: 3,
minHeight: "70vh"
height: "100%",
minHeight: "100vh"
}}
>
{RemoteComponent && <RemoteComponent />}
File diff suppressed because it is too large Load Diff
+4 -2
View File
@@ -2,7 +2,7 @@
import React from "react";
import Title from "../components/Title";
const PageNotFound = () => {
const PageNotFound = ({ prefix }) => {
return (
<div className="flex items-center justify-center h-screen w-full bg-white rounded">
<Title title={"Page Not Found"} />
@@ -10,7 +10,9 @@ const PageNotFound = () => {
<h1 className="text-[60px] lg:text-[120px] font-semibold text-black">
404
</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>
);
+85 -44
View File
@@ -5,7 +5,7 @@ import axios from "axios";
import { fetchAppInfo, showTenantName } from "../redux/actions/index";
import { connect } from "react-redux";
import Title from "../components/Title";
import { useNavigate } from "react-router-dom";
import { useNavigate, useLocation } from "react-router-dom";
const appId = localStorage.getItem("AppID12");
const server = localStorage.getItem("BaseUrl12");
@@ -13,6 +13,7 @@ Parse.serverURL = server;
Parse.initialize(appId);
const PgSignUp = (props) => {
const navigate = useNavigate();
const location = useLocation();
const [parseBaseUrl] = useState(localStorage.getItem("BaseUrl12"));
const [parseAppId] = useState(localStorage.getItem("AppID12"));
const [formData, setFormData] = useState({
@@ -21,6 +22,9 @@ const PgSignUp = (props) => {
});
const [validationMessage, setValidationMessage] = useState("");
const [isLoader, setIsLoader] = useState(true);
const [lengthValid, setLengthValid] = useState(false);
const [caseDigitValid, setCaseDigitValid] = useState(false);
const [specialCharValid, setSpecialCharValid] = useState(false);
// below useEffect is used to fetch App data and save to redux state
useEffect(() => {
@@ -67,13 +71,12 @@ const PgSignUp = (props) => {
const userSettings = JSON.parse(localStorage.getItem("userSettings"));
const extClass = userSettings[0].extended_class;
// console.log("extClass ", extClass);
const checkUser = new Parse.Query(extClass);
checkUser.equalTo("Email", userDetails.email);
const res = await checkUser.first();
const params = { email: userDetails.email };
const res = await Parse.Cloud.run("getUserDetails", params);
// console.log("res", res);
if (res) {
const checkUser = new Parse.Query(extClass);
const updateQuery = await checkUser.get(res.id);
const updateQuery = new Parse.Object(extClass);
updateQuery.id = res.id;
updateQuery.set(
"Next_billing_date",
new Date(zohoRes.data.result.nextBillingDate)
@@ -105,21 +108,23 @@ const PgSignUp = (props) => {
// "handleSubmit" is used to save user details signup him/her who come from plan-pricing page
const handleSubmit = (e) => {
e.preventDefault();
setIsLoader(true);
if (formData.password === formData.confirmPassword) {
const url = window.location.href;
let paramString = url.split("?")[1];
let queryString = new URLSearchParams(paramString);
// console.log("url ", queryString);
if (lengthValid && caseDigitValid && specialCharValid) {
setIsLoader(true);
if (formData.password === formData.confirmPassword) {
const url = window.location.href;
let paramString = url.split("?")[1];
let queryString = new URLSearchParams(paramString);
// console.log("url ", queryString);
let obj = { ...formData };
for (let pair of queryString.entries()) {
// console.log("Key is: " + pair[0]);
// console.log("Value is: " + pair[1]);
obj = { ...obj, [pair[0]]: pair[1] };
let obj = { ...formData };
for (let pair of queryString.entries()) {
// console.log("Key is: " + pair[0]);
// console.log("Value is: " + pair[1]);
obj = { ...obj, [pair[0]]: pair[1] };
}
saveUser(obj);
// console.log("obj ", obj);}
}
saveUser(obj);
// console.log("obj ", obj);}
}
};
const saveUser = async (obj) => {
@@ -152,6 +157,7 @@ const PgSignUp = (props) => {
if (res) {
const params = {
userDetails: {
jobTitle: zohoRes.data.result.jobTitle,
company: zohoRes.data.result.company,
name: zohoRes.data.result.name,
email: zohoRes.data.result.email,
@@ -182,7 +188,7 @@ const PgSignUp = (props) => {
console.log("err ", error);
if (error.message === "Account already exists for this username.") {
alert("Account already exists!");
navigate("/");
navigate("/", { replace: true });
} else {
setIsLoader(false);
alert("Something went wrong, please try again later!");
@@ -194,6 +200,15 @@ const PgSignUp = (props) => {
const newPassword = e.target.value;
setFormData({ ...formData, [e.target.name]: e.target.value });
validatePasswords(newPassword, formData.confirmPassword);
// Check conditions separately
setLengthValid(newPassword.length >= 8);
setCaseDigitValid(
/[a-z]/.test(newPassword) &&
/[A-Z]/.test(newPassword) &&
/\d/.test(newPassword)
);
setSpecialCharValid(/[!@#$%^&*()\-_=+{};:,<.>]/.test(newPassword));
};
const handleConFirmPassowordChange = (e) => {
const newConfirmPassword = e.target.value;
@@ -279,13 +294,6 @@ const PgSignUp = (props) => {
""
);
localStorage.setItem("_user_role", _role);
if (element.enableCart) {
localStorage.setItem("EnableCart", element.enableCart);
props.setEnableCart(element.enableCart);
} else {
localStorage.removeItem("EnableCart");
}
// Get TenentID from Extendend Class
localStorage.setItem(
"extended_class",
@@ -293,14 +301,12 @@ const PgSignUp = (props) => {
);
localStorage.setItem("userpointer", element.userpointer);
const extendedClass = Parse.Object.extend(
element.extended_class
);
let query = new Parse.Query(extendedClass);
query.equalTo("UserId", Parse.User.current());
query.include("TenantId");
await query.find().then(
(results) => {
const currentUser = Parse.User.current();
await Parse.Cloud.run("getUserDetails", {
email: currentUser.get("email")
}).then(
(result) => {
const results = [result];
let tenentInfo = [];
if (results) {
let extendedInfo_stringify =
@@ -346,7 +352,7 @@ const PgSignUp = (props) => {
element.pageType
);
setIsLoader(false);
navigate("/");
navigate("/", { replace: true });
} else {
extendedInfo.forEach((x) => {
if (x.TenantId) {
@@ -384,9 +390,12 @@ const PgSignUp = (props) => {
);
setIsLoader(false);
alert("Registered user successfully");
navigate(
`/${element.pageType}/${element.pageId}`
);
const redirectUrl =
location?.state?.from ||
`/${element.pageType}/${element.pageId}`;
// Redirect to the appropriate URL after successful login
navigate(redirectUrl);
}
} else {
alert("Registered user successfully");
@@ -397,7 +406,12 @@ const PgSignUp = (props) => {
);
localStorage.setItem("pageType", element.pageType);
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) => {
@@ -415,7 +429,7 @@ const PgSignUp = (props) => {
}
})
.catch((err) => {
console.log('err', err)
console.log("err", err);
setIsLoader(false);
});
}
@@ -448,10 +462,10 @@ const PgSignUp = (props) => {
) : (
<form id="signup" className="pgsignup-content" onSubmit={handleSubmit}>
<div className="pgsignup-container">
<h1 className="text-4xl font-bold">Choose Password</h1>
<h1 className="text-2xl md:text-3xl font-bold">Choose Password</h1>
<hr className="hrt" />
<label htmlFor="password">
<b>Password</b>
<b className="text-[13px]">Password</b>
</label>
<input
type="password"
@@ -464,7 +478,7 @@ const PgSignUp = (props) => {
/>
<label htmlFor="confirmPassword">
<b>Confirm Password</b>
<b className="text-[13px]">Confirm Password</b>
</label>
<input
type="password"
@@ -494,6 +508,33 @@ const PgSignUp = (props) => {
>
{validationMessage}
</div>
{formData.password.length > 0 && (
<div className="mt-1 text-[11px]">
<p
className={`${
lengthValid ? "text-green-600" : "text-red-600"
}`}
>
{lengthValid ? "✓" : "✗"} Password should be 8 characters long
</p>
<p
className={`${
caseDigitValid ? "text-green-600" : "text-red-600"
}`}
>
{caseDigitValid ? "✓" : "✗"} Password should contain uppercase
letter, lowercase letter, digit
</p>
<p
className={`${
specialCharValid ? "text-green-600" : "text-red-600"
}`}
>
{specialCharValid ? "✓" : "✗"} Password should contain special
character
</p>
</div>
)}
<div className="clearfix">
<button type="submit" className="signupbtn">
Submit
+43 -44
View File
@@ -2,14 +2,14 @@ import React, { useState, useEffect } from "react";
import { useNavigate } from "react-router";
import { NavLink } from "react-router-dom";
import checkmark from "../assets/images/checkmark.png";
import plansArr from '../json/plansArr.json'
import plansArr from "../json/plansArr.json";
import Title from "../components/Title";
const listItemStyle = {
paddingLeft: '20px', // Add padding to create space for the image
paddingLeft: "20px", // Add padding to create space for the image
backgroundImage: `url(${checkmark})`, // Set your image as the list style image
backgroundPosition: 'left',
backgroundRepeat: 'no-repeat',
backgroundSize: '16px 16px', // Adjust the size of the image
backgroundPosition: "left",
backgroundRepeat: "no-repeat",
backgroundSize: "16px 16px" // Adjust the size of the image
};
const PlanSubscriptions = () => {
@@ -28,20 +28,25 @@ const PlanSubscriptions = () => {
: "";
const phone =
userDetails && userDetails.phone ? "&mobile=" + userDetails.phone : "";
const details = "?" + name + email + company + phone;
const details =
"?shipping_country_code=US&billing_country_code=US&billing_state_code=CA&" +
name +
email +
company +
phone;
useEffect(() => {
if (localStorage.getItem("accesstoken")) {
setIsLoader(false);
setYearlyVisible(false);
} else {
navigate("/");
navigate("/", { replace: true });
}
// eslint-disable-next-line
}, []);
return (
<>
<Title title={"Subscriptions"} />
<Title title={"Subscriptions"} />
{isLoader ? (
<div
style={{
@@ -73,31 +78,6 @@ const PlanSubscriptions = () => {
id="monthlyPlans"
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">
<ul className=" flex flex-col md:flex-row h-full bg-white justify-center border-collapse border-[1px] border-gray-300">
{plansArr.map((item) => (
@@ -124,22 +104,41 @@ const PlanSubscriptions = () => {
<div
className={`${
item.subtitle.length <= 32
? "w-[150px] text-center"
? "w-[150px] text-center"
: ""
} 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 className="bg-[#002862] w-full text-white py-2 rounded">
<NavLink
to={item.url + details}
className="rounded uppercase hover:no-underline hover:text-white"
target="_self"
>
{item.btnText}
</NavLink>
</div>
<NavLink
to={
item.btnText === "Subscribe"
? item.url + details
: item.url
}
className="bg-[#002862] w-full text-white py-2 rounded uppercase hover:no-underline hover:text-white"
target={item.target}
>
{item.btnText}
</NavLink>
</div>
<hr className="w-full bg-gray-300 p-[.5px]" />
<ul className="mx-1 p-3 text-left break-words text-sm list-none">
+20 -23
View File
@@ -5,6 +5,7 @@ import axios from "axios";
import reportJson from "../json/ReportJson";
import { useParams } from "react-router-dom";
import Title from "../components/Title";
import PageNotFound from "./PageNotFound";
const Report = () => {
const { id } = useParams();
@@ -12,9 +13,12 @@ const Report = () => {
const [isLoader, setIsLoader] = useState(true);
const [reportName, setReportName] = useState("");
const [actions, setActions] = useState([]);
const [heading, setHeading] = useState([]);
const [isNextRecord, setIsNextRecord] = useState(false);
const [isMoreDocs, setIsMoreDocs] = useState(true);
const [form, setForm] = useState("");
const abortController = new AbortController();
const docPerPage = 10;
// below useEffect is call when id param change
useEffect(() => {
@@ -46,31 +50,27 @@ const Report = () => {
const json = reportJson(id);
if (json) {
setActions(json.actions);
setHeading(json.heading);
setReportName(json.reportName);
const { className, params, keys, orderBy } = json;
setForm(json.form);
Parse.serverURL = localStorage.getItem("BaseUrl12");
Parse.initialize(localStorage.getItem("AppID12"));
const currentUser = Parse.User.current().id;
const serverURL =
localStorage.getItem("BaseUrl12") + "classes/" + className;
const strParams = JSON.stringify(params);
const strKeys = keys.join();
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("AppID12"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
sessiontoken: localStorage.getItem("accesstoken")
};
try {
const url = `${serverURL}?where=${strParams}&keys=${strKeys}&order=${orderBy}&skip=${skipUserRecord}&limit=${limit}&include=AuditTrail.UserPtr`;
const res = await axios.get(url, {
const params = { reportId: id, skip: skipUserRecord, limit: limit };
const url = `${localStorage.getItem("BaseUrl12")}/functions/getReport`;
const res = await axios.post(url, params, {
headers: headers,
signal: abortController.signal // is used to cancel fetch query
});
if (id === "4Hhwbp482K") {
const listData = res.data?.results.filter(
(x) => x.Signers.length > 0
);
const listData = res.data?.result.filter((x) => x.Signers.length > 0);
let arr = [];
for (const obj of listData) {
const isSigner = obj.Signers.some(
@@ -92,7 +92,7 @@ const Report = () => {
}
}
}
if (arr.length === 10) {
if (arr.length === docPerPage) {
setIsMoreDocs(true);
} else {
setIsMoreDocs(false);
@@ -101,17 +101,16 @@ const Report = () => {
prevRecord.length > 0 ? [...prevRecord, ...arr] : arr
);
} else {
if (res.data.results.length === 10) {
if (res.data.result.length === docPerPage) {
setIsMoreDocs(true);
console.log("here");
} else {
setIsMoreDocs(false);
}
setIsNextRecord(false);
setList((prevRecord) =>
prevRecord.length > 0
? [...prevRecord, ...res.data.results]
: res.data.results
? [...prevRecord, ...res.data.result]
: res.data.result
);
}
setIsLoader(false);
@@ -152,18 +151,16 @@ const Report = () => {
<ReportTable
ReportName={reportName}
List={List}
setList={setList}
actions={actions}
heading={heading}
setIsNextRecord={setIsNextRecord}
isMoreDocs={isMoreDocs}
docPerPage={docPerPage}
form={form}
/>
) : (
<div className="flex items-center justify-center h-screen w-full bg-white rounded">
<div className="text-center">
<p className="text-[30px] lg:text-[50px] text-black">
Report Not Found
</p>
</div>
</div>
<PageNotFound prefix={"Report"} />
)}
</>
)}
+186 -112
View File
@@ -6,8 +6,10 @@ import Title from "../components/Title";
import { fetchAppInfo, showTenantName } from "../redux/actions";
import { useNavigate, NavLink } from "react-router-dom";
import login_img from "../assets/images/login_img.svg";
import { useWindowSize } from "../hook/useWindowSize";
const Signup = (props) => {
const { width } = useWindowSize();
const navigate = useNavigate();
const [name, setName] = useState("");
const [phone, setPhone] = useState("");
@@ -18,93 +20,143 @@ const Signup = (props) => {
const [company, setCompany] = useState("");
const [jobTitle, setJobTitle] = useState("");
const [state, setState] = useState({
hideNav: "",
loading: false,
toastColor: "#5cb85c",
toastDescription: ""
});
const [showPassword, setShowPassword] = useState(false);
const [lengthValid, setLengthValid] = useState(false);
const [caseDigitValid, setCaseDigitValid] = useState(false);
const [specialCharValid, setSpecialCharValid] = useState(false);
const togglePasswordVisibility = () => setShowPassword(!showPassword);
const image = props.appInfo.applogo;
const handleSubmit = (event) => {
setState({ loading: true });
const userDetails = {
name: name,
email: email,
phone: phone,
company: company,
jobTitle: jobTitle
};
localStorage.setItem("userDetails", JSON.stringify(userDetails));
try {
event.preventDefault();
Parse.serverURL = parseBaseUrl;
Parse.initialize(parseAppId);
event.preventDefault();
var user = new Parse.User();
user.set("name", name);
user.set("email", email);
user.set("password", password);
user.set("phone", phone);
user.set("username", email);
let res = user.save();
res
.then(async (r) => {
if (r) {
let roleurl = `${parseBaseUrl}functions/AddUserToRole`;
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": parseAppId,
sessionToken:
r.getSessionToken() || localStorage.getItem("accesstoken")
};
let body = {
appName: props.appInfo.appname,
roleName: props.appInfo.defaultRole,
userId: r.id
};
await axios.post(roleurl, body, { headers: headers });
const clearStorage = async () => {
if (Parse.User.current()) {
await Parse.User.logOut();
}
let baseUrl = localStorage.getItem("BaseUrl12");
let appid = localStorage.getItem("AppID12");
let applogo = localStorage.getItem("appLogo");
let domain = localStorage.getItem("domain");
let appversion = localStorage.getItem("appVersion");
let appTitle = localStorage.getItem("appTitle");
let defaultmenuid = localStorage.getItem("defaultmenuid");
let PageLanding = localStorage.getItem("PageLanding");
let _appName = localStorage.getItem("_appName");
let _app_objectId = localStorage.getItem("_app_objectId");
let appName = localStorage.getItem("appName");
let userSettings = localStorage.getItem("userSettings");
let roleData = props.appInfo.settings;
if (roleData && roleData.length > 0) {
roleData.forEach((rld) => {
if (rld.role === props.appInfo.defaultRole) {
const extCls = Parse.Object.extend(rld.extended_class);
const newObj = new extCls();
newObj.set("UserId", {
__type: "Pointer",
className: "_User",
objectId: r.id
});
newObj.set("UserRole", props.appInfo.defaultRole);
newObj.set("Email", email);
newObj.set("Name", name);
newObj.set("Phone", phone);
newObj.set("Company", company);
newObj.set("JobTitle", jobTitle);
newObj
.save()
.then((ex) => {
if (ex) {
handleNavigation(r.getSessionToken());
}
})
.catch((err) => {
alert(err.message);
setState({ loading: false });
});
localStorage.clear();
localStorage.setItem("BaseUrl12", baseUrl);
localStorage.setItem("AppID12", appid);
localStorage.setItem("appLogo", applogo);
localStorage.setItem("domain", domain);
localStorage.setItem("appversion", appversion);
localStorage.setItem("appTitle", appTitle);
localStorage.setItem("defaultmenuid", defaultmenuid);
localStorage.setItem("PageLanding", PageLanding);
localStorage.setItem("_appName", _appName);
localStorage.setItem("_app_objectId", _app_objectId);
localStorage.setItem("appName", appName);
localStorage.setItem("userSettings", userSettings);
localStorage.setItem("baseUrl", baseUrl);
localStorage.setItem("parseAppId", appid);
};
const handleSubmit = (event) => {
event.preventDefault();
if (lengthValid && caseDigitValid && specialCharValid) {
clearStorage();
setState({ loading: true });
const userDetails = {
name: name,
email: email,
phone: phone,
company: company,
jobTitle: jobTitle
};
localStorage.setItem("userDetails", JSON.stringify(userDetails));
try {
Parse.serverURL = parseBaseUrl;
Parse.initialize(parseAppId);
event.preventDefault();
var user = new Parse.User();
user.set("name", name);
user.set("email", email);
user.set("password", password);
user.set("phone", phone);
user.set("username", email);
let res = user.save();
res
.then(async (r) => {
if (r) {
let roleData = props.appInfo.settings;
if (roleData && roleData.length > 0) {
const params = {
userDetails: {
jobTitle: jobTitle,
company: company,
name: name,
email: email,
phone: phone,
role: props.appInfo.defaultRole
}
};
try {
const usersignup = await Parse.Cloud.run(
"usersignup",
params
);
if (usersignup) {
handleNavigation(r.getSessionToken());
}
} catch (err) {
alert(err.message);
setState({ loading: false });
}
});
}
}
}
})
.catch((err) => {
alert(err.message);
setState({ loading: false });
});
} catch (error) {
console.log("err ", error);
})
.catch(async (err) => {
if (err.code === 202) {
const params = { email: email };
const res = await Parse.Cloud.run("getUserDetails", params);
// console.log("Res ", res);
if (res) {
alert("User already exists with this username!");
setState({ loading: false });
} else {
let baseUrl = localStorage.getItem("BaseUrl12");
let parseAppId = localStorage.getItem("AppID12");
// console.log("state.email ", email);
try {
Parse.serverURL = baseUrl;
Parse.initialize(parseAppId);
await Parse.User.requestPasswordReset(email).then(
async function (res1) {
if (res1.data === undefined) {
alert(
"Verification mail has been sent to your E-mail!"
);
}
}
);
} catch (err) {
console.log(err);
}
setState({ loading: false });
}
} else {
alert(err.message);
setState({ loading: false });
}
});
} catch (error) {
console.log("err ", error);
}
}
};
@@ -179,13 +231,6 @@ const Signup = (props) => {
""
);
localStorage.setItem("_user_role", _role);
if (element.enableCart) {
localStorage.setItem("EnableCart", element.enableCart);
props.setEnableCart(element.enableCart);
} else {
localStorage.removeItem("EnableCart");
}
// Get TenentID from Extendend Class
localStorage.setItem(
"extended_class",
@@ -193,15 +238,12 @@ const Signup = (props) => {
);
localStorage.setItem("userpointer", element.userpointer);
const extendedClass = Parse.Object.extend(
element.extended_class
);
let query = new Parse.Query(extendedClass);
query.equalTo("UserId", Parse.User.current());
query.include("TenantId");
await query.find().then(
(results) => {
await Parse.Cloud.run("getUserDetails", {
email: email
}).then(
(result) => {
let tenentInfo = [];
const results = [result];
if (results) {
let extendedInfo_stringify =
JSON.stringify(results);
@@ -289,7 +331,7 @@ const Signup = (props) => {
);
setState({ loading: false });
if (process.env.REACT_APP_ENABLE_SUBSCRIPTION) {
navigate("/subscription");
navigate(`/subscription`, { replace: true });
} else {
alert("Registered user successfully");
navigate(
@@ -307,7 +349,7 @@ const Signup = (props) => {
localStorage.setItem("pageType", element.pageType);
setState({ loading: false });
if (process.env.REACT_APP_ENABLE_SUBSCRIPTION) {
navigate("/subscription");
navigate(`/subscription`, { replace: true });
} else {
navigate(
`/${element.pageType}/${element.pageId}`
@@ -392,23 +434,26 @@ const Signup = (props) => {
}
};
useEffect(() => {
window.addEventListener("resize", resize);
props.fetchAppInfo(
localStorage.getItem("domain"),
localStorage.getItem("BaseUrl12"),
localStorage.getItem("AppID12")
);
return () => {
window.removeEventListener("resize", resize);
};
// eslint-disable-next-line
}, []);
const resize = () => {
let currentHideNav = window.innerWidth <= 760;
if (currentHideNav !== state.hideNav) {
setState({ hideNav: currentHideNav });
}
const handlePasswordChange = (e) => {
const newPassword = e.target.value;
setPassword(newPassword);
// Check conditions separately
setLengthValid(newPassword.length >= 8);
setCaseDigitValid(
/[a-z]/.test(newPassword) &&
/[A-Z]/.test(newPassword) &&
/\d/.test(newPassword)
);
setSpecialCharValid(/[!@#$%^&*()\-_=+{};:,<.>]/.test(newPassword));
};
return (
<div className="bg-white">
@@ -443,17 +488,13 @@ const Signup = (props) => {
<div>
<div className="md:m-10 lg:m-16 md:p-4 lg:p-10 p-5 bg-[#ffffff] md:border-[1px] md:border-gray-400 ">
<div className="w-[250px] h-[66px] inline-block">
{state.hideNav ? (
<img src={image} width="100%" alt="" />
) : (
<img src={image} width="100%" alt="" />
)}
<img src={image} width="100%" alt="" />
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-2">
<div className="">
<form onSubmit={handleSubmit}>
<h2 className="text-[30px] mt-6">Create Account !</h2>
<div className="shadow-md rounded my-4">
<div className="outline outline-1 outline-slate-300/50 shadow-md rounded my-4">
<div className="px-6 py-4 text-xs">
<label className="block ">
Name{" "}
@@ -472,6 +513,7 @@ const Signup = (props) => {
<span style={{ color: "red", fontSize: 13 }}>*</span>
</label>
<input
id="email"
type="text"
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
value={email}
@@ -525,7 +567,7 @@ const Signup = (props) => {
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
name="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
onChange={(e) => handlePasswordChange(e)}
required
/>
<span
@@ -541,6 +583,38 @@ const Signup = (props) => {
)}
</span>
</div>
{password.length > 0 && (
<div className="mt-1 text-[11px]">
<p
className={`${
lengthValid ? "text-green-600" : "text-red-600"
}`}
>
{lengthValid ? "✓" : "✗"} Password should be 8
characters long
</p>
<p
className={`${
caseDigitValid ? "text-green-600" : "text-red-600"
}`}
>
{caseDigitValid ? "✓" : "✗"} Password should contain
uppercase letter, lowercase letter, digit
</p>
<p
className={`${
specialCharValid
? "text-green-600"
: "text-red-600"
}`}
>
{specialCharValid ? "✓" : "✗"} Password should
contain special character
</p>
{/* </>
)} */}
</div>
)}
</div>
</div>
<div className="flex flex-col md:flex-row justify-between items-stretch gap-8 text-center text-xs font-bold mt-2">
@@ -554,16 +628,16 @@ const Signup = (props) => {
<NavLink
className="rounded-sm cursor-pointer bg-white border-[1px] border-[#15b4e9] text-[#15b4e9] w-full py-3 shadow uppercase"
to="/"
style={state.hideNav ? { textAlign: "center" } : {}}
style={width < 768 ? { textAlign: "center" } : {}}
>
Login
</NavLink>
</div>
</form>
</div>
{!state.hideNav && (
{width >= 768 && (
<div className="self-center">
<div className="mx-auto md:w-[300px] lg:w-[500px]">
<div className="mx-auto md:w-[300px] lg:w-[400px] xl:w-[500px]">
<img src={login_img} alt="bisec" width="100%" />
</div>
</div>
+139 -109
View File
@@ -5,7 +5,7 @@ import { SaveFileSize } from "../constant/saveFileSize";
import dp from "../assets/images/dp.png";
import Title from "../components/Title";
import sanitizeFileName from "../primitives/sanitizeFileName";
import axios from "axios";
function UserProfile() {
const navigate = useNavigate();
let UserProfile = JSON.parse(localStorage.getItem("UserInformation"));
@@ -16,6 +16,8 @@ function UserProfile() {
const [Phone, SetPhone] = useState(UserProfile && UserProfile.phone);
const [Image, setImage] = useState(localStorage.getItem("profileImg"));
const [isLoader, setIsLoader] = useState(false);
const [percentage, setpercentage] = useState(0);
Parse.serverURL = parseBaseUrl;
Parse.initialize(parseAppId);
const handleSubmit = async (e) => {
@@ -44,7 +46,7 @@ function UserProfile() {
await updateExtUser({ Name: res.name, Phone: res.phone });
alert("Profile updated successfully.");
setEditMode(false);
navigate("/");
navigate("/dashboard/35KBoSgoAK");
}
},
(error) => {
@@ -64,18 +66,24 @@ function UserProfile() {
const extClass = localStorage.getItem("extended_class");
const extData = JSON.parse(localStorage.getItem("Extand_Class"));
const ExtUserId = extData[0].objectId;
// console.log("extData ", extData);
// console.log("UserId ", ExtUserId);
const body = { Phone: obj.Phone, Name: obj.Name };
await axios.put(
parseBaseUrl + "classes/" + extClass + "/" + ExtUserId,
body,
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": parseAppId,
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
}
}
);
const res = await Parse.Cloud.run("getUserDetails", {
email: extData[0].Email
});
const extQuery = new Parse.Query(extClass);
const update = await extQuery.get(ExtUserId);
// console.log("update ", update);
update.set("Phone", obj.Phone);
update.set("Name", obj.Name);
const updateRes = await update.save();
const json = JSON.parse(JSON.stringify([updateRes]));
const json = JSON.parse(JSON.stringify([res]));
const extRes = JSON.stringify(json);
localStorage.setItem("Extand_Class", extRes);
@@ -96,7 +104,15 @@ function UserProfile() {
const parseFile = new Parse.File(name, pdfFile);
try {
const response = await parseFile.save();
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);
}
}
});
// // The response object will contain information about the uploaded file
// console.log("File uploaded:", response);
@@ -105,6 +121,7 @@ function UserProfile() {
if (response.url()) {
setImage(response.url());
localStorage.setItem("profileImg", response.url());
setpercentage(0);
SaveFileSize(size, response.url());
return response.url();
}
@@ -141,113 +158,126 @@ function UserProfile() {
></div>
</div>
) : (
<div className="bg-white flex flex-col justify-center shadow rounded">
<div className="flex flex-col justify-center items-center my-4">
<div className="w-[200px] h-[200px] overflow-hidden rounded-full">
<img
className="object-contain w-full h-full"
src={Image === "" ? dp : Image}
alt="dp"
/>
</div>
{editmode && (
<input
type="file"
className="max-w-[270px] text-sm py-1 px-2 mt-4 border-[1px] border-[#15b4e9] text-black rounded"
onChange={(e) => {
let files = e.target.files;
fileUpload(files[0]);
}}
/>
)}
<div className="text-base font-semibold pt-4">
{" "}
{localStorage.getItem("_user_role")}
</div>
</div>
<ul className="w-full flex flex-col p-2 text-sm">
<li
className={`flex justify-between items-center border-t-[1px] border-gray-300 break-all ${
editmode ? "py-1" : "py-2"
}`}
>
<span>Name:</span>{" "}
{editmode ? (
<input
type="text"
value={name}
className="py-1 px-2 text-sm border-[1px] border-[#15b4e9] text-black rounded"
onChange={(e) => SetName(e.target.value)}
<div className="flex justify-center items-center w-full">
<div className="bg-white flex flex-col justify-center shadow rounded w-[450px]">
<div className="flex flex-col justify-center items-center my-4">
<div className="w-[200px] h-[200px] overflow-hidden rounded-full">
<img
className="object-contain w-full h-full"
src={Image === "" ? dp : Image}
alt="dp"
/>
) : (
<span>{localStorage.getItem("username")}</span>
)}
</li>
<li
className={`flex justify-between items-center border-t-[1px] border-gray-300 break-all ${
editmode ? "py-1" : "py-2"
}`}
>
<span>Phone:</span>{" "}
{editmode ? (
</div>
{editmode && (
<input
type="text"
className="py-1 px-2 text-sm border-[1px] border-[#15b4e9] text-black rounded"
onChange={(e) => SetPhone(e.target.value)}
value={Phone}
type="file"
className="max-w-[270px] text-sm py-1 px-2 mt-4 border-[1px] border-[#15b4e9] text-black rounded"
accept="image/png, image/gif, image/jpeg"
onChange={(e) => {
let files = e.target.files;
fileUpload(files[0]);
}}
/>
) : (
<span>{UserProfile && UserProfile.phone}</span>
)}
</li>
<li className="flex justify-between items-center border-t-[1px] border-gray-300 py-2 break-all">
<span>Email:</span>{" "}
<span>{UserProfile && UserProfile.email}</span>
</li>
<li className="flex justify-between items-center border-y-[1px] border-gray-300 py-2 break-all">
<span>Is Email verified:</span>{" "}
<span>
{UserProfile && UserProfile.emailVerified
? "Verified"
: "Not verified"}
</span>
</li>
</ul>
<div className="flex justify-center pb-4">
<button
type="button"
onClick={() => {
if (editmode) {
setEditMode(false);
} else {
navigate("/changepassword");
}
}}
className={`rounded shadow text-white bg-[#3598dc] mr-4 ${
editmode ? "px-4 py-2 " : "p-2"
}`}
>
{editmode ? "Cancel" : "Change Password"}
</button>
{editmode ? (
<button
type="button"
onClick={handleSubmit}
className="rounded bg-white border-[1px] border-[#15b4e9] text-[#15b4e9] px-4 py-2"
{percentage !== 0 && (
<div className="flex items-center gap-x-2">
<div className="h-2 rounded-full w-[200px] md:w-[400px] bg-gray-200">
<div
className="h-2 rounded-full bg-blue-500"
style={{ width: `${percentage}%` }}
></div>
</div>
<span className="text-black text-sm">{percentage}%</span>
</div>
)}
<div className="text-base font-semibold pt-4">
{localStorage.getItem("_user_role")}
</div>
</div>
<ul className="w-full flex flex-col p-2 text-sm">
<li
className={`flex justify-between items-center border-t-[1px] border-gray-300 break-all ${
editmode ? "py-1" : "py-2"
}`}
>
Save
</button>
) : (
<span className="font-semibold">Name:</span>{" "}
{editmode ? (
<input
type="text"
value={name}
className="py-1 px-2 text-sm border-[1px] border-[#15b4e9] text-black rounded"
onChange={(e) => SetName(e.target.value)}
/>
) : (
<span>{localStorage.getItem("username")}</span>
)}
</li>
<li
className={`flex justify-between items-center border-t-[1px] border-gray-300 break-all ${
editmode ? "py-1" : "py-2"
}`}
>
<span className="font-semibold">Phone:</span>{" "}
{editmode ? (
<input
type="text"
className="py-1 px-2 text-sm border-[1px] border-[#15b4e9] text-black rounded"
onChange={(e) => SetPhone(e.target.value)}
value={Phone}
/>
) : (
<span>{UserProfile && UserProfile.phone}</span>
)}
</li>
<li className="flex justify-between items-center border-t-[1px] border-gray-300 py-2 break-all">
<span className="font-semibold">Email:</span>{" "}
<span>{UserProfile && UserProfile.email}</span>
</li>
<li className="flex justify-between items-center border-y-[1px] border-gray-300 py-2 break-all">
<span className="font-semibold">Is Email verified:</span>{" "}
<span>
{UserProfile && UserProfile.emailVerified
? "Verified"
: "Not verified"}
</span>
</li>
</ul>
<div className="flex justify-center pt-2 pb-3 md:pt-3 md:pb-4">
{editmode ? (
<button
type="button"
onClick={handleSubmit}
className="rounded shadow focus:outline-none border-[2px] border-[#15b4e9] bg-white text-[#15b4e9] px-4 py-2 mr-4"
>
Save
</button>
) : (
<button
type="button"
onClick={() => {
setEditMode(true);
}}
className="rounded shadow focus:outline-none text-white bg-[#e7505a] px-4 py-2 mr-4"
>
Edit
</button>
)}
<button
type="button"
onClick={() => {
setEditMode(true);
if (editmode) {
setEditMode(false);
} else {
navigate("/changepassword");
}
}}
className="rounded shadow text-white bg-[#e7505a] px-4 py-2"
className={`rounded shadow focus:outline-none text-white bg-[#3598dc] ${
editmode ? "px-4 py-2 " : "p-2"
}`}
>
Edit
{editmode ? "Cancel" : "Change Password"}
</button>
)}
</div>
</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
+29 -9
View File
@@ -1,12 +1,14 @@
/* Full-width input fields */
.inputt {
width: 100%;
padding: 15px;
margin: 5px 0 22px 0;
padding: 8px;
margin-bottom: 10px;
/* margin: 5px 0 14px 0; */
display: inline-block;
border: none;
background: #f1f1f1;
color: black;
font-size: 12px;
}
/* Add a background color when the inputs get focus */
@@ -18,11 +20,12 @@
.confirmInputt {
width: 100%;
padding: 15px;
margin: 5px 0 1px 0;
padding: 8px;
/* margin: 5px 0 14px 0; */
display: inline-block;
background: #f1f1f1;
color: black;
font-size: 12px;
}
.inputt::placeholder,
@@ -42,11 +45,10 @@
.signupbtn {
background-color: #15b4e9;
color: white;
padding: 14px 20px;
padding: 12px 12px;
margin: 8px 0;
border: none;
cursor: pointer;
width: 100%;
opacity: 0.9;
float: left;
width: 50%;
@@ -87,7 +89,7 @@
margin: 5% auto 15% auto;
/* 5% from the top, 15% from the bottom and centered */
border: 1px solid #888;
width: 80%;
width: 50%;
/* Could be more or less, depending on screen size */
}
@@ -111,8 +113,26 @@
}
/* Change styles for cancel button and signup button on extra small screens */
@media screen and (max-width: 300px) {
@media screen and (max-width: 768px) {
/* pgsignup Content/Box */
.pgsignup-content {
background-color: #fefefe;
margin: 5% auto 15% auto;
/* 5% from the top, 15% from the bottom and centered */
border: 1px solid #888;
width: 90%;
/* Could be more or less, depending on screen size */
}
.signupbtn {
width: 100%;
font-size: 16px;
}
}
/* Style the horizontal ruler */
.hrt {
border: 1px solid #f1f1f1;
margin-bottom: 16px;
}
}
+36
View File
@@ -0,0 +1,36 @@
.alertBox {
z-index: 1;
position: absolute;
top: 10%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 13px;
animation: inAnimation 2s ease-in-out;
}
@keyframes inAnimation {
0% {
opacity: 0;
visibility: hidden;
}
25% {
opacity: 1;
visibility: visible;
}
50% {
opacity: 1;
visibility: visible;
}
75% {
opacity: 1;
visibility: visible;
}
100% {
opacity: 0;
visibility: hidden;
}
}
+53 -198
View File
@@ -1,209 +1,64 @@
#snackbar {
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%;
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;
}
#snackbar.show {
visibility: visible;
-webkit-animation: fadein 0.5s;
}
@-webkit-keyframes fadein {
from {
top: 0;
opacity: 0;
}
to {
top: 30px;
font-size: 14px;
opacity: 1;
}
#_editsnackbar {
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%;
}
@keyframes fadein {
from {
top: 0;
opacity: 0;
}
to {
top: 30px;
font-size: 14px;
opacity: 1;
}
#_editsnackbar.show {
visibility: visible;
-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%;
}
@-webkit-keyframes fadeout {
from {
top: 30px;
font-size: 14px;
opacity: 1;
}
#deleteObj.show {
visibility: visible;
-webkit-animation: fadein 0.5s;
to {
top: 0;
opacity: 0;
}
#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%;
}
@keyframes fadeout {
from {
top: 30px;
font-size: 14px;
opacity: 1;
}
#UpdateColumnValue {
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;
to {
top: 0;
opacity: 0;
}
#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
FROM node:16
FROM node:18
# Set the working directory inside the container
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;
}
@@ -4,6 +4,12 @@ import multerS3 from 'multer-s3';
import aws from 'aws-sdk';
import dotenv from 'dotenv';
dotenv.config();
function sanitizeFileName(fileName) {
// Remove spaces and invalid characters
return fileName.replace(/[^a-zA-Z0-9._-]/g, '');
}
async function uploadFile(req, res) {
try {
//--size extended to 100 mb
@@ -41,14 +47,79 @@ async function uploadFile(req, res) {
const DO_ACCESS_KEY_ID = process.env.DO_ACCESS_KEY_ID;
const DO_SECRET_ACCESS_KEY = process.env.DO_SECRET_ACCESS_KEY;
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 parseAppId = process.env.APP_ID;
let fileStorage;
if (process.env.USE_LOCAL == 'TRUE') {
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);
},
});
} else {
try {
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,
});
fileStorage = multerS3({
acl: 'public-read',
s3,
bucket: DO_SPACE,
metadata: function (req, file, cb) {
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 upload = multer({
@@ -59,24 +130,7 @@ async function uploadFile(req, res) {
// otherwise, return error
return cb('Only ' + accepted_extensions.join(', ') + ' files are allowed!');
},
storage: multerS3({
acl: 'public-read',
s3,
bucket: DO_SPACE,
metadata: function (req, file, cb) {
cb(null, { fieldName: 'OPENSIGN_METADATA' });
},
key: function (req, file, cb) {
//console.log(file);
let filename = file.originalname;
let filenam = filename.split('.')[0];
let extension = filename.split('.')[1];
filenam = filenam + '_' + new Date().toISOString() + '.' + extension;
console.log(filenam);
cb(null, filenam);
},
}),
storage: fileStorage,
limits: { fileSize: size },
}).single('file');
@@ -93,7 +147,14 @@ async function uploadFile(req, res) {
const status = 'Success';
//res.header("Access-Control-Allow-Headers", "Content-Type");
//res.setHeader("Access-Control-Allow-Origin", "*");
return res.json({ status, imageUrl: req.file.location });
if (process.env.USE_LOCAL == 'TRUE') {
console.log(req.file);
var fileUrl = `${parseBaseUrl}/files/${parseAppId}/${req.file.filename}`;
} else {
var fileUrl = req.file.location;
}
return res.json({ status, imageUrl: fileUrl });
});
} catch (err) {
console.log('Exeption in query ' + err.stack);
@@ -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!' });
}
}

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