Merge pull request #1672 from OpenSignLabs/updates-14279056892

v2.16.0
This commit is contained in:
prafull-opensignlabs
2025-04-05 11:36:59 +05:30
committed by GitHub
49 changed files with 992 additions and 1443 deletions
+5 -416
View File
@@ -12,7 +12,6 @@
"@lottiefiles/dotlottie-react": "^0.13.2",
"@pdf-lib/fontkit": "^1.1.1",
"@radix-ui/themes": "^3.1.6",
"@react-pdf/renderer": "^4.3.0",
"@reduxjs/toolkit": "^2.5.1",
"axios": "^1.8.4",
"css-minimizer-webpack-plugin": "^7.0.2",
@@ -6107,174 +6106,6 @@
"resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz",
"integrity": "sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA=="
},
"node_modules/@react-pdf/fns": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@react-pdf/fns/-/fns-3.1.2.tgz",
"integrity": "sha512-qTKGUf0iAMGg2+OsUcp9ffKnKi41RukM/zYIWMDJ4hRVYSr89Q7e3wSDW/Koqx3ea3Uy/z3h2y3wPX6Bdfxk6g==",
"license": "MIT"
},
"node_modules/@react-pdf/font": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@react-pdf/font/-/font-4.0.2.tgz",
"integrity": "sha512-/dAWu7Y2RD1RxarDZ9SkYPHgBYOhmcDnet4W/qN/m8k+A2Hr3ja54GymSR7GGxWBtxjKtNauVKrTa9LS1n8WUw==",
"license": "MIT",
"dependencies": {
"@react-pdf/pdfkit": "^4.0.3",
"@react-pdf/types": "^2.9.0",
"fontkit": "^2.0.2",
"is-url": "^1.2.4"
}
},
"node_modules/@react-pdf/image": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@react-pdf/image/-/image-3.0.3.tgz",
"integrity": "sha512-lvP5ryzYM3wpbO9bvqLZYwEr5XBDX9jcaRICvtnoRqdJOo7PRrMnmB4MMScyb+Xw10mGeIubZAAomNAG5ONQZQ==",
"license": "MIT",
"dependencies": {
"@react-pdf/png-js": "^3.0.0",
"jay-peg": "^1.1.1"
}
},
"node_modules/@react-pdf/layout": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/@react-pdf/layout/-/layout-4.4.0.tgz",
"integrity": "sha512-Aq+Cc6JYausWLoks2FvHe3PwK9cTuvksB2uJ0AnkKJEUtQbvCq8eCRb1bjbbwIji9OzFRTTzZij7LzkpKHjIeA==",
"license": "MIT",
"dependencies": {
"@react-pdf/fns": "3.1.2",
"@react-pdf/image": "^3.0.3",
"@react-pdf/primitives": "^4.1.1",
"@react-pdf/stylesheet": "^6.1.0",
"@react-pdf/textkit": "^6.0.0",
"@react-pdf/types": "^2.9.0",
"emoji-regex": "^10.3.0",
"queue": "^6.0.1",
"yoga-layout": "^3.2.1"
}
},
"node_modules/@react-pdf/pdfkit": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/@react-pdf/pdfkit/-/pdfkit-4.0.3.tgz",
"integrity": "sha512-k+Lsuq8vTwWsCqTp+CCB4+2N+sOTFrzwGA7aw3H9ix/PDWR9QksbmNg0YkzGbLAPI6CeawmiLHcf4trZ5ecLPQ==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.20.13",
"@react-pdf/png-js": "^3.0.0",
"browserify-zlib": "^0.2.0",
"crypto-js": "^4.2.0",
"fontkit": "^2.0.2",
"jay-peg": "^1.1.1",
"linebreak": "^1.1.0",
"vite-compatible-readable-stream": "^3.6.1"
}
},
"node_modules/@react-pdf/png-js": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@react-pdf/png-js/-/png-js-3.0.0.tgz",
"integrity": "sha512-eSJnEItZ37WPt6Qv5pncQDxLJRK15eaRwPT+gZoujP548CodenOVp49GST8XJvKMFt9YqIBzGBV/j9AgrOQzVA==",
"license": "MIT",
"dependencies": {
"browserify-zlib": "^0.2.0"
}
},
"node_modules/@react-pdf/primitives": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/@react-pdf/primitives/-/primitives-4.1.1.tgz",
"integrity": "sha512-IuhxYls1luJb7NUWy6q5avb1XrNaVj9bTNI40U9qGRuS6n7Hje/8H8Qi99Z9UKFV74bBP3DOf3L1wV2qZVgVrQ==",
"license": "MIT"
},
"node_modules/@react-pdf/reconciler": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/@react-pdf/reconciler/-/reconciler-1.1.4.tgz",
"integrity": "sha512-oTQDiR/t4Z/Guxac88IavpU2UgN7eR0RMI9DRKvKnvPz2DUasGjXfChAdMqDNmJJxxV26mMy9xQOUV2UU5/okg==",
"license": "MIT",
"dependencies": {
"object-assign": "^4.1.1",
"scheduler": "0.25.0-rc-603e6108-20241029"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
"node_modules/@react-pdf/render": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/@react-pdf/render/-/render-4.3.0.tgz",
"integrity": "sha512-MdWfWaqO6d7SZD75TZ2z5L35V+cHpyA43YNRlJNG0RJ7/MeVGDQv12y/BXOJgonZKkeEGdzM3EpAt9/g4E22WA==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.20.13",
"@react-pdf/fns": "3.1.2",
"@react-pdf/primitives": "^4.1.1",
"@react-pdf/textkit": "^6.0.0",
"@react-pdf/types": "^2.9.0",
"abs-svg-path": "^0.1.1",
"color-string": "^1.9.1",
"normalize-svg-path": "^1.1.0",
"parse-svg-path": "^0.1.2",
"svg-arc-to-cubic-bezier": "^3.2.0"
}
},
"node_modules/@react-pdf/renderer": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/@react-pdf/renderer/-/renderer-4.3.0.tgz",
"integrity": "sha512-28gpA69fU9ZQrDzmd5xMJa1bDf8t0PT3ApUKBl2PUpoE/x4JlvCB5X66nMXrfFrgF2EZrA72zWQAkvbg7TE8zw==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.20.13",
"@react-pdf/fns": "3.1.2",
"@react-pdf/font": "^4.0.2",
"@react-pdf/layout": "^4.4.0",
"@react-pdf/pdfkit": "^4.0.3",
"@react-pdf/primitives": "^4.1.1",
"@react-pdf/reconciler": "^1.1.4",
"@react-pdf/render": "^4.3.0",
"@react-pdf/types": "^2.9.0",
"events": "^3.3.0",
"object-assign": "^4.1.1",
"prop-types": "^15.6.2",
"queue": "^6.0.1"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
"node_modules/@react-pdf/stylesheet": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/@react-pdf/stylesheet/-/stylesheet-6.1.0.tgz",
"integrity": "sha512-BGZ2sYNUp38VJUegjva/jsri3iiRGnVNjWI+G9dTwAvLNOmwFvSJzqaCsEnqQ/DW5mrTBk/577FhDY7pv6AidA==",
"license": "MIT",
"dependencies": {
"@react-pdf/fns": "3.1.2",
"@react-pdf/types": "^2.9.0",
"color-string": "^1.9.1",
"hsl-to-hex": "^1.0.0",
"media-engine": "^1.0.3",
"postcss-value-parser": "^4.1.0"
}
},
"node_modules/@react-pdf/textkit": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/@react-pdf/textkit/-/textkit-6.0.0.tgz",
"integrity": "sha512-fDt19KWaJRK/n2AaFoVm31hgGmpygmTV7LsHGJNGZkgzXcFyLsx+XUl63DTDPH3iqxj3xUX128t104GtOz8tTw==",
"license": "MIT",
"dependencies": {
"@react-pdf/fns": "3.1.2",
"bidi-js": "^1.0.2",
"hyphen": "^1.6.4",
"unicode-properties": "^1.4.1"
}
},
"node_modules/@react-pdf/types": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/@react-pdf/types/-/types-2.9.0.tgz",
"integrity": "sha512-ckj80vZLlvl9oYrQ4tovEaqKWP3O06Eb1D48/jQWbdwz1Yh7Y9v1cEmwlP8ET+a1Whp8xfdM0xduMexkuPANCQ==",
"license": "MIT",
"dependencies": {
"@react-pdf/font": "^4.0.2",
"@react-pdf/primitives": "^4.1.1",
"@react-pdf/stylesheet": "^6.1.0"
}
},
"node_modules/@reduxjs/toolkit": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.5.1.tgz",
@@ -7534,12 +7365,6 @@
"optional": true,
"peer": true
},
"node_modules/abs-svg-path": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/abs-svg-path/-/abs-svg-path-0.1.1.tgz",
"integrity": "sha512-d8XPSGjfyzlXC3Xx891DJRyZfqk5JU0BJrDQcsWomFIV1/BIzPW5HDH5iDdWpqWaav0YVIEzT1RHTwWr0FFshA==",
"license": "MIT"
},
"node_modules/accepts": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
@@ -8429,6 +8254,7 @@
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
"devOptional": true,
"funding": [
{
"type": "github",
@@ -8464,15 +8290,6 @@
"node": ">= 8.0.0"
}
},
"node_modules/bidi-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz",
"integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==",
"license": "MIT",
"dependencies": {
"require-from-string": "^2.0.2"
}
},
"node_modules/big.js": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
@@ -8727,29 +8544,11 @@
"node": ">=8"
}
},
"node_modules/brotli": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz",
"integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==",
"license": "MIT",
"dependencies": {
"base64-js": "^1.1.2"
}
},
"node_modules/browser-process-hrtime": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz",
"integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow=="
},
"node_modules/browserify-zlib": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz",
"integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==",
"license": "MIT",
"dependencies": {
"pako": "~1.0.5"
}
},
"node_modules/browserslist": {
"version": "4.24.4",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz",
@@ -9455,15 +9254,6 @@
"node": ">=12"
}
},
"node_modules/clone": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
"integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
"license": "MIT",
"engines": {
"node": ">=0.8"
}
},
"node_modules/clone-deep": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz",
@@ -9535,16 +9325,6 @@
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
},
"node_modules/color-string": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
"integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
"license": "MIT",
"dependencies": {
"color-name": "^1.0.0",
"simple-swizzle": "^0.2.2"
}
},
"node_modules/color-support": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
@@ -9952,7 +9732,8 @@
"node_modules/crypto-js": {
"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=="
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==",
"optional": true
},
"node_modules/crypto-random-string": {
"version": "2.0.0",
@@ -11062,12 +10843,6 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"node_modules/dfa": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/dfa/-/dfa-1.2.0.tgz",
"integrity": "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==",
"license": "MIT"
},
"node_modules/didyoumean": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
@@ -11360,7 +11135,8 @@
"node_modules/emoji-regex": {
"version": "10.4.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz",
"integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw=="
"integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==",
"dev": true
},
"node_modules/emojis-list": {
"version": "3.0.0",
@@ -12689,23 +12465,6 @@
}
}
},
"node_modules/fontkit": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/fontkit/-/fontkit-2.0.4.tgz",
"integrity": "sha512-syetQadaUEDNdxdugga9CpEYVaQIxOwk7GlwZWWZ19//qW4zE5bknOKeMBDYAASwnpaSHKJITRLMF9m1fp3s6g==",
"license": "MIT",
"dependencies": {
"@swc/helpers": "^0.5.12",
"brotli": "^1.3.2",
"clone": "^2.1.2",
"dfa": "^1.2.0",
"fast-deep-equal": "^3.1.3",
"restructure": "^3.0.0",
"tiny-inflate": "^1.0.3",
"unicode-properties": "^1.4.0",
"unicode-trie": "^2.0.0"
}
},
"node_modules/for-each": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
@@ -13559,21 +13318,6 @@
"wbuf": "^1.1.0"
}
},
"node_modules/hsl-to-hex": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/hsl-to-hex/-/hsl-to-hex-1.0.0.tgz",
"integrity": "sha512-K6GVpucS5wFf44X0h2bLVRDsycgJmf9FF2elg+CrqD8GcFU8c6vYhgXn8NjUkFCwj+xDFb70qgLbTUm6sxwPmA==",
"license": "MIT",
"dependencies": {
"hsl-to-rgb-for-reals": "^1.1.0"
}
},
"node_modules/hsl-to-rgb-for-reals": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/hsl-to-rgb-for-reals/-/hsl-to-rgb-for-reals-1.1.1.tgz",
"integrity": "sha512-LgOWAkrN0rFaQpfdWBQlv/VhkOxb5AsBjk6NQVx4yEzWS923T07X0M1Y0VNko2H52HeSpZrZNNMJ0aFqsdVzQg==",
"license": "ISC"
},
"node_modules/html-encoding-sniffer": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz",
@@ -13790,12 +13534,6 @@
"node": ">=16.17.0"
}
},
"node_modules/hyphen": {
"version": "1.10.6",
"resolved": "https://registry.npmjs.org/hyphen/-/hyphen-1.10.6.tgz",
"integrity": "sha512-fXHXcGFTXOvZTSkPJuGOQf5Lv5T/R2itiiCVPg9LxAje5D00O0pP83yJShFq5V89Ly//Gt6acj7z8pbBr34stw==",
"license": "ISC"
},
"node_modules/i18next": {
"version": "23.16.8",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-23.16.8.tgz",
@@ -14717,12 +14455,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/is-url": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz",
"integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==",
"license": "MIT"
},
"node_modules/is-utf8": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
@@ -15043,15 +14775,6 @@
"node": ">=8"
}
},
"node_modules/jay-peg": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/jay-peg/-/jay-peg-1.1.1.tgz",
"integrity": "sha512-D62KEuBxz/ip2gQKOEhk/mx14o7eiFRaU+VNNSP4MOiIkwb/D6B3G1Mfas7C/Fit8EsSV2/IWjZElx/Gs6A4ww==",
"license": "MIT",
"dependencies": {
"restructure": "^3.0.0"
}
},
"node_modules/jest": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz",
@@ -17517,25 +17240,6 @@
"url": "https://github.com/sponsors/antonk52"
}
},
"node_modules/linebreak": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/linebreak/-/linebreak-1.1.0.tgz",
"integrity": "sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==",
"license": "MIT",
"dependencies": {
"base64-js": "0.0.8",
"unicode-trie": "^2.0.0"
}
},
"node_modules/linebreak/node_modules/base64-js": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz",
"integrity": "sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/lines-and-columns": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
@@ -18150,12 +17854,6 @@
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz",
"integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA=="
},
"node_modules/media-engine": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/media-engine/-/media-engine-1.0.3.tgz",
"integrity": "sha512-aa5tG6sDoK+k70B9iEX1NeyfT8ObCKhNDs6lJVpwF6r8vhUfuKMslIcirq6HIUYuuUYLefcEQOn9bSBOvawtwg==",
"license": "MIT"
},
"node_modules/media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@@ -18624,15 +18322,6 @@
"node": ">=0.10.0"
}
},
"node_modules/normalize-svg-path": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/normalize-svg-path/-/normalize-svg-path-1.1.0.tgz",
"integrity": "sha512-r9KHKG2UUeB5LoTouwDzBy2VxXlHsiM6fyLQvnJa0S5hrhzqElH/CH7TUGhT1fVvIYBIKf3OpY4YJ4CK+iaqHg==",
"license": "MIT",
"dependencies": {
"svg-arc-to-cubic-bezier": "^3.0.0"
}
},
"node_modules/normalize-url": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz",
@@ -19193,12 +18882,6 @@
"node": ">=0.10.0"
}
},
"node_modules/parse-svg-path": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/parse-svg-path/-/parse-svg-path-0.1.2.tgz",
"integrity": "sha512-JyPSBnkTJ0AI8GGJLfMXvKq42cj5c006fnLz6fXy6zfoVjJizi8BNTpu8on8ziI1cKy9d9DGNuY17Ce7wuejpQ==",
"license": "MIT"
},
"node_modules/parse5": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
@@ -21186,15 +20869,6 @@
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
"integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="
},
"node_modules/queue": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz",
"integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==",
"license": "MIT",
"dependencies": {
"inherits": "~2.0.3"
}
},
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -24284,12 +23958,6 @@
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
"dev": true
},
"node_modules/restructure": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/restructure/-/restructure-3.0.2.tgz",
"integrity": "sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw==",
"license": "MIT"
},
"node_modules/retry": {
"version": "0.13.1",
"resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz",
@@ -24549,12 +24217,6 @@
"node": ">=10"
}
},
"node_modules/scheduler": {
"version": "0.25.0-rc-603e6108-20241029",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0-rc-603e6108-20241029.tgz",
"integrity": "sha512-pFwF6H1XrSdYYNLfOcGlM28/j8CGLu8IvdrxqhjWULe2bPcKiKW4CV+OWqR/9fT52mywx65l7ysNkjLKBda7eA==",
"license": "MIT"
},
"node_modules/schema-utils": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz",
@@ -25060,21 +24722,6 @@
"simple-concat": "^1.0.0"
}
},
"node_modules/simple-swizzle": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
"integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
"license": "MIT",
"dependencies": {
"is-arrayish": "^0.3.1"
}
},
"node_modules/simple-swizzle/node_modules/is-arrayish": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
"license": "MIT"
},
"node_modules/sisteransi": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
@@ -25871,12 +25518,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/svg-arc-to-cubic-bezier": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/svg-arc-to-cubic-bezier/-/svg-arc-to-cubic-bezier-3.2.0.tgz",
"integrity": "sha512-djbJ/vZKZO+gPoSDThGNpKDO+o+bAeA4XQKovvkNCqnIS2t+S4qnLAGQhyyrulhCFRl1WWzAp0wUDV8PpTVU3g==",
"license": "ISC"
},
"node_modules/svg-parser": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz",
@@ -26307,12 +25948,6 @@
"resolved": "https://registry.npmjs.org/timezone-soft/-/timezone-soft-1.5.2.tgz",
"integrity": "sha512-BUr+CfBfeWXJwFAuEzPO9uF+v6sy3pL5SKLkDg4vdEhsyXgbBnpFoBCW8oEKSNTqNq9YHbVOjNb31xE7WyGmrA=="
},
"node_modules/tiny-inflate": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz",
"integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==",
"license": "MIT"
},
"node_modules/tiny-invariant": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz",
@@ -26699,16 +26334,6 @@
"node": ">=4"
}
},
"node_modules/unicode-properties": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz",
"integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==",
"license": "MIT",
"dependencies": {
"base64-js": "^1.3.0",
"unicode-trie": "^2.0.0"
}
},
"node_modules/unicode-property-aliases-ecmascript": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz",
@@ -26717,22 +26342,6 @@
"node": ">=4"
}
},
"node_modules/unicode-trie": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz",
"integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==",
"license": "MIT",
"dependencies": {
"pako": "^0.2.5",
"tiny-inflate": "^1.0.0"
}
},
"node_modules/unicode-trie/node_modules/pako": {
"version": "0.2.9",
"resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz",
"integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==",
"license": "MIT"
},
"node_modules/unique-string": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz",
@@ -26987,20 +26596,6 @@
"node": ">= 0.8"
}
},
"node_modules/vite-compatible-readable-stream": {
"version": "3.6.1",
"resolved": "https://registry.npmjs.org/vite-compatible-readable-stream/-/vite-compatible-readable-stream-3.6.1.tgz",
"integrity": "sha512-t20zYkrSf868+j/p31cRIGN28Phrjm3nRSLR2fyc2tiWi4cZGVdv68yNlwnIINTkMTmPoMiSlc0OadaO7DXZaQ==",
"license": "MIT",
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/void-elements": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
@@ -28136,12 +27731,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/yoga-layout": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/yoga-layout/-/yoga-layout-3.2.1.tgz",
"integrity": "sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ==",
"license": "MIT"
},
"node_modules/zoom-level": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/zoom-level/-/zoom-level-2.5.0.tgz",
-1
View File
@@ -7,7 +7,6 @@
"@lottiefiles/dotlottie-react": "^0.13.2",
"@pdf-lib/fontkit": "^1.1.1",
"@radix-ui/themes": "^3.1.6",
"@react-pdf/renderer": "^4.3.0",
"@reduxjs/toolkit": "^2.5.1",
"axios": "^1.8.4",
"css-minimizer-webpack-plugin": "^7.0.2",
@@ -151,7 +151,8 @@
"extend-expiry-date": "Ablaufdatum verlängern",
"Duplicate Template": "Vorlage duplizieren",
"Duplicate": "Duplikat",
"daily-mail-quota": "Tägliches E-Mail-Kontingent"
"daily-mail-quota": "Tägliches E-Mail-Kontingent",
"Save as template": "Als Vorlage speichern"
},
"report-heading": {
"Sr.No": "Nr.",
@@ -308,7 +309,7 @@
"revoke-document": "Dokument widerrufen",
"revoke-document-alert": "Sind Sie sicher, dass Sie dieses Dokument widerrufen möchten?",
"resend-mail": "E-Mail erneut senden",
"resend-mail-help": "Sie können folgende Variablen verwenden, die durch ihre tatsächlichen Werte ersetzt werden: {{document_title}}, {{sender_name}}, {{sender_mail}}, {{sender_phone}}, {{receiver_name}}, {{receiver_email}}, {{receiver_phone}}, {{expiry_date}}, {{company_name}}, {{signing_url}}.",
"resend-mail-help": "Sie können folgende Variablen verwenden, die durch ihre tatsächlichen Werte ersetzt werden: {{document_title}}, {{sender_name}}, {{sender_mail}}, {{sender_phone}}, {{receiver_name}}, {{receiver_email}}, {{receiver_phone}}, {{expiry_date}}, {{company_name}}, {{signing_url}}, {{note}}.",
"subject": "Betreff",
"body": "Inhalt",
"add-contact": "Kontakt hinzufügen",
@@ -522,7 +523,7 @@
"correct-password": "Bitte korrektes Passwort angeben",
"decrypting-pdf": "PDF wird entschlüsselt, bitte warten...",
"invalid-otp": "Ungültiger OTP",
"user-not-found": "Benutzer nicht gefunden!",
"user-not-found": "Benutzer nicht gefunden",
"enter-otp-alert": "Bitte OTP eingeben!",
"get-verification-code": "Verifizierungscode erhalten",
"get-verification-code-2": "Sie erhalten einen Verifizierungscode per E-Mail",
@@ -858,10 +859,19 @@
"indexing-public-profile": "Erlaube die Indexierung des öffentlichen Profils durch Suchmaschinen",
"user-created-successfully": "Benutzer erfolgreich erstellt.",
"only-15-reminder-allowed": "Sie können bis zu 15 automatische Erinnerungen festlegen. Wenn zum Beispiel 'TimeToComplete' auf 15 Tage und 'RemindOnceInEvery' auf 1 Tag eingestellt ist, erreichen Sie das maximale Limit von 15 Erinnerungen. Passen Sie Ihre Einstellungen entsprechend an.",
"rate-your-experience": "👋 Bitte bewerten Sie Ihre Erfahrung mit Opensign",
"rate-your-experience": "Wie war Ihre Erfahrung mit {{appName}}?",
"thanks-for-feedback": "Danke für Ihr Feedback 🙏",
"share-your-feedback": "Teilen Sie Ihr Feedback",
"share-your-review": "Teilen Sie Ihre Bewertung",
"date-format": "Datumsformat",
"document-deleted": "Das Dokument wurde gelöscht oder Sie haben keinen Zugriff. Bitte kontaktieren Sie den Absender."
"document-deleted": "Das Dokument wurde gelöscht oder Sie haben keinen Zugriff. Bitte kontaktieren Sie den Absender.",
"save-as-template-?": "Sind Sie sicher, dass Sie dieses Dokument als Vorlage speichern möchten?",
"go-to-manage-templates": "Zu 'Vorlagen verwalten' gehen",
"template-created": "Vorlage erstellt",
"how-would-you-like-to-proceed?": "Wie möchten Sie fortfahren?",
"failed-to-load-refresh-page": "Fehler beim Laden des Dokuments. Bitte versuchen Sie, diese Seite zu aktualisieren.",
"document-has-been-signed": "Das Dokument wurde erfolgreich unterschrieben!",
"document-has-been-signed-by-you": "Das Dokument wurde erfolgreich von Ihnen unterschrieben!",
"participant-completed-signing": "Alle Teilnehmer haben den Signaturprozess abgeschlossen.",
"you-will-receive-email-shortly": "✅ Das war's! Sie erhalten in Kürze eine Bestätigungs-E-Mail."
}
@@ -151,7 +151,8 @@
"extend-expiry-date": "Extend expiry date",
"Duplicate Template": "Duplicate template",
"Duplicate": "Duplicate",
"daily-mail-quota": "Daily Email Quota"
"daily-mail-quota": "Daily Email Quota",
"Save as template": "Save as template"
},
"report-heading": {
"Sr.No": "Sr.No",
@@ -308,7 +309,7 @@
"revoke-document": "Revoke document",
"revoke-document-alert": "Are you sure you want to revoke this document?",
"resend-mail": "Resend mail",
"resend-mail-help": "You can use following variables which will get replaced with their actual values:- {{document_title}}, {{sender_name}}, {{sender_mail}}, {{sender_phone}}, {{receiver_name}}, {{receiver_email}}, {{receiver_phone}}, {{expiry_date}}, {{company_name}}, {{signing_url}}.",
"resend-mail-help": "You can use following variables which will get replaced with their actual values:- {{document_title}}, {{sender_name}}, {{sender_mail}}, {{sender_phone}}, {{receiver_name}}, {{receiver_email}}, {{receiver_phone}}, {{expiry_date}}, {{company_name}}, {{signing_url}}, {{note}}.",
"subject": "Subject",
"body": "Body",
"add-contact": "Add contact",
@@ -522,7 +523,7 @@
"correct-password": "Please provide correct password",
"decrypting-pdf": " Decrypting pdf please wait...",
"invalid-otp": "Invalid otp",
"user-not-found": "User not found!",
"user-not-found": "User not found",
"enter-otp-alert": "Please enter OTP!",
"get-verification-code": "Get verification code",
"get-verification-code-2": "You will get a verification code via Email",
@@ -858,10 +859,19 @@
"indexing-public-profile": "Allow indexing of public profile by search engines",
"user-created-successfully": "user created successfully.",
"only-15-reminder-allowed": "You can set up to 15 automatic reminders. For example, if 'TimeToComplete' is 15 days and 'RemindOnceInEvery' is 1 day, you'll reach the maximum limit of 15 reminders. Adjust your settings accordingly.",
"rate-your-experience": "👋 Please rate your experience with Opensign",
"rate-your-experience": "How was your experience with {{appName}}?",
"thanks-for-feedback": "Thanks for your feedback 🙏",
"share-your-feedback": "Share your feedback",
"share-your-review": "Share your review",
"date-format": "Date format",
"document-deleted": "The document has been deleted or you don't have access. Please contact the sender."
"document-deleted": "The document has been deleted or you don't have access. Please contact the sender.",
"save-as-template-?": "Are you sure you want to save this document as template?",
"go-to-manage-templates": "go to 'Manage templates'",
"template-created": "Template Created",
"how-would-you-like-to-proceed?": "How would you like to proceed?",
"failed-to-load-refresh-page": "Failed to load the document. Please try refreshing this page.",
"document-has-been-signed": "The document has been signed successfully!",
"document-has-been-signed-by-you": "The document has been successfully signed by you!",
"participant-completed-signing": "All participants have completed the signing process.",
"you-will-receive-email-shortly": "✅ That's it! You'll receive a confirmation email shortly."
}
@@ -151,7 +151,8 @@
"extend-expiry-date": "Date d'expiration",
"Duplicate Template": "Plantilla duplicada",
"Duplicate": "Duplicada",
"daily-mail-quota": "Cuota diaria de correos electrónicos"
"daily-mail-quota": "Cuota diaria de correos electrónicos",
"Save as template": "Guardar como plantilla"
},
"report-heading": {
"Sr.No": "Nº",
@@ -309,7 +310,7 @@
"revoke-document": "Revocar documento",
"revoke-document-alert": "¿En definitiva quieres revocar este documento?",
"resend-mail": "Reenviar correo",
"resend-mail-help": "Puedes usar las siguientes variables que serán reemplazadas por sus valores reales:- {{document_title}}, {{sender_name}}, {{sender_mail}}, {{sender_phone}}, {{receiver_name}}, {{receiver_email}}, {{receiver_phone}}, {{expiry_date}}, {{company_name}}, {{signing_url}}.",
"resend-mail-help": "Puedes usar las siguientes variables que serán reemplazadas por sus valores reales:- {{document_title}}, {{sender_name}}, {{sender_mail}}, {{sender_phone}}, {{receiver_name}}, {{receiver_email}}, {{receiver_phone}}, {{expiry_date}}, {{company_name}}, {{signing_url}}, {{note}}.",
"subject": "Asunto",
"body": "Cuerpo",
"add-contact": "Agregar contacto",
@@ -522,7 +523,7 @@
"correct-password": "Por favor, proporciona la contraseña correcta",
"decrypting-pdf": " Desencriptando PDF, por favor, espera...",
"invalid-otp": "OTP inválido",
"user-not-found": "¡Usuario no encontrado!",
"user-not-found": "Usuario no encontrado",
"enter-otp-alert": "¡Por favor, ingresa el OTP!",
"get-verification-code": "Obtener código de verificación",
"get-verification-code-2": "Obtendrás un código de verificación por correo",
@@ -858,10 +859,19 @@
"indexing-public-profile": "Permitir la indexación del perfil público por los motores de búsqueda",
"user-created-successfully": "Usuario creado con éxito.",
"only-15-reminder-allowed": "Puede configurar hasta 15 recordatorios automáticos. Por ejemplo, si 'TimeToComplete' es de 15 días y 'RemindOnceInEvery' es de 1 día, alcanzará el límite máximo de 15 recordatorios. Ajuste su configuración en consecuencia.",
"rate-your-experience": "👋 Por favor, califique su experiencia con Opensign",
"rate-your-experience": "¿Cómo fue su experiencia con {{appName}}?",
"thanks-for-feedback": "Gracias por su comentario 🙏",
"share-your-feedback": "Comparta sus comentarios",
"share-your-review": "Comparta su reseña",
"date-format": "Formato de fecha",
"document-deleted": "El documento ha sido eliminado o no tiene acceso. Por favor, contacte al remitente."
"document-deleted": "El documento ha sido eliminado o no tiene acceso. Por favor, contacte al remitente.",
"save-as-template-?": "¿Está seguro de que desea guardar este documento como plantilla?",
"go-to-manage-templates": "Ir a 'Gestionar plantillas'",
"template-created": "Plantilla creada",
"how-would-you-like-to-proceed?": "¿Cómo le gustaría proceder?",
"failed-to-load-refresh-page": "Error al cargar el documento. Intente actualizar esta página.",
"document-has-been-signed": "¡El documento ha sido firmado con éxito!",
"document-has-been-signed-by-you": "¡El documento ha sido firmado con éxito por usted!",
"participant-completed-signing": "Todos los participantes han completado el proceso de firma.",
"you-will-receive-email-shortly": "✅ ¡Eso es todo! Recibirá un correo de confirmación en breve."
}
@@ -172,7 +172,8 @@
"extend-expiry-date": "Prolonger la date d'expiration",
"Duplicate Template": "dupliquer le modèle",
"Duplicate": "Double",
"daily-mail-quota": "Quota d'e-mails quotidien"
"daily-mail-quota": "Quota d'e-mails quotidien",
"Save as template": "Enregistrer comme modèle"
},
"report-help": {
"Draft Documents": "Il s'agit de documents que vous avez commencés mais que vous n'avez pas finalisés pour envoi.",
@@ -308,7 +309,7 @@
"revoke-document": "Révoquer le document",
"revoke-document-alert": "Êtes-vous sûr de vouloir révoquer ce document ?",
"resend-mail": "Renvoyer le courrier",
"resend-mail-help": "Vous pouvez utiliser les variables suivantes qui seront remplacées par leurs valeurs réelles : - {{document_title}}, {{sender_name}}, {{sender_mail}}, {{sender_phone}}, {{receiver_name}}, {{receiver_email} }, {{receiver_phone}}, {{expiry_date}}, {{company_name}}, {{signing_url}}.",
"resend-mail-help": "Vous pouvez utiliser les variables suivantes qui seront remplacées par leurs valeurs réelles : - {{document_title}}, {{sender_name}}, {{sender_mail}}, {{sender_phone}}, {{receiver_name}}, {{receiver_email} }, {{receiver_phone}}, {{expiry_date}}, {{company_name}}, {{signing_url}}, {{note}}.",
"subject": "Sujet",
"body": "Corps",
"add-contact": "Ajouter le contact",
@@ -522,7 +523,7 @@
"correct-password": "Veuillez fournir un mot de passe correct",
"decrypting-pdf": "Décryptage du pdf, veuillez patienter...",
"invalid-otp": "OTP invalide",
"user-not-found": "Utilisateur non trouvé!",
"user-not-found": "Utilisateur non trouvé",
"enter-otp-alert": "Veuillez saisir OTP !",
"get-verification-code": "Obtenir le code de vérification",
"get-verification-code-2": "Vous recevrez un code de vérification par e-mail",
@@ -858,10 +859,19 @@
"indexing-public-profile": "Autoriser l'indexation du profil public par les moteurs de recherche",
"user-created-successfully": "Utilisateur créé avec succès.",
"only-15-reminder-allowed": "Vous pouvez définir jusqu'à 15 rappels automatiques. Par exemple, si 'TimeToComplete' est de 15 jours et 'RemindOnceInEvery' est de 1 jour, vous atteindrez la limite maximale de 15 rappels. Ajustez vos paramètres en conséquence.",
"rate-your-experience": "👋 Veuillez évaluer votre expérience avec Opensign",
"rate-your-experience": "Comment s'est passée votre expérience avec {{appName}} ?",
"thanks-for-feedback": "Merci pour votre retour 🙏",
"share-your-feedback": "Partagez votre avis",
"share-your-review": "Partagez votre avis",
"date-format": "Format de date",
"document-deleted": "Le document a été supprimé ou vous n'y avez pas accès. Veuillez contacter l'expéditeur."
"document-deleted": "Le document a été supprimé ou vous n'y avez pas accès. Veuillez contacter l'expéditeur.",
"save-as-template-?": "Êtes-vous sûr de vouloir enregistrer ce document comme modèle ?",
"go-to-manage-templates": "Aller à 'Gérer les modèles'",
"template-created": "Modèle créé",
"how-would-you-like-to-proceed?": "Comment souhaitez-vous procéder ?",
"failed-to-load-refresh-page": "Échec du chargement du document. Veuillez essayer d'actualiser cette page.",
"document-has-been-signed": "Le document a été signé avec succès !",
"document-has-been-signed-by-you": "Le document a été signé avec succès par vous !",
"participant-completed-signing": "Tous les participants ont terminé le processus de signature.",
"you-will-receive-email-shortly": "✅ Voilà, c'est fait ! Vous recevrez un e-mail de confirmation sous peu."
}
@@ -151,7 +151,8 @@
"extend-expiry-date": "Estendi data di scadenza",
"Duplicate Template": "Duplica modello",
"Duplicate": "Duplica",
"daily-mail-quota": "Quota e-mail giornaliera"
"daily-mail-quota": "Quota e-mail giornaliera",
"Save as template": "Salva come modello"
},
"report-heading": {
"Sr.No": "Nr.",
@@ -308,7 +309,7 @@
"revoke-document": "Revoca documento",
"revoke-document-alert": "Sei sicuro di voler revocare questo documento?",
"resend-mail": "Reinvia email",
"resend-mail-help": "Puoi usare le seguenti variabili che verranno sostituite con i loro valori effettivi: {{document_title}}, {{sender_name}}, {{sender_mail}}, {{sender_phone}}, {{receiver_name}}, {{receiver_email}}, {{receiver_phone}}, {{expiry_date}}, {{company_name}}, {{signing_url}}.",
"resend-mail-help": "Puoi usare le seguenti variabili che verranno sostituite con i loro valori effettivi: {{document_title}}, {{sender_name}}, {{sender_mail}}, {{sender_phone}}, {{receiver_name}}, {{receiver_email}}, {{receiver_phone}}, {{expiry_date}}, {{company_name}}, {{signing_url}}, {{note}}.",
"subject": "Oggetto",
"body": "Corpo del messaggio",
"add-contact": "Aggiungi contatto",
@@ -522,7 +523,7 @@
"correct-password": "Fornisci la password corretta",
"decrypting-pdf": "Decrittazione PDF, attendi...",
"invalid-otp": "OTP non valido",
"user-not-found": "Utente non trovato!",
"user-not-found": "Utente non trovato",
"enter-otp-alert": "Inserisci l'OTP!",
"get-verification-code": "Ottieni codice di verifica",
"get-verification-code-2": "Riceverai un codice di verifica tramite Email",
@@ -858,10 +859,19 @@
"indexing-public-profile": "Consenti l'indicizzazione del profilo pubblico dai motori di ricerca",
"user-created-successfully": "Utente creato con successo.",
"only-15-reminder-allowed": "Puoi impostare fino a 15 promemoria automatici. Ad esempio, se 'TimeToComplete' è di 15 giorni e 'RemindOnceInEvery' è di 1 giorno, raggiungerai il limite massimo di 15 promemoria. Regola le tue impostazioni di conseguenza.",
"rate-your-experience": "👋 Valuta la tua esperienza con Opensign",
"rate-your-experience": "Com'è stata la sua esperienza con {{appName}}?",
"thanks-for-feedback": "Grazie per il tuo feedback 🙏",
"share-your-feedback": "Condividi il tuo feedback",
"share-your-review": "Condividi la tua recensione",
"date-format": "Formato data",
"document-deleted": "Il documento è stato eliminato o non hai accesso. Si prega di contattare il mittente."
"document-deleted": "Il documento è stato eliminato o non hai accesso. Si prega di contattare il mittente.",
"save-as-template-?": "Sei sicuro di voler salvare questo documento come modello?",
"go-to-manage-templates": "Vai a 'Gestisci modelli'",
"template-created": "Modello creato",
"how-would-you-like-to-proceed?": "Come desideri procedere?",
"failed-to-load-refresh-page": "Impossibile caricare il documento. Prova ad aggiornare questa pagina.",
"document-has-been-signed": "Il documento è stato firmato con successo!",
"document-has-been-signed-by-you": "Il documento è stato firmato con successo da lei!",
"participant-completed-signing": "Tutti i partecipanti hanno completato il processo di firma.",
"you-will-receive-email-shortly": "✅ È tutto! Riceverà a breve un'e-mail di conferma."
}
@@ -1,7 +1,9 @@
import React from "react";
import { Document, Page } from "react-pdf";
import { Stage, Layer, Rect, Text } from "react-konva";
import { useTranslation } from "react-i18next";
const RenderDebugPdf = (props) => {
const { t } = useTranslation();
return (
<div>
<div className="sticky top-0 p-[10px] z-10 bg-white border-[1px] border-[gray] my-[5px]">
@@ -12,10 +14,9 @@ const RenderDebugPdf = (props) => {
onMouseMove={props.handleMouseMoveDiv}
>
<Document
onLoadError={() => {
props.setPdfLoadFail(false);
}}
loading={"Loading Document.."}
onLoadError={() => props.setPdfLoadFail(false)}
loading={t("loading-doc")}
error={<p className="mx-2">{t("failed-to-load-refresh-page")}</p>}
onLoadSuccess={props.pageDetails}
ref={props.pdfRef}
file={props.pdfUrl}
@@ -17,8 +17,8 @@ const AddRoleModal = (props) => {
onChange={(e) => props.setRoleName(e.target.value)}
placeholder={
props.signersdata.length > 0
? "User " + (props.signersdata.length + 1)
: "User 1"
? "Role " + (props.signersdata.length + 1)
: "Role 1"
}
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs mt-1"
/>
@@ -1,276 +0,0 @@
import React, { useEffect, useState } from "react";
import opensignLogo from "../../assets/images/logo.png";
import {
Page,
Text,
View,
Document,
StyleSheet,
Image
} from "@react-pdf/renderer";
function Certificate({ pdfData }) {
const [isMultiSigners, setIsMultiSigners] = useState();
const [multiSigner, setMultiSigners] = useState([]);
const [isLoad, setIsLoad] = useState(false);
useEffect(() => {
handleSignerData();
// eslint-disable-next-line
}, []);
const handleSignerData = () => {
const checkSigners = pdfData.filter((data) => data.Signers);
if (checkSigners && checkSigners.length > 0) {
setIsMultiSigners(true);
const checkSignSigners =
pdfData[0].AuditTrail &&
pdfData[0].AuditTrail.length > 0 &&
pdfData[0].AuditTrail.filter((data) => data.Activity === "Signed");
setMultiSigners(checkSignSigners);
} else {
setIsMultiSigners(false);
}
setIsLoad(true);
};
const styles = StyleSheet.create({
page: {
borderRadius: "5px",
padding: "10px",
backgroundColor: "white"
},
section1: {
border: "1px solid rgb(177, 174, 174)",
padding: "20px"
},
textStyle: {
fontWeight: "bold",
fontSize: "11px",
marginBottom: "10px"
},
textStyle2: {
fontWeight: "600",
fontSize: "11px",
marginBottom: "10px",
color: "gray"
},
image: {
width: "71px",
height: "17px"
}
});
const generatedDate = () => {
const newDate = new Date();
const utcTime = newDate.toUTCString();
return (
<Text
style={{
color: "gray",
fontSize: "10px"
}}
>
Generated On {utcTime}
</Text>
);
};
const changeCompletedDate = () => {
const completedOn = pdfData[0].updatedAt;
const newDate = new Date(completedOn);
const utcTime = newDate.toUTCString();
return <Text style={styles.textStyle2}>{utcTime}</Text>;
};
const signerName = (data) => {
const getSignerName = pdfData[0].Signers.filter(
(sign) => sign.objectId === data.UserPtr.objectId
);
return (
getSignerName[0] &&
getSignerName.length > 0 && (
<>
<Text style={styles.textStyle}>
Name : &nbsp;
<Text style={styles.textStyle2}>{getSignerName[0].Name}</Text>
</Text>
<Text style={styles.textStyle}>
Email : &nbsp;
<Text style={styles.textStyle2}>{getSignerName[0].Email}</Text>
</Text>
</>
)
);
};
return (
isLoad && (
<Document>
{/** Page defines a single page of content. */}
<Page size="A4" style={styles.page}>
<View style={styles.section1}>
<View
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
marginBottom: "30px"
}}
>
<Image src={opensignLogo} style={styles.image} />
{generatedDate()}
</View>
<View style={{ justifyContent: "center" }}>
<Text
style={{
textAlign: "center",
fontSize: "20px",
fontWeight: "bold",
color: "#31bceb",
marginBottom: "10px"
}}
>
{" "}
Certificate of Completion
</Text>
<View style={{ border: "1px solid #bdbbbb" }}></View>
<View>
<View>
<Text
style={{
fontSize: "16px",
fontWeight: "bold",
color: "#31bceb",
margin: "10px 0px 10px 0px"
}}
>
Summary
</Text>
</View>
<View style={{ display: "flex", flexDirection: "column" }}>
<Text style={styles.textStyle}>
Document ID : &nbsp;
<Text style={styles.textStyle2}>{pdfData[0].objectId}</Text>
</Text>
<Text style={styles.textStyle}>
Document Name : &nbsp;
<Text style={styles.textStyle2}>{pdfData[0].Name}</Text>
</Text>
<Text style={styles.textStyle}>
Organization : &nbsp;
<Text style={styles.textStyle2}>
{pdfData[0].ExtUserPtr.Company}
</Text>
</Text>
<Text style={styles.textStyle}>
Completed on : &nbsp;{changeCompletedDate()}
</Text>
{multiSigner && multiSigner.length > 0 && (
<Text style={styles.textStyle}>
Signers : &nbsp;
<Text style={styles.textStyle2}>
{multiSigner.length}
</Text>
</Text>
)}
</View>
{isMultiSigners ? (
<View style={{ display: "flex", flexDirection: "column" }}>
<Text
style={{
fontSize: "16px",
fontWeight: "bold",
color: "#31bceb",
margin: "10px 0px 10px 0px"
}}
>
Recipients
</Text>
<View>
{multiSigner &&
multiSigner.map((data, ind) => {
return (
<View
key={ind}
style={{
display: "flex",
flexDirection: "column"
}}
>
<View
style={{
border: "0.4px solid #bdbbbb",
marginBottom: "10px"
}}
></View>
{signerName(data)}
<Text style={styles.textStyle}>
Accessed from : &nbsp;
<Text style={styles.textStyle2}>
{data.ipAddress}
</Text>
</Text>
</View>
);
})}
</View>
</View>
) : (
<View style={{ display: "flex", flexDirection: "column" }}>
<Text
style={{
fontSize: "16px",
fontWeight: "bold",
color: "#31bceb",
margin: "10px 0px 10px 0px"
}}
>
Recipients
</Text>
<Text style={styles.textStyle}>
Signers : &nbsp;<Text style={styles.textStyle2}>1</Text>
</Text>
<Text style={styles.textStyle}>
Name : &nbsp;
<Text style={styles.textStyle2}>
{pdfData[0].ExtUserPtr.Name}
</Text>
</Text>
<Text style={styles.textStyle}>
Email : &nbsp;
<Text style={styles.textStyle2}>
{pdfData[0].ExtUserPtr.Email}
</Text>
</Text>
<Text style={styles.textStyle}>
Accessed from : &nbsp;
<Text style={styles.textStyle2}>
{pdfData[0].AuditTrail &&
pdfData[0].AuditTrail[0].ipAddress}
</Text>
</Text>
<Text style={styles.textStyle}>
Signed on : &nbsp;{changeCompletedDate()}
</Text>
</View>
)}
</View>
</View>
</View>
</Page>
</Document>
)
);
}
export default Certificate;
@@ -14,6 +14,7 @@ import ModalUi from "../../primitives/ModalUi";
import Loader from "../../primitives/Loader";
import { useTranslation } from "react-i18next";
import { PDFDocument } from "pdf-lib";
import { maxFileSize } from "../../constant/const";
function Header(props) {
const { t } = useTranslation();
@@ -50,6 +51,13 @@ function Header(props) {
}
};
// `removeFile` is used to remove file if exists
const removeFile = (e) => {
if (e) {
e.target.value = "";
}
};
const handleFileUpload = async (e) => {
const file = e.target.files[0];
if (!file) {
@@ -60,6 +68,13 @@ function Header(props) {
alert("Only PDF files are allowed.");
return;
}
const mb = Math.round(file?.size / Math.pow(1024, 2));
if (mb > maxFileSize) {
alert(`${t("file-alert-1")} ${maxFileSize} MB`);
removeFile(e);
return;
}
try {
const uploadedPdfBytes = await file.arrayBuffer();
const uploadedPdfDoc = await PDFDocument.load(uploadedPdfBytes, {
@@ -7,6 +7,7 @@ import {
} from "../../constant/Utils";
import ModalUi from "../../primitives/ModalUi";
import { PDFDocument } from "pdf-lib";
import { maxFileSize } from "../../constant/const";
function PdfZoom(props) {
const { t } = useTranslation();
@@ -41,6 +42,14 @@ function PdfZoom(props) {
console.log("error in delete pdf page", e);
}
};
// `removeFile` is used to remove file if exists
const removeFile = (e) => {
if (e) {
e.target.value = "";
}
};
const handleFileUpload = async (e) => {
const file = e.target.files[0];
if (!file) {
@@ -51,6 +60,12 @@ function PdfZoom(props) {
alert("Only PDF files are allowed.");
return;
}
const mb = Math.round(file?.size / Math.pow(1024, 2));
if (mb > maxFileSize) {
alert(`${t("file-alert-1")} ${maxFileSize} MB`);
removeFile(e);
return;
}
try {
const uploadedPdfBytes = await file.arrayBuffer();
const uploadedPdfDoc = await PDFDocument.load(uploadedPdfBytes, {
@@ -4,6 +4,7 @@ import { Document, Page } from "react-pdf";
import { useSelector } from "react-redux";
import { PDFDocument } from "pdf-lib";
import { base64ToArrayBuffer } from "../../constant/Utils";
import { maxFileSize } from "../../constant/const";
function RenderAllPdfPage(props) {
const { t } = useTranslation();
@@ -62,6 +63,12 @@ function RenderAllPdfPage(props) {
};
const pdfDataBase64 = `data:application/pdf;base64,${props?.pdfBase64Url}`;
// `removeFile` is used to remove file if exists
const removeFile = (e) => {
if (e) {
e.target.value = "";
}
};
// `handleFileUpload` is trigger when user click on add pages btn and is used to merge multiple pdf
const handleFileUpload = async (e) => {
const file = e.target.files[0];
@@ -73,6 +80,12 @@ function RenderAllPdfPage(props) {
alert("Only PDF files are allowed.");
return;
}
const mb = Math.round(file?.size / Math.pow(1024, 2));
if (mb > maxFileSize) {
alert(`${t("file-alert-1")} ${maxFileSize} MB`);
removeFile(e);
return;
}
try {
const uploadedPdfBytes = await file.arrayBuffer();
const uploadedPdfDoc = await PDFDocument.load(uploadedPdfBytes, {
@@ -110,6 +123,7 @@ function RenderAllPdfPage(props) {
autoSignScroll hide-scrollbar max-h-[100vh] `}
>
<Document
error=""
loading={t("loading-doc")}
onLoadSuccess={onDocumentLoad}
file={pdfDataBase64}
+10 -13
View File
@@ -381,17 +381,15 @@ function RenderPdf(props) {
</React.Fragment>
);
}))}
{/* Mobile */}
<Document
error={<p className="mx-2">{t("failed-to-load-refresh-page")}</p>}
onLoadError={() => props.setPdfLoad(false)}
loading={t("loading-doc")}
onLoadSuccess={props.pageDetails}
// ref={pdfRef}'
onClick={() => {
if (props.setSelectWidgetId) {
props.setSelectWidgetId("");
}
}}
onClick={() =>
props.setSelectWidgetId && props.setSelectWidgetId("")
}
file={pdfDataBase64}
>
<Page
@@ -601,17 +599,16 @@ function RenderPdf(props) {
</React.Fragment>
);
}))}
{/* large device */}
{/* this component for render pdf document is in middle of the component */}
<Document
error={<p className="mx-2">{t("failed-to-load-refresh-page")}</p>}
onLoadError={() => props.setPdfLoad(false)}
loading={t("loading-doc")}
onLoadSuccess={props.pageDetails}
onClick={() => {
if (props.setSelectWidgetId) {
props.setSelectWidgetId("");
}
}}
onClick={() =>
props.setSelectWidgetId && props.setSelectWidgetId("")
}
file={pdfDataBase64}
>
<Page
+6 -2
View File
@@ -2182,7 +2182,9 @@ export const handleSendOTP = async (email) => {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId")
};
const body = { email: email };
const body = {
email: email
};
await axios.post(url, body, { headers: headers });
} catch (error) {
alert(error.message);
@@ -2960,8 +2962,10 @@ export const mailTemplate = (param) => {
param.senderMail +
"</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'> " +
param.organization +
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Expire on</td><td></td><td style='color:#626363;font-weight:bold'>" +
"</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'>" +
param.localExpireDate +
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Note</td><td></td><td style='color:#626363;font-weight:bold'>" +
param.note +
"</td></tr><tr><td></td><td></td></tr></table></div> <div style='margin-left:70px'><a target=_blank href=" +
param.sigingUrl +
"><button style='padding:12px;background-color:#d46b0f;color:white;border:0px;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 " +
+1
View File
@@ -4,3 +4,4 @@ export const documentCls = "contracts_Document";
export const themeColor = "#47a3ad";
export const iconColor = "#686968";
export const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
export const maxFileSize = 10; // 10MB
+100 -1
View File
@@ -1,4 +1,3 @@
export default function reportJson(id) {
// console.log("json ", json);
const head = ["Title", "Note", "Folder", "File", "Owner", "Signers"];
@@ -29,6 +28,25 @@ export default function reportJson(id) {
btnIcon: "fa-light fa-trash",
redirectUrl: "",
action: "delete"
},
{
btnId: "22534",
hoverLabel: "option",
btnColor: "",
restrictBtn: true,
textColor: "black",
btnIcon: "fa-light fa-ellipsis-vertical fa-lg",
action: "option",
subaction: [
{
btnId: "1630",
btnLabel: "Save as template",
hoverLabel: "Save as template",
btnIcon: "fa-light fa-envelope",
redirectUrl: "",
action: "saveastemplate"
}
]
}
],
helpMsg:
@@ -107,6 +125,14 @@ export default function reportJson(id) {
redirectUrl: "",
action: "revoke"
},
{
btnId: "0630",
btnLabel: "Save as template",
hoverLabel: "Save as template",
btnIcon: "fa-light fa-envelope",
redirectUrl: "",
action: "saveastemplate"
},
{
btnId: "1488",
btnLabel: "Delete",
@@ -143,6 +169,25 @@ export default function reportJson(id) {
restrictBtn: true,
redirectUrl: "",
action: "delete"
},
{
btnId: "33534",
hoverLabel: "option",
btnColor: "",
restrictBtn: true,
textColor: "black",
btnIcon: "fa-light fa-ellipsis-vertical fa-lg",
action: "option",
subaction: [
{
btnId: "0930",
btnLabel: "Save as template",
hoverLabel: "Save as template",
btnIcon: "fa-light fa-envelope",
redirectUrl: "",
action: "saveastemplate"
}
]
}
],
helpMsg:
@@ -169,6 +214,25 @@ export default function reportJson(id) {
btnIcon: "fa-light fa-trash",
redirectUrl: "",
action: "delete"
},
{
btnId: "44534",
hoverLabel: "option",
btnColor: "",
restrictBtn: true,
textColor: "black",
btnIcon: "fa-light fa-ellipsis-vertical fa-lg",
action: "option",
subaction: [
{
btnId: "0940",
btnLabel: "Save as template",
hoverLabel: "Save as template",
btnIcon: "fa-light fa-envelope",
redirectUrl: "",
action: "saveastemplate"
}
]
}
],
helpMsg:
@@ -212,6 +276,14 @@ export default function reportJson(id) {
btnIcon: "fa-light fa-hourglass-end",
redirectUrl: "",
action: "extendexpiry"
},
{
btnId: "5530",
btnLabel: "Save as template",
hoverLabel: "Save as template",
btnIcon: "fa-light fa-envelope",
redirectUrl: "",
action: "saveastemplate"
}
]
}
@@ -273,6 +345,14 @@ export default function reportJson(id) {
redirectUrl: "",
action: "revoke"
},
{
btnId: "7730",
btnLabel: "Save as template",
hoverLabel: "Save as template",
btnIcon: "fa-light fa-envelope",
redirectUrl: "",
action: "saveastemplate"
},
{
btnId: "2000",
btnLabel: "Delete",
@@ -323,6 +403,25 @@ export default function reportJson(id) {
btnIcon: "fa-light fa-trash",
redirectUrl: "",
action: "delete"
},
{
btnId: "55534",
hoverLabel: "option",
btnColor: "",
restrictBtn: true,
textColor: "black",
btnIcon: "fa-light fa-ellipsis-vertical fa-lg",
action: "option",
subaction: [
{
btnId: "6630",
btnLabel: "Save as template",
hoverLabel: "Save as template",
btnIcon: "fa-light fa-envelope",
redirectUrl: "",
action: "saveastemplate"
}
]
}
]
};
+4 -5
View File
@@ -15,8 +15,7 @@ import { showHeader } from "../redux/reducers/showHeader";
import { useTranslation } from "react-i18next";
const HomeLayout = () => {
const appName =
"OpenSign™";
const appName = "OpenSign™";
const { t, i18n } = useTranslation();
const navigate = useNavigate();
const location = useLocation();
@@ -54,8 +53,8 @@ const HomeLayout = () => {
});
if (user) {
localStorage.setItem("profileImg", user.get("ProfilePic") || "");
setIsUserValid(true);
setIsLoader(false);
setIsUserValid(true);
setIsLoader(false);
} else {
setIsUserValid(false);
}
@@ -72,7 +71,7 @@ const HomeLayout = () => {
//function to use save data in cookies storage
const saveCookies = () => {
const main_Domain = window.location.origin;
const domainName = window.location.hostname; //app.opensignlabs.com
const domainName = window.location.hostname;
// Find the index of the first dot in the string
const indexOfFirstDot = domainName.indexOf(".");
// Remove the first dot and get the substring starting from the next character
+81 -44
View File
@@ -1,5 +1,6 @@
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import Confetti from "react-confetti"; // Import the confetti library
import {
getBase64FromUrl,
handleDownloadCertificate,
@@ -10,19 +11,25 @@ import ModalUi from "../primitives/ModalUi";
import Loader from "../primitives/Loader";
import DownloadPdfZip from "../primitives/DownloadPdfZip";
import Title from "../components/Title";
import CheckCircle from "../primitives/CheckCircle";
const DocSuccessPage = () => {
const { t } = useTranslation();
const signed = window.location?.search?.includes("docid");
const sent = window.location?.search?.includes("message");
const [isDownloading, setIsDownloading] = useState(false);
const [isDownloadModal, setIsDownloadModal] = useState(false);
const [pdfDetails, setPdfDetails] = useState([]);
const [pdfBase64Url, setPdfBase64Url] = useState("");
const { t } = useTranslation();
const [showConfetti, setShowConfetti] = useState(true); // State to control confetti
useEffect(() => {
initialsetup();
// Stop confetti after 5 seconds
const timer = setTimeout(() => setShowConfetti(false), 5000);
return () => clearTimeout(timer);
}, []);
const initialsetup = async () => {
const search = window.location.search.split("?")[1];
if (search) {
@@ -44,6 +51,7 @@ const DocSuccessPage = () => {
}
}
};
const handleDownload = () => {
if (pdfDetails?.[0]?.IsCompleted) {
setIsDownloadModal(true);
@@ -51,50 +59,79 @@ const DocSuccessPage = () => {
handleDownloadPdf(pdfDetails, setIsDownloading, pdfBase64Url);
}
};
return (
<div className="flex h-screen justify-center items-center text-sm md:text-base">
<>
<Title title="Success" />
{/* Confetti Effect */}
{showConfetti && (
<Confetti width={window.innerWidth} height={window.innerHeight} />
)}
{sent ? (
<div>{t("doc-sent")}</div>
<div className="min-h-screen flex flex-col items-center justify-center p-3 md:p-8 text-center">
<div className="max-w-lg md:max-w-2xl bg-white rounded-lg shadow-lg p-3 md:p-10">
{t("doc-sent")}
</div>
</div>
) : signed ? (
<div className="text-center">
<p>
{pdfDetails?.[0]?.IsCompleted
? t("document-signed-alert-4")
: t("document-signed-alert")}
</p>
<div className="m-2">
<button
onClick={(e) => handleToPrint(e, setIsDownloading, pdfDetails)}
type="button"
className="font-[500] text-[13px] mr-[5px] op-btn op-btn-neutral"
>
<i className="fa-light fa-print" aria-hidden="true"></i>
<span className="hidden lg:block">{t("print")}</span>
</button>
{pdfDetails?.[0]?.IsCompleted && (
<button
type="button"
onClick={() =>
handleDownloadCertificate(pdfDetails, setIsDownloading)
}
className="font-[500] text-[13px] mr-[5px] op-btn op-btn-secondary"
>
<i
className="fa-light fa-award mx-[3px] lg:mx-0"
aria-hidden="true"
></i>
<span className="hidden lg:block">{t("certificate")}</span>
</button>
)}
<button
type="button"
className="font-[500] text-[13px] mr-[5px] op-btn op-btn-primary"
onClick={() => handleDownload()}
>
<i className="fa-light fa-download" aria-hidden="true"></i>
<span className="hidden lg:block">{t("download")}</span>
</button>
<>
<div className="min-h-screen flex flex-col items-center justify-center p-3 md:p-8 text-center">
<div className="max-w-lg md:max-w-2xl bg-white rounded-lg shadow-lg p-3 md:p-10">
<div className="flex flex-col items-center space-y-4 ">
<CheckCircle className="text-green-500 w-12 h-12 md:w-14 md:h-14" />
<h1 className="text-xl md:text-2xl font-semibold text-gray-800">
{pdfDetails?.[0]?.IsCompleted
? t("document-has-been-signed")
: t("document-has-been-signed-by-you")}
</h1>
{pdfDetails?.[0]?.IsCompleted && (
<p className="text-sm md:text-base text-gray-600">
{t("participant-completed-signing")}
</p>
)}
</div>
{/* Action Buttons */}
<div className="mt-6 flex flex-wrap justify-center gap-2">
<button
type="button"
className="font-medium text-sm md:text-[13px] md:px-4 py-2 op-btn op-btn-primary"
onClick={() => handleDownload()}
>
<i className="fa-light fa-download" aria-hidden="true"></i>
<span>{t("download")}</span>
</button>
{pdfDetails?.[0]?.IsCompleted && (
<button
type="button"
onClick={() =>
handleDownloadCertificate(pdfDetails, setIsDownloading)
}
className="font-medium text-sm md:text-[13px] md:px-4 py-2 op-btn op-btn-secondary"
>
<i
className="fa-light fa-award mx-[3px] md:mx-0"
aria-hidden="true"
></i>
<span>{t("certificate")}</span>
</button>
)}
<button
onClick={(e) =>
handleToPrint(e, setIsDownloading, pdfDetails)
}
type="button"
className="font-medium text-sm md:text-[13px] px-4 py-2 op-btn op-btn-neutral"
>
<i className="fa-light fa-print" aria-hidden="true"></i>
<span>{t("print")}</span>
</button>
</div>
{/* Footer Message */}
<p className="mt-4 md:mt-6 text-xs md:text-sm text-gray-500">
{t("you-will-receive-email-shortly")}
</p>
</div>
</div>
{isDownloading === "pdf" && (
<div className="fixed z-[1000] inset-0 flex justify-center items-center bg-black bg-opacity-30">
@@ -114,7 +151,7 @@ const DocSuccessPage = () => {
}
handleClose={() => setIsDownloading("")}
>
<div className="p-3 md:p-5 text-[13px] md:text-base text-center text-base-content">
<div className="p-3 md:p-5 text-sm md:text-base text-center text-base-content">
{isDownloading === "certificate" ? (
<p>{t("generate-certificate-alert")}</p>
) : (
@@ -129,11 +166,11 @@ const DocSuccessPage = () => {
isDocId={true}
pdfBase64={pdfBase64Url}
/>
</div>
</>
) : (
<></>
)}
</div>
</>
);
};
+1 -1
View File
@@ -18,6 +18,7 @@ import {
} from "../constant/Utils";
import { PDFDocument } from "pdf-lib";
import axios from "axios";
import { maxFileSize } from "../constant/const";
import ModalUi from "../primitives/ModalUi";
import { Tooltip } from "react-tooltip";
import Loader from "../primitives/Loader";
@@ -38,7 +39,6 @@ function Form() {
const Forms = (props) => {
const appName = "OpenSign™";
const { t } = useTranslation();
const maxFileSize = 20;
const abortController = new AbortController();
const inputFileRef = useRef(null);
const navigate = useNavigate();
+16 -14
View File
@@ -1,13 +1,8 @@
import React, { useState, useEffect } from "react";
import { useNavigate, useParams } from "react-router";
import axios from "axios";
import {
emailRegex,
} from "../constant/const";
import {
contractUsers,
saveLanguageInLocal
} from "../constant/Utils";
import { emailRegex } from "../constant/const";
import { contractUsers, saveLanguageInLocal } from "../constant/Utils";
import logo from "../assets/images/logo.png";
import { appInfo } from "../constant/appinfo";
import Parse from "parse";
@@ -63,13 +58,10 @@ function GuestLogin() {
//function generate serverUrl and parseAppId from url and save it in local storage
const handleServerUrl = async () => {
setAppLogo(logo);
setAppLogo(logo);
localStorage.clear(); // Clears everything
localStorage.setItem(
"appname",
"OpenSign™"
);
localStorage.setItem("appname", "OpenSign™");
//save isGuestSigner true in local to handle login flow header in mobile view
localStorage.setItem("isGuestSigner", true);
saveLanguageInLocal(i18n);
@@ -113,7 +105,10 @@ function GuestLogin() {
setLoading(true);
setEmail(email);
try {
const params = { email: email.toString(), docId: documentId };
const params = {
email: email.toString(),
docId: documentId
};
const Otp = await Parse.Cloud.run("SendOTPMailV1", params);
if (Otp) {
setLoading(false);
@@ -216,7 +211,14 @@ function GuestLogin() {
}
};
const handleInputChange = (e) => {
setContact((prev) => ({ ...prev, [e.target.name]: e.target.value }));
if (e.target.name === "email") {
setContact((prev) => ({
...prev,
[e.target.name]: e.target.value?.toLowerCase()?.replace(/\s/g, "")
}));
} else {
setContact((prev) => ({ ...prev, [e.target.name]: e.target.value }));
}
};
return (
<div>
+19 -98
View File
@@ -54,6 +54,10 @@ function Login() {
// eslint-disable-next-line
}, []);
const showToast = (type, msg) => {
setState({ ...state, loading: false, alertType: type, alertMsg: msg });
setTimeout(() => setState({ ...state, alertMsg: "" }), 2000);
};
const checkUserExt = async () => {
const app = await getAppLogo();
if (app?.error === "invalid_json") {
@@ -156,60 +160,25 @@ function Login() {
setIsModal(true);
}
} else {
setState({
...state,
loading: false,
alertType: "danger",
alertMsg:
"You don't have access, please contact the admin."
});
showToast("danger", t("do-not-access-contact-admin"));
logOutUser();
}
} else {
setState({ ...state, loading: false });
setState({
...state,
loading: false,
alertType: "danger",
alertMsg: "User not found."
});
showToast("danger", t("user-not-found"));
logOutUser();
}
})
.catch((error) => {
setState({
...state,
loading: false,
alertType: "danger",
alertMsg: t("something-went-wrong-mssg")
});
setTimeout(() => setState({ ...state, alertMsg: "" }), 2000);
showToast("danger", t("something-went-wrong-mssg"));
console.error("Error while fetching Follow", error);
});
} catch (error) {
setState({
...state,
loading: false,
alertType: "danger",
alertMsg: `${error.message}`
});
console.log(error);
setTimeout(() => setState({ ...state, alertMsg: "" }), 2000);
showToast("danger", `${error.message}`);
}
}
} catch (error) {
setState({
...state,
loading: false,
alertType: "danger",
alertMsg: "Invalid username/password or region"
});
console.error("Error while logging in user", error);
} finally {
setTimeout(
() => setState((prev) => ({ ...prev, alertMsg: "" })),
2000
);
showToast("danger", "Invalid username/password or region");
}
}
}
@@ -279,53 +248,29 @@ function Login() {
localStorage.setItem("pageType", menu.pageType);
navigate(redirectUrl);
} else {
setState({
...state,
loading: false,
alertType: "danger",
alertMsg: "Role not found."
});
showToast("danger", t("role-not-found"));
logOutUser();
}
} else {
setState({
...state,
loading: false,
alertType: "danger",
alertMsg: "You don't have access, please contact the admin."
});
showToast("danger", t("do-not-access-contact-admin"));
logOutUser();
}
} else {
setState({
...state,
alertType: "danger",
alertMsg: "User not found."
});
showToast("danger", t("user-not-found"));
logOutUser();
}
})
.catch((err) => {
console.error("err in fetching extUser", err);
setState({
...state,
alertType: "danger",
alertMsg: `${err.message}`
});
showToast("danger", `${err.message}`);
const payload = { sessionToken: sessionToken };
handleSubmitbtn(payload);
});
} catch (error) {
setState({
...state,
alertType: "danger",
alertMsg: `${error.message}`
});
showToast("danger", `${error.message}`);
console.log(error);
} finally {
setThirdpartyLoader(false);
setState({ ...state, loading: false });
setTimeout(() => setState({ ...state, alertMsg: "" }), 2000);
}
}
};
@@ -382,33 +327,17 @@ function Login() {
logOutUser();
}
} else {
setState({
...state,
loading: false,
alertType: "danger",
alertMsg: "You don't have access, please contact the admin."
});
showToast("danger", t("do-not-access-contact-admin"));
logOutUser();
}
} else {
setState({
...state,
alertType: "danger",
alertMsg: "User not found."
});
showToast("danger", t("user-not-found"));
logOutUser();
}
});
} catch (error) {
setState({
...state,
alertType: "danger",
alertMsg: t("something-went-wrong-mssg")
});
showToast("danger", t("something-went-wrong-mssg"));
console.log("err", error);
} finally {
setState({ ...state, loading: false });
setTimeout(() => setState({ ...state, alertMsg: "" }), 2000);
}
};
@@ -420,8 +349,6 @@ function Login() {
e.preventDefault();
if (userDetails.Destination && userDetails.Company) {
setThirdpartyLoader(true);
// console.log("handelSubmit", userDetails);
// const payload = await Parse.User.logIn(state.email, state.password);
const payload = { sessionToken: localStorage.getItem("accesstoken") };
const userInformation = JSON.parse(
localStorage.getItem("UserInformation")
@@ -461,13 +388,7 @@ function Login() {
alert(t("server-error"));
}
} else {
setState({
...state,
loading: false,
alertType: "warning",
alertMsg: "Please fill required details."
});
setTimeout(() => setState((prev) => ({ ...prev, alertMsg: "" })), 2000);
showToast("warning", t("fill-required-details!"));
}
};
@@ -516,7 +437,7 @@ function Login() {
<div
aria-labelledby="loginHeading"
role="region"
className="pb-1 md:pb-4 pt-10 md:px-10 lg:px-16"
className="pb-1 md:pb-4 pt-10 md:px-10 lg:px-16 h-screen"
>
<div className="md:p-4 lg:p-10 p-4 bg-base-100 text-base-content op-card">
<div className="w-[250px] h-[66px] inline-block overflow-hidden">
@@ -521,6 +521,14 @@ function PdfRequestFiles() {
}
);
const contact = resContact?.data?.result;
localStorage.setItem(
"signer",
JSON.stringify({
Name: contact?.Name,
Email: contact?.Email,
UserId: contact?.UserId?.objectId
})
);
setContractName("_Contactbook");
setSignerUserId(contact?.objectId);
const tourData = contact?.TourStatus && contact?.TourStatus;
@@ -877,6 +885,7 @@ function PdfRequestFiles() {
const variables = {
document_title: documentName,
note: pdfDetails?.[0]?.Note,
sender_name: senderName,
sender_mail: senderEmail,
sender_phone: senderPhone,
@@ -894,6 +903,7 @@ function PdfRequestFiles() {
);
}
const mailparam = {
note: pdfDetails?.[0]?.Note || "",
senderName: senderName,
senderMail: senderEmail,
title: documentName,
@@ -1182,6 +1182,7 @@ function PlaceHolderSign() {
const variables = {
document_title: documentName,
note: pdfDetails?.[0]?.Note,
sender_name: senderName,
sender_mail: senderEmail,
sender_phone: senderPhone || "",
@@ -1207,6 +1208,7 @@ function PlaceHolderSign() {
"</body> </html>";
const variables = {
document_title: documentName,
note: pdfDetails?.[0]?.Note,
sender_name: senderName,
sender_mail: senderEmail,
sender_phone: senderPhone || "",
@@ -1221,6 +1223,7 @@ function PlaceHolderSign() {
}
const mailparam = {
senderName: senderName,
note: pdfDetails?.[0]?.Note || "",
senderMail: senderEmail,
title: documentName,
organization: orgName,
+18 -14
View File
@@ -244,13 +244,15 @@ const Preferences = () => {
setIsLoader(true);
const replacedHtmlBody = completionBody.replace(/"/g, "'");
const htmlBody = `<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body>${replacedHtmlBody}</body></html>`;
const tenantQuery = new Parse.Query("partners_Tenant");
const updateTenantObj = await tenantQuery.get(tenantId);
updateTenantObj.set("CompletionBody", htmlBody);
updateTenantObj.set("CompletionSubject", completionsubject);
const res = await updateTenantObj.save();
if (res) {
const updateRes = JSON.parse(JSON.stringify(res));
const updateTenant = await Parse.Cloud.run("updatetenant", {
tenantId: tenantId,
details: {
CompletionBody: htmlBody,
CompletionSubject: completionsubject
}
});
if (updateTenant) {
const updateRes = JSON.parse(JSON.stringify(updateTenant));
SetCompletionBody(updateRes?.CompletionBody);
setCompletionSubject(updateRes?.CompletionSubject);
setIsAlert({ type: "success", msg: t("saved-successfully") });
@@ -271,13 +273,15 @@ const Preferences = () => {
setIsLoader(true);
const replacedHtmlBody = requestBody.replace(/"/g, "'");
const htmlBody = `<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body>${replacedHtmlBody}</body></html>`;
const tenantQuery = new Parse.Query("partners_Tenant");
const updateTenantObj = await tenantQuery.get(tenantId);
updateTenantObj.set("RequestBody", htmlBody);
updateTenantObj.set("RequestSubject", requestSubject);
const res = await updateTenantObj.save();
if (res) {
const updateRes = JSON.parse(JSON.stringify(res));
const updateTenant = await Parse.Cloud.run("updatetenant", {
tenantId: tenantId,
details: {
RequestBody: htmlBody,
RequestSubject: requestSubject
}
});
if (updateTenant) {
const updateRes = JSON.parse(JSON.stringify(updateTenant));
setRequestBody(updateRes?.RequestBody);
setRequestSubject(updateRes?.RequestSubject);
setIsAlert({ type: "success", msg: t("saved-successfully") });
+1 -1
View File
@@ -1212,7 +1212,7 @@ function SignYourSelf() {
setPdfBase64Url={setPdfBase64Url}
setIsUploadPdf={setIsUploadPdf}
pdfArrayBuffer={pdfArrayBuffer}
isMergePdfBtn={true}
isMergePdfBtn={!pdfDetails?.[0]?.IsCompleted}
/>
<div className=" w-full md:w-[57%] flex mr-4">
<PdfZoom
@@ -284,14 +284,14 @@ const TemplatePlaceholder = () => {
const updatedSigners = documentData[0].Signers.map((x, index) => ({
...x,
Id: randomId(),
Role: "User " + (index + 1)
Role: "Role " + (index + 1)
}));
setSignersData(updatedSigners);
setUniqueId(updatedSigners[0].Id);
setBlockColor(updatedSigners[0].blockColor);
}
} else {
setRoleName("User 1");
setRoleName("Role 1");
if (
documentData[0].Placeholders &&
documentData[0].Placeholders.length > 0
@@ -1101,7 +1101,7 @@ const TemplatePlaceholder = () => {
const Id = randomId();
const index = signersdata.length;
const obj = {
Role: roleName || "User " + count,
Role: roleName || "Role " + count,
Id: Id,
blockColor: color[index]
};
@@ -1110,7 +1110,7 @@ const TemplatePlaceholder = () => {
signerPtr: {},
signerObjId: "",
blockColor: color[index],
Role: roleName || "User " + count,
Role: roleName || "Role " + count,
Id: Id
};
+1 -1
View File
@@ -11,7 +11,7 @@ const Alert = ({ children, type, className }) => {
case "danger":
return "op-alert-error";
case "warning":
return "op-alert-warning";
return "op-alert-warning text-black";
default:
return "";
}
@@ -0,0 +1,34 @@
import React from "react";
const CheckCircle = ({ size = 56, color = "text-green-500" }) => {
return (
<div className={`flex items-center justify-center ${color}`}>
<svg
xmlns="http://www.w3.org/2000/svg"
className={`w-${size / 4} h-${size / 4}`}
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth={2}
>
<circle
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="2"
fill="none"
/>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M9 12l2 2l4-4"
/>
</svg>
</div>
);
};
export default CheckCircle;
+337 -317
View File
@@ -1,6 +1,6 @@
import React, { useState, useEffect, useRef } from "react";
import pad from "../assets/images/pad.svg";
import { useLocation, useNavigate } from "react-router";
import { Link, useLocation, useNavigate } from "react-router";
import axios from "axios";
import ModalUi from "./ModalUi";
import AddSigner from "../components/AddSigner";
@@ -46,7 +46,6 @@ const ReportTable = (props) => {
location?.pathname === "/dashboard/35KBoSgoAK" ? true : false;
const [currentPage, setCurrentPage] = useState(1);
const [actLoader, setActLoader] = useState({});
const [isAlert, setIsAlert] = useState(false);
const [isContactform, setIsContactform] = useState(false);
const [isDeleteModal, setIsDeleteModal] = useState({});
const [isRevoke, setIsRevoke] = useState({});
@@ -81,6 +80,8 @@ const ReportTable = (props) => {
const [invalidRecords, setInvalidRecords] = useState(0);
const [renameDoc, setRenameDoc] = useState("");
const [contact, setContact] = useState({ Name: "", Email: "", Phone: "" });
const [isSuccess, setIsSuccess] = useState({});
const [templateId, setTemplateId] = useState("");
const recordsPerPage = 5;
const startIndex = (currentPage - 1) * props.docPerPage;
const { isMoreDocs, setIsNextRecord } = props;
@@ -136,6 +137,10 @@ const ReportTable = (props) => {
return pages;
};
const showAlert = (type, message, time = 1500) => {
setAlertMsg({ type: type, message: message });
setTimeout(() => setAlertMsg({ type: "", message: "" }), time);
};
const pageNumbers = getPaginationRange();
// below useEffect reset currenpage to 1 if user change route
useEffect(() => {
@@ -225,164 +230,143 @@ const ReportTable = (props) => {
navigate(`/${act.redirectUrl}/${item.objectId}`);
} else {
setActLoader({ [`${item.objectId}_${act.btnId}`]: 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")
}
}
);
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 extUserId = Doc.ExtUserPtr.objectId;
let creatorId = Doc.CreatedBy.objectId;
if (extClass && extClass.length > 0) {
if (Doc.ExtUserPtr?.objectId !== extClass[0].objectId) {
const Extand_Class = localStorage.getItem("Extand_Class");
const extClass = Extand_Class && JSON.parse(Extand_Class);
if (extClass && extClass.length > 0) {
extUserId = extClass[0].objectId;
creatorId = extClass[0]?.UserId.objectId;
}
}
}
const tenantSignTypes = await fetchTenantDetails();
const docSignTypes = Doc?.SignatureType || signatureTypes;
const updatedSignatureType = await handleSignatureType(
tenantSignTypes,
docSignTypes
);
const SignatureType =
updatedSignatureType.length > 0
? { SignatureType: updatedSignatureType }
: {};
const NotifyOnSignatures =
Doc?.NotifyOnSignatures !== undefined
? { NotifyOnSignatures: Doc.NotifyOnSignatures }
: {};
const Bcc = Doc?.Bcc?.length > 0 ? { Bcc: Doc?.Bcc } : {};
const RedirectUrl = Doc?.RedirectUrl
? { RedirectUrl: Doc?.RedirectUrl }
: {};
let placeholdersArr = [];
if (Doc.Placeholders?.length > 0) {
placeholdersArr = Doc.Placeholders;
const data = {
Name: Doc.Name,
URL: Doc.URL,
SignedUrl: Doc.SignedUrl,
SentToOthers: Doc?.SentToOthers || false,
Description: Doc.Description,
Note: Doc.Note,
Placeholders: placeholdersArr,
ExtUserPtr: {
__type: "Pointer",
className: "contracts_Users",
objectId: extUserId
},
CreatedBy: {
__type: "Pointer",
className: "_User",
objectId: creatorId
},
Signers: signers,
SendinOrder: Doc?.SendinOrder || false,
AutomaticReminders: Doc?.AutomaticReminders || false,
RemindOnceInEvery: Doc?.RemindOnceInEvery || 5,
IsEnableOTP: Doc?.IsEnableOTP || false,
TimeToCompleteDays: parseInt(Doc?.TimeToCompleteDays) || 15,
AllowModifications: Doc?.AllowModifications || false,
...SignatureType,
...NotifyOnSignatures,
...Bcc,
...RedirectUrl
};
try {
const res = await axios.post(
`${localStorage.getItem(
"baseUrl"
)}classes/contracts_Document`,
data,
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id":
localStorage.getItem("parseAppId"),
"X-Parse-Session-Token":
localStorage.getItem("accesstoken")
}
}
);
if (res.data && res.data.objectId) {
setActLoader({});
setIsAlert(true);
setTimeout(() => setIsAlert(false), 1500);
navigate(`/${act.redirectUrl}/${res.data.objectId}`, {
state: { title: "Use Template" }
});
}
} catch (err) {
console.log("Err", err);
setIsAlert(true);
setAlertMsg({
type: "danger",
message: t("something-went-wrong-mssg")
});
setTimeout(() => setIsAlert(false), 1500);
setActLoader({});
}
} else {
setActLoader({});
}
} else {
setIsAlert(true);
setAlertMsg({
type: "danger",
message: t("something-went-wrong-mssg")
});
setTimeout(() => setIsAlert(false), 1500);
setActLoader({});
}
} catch (err) {
console.log("err", err);
setIsAlert(true);
setAlertMsg({
type: "danger",
message: t("something-went-wrong-mssg")
});
setTimeout(() => setIsAlert(false), 1500);
setActLoader({});
}
handleUseTemplate(item.objectId, act.redirectUrl);
}
} else {
navigate(`/${act.redirectUrl}?docId=${item?.objectId}`);
}
};
const handleUseTemplate = async (templateId, redirectUrl) => {
try {
const params = { templateId: templateId };
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")
}
}
);
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) {
signers.push({
__type: "Pointer",
className: "contracts_Contactbook",
objectId: x.objectId
});
}
});
}
let extUserId = Doc.ExtUserPtr.objectId;
let creatorId = Doc.CreatedBy.objectId;
if (extClass && extClass.length > 0) {
if (Doc.ExtUserPtr?.objectId !== extClass[0].objectId) {
const Extand_Class = localStorage.getItem("Extand_Class");
const extClass = Extand_Class && JSON.parse(Extand_Class);
if (extClass && extClass.length > 0) {
extUserId = extClass[0].objectId;
creatorId = extClass[0]?.UserId.objectId;
}
}
}
const tenantSignTypes = await fetchTenantDetails();
const docSignTypes = Doc?.SignatureType || signatureTypes;
const updatedSignatureType = await handleSignatureType(
tenantSignTypes,
docSignTypes
);
const SignatureType =
updatedSignatureType.length > 0
? { SignatureType: updatedSignatureType }
: {};
const NotifyOnSignatures =
Doc?.NotifyOnSignatures !== undefined
? { NotifyOnSignatures: Doc.NotifyOnSignatures }
: {};
const Bcc = Doc?.Bcc?.length > 0 ? { Bcc: Doc?.Bcc } : {};
const RedirectUrl = Doc?.RedirectUrl
? { RedirectUrl: Doc?.RedirectUrl }
: {};
let placeholdersArr = [];
if (Doc.Placeholders?.length > 0) {
placeholdersArr = Doc.Placeholders;
const data = {
Name: Doc.Name,
URL: Doc.URL,
SignedUrl: Doc.SignedUrl,
SentToOthers: Doc?.SentToOthers || false,
Description: Doc.Description,
Note: Doc.Note,
Placeholders: placeholdersArr,
ExtUserPtr: {
__type: "Pointer",
className: "contracts_Users",
objectId: extUserId
},
CreatedBy: {
__type: "Pointer",
className: "_User",
objectId: creatorId
},
Signers: signers,
SendinOrder: Doc?.SendinOrder || false,
AutomaticReminders: Doc?.AutomaticReminders || false,
RemindOnceInEvery: Doc?.RemindOnceInEvery || 5,
IsEnableOTP: Doc?.IsEnableOTP || false,
TimeToCompleteDays: parseInt(Doc?.TimeToCompleteDays) || 15,
AllowModifications: Doc?.AllowModifications || false,
...SignatureType,
...NotifyOnSignatures,
...Bcc,
...RedirectUrl
};
try {
const res = await axios.post(
`${localStorage.getItem("baseUrl")}classes/contracts_Document`,
data,
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
}
}
);
if (res.data && res.data.objectId) {
setActLoader({});
navigate(`/${redirectUrl}/${res.data.objectId}`, {
state: { title: "Use Template" }
});
}
} catch (err) {
console.log("Err", err);
showAlert("danger", t("something-went-wrong-mssg"));
setActLoader({});
}
} else {
setActLoader({});
}
} else {
showAlert("danger", t("something-went-wrong-mssg"));
setActLoader({});
}
} catch (err) {
console.log("err", err);
showAlert("danger", t("something-went-wrong-mssg"));
setActLoader({});
}
};
const handleActionBtn = async (act, item) => {
if (act.action === "redirect") {
handleURL(item, act);
@@ -415,6 +399,8 @@ const ReportTable = (props) => {
} else if (act.action === "edit") {
setContact(item);
setIsModal({ [`edit_${item.objectId}`]: true });
} else if (act.action === "saveastemplate") {
setIsModal({ [`saveastemplate_${item.objectId}`]: true });
} else if (act.action) {
setIsModal({ [`extendexpiry_${item.objectId}`]: true });
}
@@ -470,12 +456,7 @@ const ReportTable = (props) => {
});
if (res.data && res.data.updatedAt) {
setActLoader({});
setIsAlert(true);
setAlertMsg({
type: "success",
message: t("record-delete-alert")
});
setTimeout(() => setIsAlert(false), 1500);
showAlert("success", t("record-delete-alert"));
const upldatedList = props.List.filter(
(x) => x.objectId !== item.objectId
);
@@ -483,12 +464,7 @@ const ReportTable = (props) => {
}
} catch (err) {
console.log("err", err);
setIsAlert(true);
setAlertMsg({
type: "danger",
message: t("something-went-wrong-mssg")
});
setTimeout(() => setIsAlert(false), 1500);
showAlert("danger", t("something-went-wrong-mssg"));
setActLoader({});
}
};
@@ -563,12 +539,7 @@ const ReportTable = (props) => {
const res = result.data;
if (res) {
setActLoader({});
setIsAlert(true);
setAlertMsg({
type: "success",
message: t("record-revoke-alert")
});
setTimeout(() => setIsAlert(false), 1500);
showAlert("success", t("record-revoke-alert"));
const upldatedList = props.List.filter(
(x) => x.objectId !== item.objectId
);
@@ -579,12 +550,7 @@ const ReportTable = (props) => {
.catch((err) => {
console.log("err", err);
setReason("");
setIsAlert(true);
setAlertMsg({
type: "danger",
message: t("something-went-wrong-mssg")
});
setTimeout(() => setIsAlert(false), 1500);
showAlert("danger", t("something-went-wrong-mssg"));
setActLoader({});
});
};
@@ -678,6 +644,7 @@ const ReportTable = (props) => {
const signPdf = `${window.location.origin}/login/${encodeBase64}`;
const variables = {
document_title: doc.Name,
note: doc?.Note || "",
sender_name: doc.ExtUserPtr.Name,
sender_mail: doc.ExtUserPtr.Email,
sender_phone: doc.ExtUserPtr?.Phone || "",
@@ -707,6 +674,7 @@ const ReportTable = (props) => {
const signPdf = `${window.location.origin}/login/${encodeBase64}`;
const variables = {
document_title: doc.Name,
note: doc?.Note || "",
sender_name: doc.ExtUserPtr.Name,
sender_mail: doc.ExtUserPtr.Email,
sender_phone: doc.ExtUserPtr?.Phone || "",
@@ -748,6 +716,7 @@ const ReportTable = (props) => {
const signPdf = `${window.location.origin}/login/${encodeBase64}`;
const variables = {
document_title: doc.Name,
note: doc?.Note || "",
sender_name: doc.ExtUserPtr.Name,
sender_mail: doc.ExtUserPtr.Email,
sender_phone: doc.ExtUserPtr?.Phone || "",
@@ -789,25 +758,15 @@ const ReportTable = (props) => {
try {
const res = await axios.post(url, params, { headers: headers });
if (res?.data?.result?.status === "success") {
setIsAlert(true);
setAlertMsg({ type: "success", message: t("mail-sent-alert") });
showAlert("success", t("mail-sent-alert"));
setIsResendMail({});
} else {
setIsAlert(true);
setAlertMsg({
type: "danger",
message: t("something-went-wrong-mssg")
});
showAlert("danger", t("something-went-wrong-mssg"));
}
} catch (err) {
console.log("err in sendmail", err);
setIsAlert(true);
setAlertMsg({
type: "danger",
message: t("something-went-wrong-mssg")
});
showAlert("danger", t("something-went-wrong-mssg"));
} finally {
setTimeout(() => setIsAlert(false), 1500);
setIsNextStep({});
setUserDetails({});
setActLoader({});
@@ -840,27 +799,10 @@ const ReportTable = (props) => {
// `handleQuickSendClose` is trigger when bulk send component trigger close event
const handleQuickSendClose = (status, count) => {
setIsBulkSend({});
setIsAlert(true);
if (status === "success") {
if (count > 1) {
setAlertMsg({
type: "success",
message: count + " " + t("document-sent-alert")
});
setTimeout(() => setIsAlert(false), 1500);
} else {
setAlertMsg({
type: "success",
message: count + " " + t("document-sent-alert")
});
setTimeout(() => setIsAlert(false), 1500);
}
showAlert("success", count + " " + t("document-sent-alert"));
} else {
setAlertMsg({
type: "danger",
message: t("something-went-wrong-mssg")
});
setTimeout(() => setIsAlert(false), 1500);
showAlert("danger", t("something-went-wrong-mssg"));
}
};
@@ -899,9 +841,7 @@ const ReportTable = (props) => {
} catch (err) {
console.log("err in fetch template in bulk modal", err);
setIsBulkSend({});
setIsAlert(true);
setAlertMsg({ type: "danger", message: t("something-went-wrong-mssg") });
setTimeout(() => setIsAlert(false), 1500);
showAlert("danger", t("something-went-wrong-mssg"));
}
};
@@ -925,21 +865,12 @@ const ReportTable = (props) => {
templateCls.set("SharedWith", teamArr);
const res = await templateCls.save();
if (res) {
setIsAlert(true);
setAlertMsg({
type: "success",
message: t("template-share-alert")
});
showAlert("success", t("template-share-alert"));
}
} catch (err) {
setIsAlert(true);
setAlertMsg({
type: "danger",
message: t("something-went-wrong-mssg")
});
showAlert("danger", t("something-went-wrong-mssg"));
} finally {
setActLoader({});
setTimeout(() => setIsAlert(false), 1500);
}
};
@@ -966,13 +897,13 @@ const ReportTable = (props) => {
}
});
if (res.data && res.data.updatedAt) {
setIsAlert(true);
setAlertMsg({
type: "success",
message: t("expiry-date-updated", {
showAlert(
"success",
t("expiry-date-updated", {
newexpirydate: new Date(expiryDate)?.toLocaleDateString()
})
});
}),
2000
);
if (props.ReportName === "Expired Documents") {
const upldatedList = props.List.filter(
(x) => x.objectId !== item.objectId
@@ -982,70 +913,39 @@ const ReportTable = (props) => {
}
} catch (err) {
console.log("err", err);
setIsAlert(true);
setAlertMsg({
type: "danger",
message: t("something-went-wrong-mssg")
});
showAlert("danger", t("something-went-wrong-mssg"), 2000);
} finally {
setActLoader({});
setExpiryDate();
setTimeout(() => setIsAlert(false), 2000);
setIsModal({});
}
} else {
setIsAlert(true);
setAlertMsg({ type: "danger", message: t("expiry-date-error") });
setTimeout(() => setIsAlert(false), 2000);
showAlert("danger", t("expiry-date-error"), 2000);
}
} else {
setIsAlert(true);
setAlertMsg({ type: "danger", message: t("expiry-date-error") });
setTimeout(() => setIsAlert(false), 2000);
showAlert("danger", t("expiry-date-error"), 2000);
}
};
// `formatStatusRow` is used to format status row
const formatStatusRow = (item) => {
const timezone = extClass?.[0]?.Timezone || "";
const DateFormat = extClass?.[0]?.DateFormat || "MM/DD/YYYY";
const Is12Hr = extClass?.[0]?.Is12HourTime || false;
const signers = item?.Placeholders?.map((x, i) => {
const matchSigner = item?.AuditTrail?.find(
const audit = item?.AuditTrail?.find(
(audit) => audit?.UserPtr?.objectId === x.signerObjId
);
if (matchSigner) {
const timezone = extClass?.[0]?.Timezone || "";
const DateFormat = extClass?.[0]?.DateFormat || "MM/DD/YYYY";
const Is12Hr = extClass?.[0]?.Is12HourTime || false;
const signedon = matchSigner?.SignedOn
? formatDateTime(
new Date(matchSigner?.SignedOn),
DateFormat,
timezone,
Is12Hr
)
const format = (date) =>
date
? formatDateTime(new Date(date), DateFormat, timezone, Is12Hr)
: "-";
const viewedon = matchSigner?.ViewedOn
? formatDateTime(
new Date(matchSigner?.ViewedOn),
DateFormat,
timezone,
Is12Hr
)
: "-";
return {
id: i,
Email: matchSigner.UserPtr.Email,
Activity: matchSigner?.Activity?.toUpperCase() || "-",
SignedOn: signedon,
ViewedOn: viewedon
};
} else {
return {
id: i,
Email: x?.signerPtr?.Email || x?.email,
Activity: "SENT",
SignedOn: "-",
ViewedOn: "-"
};
}
return {
id: i,
Email: x?.signerPtr?.Email || x?.email,
Activity: audit?.Activity?.toUpperCase() || "SENT",
SignedOn: format(audit?.SignedOn),
ViewedOn: format(audit?.ViewedOn)
};
});
// Decide how many signers to display based on `showAllSignes` state
const displaySigners = isShowAllSigners[item.objectId]
@@ -1075,7 +975,7 @@ const ReportTable = (props) => {
<ModalUi
isOpen
title={t("document-logs")}
handleClose={() => setIsModal({})}
handleClose={handleCloseModal}
>
<div className="pl-3 first:mt-2 border-t-[1px] border-gray-600 text-[12px] py-2">
<p className="font-bold"> {x?.Email}</p>
@@ -1289,28 +1189,25 @@ const ReportTable = (props) => {
const contacts = JSON.stringify(filterdata);
const res = await Parse.Cloud.run("createbatchcontact", { contacts });
if (res) {
setIsAlert(true);
setAlertMsg({
type: "info",
message: t("contact-imported", {
showAlert(
"info",
t("contact-imported", {
imported: res?.success || 0,
failed: res?.failed || 0
})
});
);
if (res?.success > 0) {
setTimeout(() => window.location.reload(), 2000);
setTimeout(() => window.location.reload(), 1500);
}
}
} catch (err) {
console.log("err while creating batch contact", err);
setIsAlert(true);
setAlertMsg({ type: "danger", message: t("something-went-wrong-mssg") });
showAlert("danger", t("something-went-wrong-mssg"));
} finally {
setActLoader({});
setIsModal({});
setImportedData([]);
setInvalidRecords(0);
setTimeout(() => setIsAlert(false), 2000);
}
};
@@ -1325,22 +1222,13 @@ const ReportTable = (props) => {
if (duplicateRes) {
const newTemplate = JSON.parse(JSON.stringify(duplicateRes));
props.setList((prevData) => [newTemplate, ...prevData]);
setIsAlert(true);
setAlertMsg({
type: "success",
message: t("duplicate-template-created")
});
showAlert("success", t("duplicate-template-created"));
}
} catch (err) {
setIsAlert(true);
setAlertMsg({
type: "danger",
message: t("something-went-wrong-mssg")
});
showAlert("danger", t("something-went-wrong-mssg"));
console.log("Err while create duplicate template", err);
} finally {
setActLoader({});
setTimeout(() => setIsAlert(false), 2000);
}
};
// `handleRenameDoc` is used to update document name
@@ -1361,21 +1249,11 @@ const ReportTable = (props) => {
x.objectId === item.objectId ? { ...x, Name: renameDoc } : x
);
props.setList(updateList);
setIsAlert(true);
setAlertMsg({
type: "success",
message: "Document updated"
});
setActLoader({});
setTimeout(() => setIsAlert(false), 2000);
showAlert("success", "Document updated", 2000);
} catch (err) {
setIsAlert(true);
setAlertMsg({
type: "danger",
message: t("something-went-wrong-mssg")
});
showAlert("danger", t("something-went-wrong-mssg"), 2000);
setActLoader({});
setTimeout(() => setIsAlert(false), 2000);
}
};
const handleBtnVisibility = (act, item) => {
@@ -1399,6 +1277,65 @@ const ReportTable = (props) => {
const handleCloseModal = () => {
setIsModal({});
};
const handleSaveAsTemplate = async (doc) => {
try {
const params = { docId: doc?.objectId };
const templateRes = await Parse.Cloud.run("saveastemplate", params);
// console.log("templateRes ", templateRes);
setTemplateId(templateRes?.id);
setIsSuccess({ [doc.objectId]: true });
} catch (err) {
console.log("Err in saveastemplate", err);
} finally {
setActLoader({});
}
};
const handleCloseTemplate = () => {
setTemplateId("");
setIsSuccess({});
handleCloseModal();
setActLoader({});
handleClose();
};
// `handleBulkSend` is used to open modal as well as fetch template
// and show Ui on the basis template response
const handleBulkSendTemplate = async (templateId, docId) => {
setIsBulkSend({ [docId]: true });
setIsLoader({ [docId]: true });
try {
const params = {
templateId: templateId,
include: ["Placeholders.signerPtr"]
};
const axiosRes = 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")
}
}
);
const templateRes = axiosRes.data && axiosRes.data.result;
const tenantSignTypes = await fetchTenantDetails();
const docSignTypes = templateRes?.SignatureType || signatureTypes;
const updatedSignatureType = await handleSignatureType(
tenantSignTypes,
docSignTypes
);
setSignatureType(updatedSignatureType);
setPlaceholders(templateRes?.Placeholders);
setTemplateDetails(templateRes);
setIsLoader({});
} catch (err) {
console.log("err in fetch template in bulk modal", err);
setIsBulkSend({});
showAlert("danger", t("something-went-wrong-mssg"));
}
};
return (
<div className="relative">
{Object.keys(actLoader)?.length > 0 && (
@@ -1407,7 +1344,9 @@ const ReportTable = (props) => {
</div>
)}
<div className="p-2 w-full bg-base-100 text-base-content op-card shadow-lg">
{isAlert && <Alert type={alertMsg.type}>{alertMsg.message}</Alert>}
{alertMsg.message && (
<Alert type={alertMsg.type}>{alertMsg.message}</Alert>
)}
{props.tourData && props.ReportName === "Templates" && (
<>
<Tour
@@ -1781,7 +1720,7 @@ const ReportTable = (props) => {
isOpen={
isModal["duplicate_" + item.objectId]
}
handleClose={() => setIsModal({})}
handleClose={handleCloseModal}
>
<div className=" flex flex-col px-4 pb-3 pt-2 ">
<p className="text-base">
@@ -1798,7 +1737,7 @@ const ReportTable = (props) => {
</button>
<button
className="w-[100px] op-btn op-btn-secondary op-btn-md"
onClick={() => setIsModal({})}
onClick={handleCloseModal}
>
{t("no")}
</button>
@@ -1869,12 +1808,93 @@ const ReportTable = (props) => {
)
)}
</div>
{isModal["saveastemplate_" + item.objectId] && (
<ModalUi
isOpen
title={
isSuccess[item.objectId]
? t("template-created")
: t("btnLabel.Save as template")
}
handleClose={handleCloseTemplate}
>
{isSuccess[item.objectId] ? (
<div className="mx-[10px] my-[15px]">
<p className="text-base text-center">
{t("how-would-you-like-to-proceed?")}
</p>
<div className="flex flex-wrap gap-1 items-center justify-center mt-2">
<button
className="op-btn-primary op-btn op-btn-sm focus:outline-none text-sm relative"
onClick={() =>
handleUseTemplate(
templateId,
"placeHolderSign"
)
}
>
<i className="fa-light fa-plus"></i>{" "}
{t("btnLabel.Use")}
</button>
<button
className="op-btn-secondary op-btn op-btn-sm focus:outline-none text-sm relative"
onClick={() =>
handleBulkSendTemplate(
templateId,
item.objectId
)
}
>
<i className="fa-light fa-plus"></i>{" "}
{`${t(`btnLabel.Quick send`)}`}
</button>
<button
className="op-btn-secondary op-btn op-btn-sm focus:outline-none text-sm relative"
onClick={() =>
navigate(`/template/${templateId}`)
}
>
<i className="fa-light fa-pen"></i>{" "}
{t(`btnLabel.Edit`)}
</button>
</div>
<Link
to="/report/6TeaPr321t"
className="cursor-pointer underline text-sm w-full flex justify-center mt-2"
>
{t("go-to-manage-templates")}
</Link>
</div>
) : (
<div className="m-[20px]">
<div className="text-lg font-normal text-black">
{t("save-as-template-?")}
</div>
<hr className="bg-[#ccc] mt-3" />
<div className="flex items-center mt-3 gap-2 text-white">
<button
onClick={() => handleSaveAsTemplate(item)}
className="op-btn op-btn-primary w-[100px]"
>
{t("yes")}
</button>
<button
onClick={handleCloseTemplate}
className="op-btn op-btn-secondary w-[100px]"
>
{t("no")}
</button>
</div>
</div>
)}
</ModalUi>
)}
{isModal["extendexpiry_" + item.objectId] && (
<ModalUi
isOpen
title={t("btnLabel.extend-expiry-date")}
reduceWidth={"md:max-w-[450px]"}
handleClose={() => setIsModal({})}
handleClose={handleCloseModal}
>
<form
className="px-4 py-2 flex flex-col"
@@ -2233,7 +2253,7 @@ const ReportTable = (props) => {
<ModalUi
title={t("btnLabel.Rename")}
isOpen={isModal["rename_" + item.objectId]}
handleClose={() => setIsModal({})}
handleClose={handleCloseModal}
>
<div className=" flex flex-col px-4 pb-3 pt-2 ">
<div className="flex flex-col gap-2">
@@ -2255,7 +2275,7 @@ const ReportTable = (props) => {
</button>
<button
className="w-[100px] op-btn op-btn-secondary op-btn-md"
onClick={() => setIsModal({})}
onClick={handleCloseModal}
>
{t("cancel")}
</button>
@@ -1,7 +1,7 @@
function sanitizeFileName(fileName) {
// Remove spaces and invalid characters
const file = fileName.replace(/[^a-zA-Z0-9._-]/g, "");
const removedot = file.replace(/\.(?=.*\.)/g, "");
return removedot.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 -4
View File
@@ -49,7 +49,7 @@ export const saveFileUsage = async (size, fileUrl, userId) => {
className: '_User',
objectId: userId,
});
const tenant = await tenantQuery.first();
const tenant = await tenantQuery.first({ useMasterKey: true });
if (tenant) {
const tenantPtr = { __type: 'Pointer', className: 'partners_Tenant', objectId: tenant.id };
try {
@@ -225,6 +225,7 @@ export const flattenPdf = async pdfFile => {
export const mailTemplate = param => {
const themeColor = '#47a3ad';
const subject = `${param.senderName} has requested you to sign "${param.title}"`;
const AppName = appName;
const logo = `<img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' />`;
const opurl = ` <a href='www.opensignlabs.com' target=_blank>here</a>`;
@@ -240,15 +241,17 @@ export const mailTemplate = param => {
param.senderMail +
"</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'> " +
param.organization +
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Expire on</td><td></td><td style='color:#626363;font-weight:bold'>" +
"</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'>" +
param.localExpireDate +
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Note</td><td></td><td style='color:#626363;font-weight:bold'>" +
param.note +
"</td></tr><tr><td></td><td></td></tr></table></div> <div style='margin-left:70px'><a target=_blank href=" +
param.sigingUrl +
"><button style='padding:12px;background-color:#d46b0f;color:white;border:0px;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 " +
appName +
AppName +
'. For any queries regarding this email, please contact the sender ' +
param.senderMail +
` directly. If you think this email is inappropriate or spam, you may file a complaint with ${appName}${opurl}.</p></div></div></body></html>`;
` directly. If you think this email is inappropriate or spam, you may file a complaint with ${AppName}${opurl}.</p></div></div></body></html>`;
return { subject, body };
};
+4 -2
View File
@@ -12,7 +12,6 @@ import getDrive from './parsefunction/getDrive.js';
import getReport from './parsefunction/getReport.js';
import TemplateAfterSave from './parsefunction/TemplateAfterSave.js';
import GetTemplate from './parsefunction/GetTemplate.js';
import callWebhook from './parsefunction/callWebhook.js';
import DocumentBeforesave from './parsefunction/DocumentBeforesave.js';
import TemplateBeforeSave from './parsefunction/TemplateBeforesave.js';
import DocumentBeforeFind from './parsefunction/DocumentAfterFind.js';
@@ -50,6 +49,8 @@ import fileUpload from './parsefunction/fileUpload.js';
import getUserListByOrg from './parsefunction/getUserListByOrg.js';
import editContact from './parsefunction/editContact.js';
import forwardDoc from './parsefunction/ForwardDoc.js';
import saveAsTemplate from './parsefunction/saveAsTemplate.js';
import updateTenant from './parsefunction/updateTenant.js';
// This afterSave function triggers after an object is added or updated in the specified class, allowing for post-processing logic.
Parse.Cloud.afterSave('contracts_Document', DocumentAftersave);
@@ -80,7 +81,6 @@ Parse.Cloud.define('getDocument', getDocument);
Parse.Cloud.define('getDrive', getDrive);
Parse.Cloud.define('getReport', getReport);
Parse.Cloud.define('getTemplate', GetTemplate);
Parse.Cloud.define('callwebhook', callWebhook);
Parse.Cloud.define('verifyemail', VerifyEmail);
Parse.Cloud.define('getsignedurl', getSignedUrl);
Parse.Cloud.define('batchdocuments', createBatchDocs);
@@ -110,3 +110,5 @@ Parse.Cloud.define('fileupload', fileUpload);
Parse.Cloud.define('getuserlistbyorg', getUserListByOrg);
Parse.Cloud.define('editcontact', editContact);
Parse.Cloud.define('forwarddoc', forwardDoc);
Parse.Cloud.define('saveastemplate', saveAsTemplate);
Parse.Cloud.define('updatetenant', updateTenant);
@@ -61,7 +61,7 @@ async function addTeamAndOrg(extUser) {
async function saveUser(userDetails) {
const userQuery = new Parse.Query(Parse.User);
userQuery.equalTo('username', userDetails.email);
userQuery.equalTo('username', userDetails.email?.toLowerCase()?.replace(/\s/g, ''));
const userRes = await userQuery.first({ useMasterKey: true });
if (userRes) {
@@ -83,9 +83,9 @@ async function saveUser(userDetails) {
return { id: login.objectId, sessionToken: login.sessionToken };
} else {
const user = new Parse.User();
user.set('username', userDetails.email);
user.set('username', userDetails.email?.toLowerCase()?.replace(/\s/g, ''));
user.set('password', userDetails.password);
user.set('email', userDetails.email);
user.set('email', userDetails.email?.toLowerCase()?.replace(/\s/g, ''));
if (userDetails?.phone) {
user.set('phone', userDetails.phone);
}
@@ -111,7 +111,6 @@ export default async function AddAdmin(request) {
if (extUser) {
return { message: 'User already exist' };
} else {
// console.log("role ", role);
const partnerQuery = new Parse.Object('partners_Tenant');
partnerQuery.set('UserId', {
__type: 'Pointer',
@@ -123,7 +122,7 @@ export default async function AddAdmin(request) {
partnerQuery.set('ContactNumber', userDetails.phone);
}
partnerQuery.set('TenantName', userDetails.company);
partnerQuery.set('EmailAddress', userDetails.email);
partnerQuery.set('EmailAddress', userDetails.email?.toLowerCase()?.replace(/\s/g, ''));
partnerQuery.set('IsActive', true);
partnerQuery.set('CreatedBy', {
__type: 'Pointer',
@@ -154,7 +153,7 @@ export default async function AddAdmin(request) {
objectId: user.id,
});
newObj.set('UserRole', userDetails.role);
newObj.set('Email', userDetails.email);
newObj.set('Email', userDetails.email?.toLowerCase()?.replace(/\s/g, ''));
newObj.set('Name', userDetails.name);
if (userDetails?.phone) {
newObj.set('Phone', userDetails?.phone);
@@ -177,7 +176,7 @@ export default async function AddAdmin(request) {
const extUser = {
objectId: extRes.id,
Name: userDetails.name,
Email: userDetails.email,
Email: userDetails.email?.toLowerCase()?.replace(/\s/g, ''),
Phone: userDetails?.phone ? userDetails.phone : '',
TenantId: { objectId: tenantRes.id },
UserId: { objectId: user.id },
@@ -28,6 +28,7 @@ export default async function forwardDoc(request) {
const docName = _docRes.Name;
const fileAdapterId = _docRes?.FileAdapterId || '';
const extUserId = _docRes?.ExtUserPtr?.objectId;
const TenantAppName = appName;
const from = _docRes?.ExtUserPtr?.Email;
const replyTo = _docRes?.ExtUserPtr?.Email;
const senderName = _docRes?.ExtUserPtr?.Name;
@@ -51,8 +52,8 @@ export default async function forwardDoc(request) {
`<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'/></head><body><div style='background-color:#f5f5f5;padding:20px'><div style='background-color:white'><div>` +
`${logo}</div><div style='padding:2px;font-family:system-ui;background-color:${themeColor}'><p style='font-size:20px;font-weight:400;color:white;padding-left:20px'>Document Copy</p></div><div>` +
`<p style='padding:20px;font-family:system-ui;font-size:14px'>A copy of the document <strong>${docName}</strong> is attached to this email. Kindly download the document from the attachment.</p>` +
`</div></div><div><p>This is an automated email from ${appName}. For any queries regarding this email, please contact the sender ${replyTo} directly. ` +
`If you think this email is inappropriate or spam, you may file a complaint with ${appName}${opurl}.</p></div></div></body></html>`,
`</div></div><div><p>This is an automated email from ${TenantAppName}. For any queries regarding this email, please contact the sender ${replyTo} directly. ` +
`If you think this email is inappropriate or spam, you may file a complaint with ${TenantAppName}${opurl}.</p></div></div></body></html>`,
};
mailRes = await axios.post(`${cloudServerUrl}/functions/sendmailv3`, params, {
headers: {
@@ -6,13 +6,17 @@ export default async function GetLogoByDomain(request) {
try {
const tenantCreditsQuery = new Parse.Query('partners_Tenant');
tenantCreditsQuery.equalTo('Domain', domain);
const res = await tenantCreditsQuery.first();
const res = await tenantCreditsQuery.first({ useMasterKey: true });
if (res) {
const updateRes = JSON.parse(JSON.stringify(res));
return { logo: updateRes?.Logo, appname: appName, user: 'exist' };
return {
logo: updateRes?.Logo,
appname: appName,
user: 'exist',
};
} else {
const tenantCreditsQuery = new Parse.Query('partners_Tenant');
const tenantRes = await tenantCreditsQuery.first();
const tenantRes = await tenantCreditsQuery.first({ useMasterKey: true });
if (tenantRes) {
return { logo: '', appname: appName, user: 'exist' };
} else {
@@ -1,7 +1,7 @@
import axios from 'axios';
export default async function Newsletter(request) {
const name = request.params.name;
const email = request.params.email;
const email = request.params?.email?.toLowerCase()?.replace(/\s/g, '');
const domain = request.params.domain;
try {
const envAppId = process.env.REACT_APP_APPID || 'opensign';
@@ -22,19 +22,20 @@ async function sendMailOTPv1(request) {
//--for elearning app side
let code = Math.floor(1000 + Math.random() * 9000);
let email = request.params.email;
var TenantId = request.params.TenantId ? request.params.TenantId : undefined;
let TenantId = request.params.TenantId ? request.params.TenantId : undefined;
const AppName = appName;
if (email) {
const recipient = request.params.email;
const mailsender = smtpenable ? process.env.SMTP_USER_EMAIL : process.env.MAILGUN_SENDER;
try {
await Parse.Cloud.sendEmail({
from: appName + ' <' + mailsender + '>',
from: AppName + ' <' + mailsender + '>',
recipient: recipient,
subject: `Your ${appName} OTP`,
subject: `Your ${AppName} OTP`,
text: 'This email is a test.',
html:
`<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body><div style='background-color:#f5f5f5;padding:20px'><div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background-color:white;'><div style='background-color:red;padding:2px;font-family:system-ui; background-color:#47a3ad;'> <p style='font-size:20px;font-weight:400;color:white;padding-left:20px',>OTP Verification</p></div><div style='padding:20px'><p style='font-family:system-ui;font-size:14px'>Your OTP for ${appName} verification is:</p><p style=' text-decoration: none; font-weight: bolder; color:blue;font-size:45px;margin:20px'>` +
`<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body><div style='background-color:#f5f5f5;padding:20px'><div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background-color:white;'><div style='background-color:red;padding:2px;font-family:system-ui; background-color:#47a3ad;'> <p style='font-size:20px;font-weight:400;color:white;padding-left:20px',>OTP Verification</p></div><div style='padding:20px'><p style='font-family:system-ui;font-size:14px'>Your OTP for ${AppName} verification is:</p><p style=' text-decoration: none; font-weight: bolder; color:blue;font-size:45px;margin:20px'>` +
code +
'</p></div> </div> </div></body></html>',
});
@@ -1,108 +0,0 @@
import axios from 'axios';
import { cloudServerUrl } from '../../Utils.js';
export default async function callWebhook(request) {
const event = request.params.event;
const body = request.params.body;
const docId = body.objectId;
const contactId = request.params.contactId;
const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
const appId = process.env.APP_ID;
try {
const docQuery = new Parse.Query('contracts_Document');
docQuery.include('ExtUserPtr.TenantId');
const docRes = await docQuery.get(docId, { useMasterKey: true });
const isEnableOTP = docRes?.get('IsEnableOTP') || false;
let userId;
if (isEnableOTP) {
const userRes = await axios.get(serverUrl + '/users/me', {
headers: {
'X-Parse-Application-Id': appId,
'X-Parse-Session-Token': request.headers['sessiontoken'],
},
});
userId = userRes.data && userRes.data.objectId;
}
if (!isEnableOTP || userId) {
if (event === 'viewed' && contactId) {
if (docRes) {
const _docRes = docRes.toJSON();
const userPtr = {
__type: 'Pointer',
className: 'contracts_Contactbook',
objectId: contactId,
};
const date = new Date().toISOString();
const obj = {
UserPtr: userPtr,
SignedUrl: _docRes.SignedUrl,
Activity: 'Viewed',
ipAddress: request.headers['x-real-ip'],
ViewedOn: date,
};
const isUserExist = _docRes?.AuditTrail?.some(
x => x.UserPtr.objectId === contactId && x?.ViewedOn
);
if (!isUserExist) {
const updateDoc = new Parse.Object('contracts_Document');
updateDoc.id = docRes.id;
if (_docRes?.AuditTrail && _docRes?.AuditTrail?.length > 0) {
updateDoc.set('AuditTrail', [..._docRes?.AuditTrail, obj]);
} else {
updateDoc.set('AuditTrail', [obj]);
}
await updateDoc.save(null, { useMasterKey: true });
}
}
}
const extendcls = new Parse.Query('contracts_Users');
extendcls.equalTo('objectId', docRes.get('ExtUserPtr')?.id);
// extendcls.equalTo('UserId', { __type: 'Pointer', className: '_User', objectId: userId });
const resExt = await extendcls.first({ useMasterKey: true });
if (resExt) {
const extUser = JSON.parse(JSON.stringify(resExt));
if (extUser?.Webhook) {
const params = { event: event, ...body };
await axios
.post(extUser?.Webhook, params, {
headers: { 'Content-Type': 'application/json' },
})
.then(res => {
try {
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.message);
}
})
.catch(err => {
console.log('Err send data to webhook', err.message);
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.message);
}
});
}
return { message: 'webhook called!' };
}
} else {
return { message: 'User not found!' };
}
} catch (err) {
console.log('Err in callwebhook', err);
return { message: 'Something went wrong!' };
}
}
@@ -21,7 +21,7 @@ export default async function createBatchContact(req) {
TenantId: { __type: 'Pointer', className: 'partners_Tenant', objectId: x.TenantId },
CreatedBy: { __type: 'Pointer', className: '_User', objectId: req.user.id },
Name: x.Name,
Email: x.Email,
Email: x.Email?.toLowerCase()?.replace(/\s/g, ''),
IsDeleted: false,
IsImported: true,
...(x?.Phone ? { Phone: `${x?.Phone}` } : {}),
@@ -1,14 +1,8 @@
import axios from 'axios';
import {
cloudServerUrl,
replaceMailVaribles,
} from '../../Utils.js';
import { cloudServerUrl, replaceMailVaribles } from '../../Utils.js';
const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
const appId = process.env.APP_ID;
async function deductcount(
docsCount,
extUserId,
) {
async function deductcount(docsCount, extUserId) {
try {
const extCls = new Parse.Object('contracts_Users');
extCls.id = extUserId;
@@ -18,9 +12,9 @@ async function deductcount(
console.log('Err in deduct in quick send', err);
}
}
async function sendMail(document) {
async function sendMail(document, publicUrl) {
//sessionToken
const baseUrl = new URL(process.env.PUBLIC_URL);
const baseUrl = new URL(publicUrl); //process.env.PUBLIC_URL
// console.log("pdfDetails", pdfDetails);
const timeToCompleteDays = document?.TimeToCompleteDays || 15;
@@ -33,10 +27,8 @@ async function sendMail(document) {
year: 'numeric',
});
let signerMail = document.Placeholders;
const senderName =
document.ExtUserPtr.Name;
const senderEmail =
document.ExtUserPtr.Email;
const senderName = document.ExtUserPtr.Name;
const senderEmail = document.ExtUserPtr.Email;
if (document.SendinOrder) {
signerMail = signerMail.slice();
@@ -70,6 +62,7 @@ async function sendMail(document) {
'</body></html>';
const variables = {
document_title: document?.Name,
note: document?.Note || '',
sender_name: senderName,
sender_mail: senderEmail,
sender_phone: senderObj?.Phone || '',
@@ -83,6 +76,7 @@ async function sendMail(document) {
replaceVar = replaceMailVaribles(mailSubject, htmlReqBody, variables);
}
const mailparam = {
note: document?.Note || '',
senderName: senderName,
senderMail: senderEmail,
title: document.Name,
@@ -94,8 +88,7 @@ async function sendMail(document) {
extUserId: document.ExtUserPtr.objectId,
recipient: objectId ? existSigner?.Email : signerMail[i].email,
subject: replaceVar?.subject ? replaceVar?.subject : mailTemplate(mailparam).subject,
from:
document.ExtUserPtr.Email,
from: document.ExtUserPtr.Email,
replyto: senderEmail || '',
html: replaceVar?.body ? replaceVar?.body : mailTemplate(mailparam).body,
};
@@ -108,13 +101,7 @@ async function sendMail(document) {
}
}
}
async function batchQuery(
userId,
Documents,
Ip,
parseConfig,
type
) {
async function batchQuery(userId, Documents, Ip, parseConfig, type, publicUrl) {
const extCls = new Parse.Query('contracts_Users');
extCls.equalTo('UserId', {
__type: 'Pointer',
@@ -199,22 +186,22 @@ async function batchQuery(
};
});
// console.log('requests ', requests);
if (requests?.length > 0) {
const newrequests = [requests?.[0]];
const response = await axios.post('batch', { requests: newrequests }, parseConfig);
// Handle the batch query response
// console.log('Batch query response:', response.data);
if (response.data && response.data.length > 0) {
const document = Documents?.[0];
const updateDocuments = {
...document,
objectId: response.data[0]?.success?.objectId,
createdAt: response.data[0]?.success?.createdAt,
};
deductcount(response.data.length, resExt.id);
sendMail(updateDocuments); //sessionToken
return 'success';
}
if (requests?.length > 0) {
const newrequests = [requests?.[0]];
const response = await axios.post('batch', { requests: newrequests }, parseConfig);
// Handle the batch query response
// console.log('Batch query response:', response.data);
if (response.data && response.data.length > 0) {
const document = Documents?.[0];
const updateDocuments = {
...document,
objectId: response.data[0]?.success?.objectId,
createdAt: response.data[0]?.success?.createdAt,
};
deductcount(response.data.length, resExt.id);
sendMail(updateDocuments, publicUrl); //sessionToken
return 'success';
}
}
} catch (error) {
const code = error?.response?.data?.code || error?.response?.status || error?.code || 400;
@@ -236,6 +223,8 @@ export default async function createBatchDocs(request) {
const type = request.headers?.type || 'quicksend';
const Documents = JSON.parse(strDocuments);
const Ip = request?.headers?.['x-real-ip'] || '';
// Access the host from the headers
const publicUrl = request.headers.public_url;
const parseConfig = {
baseURL: serverUrl,
headers: {
@@ -246,9 +235,8 @@ export default async function createBatchDocs(request) {
};
try {
if (request?.user) {
return await batchQuery(request.user.id, Documents, Ip, parseConfig, '', type);
}
else {
return await batchQuery(request.user.id, Documents, Ip, parseConfig, '', type, publicUrl);
} else {
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
}
} catch (err) {
@@ -15,7 +15,7 @@ export default async function editContact(request) {
const query = new Parse.Query('contracts_Contactbook');
query.equalTo('CreatedBy', createdBy);
query.notEqualTo('IsDeleted', true);
query.equalTo('Email', email);
query.equalTo('Email', email?.toLowerCase()?.replace(/\s/g, ''));
const isContactExist = await query.first({ useMasterKey: true });
if (isContactExist) {
throw new Parse.Error(Parse.Error.DUPLICATE_VALUE, 'Contact already exists.');
@@ -25,7 +25,7 @@ export default async function editContact(request) {
if (phone) {
contactQuery.set('Phone', phone);
}
contactQuery.set('Email', email);
contactQuery.set('Email', email?.toLowerCase()?.replace(/\s/g, ''));
contactQuery.set('UserRole', 'contracts_Guest');
contactQuery.set('IsDeleted', false);
contactQuery.set('TenantId', {
@@ -37,9 +37,9 @@ export default async function editContact(request) {
const _users = Parse.Object.extend('User');
const _user = new _users();
_user.set('name', name);
_user.set('username', email);
_user.set('email', email);
_user.set('password', email);
_user.set('username', email?.toLowerCase()?.replace(/\s/g, ''));
_user.set('email', email?.toLowerCase()?.replace(/\s/g, ''));
_user.set('password', email?.toLowerCase()?.replace(/\s/g, ''));
if (phone) {
_user.set('phone', phone);
}
@@ -52,7 +52,8 @@ const saveRoleContact = async contact => {
// `linkContactToDoc` cloud function is used to create contact, add this contact in contracts_Guest role and
// save contact pointer in placeholder, signers and ACL of Document
export default async function linkContactToDoc(req) {
const email = req.params.email;
const requestemail = req.params?.email;
const email = requestemail?.toLowerCase()?.replace(/\s/g, '');
const docId = req.params.docId;
const name = req.params.name;
const phone = req.params.phone;
@@ -19,9 +19,6 @@ const APPID = process.env.APP_ID;
const masterKEY = process.env.MASTER_KEY;
const eSignName = 'OpenSign';
const eSigncontact = 'hello@opensignlabs.com';
const logo =
"<img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' style='padding:20px'/>";
const opurl = ` <a href=www.opensignlabs.com target=_blank>here</a>`;
// `updateDoc` is used to create url in from pdfFile
async function uploadFile(pdfName, filepath) {
@@ -93,8 +90,12 @@ async function updateDoc(docId, url, userId, ipAddress, data, className, sign) {
}
// `sendNotifyMail` is used to send notification mail of signer signed the document
async function sendNotifyMail(doc, signUser, mailProvider) {
async function sendNotifyMail(doc, signUser, mailProvider, publicUrl) {
try {
const TenantAppName = appName;
const logo =
"<img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' style='padding:20px'/>";
const opurl = ` <a href=www.opensignlabs.com target=_blank>here</a>`;
const auditTrailCount = doc?.AuditTrail?.filter(x => x.Activity === 'Signed')?.length || 0;
const signersCount = doc?.Placeholders?.length;
const remaingsign = signersCount - auditTrailCount;
@@ -105,18 +106,18 @@ async function sendNotifyMail(doc, signUser, mailProvider) {
const creatorEmail = doc.ExtUserPtr.Email;
const signerName = signUser.Name;
const signerEmail = signUser.Email;
const viewDocUrl = `${process.env.PUBLIC_URL}/recipientSignPdf/${doc.objectId}`;
const viewDocUrl = `${publicUrl}/recipientSignPdf/${doc.objectId}`; // ` ${process.env.PUBLIC_URL}/recipientSignPdf/${doc.objectId}`;
const subject = `Document "${pdfName}" has been signed by ${signerName}`;
const body =
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'/></head><body><div style='background-color:#f5f5f5;padding:20px'><div style='background-color:white'>" +
`<div>${logo}</div><div style='padding:2px;font-family:system-ui;background-color:#47a3ad'><p style='font-size:20px;font-weight:400;color:white;padding-left:20px'>Document signed by ${signerName}</p>` +
`</div><div style='padding:20px;font-family:system-ui;font-size:14px'><p>Dear ${creatorName},</p><p>${pdfName} has been signed by ${signerName} "${signerEmail}" successfully</p>` +
`<p><a href=${viewDocUrl} target=_blank>View Document</a></p></div></div><div><p>This is an automated email from ${appName}. For any queries regarding this email, ` +
`please contact the sender ${creatorEmail} directly. If you think this email is inappropriate or spam, you may file a complaint with ${appName}${opurl}.</p></div></div></body></html>`;
`<p><a href=${viewDocUrl} target=_blank>View Document</a></p></div></div><div><p>This is an automated email from ${TenantAppName}. For any queries regarding this email, ` +
`please contact the sender ${creatorEmail} directly. If you think this email is inappropriate or spam, you may file a complaint with ${TenantAppName}${opurl}.</p></div></div></body></html>`;
const params = {
extUserId: sender.objectId,
from: appName,
from: TenantAppName,
recipient: creatorEmail,
subject: subject,
pdfName: pdfName,
@@ -142,6 +143,10 @@ async function sendCompletedMail(obj) {
const doc = obj.doc;
const sender = obj.doc.ExtUserPtr;
const pdfName = doc.Name;
const TenantAppName = appName;
const logo =
"<img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' style='padding:20px'/>";
const opurl = ` <a href=www.opensignlabs.com target=_blank>here</a>`;
let signersMail;
if (doc?.Signers?.length > 0) {
const isOwnerExistsinSigners = doc?.Signers?.find(x => x.Email === sender.Email);
@@ -157,8 +162,8 @@ async function sendCompletedMail(obj) {
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body><div style='background-color:#f5f5f5;padding:20px'><div style='background-color:white'>" +
`<div>${logo}</div><div style='padding:2px;font-family:system-ui;background-color:#47a3ad'><p style='font-size:20px;font-weight:400;color:white;padding-left:20px'>Document signed successfully</p></div><div>` +
`<p style='padding:20px;font-family:system-ui;font-size:14px'>All parties have successfully signed the document <b>"${pdfName}"</b>. Kindly download the document from the attachment.</p>` +
`</div></div><div><p>This is an automated email from ${appName}. For any queries regarding this email, please contact the sender ${sender.Email} directly.` +
`If you think this email is inappropriate or spam, you may file a complaint with ${appName}${opurl}.</p></div></div></body></html>`;
`</div></div><div><p>This is an automated email from ${TenantAppName}. For any queries regarding this email, please contact the sender ${sender.Email} directly.` +
`If you think this email is inappropriate or spam, you may file a complaint with ${TenantAppName}${opurl}.</p></div></div></body></html>`;
if (obj?.isCustomMail) {
const tenant = sender?.TenantId;
@@ -175,7 +180,7 @@ async function sendCompletedMail(obj) {
className: '_User',
objectId: userId,
});
const tenantRes = await tenantQuery.first();
const tenantRes = await tenantQuery.first({ useMasterKey: true });
if (tenantRes) {
const _tenantRes = JSON.parse(JSON.stringify(tenantRes));
subject = _tenantRes?.CompletionSubject || '';
@@ -214,7 +219,7 @@ async function sendCompletedMail(obj) {
const params = {
extUserId: sender.objectId,
url: url,
from: appName,
from: TenantAppName,
replyto: doc?.ExtUserPtr?.Email || '',
recipient: recipient,
subject: subject,
@@ -301,6 +306,7 @@ async function PDF(req) {
const isCustomMail = req.params.isCustomCompletionMail || false;
const mailProvider = req.params.mailProvider || '';
const sign = req.params.signature || '';
const publicUrl = req.headers.public_url;
// below bode is used to get info of docId
const docQuery = new Parse.Query('contracts_Document');
docQuery.include('ExtUserPtr,Signers,ExtUserPtr.TenantId,Bcc');
@@ -426,7 +432,7 @@ async function PDF(req) {
className, // className based on flow
sign // sign base64
);
sendNotifyMail(_resDoc, signUser, mailProvider);
sendNotifyMail(_resDoc, signUser, mailProvider, publicUrl);
saveFileUsage(pdfSize, data.imageUrl, _resDoc?.CreatedBy?.objectId);
if (updatedDoc && updatedDoc.isCompleted) {
const doc = { ..._resDoc, AuditTrail: updatedDoc.AuditTrail, SignedUrl: data.imageUrl };
@@ -0,0 +1,87 @@
const randomId = () => Math.floor(1000 + Math.random() * 9000);
export default async function saveAsTemplate(request) {
const docId = request.params.docId;
const Ip = request?.headers?.['x-real-ip'] || '';
if (!request.user) {
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'user is not authenticated.');
}
try {
const docQuery = new Parse.Query('contracts_Document');
docQuery.equalTo('objectId', docId);
docQuery.equalTo('CreatedBy', request.user);
docQuery.include('ExtUserPtr');
docQuery.include('ExtUserPtr.TenantId');
docQuery.notEqualTo('IsArchive', true);
const docRes = await docQuery.first({ useMasterKey: true });
if (docRes) {
const _docRes = docRes?.toJSON();
const templateCls = new Parse.Object('contracts_Template');
templateCls.set('URL', _docRes?.URL);
templateCls.set('Name', _docRes?.Name);
templateCls.set('Note', _docRes?.Note);
templateCls.set('Description', _docRes?.Description);
templateCls.set('OriginIp', Ip);
templateCls.set('SendinOrder', _docRes?.SendinOrder || false);
templateCls.set('AutomaticReminders', _docRes?.AutomaticReminders || false);
templateCls.set('ExtUserPtr', _docRes?.ExtUserPtr);
templateCls.set('CreatedBy', _docRes?.CreatedBy);
templateCls.set('IsEnableOTP', _docRes?.IsEnableOTP === true ? true : false);
templateCls.set('IsTourEnabled', _docRes?.IsTourEnabled === true ? true : false);
templateCls.set('AllowModifications', _docRes?.AllowModifications || false);
templateCls.set('EmailSenderName', _docRes?.EmailSenderName);
templateCls.set('SenderName', _docRes?.SenderName);
templateCls.set('SenderMail', _docRes?.SenderMail);
templateCls.set('FileAdapterId', _docRes?.FileAdapterId);
templateCls.set('RequestBody', _docRes?.RequestBody);
templateCls.set('RequestSubject', _docRes?.RequestSubject);
templateCls.set('NextReminderDate', _docRes?.NextReminderDate);
templateCls.set('RedirectUrl', _docRes?.RedirectUrl);
templateCls.set(
'NotifyOnSignatures',
_docRes?.NotifyOnSignatures !== undefined ? _docRes?.NotifyOnSignatures : false
);
templateCls.set(
'TimeToCompleteDays',
_docRes?.TimeToCompleteDays ? parseInt(_docRes?.TimeToCompleteDays) : 15
);
if (_docRes?.RemindOnceInEvery) {
templateCls.set('RemindOnceInEvery', parseInt(_docRes?.RemindOnceInEvery));
}
if (_docRes?.Placeholders?.length > 0) {
if (_docRes?.IsSignyourself) {
const placeHolders = {
signerObjId: '',
signerPtr: {},
Id: randomId(),
blockColor: '#93a3db',
Role: 'Role 1',
email: '',
placeHolder: _docRes?.Placeholders,
};
templateCls.set('Placeholders', [placeHolders]);
} else {
const placeHolders = _docRes?.Placeholders?.map((x, i) => {
const email = x.email ? { email: '' } : {};
return { ...x, signerObjId: '', signerPtr: {}, Role: 'Role ' + (i + 1), ...email };
});
templateCls.set('Placeholders', placeHolders);
}
}
if (_docRes?.SignatureType?.length > 0) {
templateCls.set('SignatureType', _docRes?.SignatureType);
}
if (_docRes?.Bcc?.length > 0) {
templateCls.set('Bcc', _docRes?.Bcc);
}
const res = await templateCls.save(null, { useMasterKey: true });
return res;
} else {
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'document not found.');
}
} catch (err) {
console.log('Err in save as template', err);
throw err;
}
}
@@ -1,7 +1,8 @@
export default async function savecontact(request) {
const name = request.params.name;
const phone = request.params.phone;
const email = request.params.email;
const requestemail = request.params?.email;
const email = requestemail?.toLowerCase()?.replace(/\s/g, '');
const tenantId = request.params.tenantId;
if (request.user) {
@@ -0,0 +1,27 @@
export default async function updateTenant(request) {
const { tenantId, details } = request.params;
if (!tenantId || !details) {
throw new Parse.Error(400, 'Missing tenantId or details.');
}
if (!request.user) {
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'unauthorized');
}
try {
const tenant = new Parse.Object('partners_Tenant');
tenant.id = tenantId;
// Update tenant details
Object.keys(details).forEach(key => {
tenant.set(key, details?.[key]);
});
const tenantRes = await tenant.save(null, { useMasterKey: true });
if (tenantRes) {
const res = JSON.parse(JSON.stringify(tenantRes));
return res;
}
} catch (error) {
throw error;
}
}
@@ -1,7 +1,5 @@
import axios from 'axios';
import {
cloudServerUrl,
} from '../../Utils.js';
import { cloudServerUrl } from '../../Utils.js';
const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
const APPID = process.env.APP_ID;
const masterKEY = process.env.MASTER_KEY;
@@ -32,7 +30,7 @@ async function saveUser(userDetails) {
const user = new Parse.User();
user.set('username', userDetails.email);
user.set('password', userDetails.password);
user.set('email', userDetails.email);
user.set('email', userDetails?.email?.toLowerCase()?.replace(/\s/g, ''));
if (userDetails?.phone) {
user.set('phone', userDetails.phone);
}
@@ -73,7 +71,7 @@ export default async function usersignup(request) {
partnerQuery.set('ContactNumber', userDetails.phone);
}
partnerQuery.set('TenantName', userDetails.company);
partnerQuery.set('EmailAddress', userDetails.email);
partnerQuery.set('EmailAddress', userDetails?.email?.toLowerCase()?.replace(/\s/g, ''));
partnerQuery.set('IsActive', true);
partnerQuery.set('CreatedBy', {
__type: 'Pointer',
@@ -105,7 +103,7 @@ export default async function usersignup(request) {
objectId: user.id,
});
newObj.set('UserRole', userDetails.role);
newObj.set('Email', userDetails.email);
newObj.set('Email', userDetails?.email?.toLowerCase()?.replace(/\s/g, ''));
newObj.set('Name', userDetails.name);
if (userDetails?.phone) {
newObj.set('Phone', userDetails?.phone);
@@ -131,4 +129,3 @@ export default async function usersignup(request) {
console.log('Err ', err);
}
}
+2
View File
@@ -160,6 +160,8 @@ app.use(express.json({ limit: '50mb' }));
app.use(express.urlencoded({ limit: '50mb', extended: true }));
app.use(function (req, res, next) {
req.headers['x-real-ip'] = getUserIP(req);
const publicUrl = req.protocol + '://' + req.get('host');
req.headers['public_url'] = publicUrl; // process.env.PUBLIC_URL
next();
});
function getUserIP(request) {