diff --git a/apps/OpenSign/.husky/pre-commit b/apps/OpenSign/.husky/pre-commit old mode 100755 new mode 100644 diff --git a/apps/OpenSign/Dockerhubfile b/apps/OpenSign/Dockerhubfile index 98c41aef3..d47079973 100644 --- a/apps/OpenSign/Dockerhubfile +++ b/apps/OpenSign/Dockerhubfile @@ -14,14 +14,15 @@ RUN npm install COPY apps/OpenSign/ . COPY apps/OpenSign/.husky . +# Define environment variables if needed +ENV NODE_ENV=production +ENV REACT_APP_DEPLOYMENT=free_selfhost + # build RUN npm run build # Make port 3000 available to the world outside this container EXPOSE 3000 -# Define environment variables if needed -# ENV NODE_ENV production - # Run the application CMD ["npm", "start"] diff --git a/apps/OpenSign/package-lock.json b/apps/OpenSign/package-lock.json index 252d731ea..eaa82e276 100644 --- a/apps/OpenSign/package-lock.json +++ b/apps/OpenSign/package-lock.json @@ -9,16 +9,16 @@ "version": "0.1.0", "dependencies": { "@formkit/auto-animate": "^0.8.2", - "@lottiefiles/dotlottie-react": "^0.10.0", + "@lottiefiles/dotlottie-react": "^0.12.3", "@pdf-lib/fontkit": "^1.1.1", "@radix-ui/themes": "^3.1.6", - "@react-pdf/renderer": "^4.1.4", - "@reduxjs/toolkit": "^2.3.0", - "axios": "^1.7.7", + "@react-pdf/renderer": "^4.1.6", + "@reduxjs/toolkit": "^2.5.1", + "axios": "^1.7.9", "file-saver": "^2.0.5", - "i18next": "^23.16.5", - "i18next-browser-languagedetector": "^8.0.0", - "i18next-http-backend": "^2.6.2", + "i18next": "^23.16.8", + "i18next-browser-languagedetector": "^8.0.2", + "i18next-http-backend": "^3.0.1", "jszip": "^3.10.1", "jwt-decode": "^4.0.0", "moment": "^2.30.1", @@ -28,29 +28,30 @@ "print-js": "^1.6.0", "radix-ui": "^1.0.1", "react": "^18.2.0", - "react-bootstrap": "^2.10.5", - "react-confetti": "^6.1.0", + "react-bootstrap": "^2.10.9", + "react-confetti": "^6.2.2", "react-cookie": "^7.2.2", - "react-datepicker": "^7.5.0", + "react-datepicker": "^7.6.0", "react-dnd": "^16.0.1", "react-dnd-html5-backend": "^16.0.1", - "react-dnd-multi-backend": "^8.0.3", + "react-dnd-multi-backend": "^9.0.0", "react-dnd-touch-backend": "^16.0.1", "react-dom": "^18.2.0", "react-gtm-module": "^2.0.11", "react-helmet": "^6.1.0", - "react-i18next": "^15.1.1", + "react-i18next": "^15.4.0", "react-konva": "^18.2.10", - "react-pdf": "^9.1.1", + "react-pdf": "^9.2.1", "react-quill-new": "^3.3.3", - "react-redux": "^9.1.2", - "react-rnd": "^10.4.13", - "react-router-dom": "^6.28.0", + "react-redux": "^9.2.0", + "react-rnd": "^10.4.14", + "react-router": "^7.1.5", "react-scripts": "5.0.1", "react-scrollbars-custom": "^4.1.1", - "react-select": "^5.8.3", - "react-signature-canvas": "^1.0.6", + "react-select": "^5.10.0", + "react-signature-canvas": "^1.0.7", "react-syntax-highlighter": "^15.6.1", + "react-timezone-select": "^3.2.8", "react-tooltip": "^5.28.0", "react-web-share": "^2.0.2", "reactour": "^1.19.4", @@ -60,32 +61,33 @@ "serve": "^14.2.4", "styled-components": "^5.3.0", "web-vitals": "^4.2.4", - "ws": "^8.18.0" + "ws": "^8.18.0", + "xlsx": "^0.18.5" }, "devDependencies": { - "@babel/core": "^7.26.0", - "@babel/preset-env": "^7.26.0", - "@babel/preset-react": "^7.25.9", - "@babel/runtime-corejs2": "^7.26.0", + "@babel/core": "^7.26.8", + "@babel/preset-env": "^7.26.8", + "@babel/preset-react": "^7.26.3", + "@babel/runtime-corejs2": "^7.26.7", "autoprefixer": "^10.4.20", "babel-loader": "^9.2.1", "clean-webpack-plugin": "^4.0.0", "commitizen": "^4.3.1", - "concurrently": "^9.1.0", + "concurrently": "^9.1.2", "css-loader": "^7.1.2", - "daisyui": "^4.12.14", - "dotenv": "^16.4.5", + "daisyui": "^4.12.23", + "dotenv": "^16.4.7", "dotenv-webpack": "^8.1.0", - "eslint": "^9.14.0", - "eslint-plugin-prettier": "^5.2.1", - "eslint-plugin-react": "^7.37.2", - "lint-staged": "^15.2.10", + "eslint": "^9.20.0", + "eslint-plugin-prettier": "^5.2.3", + "eslint-plugin-react": "^7.37.4", + "lint-staged": "^15.4.3", "mini-css-extract-plugin": "^2.9.2", - "postcss": "^8.4.49", - "prettier": "^3.3.3", + "postcss": "^8.5.1", + "prettier": "^3.5.0", "pretty-quick": "^4.0.0", - "tailwindcss": "^3.4.15", - "terser-webpack-plugin": "^5.3.10", + "tailwindcss": "^3.4.17", + "terser-webpack-plugin": "^5.3.11", "webpack-cli": "^5.1.4" }, "engines": { @@ -145,28 +147,31 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.2.tgz", - "integrity": "sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==", + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz", + "integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", - "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.8.tgz", + "integrity": "sha512-l+lkXCHS6tQEc5oUpK28xBOZ6+HwaH7YwoYQbLFiYb4nS2/l1tKnZEtEWkD0GuiYdvArf9qBS0XlQGXzPMsNqQ==", + "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.26.0", - "@babel/generator": "^7.26.0", - "@babel/helper-compilation-targets": "^7.25.9", + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.8", + "@babel/helper-compilation-targets": "^7.26.5", "@babel/helper-module-transforms": "^7.26.0", - "@babel/helpers": "^7.26.0", - "@babel/parser": "^7.26.0", - "@babel/template": "^7.25.9", - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.26.0", + "@babel/helpers": "^7.26.7", + "@babel/parser": "^7.26.8", + "@babel/template": "^7.26.8", + "@babel/traverse": "^7.26.8", + "@babel/types": "^7.26.8", + "@types/gensync": "^1.0.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -207,12 +212,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.2.tgz", - "integrity": "sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==", + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.8.tgz", + "integrity": "sha512-ef383X5++iZHWAXX0SXQR6ZyQhw/0KtTkrTz61WXRhFM6dhpHulO/RJz79L8S6ugZHJkOOkUrUdxgdF2YiPFnA==", + "license": "MIT", "dependencies": { - "@babel/parser": "^7.26.2", - "@babel/types": "^7.26.0", + "@babel/parser": "^7.26.8", + "@babel/types": "^7.26.8", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" @@ -232,24 +238,12 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.25.9.tgz", - "integrity": "sha512-C47lC7LIDCnz0h4vai/tpNOI95tCd5ZT3iBt/DBH5lXKHZsyNQv18yf1wIIg2ntiQNgmAvA+DgZ82iW8Qdym8g==", - "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", - "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz", + "integrity": "sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==", "dependencies": { - "@babel/compat-data": "^7.25.9", + "@babel/compat-data": "^7.26.5", "@babel/helper-validator-option": "^7.25.9", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", @@ -296,9 +290,10 @@ } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", - "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.3.tgz", + "integrity": "sha512-HK7Bi+Hj6H+VTHA3ZvBis7V/6hu9QuTrnMXNybfUf2iiuU/N97I8VjB+KbhFF8Rld/Lx5MzoCwPCpPjfK+n8Cg==", + "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", "@babel/helper-plugin-utils": "^7.22.5", @@ -362,9 +357,9 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", - "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", + "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==", "engines": { "node": ">=6.9.0" } @@ -401,18 +396,6 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-simple-access": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.9.tgz", - "integrity": "sha512-c6WHXuiaRsJTyHYLJV75t9IqsmTbItYfdj99PnzYGQZkYKvan5/2jKJ7gu31J3/BJ/A18grImSPModuyG/Eo0Q==", - "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", @@ -463,23 +446,24 @@ } }, "node_modules/@babel/helpers": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", - "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", + "version": "7.26.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.7.tgz", + "integrity": "sha512-8NHiL98vsi0mbPQmYAGWwfcFaOy4j2HY49fXJCfuDcdE7fMIsH9a7GdaeXpIBsbT7307WU8KCMp5pUVDNL4f9A==", "dependencies": { "@babel/template": "^7.25.9", - "@babel/types": "^7.26.0" + "@babel/types": "^7.26.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.2.tgz", - "integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==", + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.8.tgz", + "integrity": "sha512-TZIQ25pkSoaKEYYaHbbxkfL36GNsQ6iFiBbeuzAkLnXayKR1yP1zFe+NxuZWWsUyvt8icPU9CCq0sgWGXR1GEw==", + "license": "MIT", "dependencies": { - "@babel/types": "^7.26.0" + "@babel/types": "^7.26.8" }, "bin": { "parser": "bin/babel-parser.js" @@ -947,13 +931,14 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.9.tgz", - "integrity": "sha512-RXV6QAzTBbhDMO9fWwOmwwTuYaiPbggWQ9INdZqAYeSHyG7FzQ+nOZaUUjNwKv9pV3aE4WFqFm1Hnbci5tBCAw==", + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.26.8.tgz", + "integrity": "sha512-He9Ej2X7tNf2zdKMAGOsmg2MrFc+hfoAhd3po4cWfo/NWjzEAKa0oQruj1ROVUdl0e6fb6/kE/G3SSxE0lRJOg==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-plugin-utils": "^7.26.5", "@babel/helper-remap-async-to-generator": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/traverse": "^7.26.8" }, "engines": { "node": ">=6.9.0" @@ -979,11 +964,11 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.25.9.tgz", - "integrity": "sha512-toHc9fzab0ZfenFpsyYinOX0J/5dgJVA2fm64xPewu7CoYHWEivIWKxkK2rMi4r3yQqLnVmheMXRdG+k239CgA==", + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.26.5.tgz", + "integrity": "sha512-chuTSY+hq09+/f5lMj8ZSYgCFpppV2CbYrhNFJ1BFoXpiWPnnAb7R0MqrafCpN8E1+YRrtM1MXZHJdIx8B6rMQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.26.5" }, "engines": { "node": ">=6.9.0" @@ -1143,11 +1128,10 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.25.9.tgz", - "integrity": "sha512-KRhdhlVk2nObA5AYa7QMgTMTVJdfHprfpAk4DjZVtllqRg9qarilstTKEhpVjyt+Npi8ThRyiV8176Am3CodPA==", + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.26.3.tgz", + "integrity": "sha512-7CAHcQ58z2chuXPWblnn1K6rLDnDWieghSOEmqQsrBenH0P9InCUtOJYD89pvngljmZlJcz3fcmgYsXFNGa1ZQ==", "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { @@ -1289,13 +1273,12 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.25.9.tgz", - "integrity": "sha512-dwh2Ol1jWwL2MgkCzUSOvfmKElqQcuswAZypBSUsScMXvgdT8Ekq5YA6TtqpTVWH+4903NmboMuH1o9i8Rxlyg==", + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz", + "integrity": "sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==", "dependencies": { - "@babel/helper-module-transforms": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-simple-access": "^7.25.9" + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1366,11 +1349,11 @@ } }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.25.9.tgz", - "integrity": "sha512-ENfftpLZw5EItALAD4WsY/KUWvhUlZndm5GC7G3evUsVeSJB6p0pBeLQUnRnBCBx7zV0RKQjR9kCuwrsIrjWog==", + "version": "7.26.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.26.6.tgz", + "integrity": "sha512-CKW8Vu+uUZneQCPtXmSBUC6NCAUdya26hWCElAWh5mVSlSRsmiCPUUDKb3Z0szng1hiAJa098Hkhg9o4SE35Qw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.26.5" }, "engines": { "node": ">=6.9.0" @@ -1694,11 +1677,12 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.9.tgz", - "integrity": "sha512-o97AE4syN71M/lxrCtQByzphAdlYluKPDBzDVzMmfCobUjjhAryZV0AIpRPrxN0eAkxXO6ZLEScmt+PNhj2OTw==", + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.26.8.tgz", + "integrity": "sha512-OmGDL5/J0CJPJZTHZbi2XpO0tyT2Ia7fzpW5GURwdtp2X3fMmN8au/ej6peC/T33/+CRiIpA8Krse8hFGVmT5Q==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.26.5" }, "engines": { "node": ">=6.9.0" @@ -1708,11 +1692,11 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.25.9.tgz", - "integrity": "sha512-v61XqUMiueJROUv66BVIOi0Fv/CUuZuZMl5NkRoCVxLAnMexZ0A3kMe7vvZ0nulxMuMp0Mk6S5hNh48yki08ZA==", + "version": "7.26.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.26.7.tgz", + "integrity": "sha512-jfoTXXZTgGg36BmhqT3cAYK5qkmqvJpvNrPhaK/52Vgjhw4Rq29s9UqpWWV0D6yuRmgiFH/BUVlkl96zJWqnaw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.26.5" }, "engines": { "node": ">=6.9.0" @@ -1799,13 +1783,14 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.0.tgz", - "integrity": "sha512-H84Fxq0CQJNdPFT2DrfnylZ3cf5K43rGfWK4LJGPpjKHiZlk0/RzwEus3PDDZZg+/Er7lCA03MVacueUuXdzfw==", + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.8.tgz", + "integrity": "sha512-um7Sy+2THd697S4zJEfv/U5MHGJzkN2xhtsR3T/SWRbVSic62nbISh51VVfU9JiO/L/Z97QczHTaFVkOU8IzNg==", + "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.26.0", - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", + "@babel/compat-data": "^7.26.8", + "@babel/helper-compilation-targets": "^7.26.5", + "@babel/helper-plugin-utils": "^7.26.5", "@babel/helper-validator-option": "^7.25.9", "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.9", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.9", @@ -1817,9 +1802,9 @@ "@babel/plugin-syntax-import-attributes": "^7.26.0", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.25.9", - "@babel/plugin-transform-async-generator-functions": "^7.25.9", + "@babel/plugin-transform-async-generator-functions": "^7.26.8", "@babel/plugin-transform-async-to-generator": "^7.25.9", - "@babel/plugin-transform-block-scoped-functions": "^7.25.9", + "@babel/plugin-transform-block-scoped-functions": "^7.26.5", "@babel/plugin-transform-block-scoping": "^7.25.9", "@babel/plugin-transform-class-properties": "^7.25.9", "@babel/plugin-transform-class-static-block": "^7.26.0", @@ -1830,7 +1815,7 @@ "@babel/plugin-transform-duplicate-keys": "^7.25.9", "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.9", "@babel/plugin-transform-dynamic-import": "^7.25.9", - "@babel/plugin-transform-exponentiation-operator": "^7.25.9", + "@babel/plugin-transform-exponentiation-operator": "^7.26.3", "@babel/plugin-transform-export-namespace-from": "^7.25.9", "@babel/plugin-transform-for-of": "^7.25.9", "@babel/plugin-transform-function-name": "^7.25.9", @@ -1839,12 +1824,12 @@ "@babel/plugin-transform-logical-assignment-operators": "^7.25.9", "@babel/plugin-transform-member-expression-literals": "^7.25.9", "@babel/plugin-transform-modules-amd": "^7.25.9", - "@babel/plugin-transform-modules-commonjs": "^7.25.9", + "@babel/plugin-transform-modules-commonjs": "^7.26.3", "@babel/plugin-transform-modules-systemjs": "^7.25.9", "@babel/plugin-transform-modules-umd": "^7.25.9", "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.9", "@babel/plugin-transform-new-target": "^7.25.9", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.25.9", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.26.6", "@babel/plugin-transform-numeric-separator": "^7.25.9", "@babel/plugin-transform-object-rest-spread": "^7.25.9", "@babel/plugin-transform-object-super": "^7.25.9", @@ -1860,17 +1845,17 @@ "@babel/plugin-transform-shorthand-properties": "^7.25.9", "@babel/plugin-transform-spread": "^7.25.9", "@babel/plugin-transform-sticky-regex": "^7.25.9", - "@babel/plugin-transform-template-literals": "^7.25.9", - "@babel/plugin-transform-typeof-symbol": "^7.25.9", + "@babel/plugin-transform-template-literals": "^7.26.8", + "@babel/plugin-transform-typeof-symbol": "^7.26.7", "@babel/plugin-transform-unicode-escapes": "^7.25.9", "@babel/plugin-transform-unicode-property-regex": "^7.25.9", "@babel/plugin-transform-unicode-regex": "^7.25.9", "@babel/plugin-transform-unicode-sets-regex": "^7.25.9", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.10", - "babel-plugin-polyfill-corejs3": "^0.10.6", + "babel-plugin-polyfill-corejs3": "^0.11.0", "babel-plugin-polyfill-regenerator": "^0.6.1", - "core-js-compat": "^3.38.1", + "core-js-compat": "^3.40.0", "semver": "^6.3.1" }, "engines": { @@ -1880,6 +1865,19 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/preset-env/node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.11.1.tgz", + "integrity": "sha512-yGCqvBT4rwMczo28xkH/noxJ6MZ4nJfkVYdoDaC/utLtWrXxv27HVrzAeSbqR8SxDsp46n0YF47EbHoixy6rXQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.3", + "core-js-compat": "^3.40.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, "node_modules/@babel/preset-modules": { "version": "0.1.6-no-external-plugins", "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", @@ -1894,9 +1892,9 @@ } }, "node_modules/@babel/preset-react": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.25.9.tgz", - "integrity": "sha512-D3to0uSPiWE7rBrdIICCd0tJSIGpLaaGptna2+w7Pft5xMqLpA1sz99DK5TZ1TjGbdQ/VI1eCSZ06dv3lT4JOw==", + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.26.3.tgz", + "integrity": "sha512-Nl03d6T9ky516DGK2YMxrTqvnpUW63TnJMOMonj+Zae0JiPC5BC9xPMSL6L8fiSpA5vP88qfygavVQvnLp+6Cw==", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-validator-option": "^7.25.9", @@ -1931,9 +1929,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.6.tgz", - "integrity": "sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", + "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -1942,9 +1940,9 @@ } }, "node_modules/@babel/runtime-corejs2": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs2/-/runtime-corejs2-7.26.0.tgz", - "integrity": "sha512-AQKSxUdaM7uTEGFmLZj1LOgX3LaLdt4udjqywaVdN6R5P2KAgqtBkDW4TS2ySRYNqcKmEe8Xv96jegHJNNb7Gg==", + "version": "7.26.7", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs2/-/runtime-corejs2-7.26.7.tgz", + "integrity": "sha512-C7fo97gUfsUP54j6GcQ+rJXyW6vgRRqF7J1ZxXesWcQtSRyzH1+eYrqFGzmU2JSUGFV0hQA2zLY/Z8AMrEx0qg==", "dev": true, "dependencies": { "core-js": "^2.6.12", @@ -1967,28 +1965,30 @@ } }, "node_modules/@babel/template": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", - "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.8.tgz", + "integrity": "sha512-iNKaX3ZebKIsCvJ+0jd6embf+Aulaa3vNBqZ41kM7iTWjx5qzWKXGHiJUW3+nTpQ18SG11hdF8OAzKrpXkb96Q==", + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.25.9", - "@babel/parser": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/code-frame": "^7.26.2", + "@babel/parser": "^7.26.8", + "@babel/types": "^7.26.8" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz", - "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.8.tgz", + "integrity": "sha512-nic9tRkjYH0oB2dzr/JoGIm+4Q6SuYeLEiIiZDwBscRMYFJ+tMAz98fuel9ZnbXViA2I0HVSSRRK8DW5fjXStA==", + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.25.9", - "@babel/generator": "^7.25.9", - "@babel/parser": "^7.25.9", - "@babel/template": "^7.25.9", - "@babel/types": "^7.25.9", + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.8", + "@babel/parser": "^7.26.8", + "@babel/template": "^7.26.8", + "@babel/types": "^7.26.8", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -1997,9 +1997,10 @@ } }, "node_modules/@babel/types": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz", - "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.8.tgz", + "integrity": "sha512-eUuWapzEGWFEpHFxgEaBG8e3n6S8L3MSu0oda755rOfabWPnh0Our1AozNFVUxGFIhbKgd1ksprsoDGMinTOTA==", + "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9" @@ -2570,9 +2571,9 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", - "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.0.tgz", + "integrity": "sha512-zdHg2FPIFNKPdcHWtiNT+jEFCHYVplAXRDlQDyqy0zGx/q2parwh7brGJSiTxRk/TSMkbM//zt/f5CHgyTyaSQ==", "dependencies": { "@eslint/object-schema": "^2.1.4", "debug": "^4.3.1", @@ -2583,17 +2584,20 @@ } }, "node_modules/@eslint/core": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.7.0.tgz", - "integrity": "sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.10.0.tgz", + "integrity": "sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw==", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/eslintrc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", - "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", + "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -2644,9 +2648,10 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "node_modules/@eslint/js": { - "version": "9.14.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.14.0.tgz", - "integrity": "sha512-pFoEtFWCPyDOl+C6Ift+wC7Ro89otjigCf5vcuWqWgqNSQbRrpjSvdeE6ofLz4dHmyxD5f7gIdGT4+p36L6Twg==", + "version": "9.20.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.20.0.tgz", + "integrity": "sha512-iZA07H9io9Wn836aVTytRaNqh00Sad+EamwOVJT12GTLw1VGMFV/4JaME+JjLtr9fiGaoWgYnS54wrfWsSs4oQ==", + "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } @@ -2660,10 +2665,11 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.3.tgz", - "integrity": "sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==", + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.5.tgz", + "integrity": "sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A==", "dependencies": { + "@eslint/core": "^0.10.0", "levn": "^0.4.1" }, "engines": { @@ -2688,17 +2694,18 @@ } }, "node_modules/@floating-ui/react": { - "version": "0.26.24", - "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.24.tgz", - "integrity": "sha512-2ly0pCkZIGEQUq5H8bBK0XJmc1xIK/RM3tvVzY3GBER7IOD1UgmC2Y2tjj4AuS+TC+vTE1KJv2053290jua0Sw==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.27.3.tgz", + "integrity": "sha512-CLHnes3ixIFFKVQDdICjel8muhFLOBdQH7fgtHNPY8UbCNqbeKZ262G7K66lGQOUQWWnYocf7ZbUsLJgGfsLHg==", + "license": "MIT", "dependencies": { "@floating-ui/react-dom": "^2.1.2", - "@floating-ui/utils": "^0.2.8", + "@floating-ui/utils": "^0.2.9", "tabbable": "^6.0.0" }, "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" + "react": ">=17.0.0", + "react-dom": ">=17.0.0" } }, "node_modules/@floating-ui/react-dom": { @@ -2714,9 +2721,10 @@ } }, "node_modules/@floating-ui/utils": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.8.tgz", - "integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==" + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.9.tgz", + "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==", + "license": "MIT" }, "node_modules/@formkit/auto-animate": { "version": "0.8.2", @@ -3649,29 +3657,27 @@ "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==" }, "node_modules/@lottiefiles/dotlottie-react": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/@lottiefiles/dotlottie-react/-/dotlottie-react-0.10.0.tgz", - "integrity": "sha512-krPJUIqpt7VluWc0aRWk0lYScCDSlbCpWvImU5eyJZeyroZ87bZYb+YlgUbtLHZ77DWmIBl4kGMhupU8+ugPSw==", - "license": "MIT", + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/@lottiefiles/dotlottie-react/-/dotlottie-react-0.12.3.tgz", + "integrity": "sha512-b0k0Lakj2hmhyIkwJSpKySh6xoelpgWRaijyrCb6fraOCnzuitKglVTtYs0VWf72rk+2aSmC/0IK8j8wruVfOw==", "dependencies": { - "@lottiefiles/dotlottie-web": "0.37.0" + "@lottiefiles/dotlottie-web": "0.40.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + "react": "^17 || ^18 || ^19" } }, "node_modules/@lottiefiles/dotlottie-web": { - "version": "0.37.0", - "resolved": "https://registry.npmjs.org/@lottiefiles/dotlottie-web/-/dotlottie-web-0.37.0.tgz", - "integrity": "sha512-dCtQkYlq9GDswJNmcIlUaAskxrsJ56SRhY8woNsHuIPWy+tfP9tgf1fA9fZ1Oj72DVdyYkK0DxLk58HhBrmpBQ==", - "license": "MIT" + "version": "0.40.1", + "resolved": "https://registry.npmjs.org/@lottiefiles/dotlottie-web/-/dotlottie-web-0.40.1.tgz", + "integrity": "sha512-iNz1rr8zRTSJ0xCZEPeoCX6YnaNhBdkF7gJWhSa8bwB4NTrYZm0vAuC0jF/aLLhU7q9nf6ykxffrz0Sf4JPSPg==" }, "node_modules/@mapbox/node-pre-gyp": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", "optional": true, + "peer": true, "dependencies": { "detect-libc": "^2.0.0", "https-proxy-agent": "^5.0.0", @@ -3693,6 +3699,7 @@ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "deprecated": "Rimraf versions prior to v4 are no longer supported", "optional": true, + "peer": true, "dependencies": { "glob": "^7.1.3" }, @@ -3708,6 +3715,7 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "optional": true, + "peer": true, "bin": { "semver": "bin/semver.js" }, @@ -3871,6 +3879,7 @@ "version": "2.11.8", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/popperjs" @@ -6044,9 +6053,10 @@ } }, "node_modules/@react-aria/ssr": { - "version": "3.9.5", - "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.5.tgz", - "integrity": "sha512-xEwGKoysu+oXulibNUSkXf8itW0npHHTa6c4AyYeZIJyRoegeteYuFpZUBPtIDE8RfHdNsSmE1ssOkxRnwbkuQ==", + "version": "3.9.7", + "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.7.tgz", + "integrity": "sha512-GQygZaGlmYjmYM+tiNBA5C6acmiDWF52Nqd40bBp0Znk4M4hP+LTmI0lpI1BuKMw45T8RIhrAsICIfKwZvi2Gg==", + "license": "Apache-2.0", "dependencies": { "@swc/helpers": "^0.5.0" }, @@ -6054,7 +6064,7 @@ "node": ">= 12" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "node_modules/@react-dnd/asap": { @@ -6102,17 +6112,17 @@ } }, "node_modules/@react-pdf/layout": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@react-pdf/layout/-/layout-4.1.2.tgz", - "integrity": "sha512-BG2MR1R0loFk+CVBLse15NRrTSaEc+0aK1isK9DnER30H5rYgbMDhFqqqr8g+YEqP04dhYkeCjhTWP172VPyNg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@react-pdf/layout/-/layout-4.2.0.tgz", + "integrity": "sha512-/0jMhDKwZH0lQs3umNsOduaPtkK0IUpaBRUEv4udHVD9lB2VzYoSNeYsCu+MJMPJyByXj70OSWV7IMjWTCKwWw==", "dependencies": { "@babel/runtime": "^7.20.13", "@react-pdf/fns": "3.0.0", "@react-pdf/image": "^3.0.1", "@react-pdf/pdfkit": "^4.0.0", "@react-pdf/primitives": "^4.0.0", - "@react-pdf/stylesheet": "^5.1.0", - "@react-pdf/textkit": "^5.0.0", + "@react-pdf/stylesheet": "^5.2.0", + "@react-pdf/textkit": "^5.0.1", "@react-pdf/types": "^2.7.0", "emoji-regex": "^10.3.0", "queue": "^6.0.1", @@ -6147,19 +6157,26 @@ "integrity": "sha512-yp4E0rDL03NaUp/CnDBz3HQNfH2Mzdlgku57yhTMGNzetwB0NJusXcjYg5XsTGIXnR7Tv80JKI4O4ajj+oaLeQ==" }, "node_modules/@react-pdf/reconciler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@react-pdf/reconciler/-/reconciler-1.1.2.tgz", - "integrity": "sha512-b4uGyT7pWtXe+F2m3cvySqNd4EAAaFknee/JKr00N/9QkNpL1s977oT5qtNPcnUmagsO0I0iH9zFAOcxHFyUNA==" + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@react-pdf/reconciler/-/reconciler-1.1.3.tgz", + "integrity": "sha512-4vqY0klmUH32kTFvuqdAszkOpwfZYKMLO4VpJ5xZWTsoUOLQSyhC2QM2QCj9eaxpB2Nd5Kl9uW+KfyutvZnMzQ==", + "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.0.1", - "resolved": "https://registry.npmjs.org/@react-pdf/render/-/render-4.0.1.tgz", - "integrity": "sha512-WkOjFh6e3lBxRJRiKobUzu9lmxoN5Ihn993cRj47Cy3SOTZmoumRGyjzZq9zMxekbLVvhhyGdanEI2LZoHvIaw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@react-pdf/render/-/render-4.0.2.tgz", + "integrity": "sha512-5QJB9sS0uU5ALTLxrtT073VT1imZhrzuOun+7kvo0nykeAr9I4lv0Shmy8rS4QhpmXn8ASmhd17WjCVm4DcJlw==", "dependencies": { "@babel/runtime": "^7.20.13", "@react-pdf/fns": "3.0.0", "@react-pdf/primitives": "^4.0.0", - "@react-pdf/textkit": "^5.0.0", + "@react-pdf/textkit": "^5.0.1", "@react-pdf/types": "^2.7.0", "abs-svg-path": "^0.1.1", "color-string": "^1.9.1", @@ -6169,17 +6186,17 @@ } }, "node_modules/@react-pdf/renderer": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@react-pdf/renderer/-/renderer-4.1.4.tgz", - "integrity": "sha512-bJZ+dVWO+nZ028PCA8K7jKuSb03NKz+Kbj+Oc3iDAA3cdsROXgdIce659SIGjOsOD6rV51sqP0YA9PURCBbVbw==", + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@react-pdf/renderer/-/renderer-4.1.6.tgz", + "integrity": "sha512-hfQ0PsuVqfoYxkYgmkj+HFkylbB1QTpXY1rnlgnzJlrlSoNXjzPrCa/ty8jcHOwYA2lNoazIAoDatBIsc8K5pw==", "dependencies": { "@babel/runtime": "^7.20.13", "@react-pdf/font": "^3.0.1", - "@react-pdf/layout": "^4.1.2", + "@react-pdf/layout": "^4.2.0", "@react-pdf/pdfkit": "^4.0.0", "@react-pdf/primitives": "^4.0.0", - "@react-pdf/reconciler": "^1.1.2", - "@react-pdf/render": "^4.0.1", + "@react-pdf/reconciler": "^1.1.3", + "@react-pdf/render": "^4.0.2", "@react-pdf/types": "^2.7.0", "events": "^3.3.0", "object-assign": "^4.1.1", @@ -6191,9 +6208,9 @@ } }, "node_modules/@react-pdf/stylesheet": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@react-pdf/stylesheet/-/stylesheet-5.1.0.tgz", - "integrity": "sha512-QOPCGzlTz+irGLXbsQtKkEqkf78n9l3hRU0Omkvpk/gwLf/IchBBt358dV6FEtc+ujMFEpN+a+fWSS6v2tB0AQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@react-pdf/stylesheet/-/stylesheet-5.2.0.tgz", + "integrity": "sha512-ST19VumM9iRG0z8EjDJnyQCG+NhPFtYUCAh5B8HY237MrsRGvMgzcwrpyyqcyuLwHHYy7S4iw8EY0mK9+Qa2XQ==", "dependencies": { "@babel/runtime": "^7.20.13", "@react-pdf/fns": "3.0.0", @@ -6205,9 +6222,9 @@ } }, "node_modules/@react-pdf/textkit": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@react-pdf/textkit/-/textkit-5.0.0.tgz", - "integrity": "sha512-+K6zkF6lDXHIZZ9nNzplJ48IrjXNGQqVfO5v73AsutHbvx44E62t46EeoGLHsmjGeMG70TooSI1Mwq/7f/5tLw==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@react-pdf/textkit/-/textkit-5.0.1.tgz", + "integrity": "sha512-4GdDiPA9l+If203hkh48slvRQmcmM3ecPLFTpXNMPrep/3retgvxUEXKMxI+xKclpw8tMzK/W6Z4hN9DgnxWMg==", "dependencies": { "@babel/runtime": "^7.20.13", "@react-pdf/fns": "3.0.0", @@ -6222,9 +6239,9 @@ "integrity": "sha512-7KrPPCpgRPKR+g+T127PE4bpw9Q84ZiY07EYRwXKVtTEVW9wJ5BZiF9smT9IvH19s+MQaDLmYRgjESsnqlyH0Q==" }, "node_modules/@reduxjs/toolkit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.3.0.tgz", - "integrity": "sha512-WC7Yd6cNGfHx8zf+iu+Q1UPTfEcXhQ+ATi7CV1hlrSAaQBdlPzg7Ww/wJHNQem7qG9rxmWoFCDCPubSvFObGzA==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.5.1.tgz", + "integrity": "sha512-UHhy3p0oUpdhnSxyDjaRDYaw8Xra75UiLbCiRozVPHjfDwNYkh0TsVm/1OmTW8Md+iDAJmYPWUKMvsMc2GtpNg==", "dependencies": { "immer": "^10.0.3", "redux": "^5.0.1", @@ -6232,7 +6249,7 @@ "reselect": "^5.1.0" }, "peerDependencies": { - "react": "^16.9.0 || ^17.0.0 || ^18", + "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" }, "peerDependenciesMeta": { @@ -6244,14 +6261,6 @@ } } }, - "node_modules/@remix-run/router": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.21.0.tgz", - "integrity": "sha512-xfSkCAchbdG5PnbrKqFWwia4Bi61nH+wm8wLEqfHDyp7Y3dZzgqS2itV8i4gAq9pC2HsTpwyBC6Ds8VHZ96JlA==", - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/@restart/hooks": { "version": "0.4.16", "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.16.tgz", @@ -6264,18 +6273,19 @@ } }, "node_modules/@restart/ui": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.8.0.tgz", - "integrity": "sha512-xJEOXUOTmT4FngTmhdjKFRrVVF0hwCLNPdatLCHkyS4dkiSK12cEu1Y0fjxktjJrdst9jJIc5J6ihMJCoWEN/g==", + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.9.4.tgz", + "integrity": "sha512-N4C7haUc3vn4LTwVUPlkJN8Ach/+yIMvRuTVIhjilNHqegY60SGLrzud6errOMNJwSnmYFnt1J0H/k8FE3A4KA==", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.21.0", - "@popperjs/core": "^2.11.6", + "@babel/runtime": "^7.26.0", + "@popperjs/core": "^2.11.8", "@react-aria/ssr": "^3.5.0", - "@restart/hooks": "^0.4.9", - "@types/warning": "^3.0.0", + "@restart/hooks": "^0.5.0", + "@types/warning": "^3.0.3", "dequal": "^2.0.3", "dom-helpers": "^5.2.0", - "uncontrollable": "^8.0.1", + "uncontrollable": "^8.0.4", "warning": "^4.0.3" }, "peerDependencies": { @@ -6283,10 +6293,23 @@ "react-dom": ">=16.14.0" } }, + "node_modules/@restart/ui/node_modules/@restart/hooks": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.5.1.tgz", + "integrity": "sha512-EMoH04NHS1pbn07iLTjIjgttuqb7qu4+/EyhAx27MHpoENcB2ZdSsLTNxmKD+WEPnZigo62Qc8zjGnNxoSE/5Q==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.3" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, "node_modules/@restart/ui/node_modules/uncontrollable": { "version": "8.0.4", "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-8.0.4.tgz", "integrity": "sha512-ulRWYWHvscPFc0QQXvyJjY6LIXU56f0h8pQFvhxiKk5V1fcI8gp9Ht9leVAhrVjzqMw0BgjspBINx9r6oyJUvQ==", + "license": "MIT", "peerDependencies": { "react": ">=16.14.0" } @@ -6814,6 +6837,12 @@ "@types/send": "*" } }, + "node_modules/@types/gensync": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@types/gensync/-/gensync-1.0.4.tgz", + "integrity": "sha512-C3YYeRQWp2fmq9OryX+FoDy8nXS6scQ7dPptD8LnFDAUNcKWJjXQKDNJD3HVm+kOUsXhTOkpi69vI4EuAr95bA==", + "license": "MIT" + }, "node_modules/@types/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", @@ -7049,14 +7078,15 @@ "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==" }, "node_modules/@types/use-sync-external-store": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", - "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", + "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==" }, "node_modules/@types/warning": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.3.tgz", - "integrity": "sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q==" + "integrity": "sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q==", + "license": "MIT" }, "node_modules/@types/ws": { "version": "8.5.12", @@ -7485,7 +7515,8 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "optional": true + "optional": true, + "peer": true }, "node_modules/abs-svg-path": { "version": "0.1.1", @@ -7579,6 +7610,14 @@ "node": ">=8.9" } }, + "node_modules/adler-32": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", + "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==", + "engines": { + "node": ">=0.8" + } + }, "node_modules/agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -7716,7 +7755,8 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", - "optional": true + "optional": true, + "peer": true }, "node_modules/arch": { "version": "2.2.0", @@ -7743,6 +7783,7 @@ "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", "deprecated": "This package is no longer supported.", "optional": true, + "peer": true, "dependencies": { "delegates": "^1.0.0", "readable-stream": "^3.6.0" @@ -7756,6 +7797,7 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "optional": true, + "peer": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -7795,12 +7837,12 @@ } }, "node_modules/array-buffer-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", - "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", "dependencies": { - "call-bind": "^1.0.5", - "is-array-buffer": "^3.0.4" + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" }, "engines": { "node": ">= 0.4" @@ -7910,14 +7952,14 @@ } }, "node_modules/array.prototype.flatmap": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", - "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -7962,18 +8004,17 @@ } }, "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", - "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", "dependencies": { "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.5", + "call-bind": "^1.0.8", "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.2.1", - "get-intrinsic": "^1.2.3", - "is-array-buffer": "^3.0.4", - "is-shared-array-buffer": "^1.0.2" + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" }, "engines": { "node": ">= 0.4" @@ -7997,6 +8038,14 @@ "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==" }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -8069,9 +8118,9 @@ } }, "node_modules/axios": { - "version": "1.7.7", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", - "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", + "version": "1.7.9", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", + "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -8456,7 +8505,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, + "devOptional": true, "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -8467,7 +8516,7 @@ "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, + "devOptional": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -8709,9 +8758,9 @@ } }, "node_modules/browserslist": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", - "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", + "version": "4.24.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", + "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", "funding": [ { "type": "opencollective", @@ -8726,11 +8775,12 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001663", - "electron-to-chromium": "^1.5.28", - "node-releases": "^2.0.18", - "update-browserslist-db": "^1.1.0" + "caniuse-lite": "^1.0.30001688", + "electron-to-chromium": "^1.5.73", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.1" }, "bin": { "browserslist": "cli.js" @@ -8751,7 +8801,7 @@ "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, + "devOptional": true, "funding": [ { "type": "github", @@ -8805,15 +8855,41 @@ } }, "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", "dependencies": { + "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", + "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", + "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" @@ -8878,9 +8954,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001663", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001663.tgz", - "integrity": "sha512-o9C3X27GLKbLeTYZ6HBOLU1tsAcBZsLis28wrVzddShCS16RujjHp9GDHKZqrB3meE0YjhawvMFsGb/igqiPzA==", + "version": "1.0.30001699", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001699.tgz", + "integrity": "sha512-b+uH5BakXZ9Do9iK+CkDmctUSEqZl+SP056vc5usa0PL+ev5OHw003rZXcnjNDv3L8P5j6rwT6C0BPKSikW08w==", "funding": [ { "type": "opencollective", @@ -8894,7 +8970,8 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/canvas": { "version": "2.11.2", @@ -8902,6 +8979,7 @@ "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", "hasInstallScript": true, "optional": true, + "peer": true, "dependencies": { "@mapbox/node-pre-gyp": "^1.0.0", "nan": "^2.17.0", @@ -8919,6 +8997,18 @@ "node": ">=4" } }, + "node_modules/cfb": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz", + "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==", + "dependencies": { + "adler-32": "~1.3.0", + "crc-32": "~1.2.0" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -9095,6 +9185,7 @@ "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", "optional": true, + "peer": true, "engines": { "node": ">=10" } @@ -9458,6 +9549,14 @@ "node": ">= 4.0" } }, + "node_modules/codepage": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz", + "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==", + "engines": { + "node": ">=0.8" + } + }, "node_modules/collect-v8-coverage": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", @@ -9490,6 +9589,7 @@ "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", "optional": true, + "peer": true, "bin": { "color-support": "bin.js" } @@ -9525,9 +9625,9 @@ } }, "node_modules/commander": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", - "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", "dev": true, "engines": { "node": ">=18" @@ -9629,10 +9729,11 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "node_modules/concurrently": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.1.0.tgz", - "integrity": "sha512-VxkzwMAn4LP7WyMnJNbHN5mKV9L2IbyDjpzemKr99sXNR3GqRNMMHdm7prV1ws9wg7ETj6WUkNOigZVsptwbgg==", + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.1.2.tgz", + "integrity": "sha512-H9MWcoPsYddwbOGM6difjVwVZHl63nwMEwDJG/L7VGtuaJhb12h2caPG2tVPWs7emuYix252iGfqOyrz1GczTQ==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.1.2", "lodash": "^4.17.21", @@ -9755,7 +9856,8 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "optional": true + "optional": true, + "peer": true }, "node_modules/content-disposition": { "version": "0.5.2", @@ -9806,11 +9908,12 @@ "hasInstallScript": true }, "node_modules/core-js-compat": { - "version": "3.38.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.38.1.tgz", - "integrity": "sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw==", + "version": "3.40.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.40.0.tgz", + "integrity": "sha512-0XEDpr5y5mijvw8Lbc6E5AkjrHfp7eEoPlu36SWeAbcL8fn1G1ANe8DBlo2XoNN89oVpxWwOjYIPVzR4ZvsKCQ==", + "license": "MIT", "dependencies": { - "browserslist": "^4.23.3" + "browserslist": "^4.24.3" }, "funding": { "type": "opencollective", @@ -9877,10 +9980,21 @@ "typescript": ">=4" } }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/cross-spawn": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.5.tgz", - "integrity": "sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -10340,10 +10454,11 @@ } }, "node_modules/daisyui": { - "version": "4.12.14", - "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-4.12.14.tgz", - "integrity": "sha512-hA27cdBasdwd4/iEjn+aidoCrRroDuo3G5W9NDKaVCJI437Mm/3eSL/2u7MkZ0pt8a+TrYF3aT2pFVemTS3how==", + "version": "4.12.23", + "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-4.12.23.tgz", + "integrity": "sha512-EM38duvxutJ5PD65lO/AFMpcw+9qEy6XAZrTpzp7WyaPeO/l+F/Qiq0ECHHmFNcFXh5aVoALY4MGrrxtCiaQCQ==", "dev": true, + "license": "MIT", "dependencies": { "css-selector-tokenizer": "^0.8", "culori": "^3", @@ -10409,13 +10524,13 @@ } }, "node_modules/data-view-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", - "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", "dependencies": { - "call-bind": "^1.0.6", + "call-bound": "^1.0.3", "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" + "is-data-view": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -10425,27 +10540,27 @@ } }, "node_modules/data-view-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", - "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", "dependencies": { - "call-bind": "^1.0.7", + "call-bound": "^1.0.3", "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" + "is-data-view": "^1.0.2" }, "engines": { "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/inspect-js" } }, "node_modules/data-view-byte-offset": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", - "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", "dependencies": { - "call-bind": "^1.0.6", + "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-data-view": "^1.0.1" }, @@ -10466,9 +10581,9 @@ } }, "node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "dependencies": { "ms": "^2.1.3" }, @@ -10491,6 +10606,7 @@ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", "optional": true, + "peer": true, "dependencies": { "mimic-response": "^2.0.0" }, @@ -10760,7 +10876,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "optional": true + "optional": true, + "peer": true }, "node_modules/depd": { "version": "2.0.0", @@ -10914,9 +11031,10 @@ } }, "node_modules/dnd-multi-backend": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/dnd-multi-backend/-/dnd-multi-backend-8.0.3.tgz", - "integrity": "sha512-yFFARotr+OEJk787Fsj+V52pi6j7+Pt/CRp3IR2Ai3fnxA/z6J54T7+gxkXzXu4cvxTNE7NiBzzAaJ2f7JjFTw==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/dnd-multi-backend/-/dnd-multi-backend-9.0.0.tgz", + "integrity": "sha512-BCUFes4x0LA2bZyEZFHeQzZ1CBZo6PB40zMOG/gNgICxjAZfN2jHgISowqkR1isdx/msUNzscxEb17SP7yc4KQ==", + "license": "MIT", "funding": { "type": "individual", "url": "https://github.com/sponsors/LouisBrunner" @@ -11045,10 +11163,11 @@ } }, "node_modules/dotenv": { - "version": "16.4.5", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", - "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "version": "16.4.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=12" }, @@ -11094,6 +11213,19 @@ "webpack": "^4 || ^5" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/duplexer": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", @@ -11124,9 +11256,10 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.28", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.28.tgz", - "integrity": "sha512-VufdJl+rzaKZoYVUijN13QcXVF5dWPZANeFTLNy+OSpHdDL5ynXTF35+60RSBbaQYB1ae723lQXHCrf4pyLsMw==" + "version": "1.5.96", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.96.tgz", + "integrity": "sha512-8AJUW6dh75Fm/ny8+kZKJzI1pgoE8bKLZlzDU2W1ENd+DXKJrx7I7l9hb8UWR4ojlnb5OlixMt00QWiYJoVw1w==", + "license": "ISC" }, "node_modules/emittery": { "version": "0.8.1", @@ -11160,6 +11293,15 @@ "node": ">= 0.8" } }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "optional": true, + "dependencies": { + "once": "^1.4.0" + } + }, "node_modules/enhanced-resolve": { "version": "5.17.1", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", @@ -11231,56 +11373,61 @@ } }, "node_modules/es-abstract": { - "version": "1.23.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", - "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "version": "1.23.9", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.9.tgz", + "integrity": "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==", "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "arraybuffer.prototype.slice": "^1.0.3", + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "data-view-buffer": "^1.0.1", - "data-view-byte-length": "^1.0.1", - "data-view-byte-offset": "^1.0.0", - "es-define-property": "^1.0.0", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", - "es-set-tostringtag": "^2.0.3", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.4", - "get-symbol-description": "^1.0.2", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.0", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", - "has-symbols": "^1.0.3", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", "hasown": "^2.0.2", - "internal-slot": "^1.0.7", - "is-array-buffer": "^3.0.4", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", - "is-data-view": "^1.0.1", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.3", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.13", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", + "is-data-view": "^1.0.2", + "is-regex": "^1.2.1", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.0", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.3", "object-keys": "^1.1.1", - "object.assign": "^4.1.5", - "regexp.prototype.flags": "^1.5.2", - "safe-array-concat": "^1.1.2", - "safe-regex-test": "^1.0.3", - "string.prototype.trim": "^1.2.9", - "string.prototype.trimend": "^1.0.8", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.3", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.2", - "typed-array-byte-length": "^1.0.1", - "typed-array-byte-offset": "^1.0.2", - "typed-array-length": "^1.0.6", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.15" + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.18" }, "engines": { "node": ">= 0.4" @@ -11295,12 +11442,9 @@ "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==" }, "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "engines": { "node": ">= 0.4" } @@ -11338,25 +11482,26 @@ "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" }, "node_modules/es-iterator-helpers": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.0.tgz", - "integrity": "sha512-tpxqxncxnpw3c93u8n3VOzACmRFoVmWJqbWXvX/JfKbkhBw1oslgPrUfeSt2psuqyEJFD6N/9lg5i7bsKpoq+Q==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz", + "integrity": "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", "define-properties": "^1.2.1", - "es-abstract": "^1.23.3", + "es-abstract": "^1.23.6", "es-errors": "^1.3.0", "es-set-tostringtag": "^2.0.3", "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", + "get-intrinsic": "^1.2.6", "globalthis": "^1.0.4", - "gopd": "^1.0.1", + "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.7", - "iterator.prototype": "^1.1.3", - "safe-array-concat": "^1.1.2" + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "iterator.prototype": "^1.1.4", + "safe-array-concat": "^1.1.3" }, "engines": { "node": ">= 0.4" @@ -11379,13 +11524,14 @@ } }, "node_modules/es-set-tostringtag": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", - "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "dependencies": { - "get-intrinsic": "^1.2.4", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", - "hasown": "^2.0.1" + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -11400,13 +11546,13 @@ } }, "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" }, "engines": { "node": ">= 0.4" @@ -11466,25 +11612,26 @@ } }, "node_modules/eslint": { - "version": "9.14.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.14.0.tgz", - "integrity": "sha512-c2FHsVBr87lnUtjP4Yhvk4yEhKrQavGafRA/Se1ouse8PfbfC/Qh9Mxa00yWsZRlqeUB9raXip0aiiUZkgnr9g==", + "version": "9.20.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.20.0.tgz", + "integrity": "sha512-aL4F8167Hg4IvsW89ejnpTwx+B/UQRzJPGgbIOl+4XqffWsahVVsLEWoZvnrVuwpWmnRd7XeXmQI1zlKcFDteA==", + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.18.0", - "@eslint/core": "^0.7.0", - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.14.0", - "@eslint/plugin-kit": "^0.2.0", + "@eslint/config-array": "^0.19.0", + "@eslint/core": "^0.11.0", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "9.20.0", + "@eslint/plugin-kit": "^0.2.5", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.0", + "@humanwhocodes/retry": "^0.4.1", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", + "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.2.0", @@ -11503,8 +11650,7 @@ "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "text-table": "^0.2.0" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" @@ -11601,9 +11747,9 @@ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, "node_modules/eslint-plugin-prettier": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz", - "integrity": "sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.3.tgz", + "integrity": "sha512-qJ+y0FfCp/mQYQ/vWQ3s7eUlFEL4PyKfAJxsnYTJ4YT73nsJBWqmEpFryxV9OeUiqmsTsYJ5Y+KDNaeP31wrRw==", "dev": true, "dependencies": { "prettier-linter-helpers": "^1.0.0", @@ -11631,27 +11777,27 @@ } }, "node_modules/eslint-plugin-react": { - "version": "7.37.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.2.tgz", - "integrity": "sha512-EsTAnj9fLVr/GZleBLFbj/sSuXeWmp1eXIN60ceYnZveqEaUCyW4X+Vh4WTdUhCkW4xutXYqTXCUSyqD4rB75w==", + "version": "7.37.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.4.tgz", + "integrity": "sha512-BGP0jRmfYyvOyvMoRX/uoUeW+GqNj9y16bPQzqAHf3AYII/tDs+jMN0dBVkl88/OZwNGwrVFxE7riHsXVfy/LQ==", "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", - "array.prototype.flatmap": "^1.3.2", + "array.prototype.flatmap": "^1.3.3", "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.1.0", + "es-iterator-helpers": "^1.2.1", "estraverse": "^5.3.0", "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", "object.entries": "^1.1.8", "object.fromentries": "^2.0.8", - "object.values": "^1.2.0", + "object.values": "^1.2.1", "prop-types": "^15.8.1", "resolve": "^2.0.0-next.5", "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.11", + "string.prototype.matchall": "^4.0.12", "string.prototype.repeat": "^1.0.0" }, "engines": { @@ -11703,6 +11849,18 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/@eslint/core": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.11.0.tgz", + "integrity": "sha512-DWUB2pksgNEb6Bz2fggIy1wh6fGgZP4Xyy/Mt0QZPiloKKXerbqq9D3SBQTlCRYOrcRPu4vuz+CGjwdfqxnoWA==", + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/eslint/node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -11921,6 +12079,15 @@ "node": ">= 0.8.0" } }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "optional": true, + "engines": { + "node": ">=6" + } + }, "node_modules/expand-tilde": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", @@ -11951,7 +12118,6 @@ "version": "4.21.2", "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", - "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", @@ -12020,8 +12186,7 @@ "node_modules/express/node_modules/path-to-regexp": { "version": "0.1.12", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", - "license": "MIT" + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" }, "node_modules/express/node_modules/range-parser": { "version": "1.2.1", @@ -12719,6 +12884,14 @@ "node": ">= 0.6" } }, + "node_modules/frac": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", + "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==", + "engines": { + "node": ">=0.8" + } + }, "node_modules/fraction.js": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", @@ -12739,6 +12912,12 @@ "node": ">= 0.6" } }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "optional": true + }, "node_modules/fs-extra": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", @@ -12758,6 +12937,7 @@ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", "optional": true, + "peer": true, "dependencies": { "minipass": "^3.0.0" }, @@ -12770,6 +12950,7 @@ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "optional": true, + "peer": true, "dependencies": { "yallist": "^4.0.0" }, @@ -12781,7 +12962,8 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true + "optional": true, + "peer": true }, "node_modules/fs-monkey": { "version": "1.0.6", @@ -12815,14 +12997,16 @@ } }, "node_modules/function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" }, "engines": { "node": ">= 0.4" @@ -12845,6 +13029,7 @@ "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", "deprecated": "This package is no longer supported.", "optional": true, + "peer": true, "dependencies": { "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.2", @@ -12864,7 +13049,8 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "optional": true + "optional": true, + "peer": true }, "node_modules/gensync": { "version": "1.0.0-beta.2", @@ -12883,9 +13069,9 @@ } }, "node_modules/get-east-asian-width": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz", - "integrity": "sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", + "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", "dev": true, "engines": { "node": ">=18" @@ -12895,15 +13081,20 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz", + "integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==", "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-proto": "^1.0.0", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -12933,6 +13124,18 @@ "node": ">=8.0.0" } }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-stream": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", @@ -12946,13 +13149,13 @@ } }, "node_modules/get-symbol-description": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", - "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", "dependencies": { - "call-bind": "^1.0.5", + "call-bound": "^1.0.3", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4" + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" @@ -12961,6 +13164,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "optional": true + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -13102,11 +13311,11 @@ } }, "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dependencies": { - "get-intrinsic": "^1.1.3" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -13174,9 +13383,12 @@ } }, "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dependencies": { + "dunder-proto": "^1.0.0" + }, "engines": { "node": ">= 0.4" }, @@ -13185,9 +13397,9 @@ } }, "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "engines": { "node": ">= 0.4" }, @@ -13213,7 +13425,8 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "optional": true + "optional": true, + "peer": true }, "node_modules/hasown": { "version": "2.0.2", @@ -13551,9 +13764,9 @@ "integrity": "sha512-fXHXcGFTXOvZTSkPJuGOQf5Lv5T/R2itiiCVPg9LxAje5D00O0pP83yJShFq5V89Ly//Gt6acj7z8pbBr34stw==" }, "node_modules/i18next": { - "version": "23.16.5", - "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.16.5.tgz", - "integrity": "sha512-KTlhE3EP9x6pPTAW7dy0WKIhoCpfOGhRQlO+jttQLgzVaoOjWwBWramu7Pp0i+8wDNduuzXfe3kkVbzrKyrbTA==", + "version": "23.16.8", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.16.8.tgz", + "integrity": "sha512-06r/TitrM88Mg5FdUXAKL96dJMzgqLE5dv3ryBAra4KCwD9mJ4ndOTS95ZuymIGoE+2hzfdaMak2X11/es7ZWg==", "funding": [ { "type": "individual", @@ -13573,17 +13786,18 @@ } }, "node_modules/i18next-browser-languagedetector": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.0.0.tgz", - "integrity": "sha512-zhXdJXTTCoG39QsrOCiOabnWj2jecouOqbchu3EfhtSHxIB5Uugnm9JaizenOy39h7ne3+fLikIjeW88+rgszw==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.0.2.tgz", + "integrity": "sha512-shBvPmnIyZeD2VU5jVGIOWP7u9qNG3Lj7mpaiPFpbJ3LVfHZJvVzKR4v1Cb91wAOFpNw442N+LGPzHOHsten2g==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.2" } }, "node_modules/i18next-http-backend": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-2.6.2.tgz", - "integrity": "sha512-Hp/kd8/VuoxIHmxsknJXjkTYYHzivAyAF15pzliKzk2TiXC25rZCEerb1pUFoxz4IVrG3fCvQSY51/Lu4ECV4A==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-3.0.1.tgz", + "integrity": "sha512-XT2lYSkbAtDE55c6m7CtKxxrsfuRQO3rUfHzj8ZyRtY9CkIX3aRGwXGTkUhpGWce+J8n7sfu3J0f2wTzo7Lw0A==", "dependencies": { "cross-fetch": "4.0.0" } @@ -13643,7 +13857,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, + "devOptional": true, "funding": [ { "type": "github", @@ -13922,13 +14136,13 @@ } }, "node_modules/internal-slot": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", - "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", "dependencies": { "es-errors": "^1.3.0", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" + "hasown": "^2.0.2", + "side-channel": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -13997,12 +14211,13 @@ } }, "node_modules/is-array-buffer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", - "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1" + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" @@ -14017,11 +14232,15 @@ "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" }, "node_modules/is-async-function": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", - "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", "dependencies": { - "has-tostringtag": "^1.0.0" + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -14031,11 +14250,14 @@ } }, "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", "dependencies": { - "has-bigints": "^1.0.1" + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -14053,12 +14275,12 @@ } }, "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.1.tgz", + "integrity": "sha512-l9qO6eFlUETHtuihLcYOaLKByJ1f+N4kthcU9YjHy3N+B3hWv0y/2Nd0mu/7lTFnRQHTrSdXF50HQ3bl5fEnng==", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -14093,10 +14315,12 @@ } }, "node_modules/is-data-view": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", - "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", "is-typed-array": "^1.1.13" }, "engines": { @@ -14107,11 +14331,12 @@ } }, "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -14152,11 +14377,14 @@ } }, "node_modules/is-finalizationregistry": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", - "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", "dependencies": { - "call-bind": "^1.0.2" + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -14183,11 +14411,14 @@ } }, "node_modules/is-generator-function": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", - "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", + "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.3", + "get-proto": "^1.0.0", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -14241,17 +14472,6 @@ "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==" }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -14261,11 +14481,12 @@ } }, "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -14363,12 +14584,14 @@ "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==" }, "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -14405,11 +14628,11 @@ } }, "node_modules/is-shared-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", - "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", "dependencies": { - "call-bind": "^1.0.7" + "call-bound": "^1.0.3" }, "engines": { "node": ">= 0.4" @@ -14431,11 +14654,12 @@ } }, "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -14445,11 +14669,13 @@ } }, "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", "dependencies": { - "has-symbols": "^1.0.2" + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -14459,11 +14685,11 @@ } }, "node_modules/is-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", - "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", "dependencies": { - "which-typed-array": "^1.1.14" + "which-typed-array": "^1.1.16" }, "engines": { "node": ">= 0.4" @@ -14512,11 +14738,14 @@ } }, "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.0.tgz", + "integrity": "sha512-SXM8Nwyys6nT5WP6pltOwKytLV7FqQ4UiibxVmW+EIosHcmCqkkjViTb5SNssDlkCiEYRP1/pdWUKVvZBmsR2Q==", "dependencies": { - "call-bind": "^1.0.2" + "call-bound": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -14690,15 +14919,16 @@ } }, "node_modules/iterator.prototype": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.3.tgz", - "integrity": "sha512-FW5iMbeQ6rBGm/oKgzq2aW4KvAGpxPzYES8N4g4xNXUKpL1mclMvOe+76AcLDTvD+Ze+sOpVhgdAQEKF4L9iGQ==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", + "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", "dependencies": { - "define-properties": "^1.2.1", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "reflect.getprototypeof": "^1.0.4", - "set-function-name": "^2.0.1" + "define-data-property": "^1.1.4", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "get-proto": "^1.0.0", + "has-symbols": "^1.1.0", + "set-function-name": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -14811,9 +15041,9 @@ } }, "node_modules/jay-peg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/jay-peg/-/jay-peg-1.1.0.tgz", - "integrity": "sha512-WhyKySfx5CEFoKDnpmHyJUrpX5fUrr/X3kqVHISmiO9jrJC73RQBOAZJB8bDrWT4PHEkl0QgNZLlWJfAWAIFew==", + "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==", "dependencies": { "restructure": "^3.0.0" } @@ -17273,9 +17503,9 @@ } }, "node_modules/lilconfig": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", - "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", "engines": { "node": ">=14" }, @@ -17289,21 +17519,21 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, "node_modules/lint-staged": { - "version": "15.2.10", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.10.tgz", - "integrity": "sha512-5dY5t743e1byO19P9I4b3x8HJwalIznL5E1FWYnU6OWw33KxNBSLAc6Cy7F2PsFEO8FKnLwjwm5hx7aMF0jzZg==", + "version": "15.4.3", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.4.3.tgz", + "integrity": "sha512-FoH1vOeouNh1pw+90S+cnuoFwRfUD9ijY2GKy5h7HS3OR7JVir2N2xrsa0+Twc1B7cW72L+88geG5cW4wIhn7g==", "dev": true, "dependencies": { - "chalk": "~5.3.0", - "commander": "~12.1.0", - "debug": "~4.3.6", - "execa": "~8.0.1", - "lilconfig": "~3.1.2", - "listr2": "~8.2.4", - "micromatch": "~4.0.8", - "pidtree": "~0.6.0", - "string-argv": "~0.3.2", - "yaml": "~2.5.0" + "chalk": "^5.4.1", + "commander": "^13.1.0", + "debug": "^4.4.0", + "execa": "^8.0.1", + "lilconfig": "^3.1.3", + "listr2": "^8.2.5", + "micromatch": "^4.0.8", + "pidtree": "^0.6.0", + "string-argv": "^0.3.2", + "yaml": "^2.7.0" }, "bin": { "lint-staged": "bin/lint-staged.js" @@ -17316,9 +17546,9 @@ } }, "node_modules/lint-staged/node_modules/chalk": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", - "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", + "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", "dev": true, "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" @@ -17328,9 +17558,9 @@ } }, "node_modules/listr2": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.4.tgz", - "integrity": "sha512-opevsywziHd3zHCVQGAj8zu+Z3yHNkkoYhWIGnq54RrCVwLz0MozotJEDnKsIBLvkfLGN6BLOyAeRrYI0pKA4g==", + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.5.tgz", + "integrity": "sha512-iyAZCeyD+c1gPyE9qpFu8af0Y+MRtmKOncdGoA2S5EY8iFq99dmmvkNnHiWo+pj0s7yH7l3KPIgee77tKpXPWQ==", "dev": true, "dependencies": { "cli-truncate": "^4.0.0", @@ -17882,6 +18112,14 @@ "tmpl": "1.0.5" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/mdn-data": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", @@ -18038,6 +18276,7 @@ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", "optional": true, + "peer": true, "engines": { "node": ">=8" }, @@ -18101,6 +18340,7 @@ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", "optional": true, + "peer": true, "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" @@ -18114,6 +18354,7 @@ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "optional": true, + "peer": true, "dependencies": { "yallist": "^4.0.0" }, @@ -18125,7 +18366,8 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true + "optional": true, + "peer": true }, "node_modules/mkdirp": { "version": "0.5.6", @@ -18138,6 +18380,12 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "optional": true + }, "node_modules/moment": { "version": "2.30.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", @@ -18192,7 +18440,8 @@ "version": "2.20.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.20.0.tgz", "integrity": "sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==", - "optional": true + "optional": true, + "peer": true }, "node_modules/nanoid": { "version": "3.3.8", @@ -18211,6 +18460,12 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/napi-build-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", + "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", + "optional": true + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -18243,6 +18498,36 @@ "tslib": "^2.0.3" } }, + "node_modules/node-abi": { + "version": "3.73.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.73.0.tgz", + "integrity": "sha512-z8iYzQGBu35ZkTQ9mtR8RqugJZ9RCLn8fv3d7LsgDBzOijGQP3RdKTX4LA7LXw03ZhU5z0l4xfhIMgSES31+cg==", + "optional": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-abi/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "optional": true + }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", @@ -18276,15 +18561,17 @@ "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==" }, "node_modules/node-releases": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==" + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "license": "MIT" }, "node_modules/nopt": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", "optional": true, + "peer": true, "dependencies": { "abbrev": "1" }, @@ -18363,6 +18650,7 @@ "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", "deprecated": "This package is no longer supported.", "optional": true, + "peer": true, "dependencies": { "are-we-there-yet": "^2.0.0", "console-control-strings": "^1.1.0", @@ -18403,9 +18691,9 @@ } }, "node_modules/object-inspect": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", - "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", + "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", "engines": { "node": ">= 0.4" }, @@ -18437,13 +18725,15 @@ } }, "node_modules/object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", "dependencies": { - "call-bind": "^1.0.5", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", "object-keys": "^1.1.1" }, "engines": { @@ -18517,11 +18807,12 @@ } }, "node_modules/object.values": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", - "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" }, @@ -18713,6 +19004,22 @@ "node": ">=0.10.0" } }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -18962,9 +19269,9 @@ } }, "node_modules/path2d": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/path2d/-/path2d-0.2.1.tgz", - "integrity": "sha512-Fl2z/BHvkTNvkuBzYTpTuirHZg6wW9z8+4SND/3mDTEcYbbNKWAy21dz9D3ePNNwrrK8pqZO5vLPZ1hLF6T7XA==", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/path2d/-/path2d-0.2.2.tgz", + "integrity": "sha512-+vnG6S4dYcYxZd+CZxzXCNKdELYZSKfohrk98yajCo1PtRoDgCTrrwOvK1GT0UoAdVszagDVllQc0U1vaX4NUQ==", "optional": true, "engines": { "node": ">=6" @@ -18987,15 +19294,29 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/pdfjs-dist": { - "version": "4.4.168", - "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-4.4.168.tgz", - "integrity": "sha512-MbkAjpwka/dMHaCfQ75RY1FXX3IewBVu6NGZOcxerRFlaBiIkZmUoR0jotX5VUzYZEXAGzSFtknWs5xRKliXPA==", + "version": "4.8.69", + "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-4.8.69.tgz", + "integrity": "sha512-IHZsA4T7YElCKNNXtiLgqScw4zPd3pG9do8UrznC757gMd7UPeHSL2qwNNMJo4r79fl8oj1Xx+1nh2YkzdMpLQ==", "engines": { "node": ">=18" }, "optionalDependencies": { - "canvas": "^2.11.2", - "path2d": "^0.2.0" + "canvas": "^3.0.0-rc2", + "path2d": "^0.2.1" + } + }, + "node_modules/pdfjs-dist/node_modules/canvas": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-3.1.0.tgz", + "integrity": "sha512-tTj3CqqukVJ9NgSahykNwtGda7V33VLObwrHfzT0vqJXu7J4d4C/7kQQW3fOEGDfZZoILPut5H00gOjyttPGyg==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "node-addon-api": "^7.0.0", + "prebuild-install": "^7.1.1" + }, + "engines": { + "node": "^18.12.0 || >= 20.9.0" } }, "node_modules/performance-now": { @@ -19242,9 +19563,9 @@ } }, "node_modules/postcss": { - "version": "8.4.49", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", - "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz", + "integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==", "funding": [ { "type": "opencollective", @@ -19259,8 +19580,9 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "nanoid": "^3.3.7", + "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -20458,6 +20780,84 @@ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, + "node_modules/prebuild-install": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", + "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^2.0.0", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prebuild-install/node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "optional": true, + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prebuild-install/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prebuild-install/node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true, + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -20467,10 +20867,11 @@ } }, "node_modules/prettier": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", - "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.0.tgz", + "integrity": "sha512-quyMrVt6svPS7CjQ9gKb3GLEX/rl3BCL2oa/QkNcXv4YNVBC9olt3s+H7ukto06q7B1Qz46PbrKLO34PR6vXcA==", "dev": true, + "license": "MIT", "bin": { "prettier": "bin/prettier.cjs" }, @@ -20797,6 +21198,16 @@ "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" }, + "node_modules/pump": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", + "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", + "optional": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", @@ -20996,12 +21407,12 @@ } }, "node_modules/re-resizable": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/re-resizable/-/re-resizable-6.10.0.tgz", - "integrity": "sha512-hysSK0xmA5nz24HBVztlk4yCqCLCvS32E6ZpWxVKop9x3tqCa4yAj1++facrmkOf62JsJHjmjABdKxXofYioCw==", + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/re-resizable/-/re-resizable-6.10.3.tgz", + "integrity": "sha512-zvWb7X3RJMA4cuSrqoxgs3KR+D+pEXnGrD2FAD6BMYAULnZsSF4b7AOVyG6pC3VVNVOtlagGDCDmZSwWLjjBBw==", "peerDependencies": { - "react": "^16.13.1 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0" + "react": "^16.13.1 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "node_modules/react": { @@ -21047,13 +21458,15 @@ "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" }, "node_modules/react-bootstrap": { - "version": "2.10.5", - "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.10.5.tgz", - "integrity": "sha512-XueAOEn64RRkZ0s6yzUTdpFtdUXs5L5491QU//8ZcODKJNDLt/r01tNyriZccjgRImH1REynUc9pqjiRMpDLWQ==", + "version": "2.10.9", + "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.10.9.tgz", + "integrity": "sha512-TJUCuHcxdgYpOqeWmRApM/Dy0+hVsxNRFvq2aRFQuxhNi/+ivOxC5OdWIeHS3agxvzJ4Ev4nDw2ZdBl9ymd/JQ==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.24.7", "@restart/hooks": "^0.4.9", - "@restart/ui": "^1.6.9", + "@restart/ui": "^1.9.4", + "@types/prop-types": "^15.7.12", "@types/react-transition-group": "^4.4.6", "classnames": "^2.3.2", "dom-helpers": "^5.2.1", @@ -21087,17 +21500,18 @@ } }, "node_modules/react-confetti": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/react-confetti/-/react-confetti-6.1.0.tgz", - "integrity": "sha512-7Ypx4vz0+g8ECVxr88W9zhcQpbeujJAVqL14ZnXJ3I23mOI9/oBVTQ3dkJhUmB0D6XOtCZEM6N0Gm9PMngkORw==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/react-confetti/-/react-confetti-6.2.2.tgz", + "integrity": "sha512-K+kTyOPgX+ZujMZ+Rmb7pZdHBvg+DzinG/w4Eh52WOB8/pfO38efnnrtEZNJmjTvLxc16RBYO+tPM68Fg8viBA==", + "license": "MIT", "dependencies": { "tween-functions": "^1.2.0" }, "engines": { - "node": ">=10.18" + "node": ">=16" }, "peerDependencies": { - "react": "^16.3.0 || ^17.0.1 || ^18.0.0" + "react": "^16.3.0 || ^17.0.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/react-cookie": { @@ -21114,18 +21528,18 @@ } }, "node_modules/react-datepicker": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-7.5.0.tgz", - "integrity": "sha512-6MzeamV8cWSOcduwePHfGqY40acuGlS1cG//ePHT6bVbLxWyqngaStenfH03n1wbzOibFggF66kWaBTb1SbTtQ==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-7.6.0.tgz", + "integrity": "sha512-9cQH6Z/qa4LrGhzdc3XoHbhrxNcMi9MKjZmYgF/1MNNaJwvdSjv3Xd+jjvrEEbKEf71ZgCA3n7fQbdwd70qCRw==", + "license": "MIT", "dependencies": { - "@floating-ui/react": "^0.26.23", + "@floating-ui/react": "^0.27.0", "clsx": "^2.1.1", - "date-fns": "^3.6.0", - "prop-types": "^15.8.1" + "date-fns": "^3.6.0" }, "peerDependencies": { - "react": "^16.9.0 || ^17 || ^18", - "react-dom": "^16.9.0 || ^17 || ^18" + "react": "^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc", + "react-dom": "^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc" } }, "node_modules/react-dev-utils": { @@ -21319,12 +21733,13 @@ } }, "node_modules/react-dnd-multi-backend": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/react-dnd-multi-backend/-/react-dnd-multi-backend-8.0.3.tgz", - "integrity": "sha512-IwH7Mf6R05KIFohX0hHMTluoAvuUD8SO15KCD+9fY0nJ4nc1FGCMCSyMZw8R1XNStKp+JnNg3ZMtiaf5DebSUg==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/react-dnd-multi-backend/-/react-dnd-multi-backend-9.0.0.tgz", + "integrity": "sha512-LAKDdyj4oMvVA/k2RiJ8KLIPO9sBiYIjIYtoFCuAgml9qQwIq+oTav2IXGfG4DrP49fBnVO7jjf5ofJMNOlWTA==", + "license": "MIT", "dependencies": { - "dnd-multi-backend": "^8.0.3", - "react-dnd-preview": "^8.0.3" + "dnd-multi-backend": "^9.0.0", + "react-dnd-preview": "^9.0.0" }, "funding": { "type": "individual", @@ -21332,21 +21747,22 @@ }, "peerDependencies": { "dnd-core": "^16.0.1", - "react": "^16.14.0 || ^17.0.2 || ^18.0.0", + "react": "^16.14.0 || ^17.0.2 || ^18.0.0 || ^19.0.0", "react-dnd": "^16.0.1", - "react-dom": "^16.14.0 || ^17.0.2 || ^18.0.0" + "react-dom": "^16.14.0 || ^17.0.2 || ^18.0.0 || ^19.0.0" } }, "node_modules/react-dnd-preview": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/react-dnd-preview/-/react-dnd-preview-8.0.3.tgz", - "integrity": "sha512-s69Ro47QYDthDhj73iQ0VioMCjtlZ1AytKBDkQaHKm5DTjA8D2bIaFKCBQd330QEW0SIzqLJrZGCSlIY2xraJg==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/react-dnd-preview/-/react-dnd-preview-9.0.0.tgz", + "integrity": "sha512-WZTbrrNDlCGYJGrITHN/obI2kpdaKV3AY6Il2LLZcA9ApzG5bbDXBlWSFwuw8eTCMjmCXs5Wcv+p2QCMxX1Afw==", + "license": "MIT", "funding": { "type": "individual", "url": "https://github.com/sponsors/LouisBrunner" }, "peerDependencies": { - "react": "^16.14.0 || ^17.0.2 || ^18.0.0", + "react": "^16.14.0 || ^17.0.2 || ^18.0.0 || ^19.0.0", "react-dnd": "^16.0.1" } }, @@ -21452,9 +21868,9 @@ } }, "node_modules/react-i18next": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.1.1.tgz", - "integrity": "sha512-R/Vg9wIli2P3FfeI8o1eNJUJue5LWpFsQePCHdQDmX0Co3zkr6kdT8gAseb/yGeWbNz1Txc4bKDQuZYsC0kQfw==", + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.4.0.tgz", + "integrity": "sha512-Py6UkX3zV08RTvL6ZANRoBh9sL/ne6rQq79XlkHEdd82cZr2H9usbWpUNVadJntIZP2pu3M2rL1CN+5rQYfYFw==", "dependencies": { "@babel/runtime": "^7.25.0", "html-parse-stringify": "^3.0.1" @@ -21526,16 +21942,16 @@ "integrity": "sha512-FNbLuG/HAdapQoybeZSoes1PWdOj0w242gb+e1R0hicf3Gyj/Mf8M9NaED2AnXVOX01b2FXomwUiw1xP1K+8sA==" }, "node_modules/react-pdf": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/react-pdf/-/react-pdf-9.1.1.tgz", - "integrity": "sha512-Cn3RTJZMqVOOCgLMRXDamLk4LPGfyB2Np3OwQAUjmHIh47EpuGW1OpAA1Z1GVDLoHx4d5duEDo/YbUkDbr4QFQ==", + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/react-pdf/-/react-pdf-9.2.1.tgz", + "integrity": "sha512-AJt0lAIkItWEZRA5d/mO+Om4nPCuTiQ0saA+qItO967DTjmGjnhmF+Bi2tL286mOTfBlF5CyLzJ35KTMaDoH+A==", "dependencies": { "clsx": "^2.0.0", "dequal": "^2.0.3", "make-cancellable-promise": "^1.3.1", "make-event-props": "^1.6.0", "merge-refs": "^1.3.0", - "pdfjs-dist": "4.4.168", + "pdfjs-dist": "4.8.69", "tiny-invariant": "^1.0.0", "warning": "^4.0.0" }, @@ -21591,16 +22007,16 @@ } }, "node_modules/react-redux": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.2.tgz", - "integrity": "sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", + "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", "dependencies": { - "@types/use-sync-external-store": "^0.0.3", - "use-sync-external-store": "^1.0.0" + "@types/use-sync-external-store": "^0.0.6", + "use-sync-external-store": "^1.4.0" }, "peerDependencies": { - "@types/react": "^18.2.25", - "react": "^18.0", + "@types/react": "^18.2.25 || ^19", + "react": "^18.0 || ^19", "redux": "^5.0.0" }, "peerDependenciesMeta": { @@ -21666,11 +22082,11 @@ } }, "node_modules/react-rnd": { - "version": "10.4.13", - "resolved": "https://registry.npmjs.org/react-rnd/-/react-rnd-10.4.13.tgz", - "integrity": "sha512-Vgbf0iihspcQ6nkaFhpOGWfmnuVbhkhoB0hBbYl8aRDA4horsQHESc4E1z7O/P27kFFjK2aqM0u5CGzfr9gEZA==", + "version": "10.4.14", + "resolved": "https://registry.npmjs.org/react-rnd/-/react-rnd-10.4.14.tgz", + "integrity": "sha512-NLGc3IymymumPfHy3DXiHNIMOiTlj6xBNb2boHqrtwCgYDasNarpg8tdUY36JlJbrs0E4BvjYBkfEGqUPBsukg==", "dependencies": { - "re-resizable": "6.10.0", + "re-resizable": "6.10.3", "react-draggable": "4.4.6", "tslib": "2.6.2" }, @@ -21685,33 +22101,35 @@ "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "node_modules/react-router": { - "version": "6.28.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.28.0.tgz", - "integrity": "sha512-HrYdIFqdrnhDw0PqG/AKjAqEqM7AvxCz0DQ4h2W8k6nqmc5uRBYDag0SBxx9iYz5G8gnuNVLzUe13wl9eAsXXg==", + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.1.5.tgz", + "integrity": "sha512-8BUF+hZEU4/z/JD201yK6S+UYhsf58bzYIDq2NS1iGpwxSXDu7F+DeGSkIXMFBuHZB21FSiCzEcUb18cQNdRkA==", + "license": "MIT", "dependencies": { - "@remix-run/router": "1.21.0" + "@types/cookie": "^0.6.0", + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0", + "turbo-stream": "2.4.0" }, "engines": { - "node": ">=14.0.0" + "node": ">=20.0.0" }, "peerDependencies": { - "react": ">=16.8" + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } } }, - "node_modules/react-router-dom": { - "version": "6.28.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.28.0.tgz", - "integrity": "sha512-kQ7Unsl5YdyOltsPGl31zOjLrDv+m2VcIEcIHqYYD3Lp0UppLjrzcfJqDJwXxFw3TH/yvapbnUvPlAj7Kx5nbg==", - "dependencies": { - "@remix-run/router": "1.21.0", - "react-router": "6.28.0" - }, + "node_modules/react-router/node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "react": ">=16.8", - "react-dom": ">=16.8" + "node": ">=18" } }, "node_modules/react-scripts": { @@ -22607,9 +23025,9 @@ } }, "node_modules/react-select": { - "version": "5.8.3", - "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.8.3.tgz", - "integrity": "sha512-lVswnIq8/iTj1db7XCG74M/3fbGB6ZaluCzvwPGT5ZOjCdL/k0CLWhEK0vCBLuU5bHTEf6Gj8jtSvi+3v+tO1w==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.10.0.tgz", + "integrity": "sha512-k96gw+i6N3ExgDwPIg0lUPmexl1ygPe6u5BdQFNBhkpbwroIgCNXdubtIzHfThYXYYTubwOBafoMnn7ruEP1xA==", "dependencies": { "@babel/runtime": "^7.12.0", "@emotion/cache": "^11.4.0", @@ -22619,11 +23037,11 @@ "memoize-one": "^6.0.0", "prop-types": "^15.6.0", "react-transition-group": "^4.3.0", - "use-isomorphic-layout-effect": "^1.1.2" + "use-isomorphic-layout-effect": "^1.2.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "node_modules/react-side-effect": { @@ -22635,17 +23053,17 @@ } }, "node_modules/react-signature-canvas": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/react-signature-canvas/-/react-signature-canvas-1.0.6.tgz", - "integrity": "sha512-NoMHomYu9HxFeLjUGbIeV9abPdWSROfFxFNDekGdwmmaIx+w5ziOEiU2C34X0Ao4GxFnwqyUy/BpYlA4lCD1CA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/react-signature-canvas/-/react-signature-canvas-1.0.7.tgz", + "integrity": "sha512-yo0x0uTMVmcClaqryuQu6F8xEVapk5zdM9/nuQ7GalDJWccoVNZPMmCFGK7U5r3I0mrEHPB9E5/rFSYUgZcfmA==", "dependencies": { "signature_pad": "^2.3.2", "trim-canvas": "^0.1.0" }, "peerDependencies": { "prop-types": "^15.5.8", - "react": "0.14 - 18", - "react-dom": "0.14 - 18" + "react": "0.14 - 19", + "react-dom": "0.14 - 19" } }, "node_modules/react-style-singleton": { @@ -22686,6 +23104,20 @@ "react": ">= 0.14.0" } }, + "node_modules/react-timezone-select": { + "version": "3.2.8", + "resolved": "https://registry.npmjs.org/react-timezone-select/-/react-timezone-select-3.2.8.tgz", + "integrity": "sha512-efEIVmYAHtm+oS+YlE/9DbieMka1Lop0v1LsW1TdLq0yCBnnAzROKDUY09CICY8TCijZlo0fk+wHZZkV5NpVNw==", + "dependencies": { + "spacetime": "^7.6.0", + "timezone-soft": "^1.5.2" + }, + "peerDependencies": { + "react": "^16 || ^17.0.1 || ^18 || ^19.0.0-0", + "react-dom": "^16 || ^17.0.1 || ^18 || ^19.0.0-0", + "react-select": "^5.8.0" + } + }, "node_modules/react-tooltip": { "version": "5.28.0", "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-5.28.0.tgz", @@ -22842,17 +23274,18 @@ } }, "node_modules/reflect.getprototypeof": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", - "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", "define-properties": "^1.2.1", - "es-abstract": "^1.23.1", + "es-abstract": "^1.23.9", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "globalthis": "^1.0.3", - "which-builtin-type": "^1.1.3" + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" }, "engines": { "node": ">= 0.4" @@ -22918,14 +23351,16 @@ "integrity": "sha512-TVILVSz2jY5D47F4mA4MppkBrafEaiUWJO/TcZHEIuI13AqoZMkK1WMA4Om1YkYbTx+9Ki1/tSUXbceyr9saRg==" }, "node_modules/regexp.prototype.flags": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", - "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", "dependencies": { - "call-bind": "^1.0.6", + "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-errors": "^1.3.0", - "set-function-name": "^2.0.1" + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -23391,13 +23826,14 @@ } }, "node_modules/safe-array-concat": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", - "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4", - "has-symbols": "^1.0.3", + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", "isarray": "^2.0.5" }, "engines": { @@ -23417,14 +23853,34 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, - "node_modules/safe-regex-test": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", - "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", "dependencies": { - "call-bind": "^1.0.6", "es-errors": "^1.3.0", - "is-regex": "^1.1.4" + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-push-apply/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" }, "engines": { "node": ">= 0.4" @@ -23496,10 +23952,15 @@ "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==" + }, "node_modules/schema-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", - "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz", + "integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==", "dependencies": { "@types/json-schema": "^7.0.9", "ajv": "^8.9.0", @@ -23507,7 +23968,7 @@ "ajv-keywords": "^5.1.0" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 10.13.0" }, "funding": { "type": "opencollective", @@ -23780,7 +24241,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "optional": true + "optional": true, + "peer": true + }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==" }, "node_modules/set-function-length": { "version": "1.2.2", @@ -23812,6 +24279,19 @@ "node": ">= 0.4" } }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", @@ -23867,14 +24347,65 @@ } }, "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "dependencies": { - "call-bind": "^1.0.7", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -23924,6 +24455,7 @@ "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", "optional": true, + "peer": true, "dependencies": { "decompress-response": "^4.2.0", "once": "^1.3.1", @@ -24086,6 +24618,11 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/spacetime": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/spacetime/-/spacetime-7.7.0.tgz", + "integrity": "sha512-m97vi+g9OdEZWmvpWFpoDjx9ApsUX8pcTw2VcTc39SCysg/pmPfTD7zhs+XSg5tfA1yr7SlRpzzprgAVFLUdeA==" + }, "node_modules/spdy": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", @@ -24132,6 +24669,17 @@ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" }, + "node_modules/ssf": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz", + "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==", + "dependencies": { + "frac": "~1.1.2" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/stable": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", @@ -24371,22 +24919,23 @@ } }, "node_modules/string.prototype.matchall": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", - "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", + "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", + "es-abstract": "^1.23.6", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.7", - "regexp.prototype.flags": "^1.5.2", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.3", "set-function-name": "^2.0.2", - "side-channel": "^1.0.6" + "side-channel": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -24405,14 +24954,17 @@ } }, "node_modules/string.prototype.trim": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", - "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", "define-properties": "^1.2.1", - "es-abstract": "^1.23.0", - "es-object-atoms": "^1.0.0" + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -24422,14 +24974,18 @@ } }, "node_modules/string.prototype.trimend": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", - "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -24851,12 +25407,13 @@ "node_modules/tabbable": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", - "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==" + "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==", + "license": "MIT" }, "node_modules/tailwindcss": { - "version": "3.4.15", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.15.tgz", - "integrity": "sha512-r4MeXnfBmSOuKUWmXe6h2CcyfzJCEk4F0pptO5jlnYSIViUkVmsawj80N5h2lO3gwcmSb4n3PuN+e+GC1Guylw==", + "version": "3.4.17", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", + "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==", "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -24867,7 +25424,7 @@ "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "jiti": "^1.21.6", - "lilconfig": "^2.1.0", + "lilconfig": "^3.1.3", "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", @@ -24889,14 +25446,6 @@ "node": ">=14.0.0" } }, - "node_modules/tailwindcss/node_modules/lilconfig": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", - "engines": { - "node": ">=10" - } - }, "node_modules/tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -24910,6 +25459,7 @@ "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", "optional": true, + "peer": true, "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -24922,11 +25472,60 @@ "node": ">=10" } }, + "node_modules/tar-fs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.2.tgz", + "integrity": "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==", + "optional": true, + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-fs/node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "optional": true + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "optional": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "optional": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/tar/node_modules/mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "optional": true, + "peer": true, "bin": { "mkdirp": "bin/cmd.js" }, @@ -24938,7 +25537,8 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true + "optional": true, + "peer": true }, "node_modules/temp-dir": { "version": "2.0.0", @@ -25020,15 +25620,15 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.10", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", - "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "version": "5.3.11", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.11.tgz", + "integrity": "sha512-RVCsMfuD0+cTt3EwX8hSl2Ks56EbFHWmhluwcqoPKtBnfjiT6olaq7PRIRfhyU8nnC2MrnDrBLfrD/RGE+cVXQ==", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.20", + "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.1", - "terser": "^5.26.0" + "schema-utils": "^4.3.0", + "serialize-javascript": "^6.0.2", + "terser": "^5.31.1" }, "engines": { "node": ">= 10.13.0" @@ -25052,51 +25652,6 @@ } } }, - "node_modules/terser-webpack-plugin/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "node_modules/terser-webpack-plugin/node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, "node_modules/terser/node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -25155,6 +25710,11 @@ "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" }, + "node_modules/timezone-soft": { + "version": "1.5.2", + "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", @@ -25314,6 +25874,23 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "optional": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/turbo-stream": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz", + "integrity": "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==" + }, "node_modules/tween-functions": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/tween-functions/-/tween-functions-1.2.0.tgz", @@ -25362,28 +25939,28 @@ } }, "node_modules/typed-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", - "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", "dependencies": { - "call-bind": "^1.0.7", + "call-bound": "^1.0.3", "es-errors": "^1.3.0", - "is-typed-array": "^1.1.13" + "is-typed-array": "^1.1.14" }, "engines": { "node": ">= 0.4" } }, "node_modules/typed-array-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", - "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" }, "engines": { "node": ">= 0.4" @@ -25393,16 +25970,17 @@ } }, "node_modules/typed-array-byte-offset": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", - "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", "dependencies": { "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" }, "engines": { "node": ">= 0.4" @@ -25412,16 +25990,16 @@ } }, "node_modules/typed-array-length": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", - "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", - "has-proto": "^1.0.3", "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0" + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" }, "engines": { "node": ">= 0.4" @@ -25452,14 +26030,17 @@ } }, "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", "dependencies": { - "call-bind": "^1.0.2", + "call-bound": "^1.0.3", "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -25607,9 +26188,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", - "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz", + "integrity": "sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==", "funding": [ { "type": "opencollective", @@ -25624,9 +26205,10 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "escalade": "^3.1.2", - "picocolors": "^1.0.1" + "escalade": "^3.2.0", + "picocolors": "^1.1.1" }, "bin": { "update-browserslist-db": "cli.js" @@ -25690,11 +26272,11 @@ } }, "node_modules/use-isomorphic-layout-effect": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", - "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.2.0.tgz", + "integrity": "sha512-q6ayo8DWoPZT0VdG4u3D3uxcgONP3Mevx2i2b0434cwWBoL+aelL1DzkXI6w3PhTZzUeR2kaVlZn70iCiseP6w==", "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@types/react": { @@ -25724,11 +26306,11 @@ } }, "node_modules/use-sync-external-store": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", - "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz", + "integrity": "sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==", "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "node_modules/util-deprecate": { @@ -26292,37 +26874,41 @@ } }, "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/which-builtin-type": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.4.tgz", - "integrity": "sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", "dependencies": { + "call-bound": "^1.0.2", "function.prototype.name": "^1.1.6", "has-tostringtag": "^1.0.2", "is-async-function": "^2.0.0", - "is-date-object": "^1.0.5", - "is-finalizationregistry": "^1.0.2", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", "is-generator-function": "^1.0.10", - "is-regex": "^1.1.4", + "is-regex": "^1.2.1", "is-weakref": "^1.0.2", "isarray": "^2.0.5", - "which-boxed-primitive": "^1.0.2", + "which-boxed-primitive": "^1.1.0", "which-collection": "^1.0.2", - "which-typed-array": "^1.1.15" + "which-typed-array": "^1.1.16" }, "engines": { "node": ">= 0.4" @@ -26354,14 +26940,15 @@ } }, "node_modules/which-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", - "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.18.tgz", + "integrity": "sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==", "dependencies": { "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", "for-each": "^0.3.3", - "gopd": "^1.0.1", + "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" }, "engines": { @@ -26376,6 +26963,7 @@ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", "optional": true, + "peer": true, "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" } @@ -26446,6 +27034,22 @@ "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", "dev": true }, + "node_modules/wmf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", + "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/word": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz", + "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==", + "engines": { + "node": ">=0.8" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -26842,6 +27446,26 @@ } } }, + "node_modules/xlsx": { + "version": "0.18.5", + "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz", + "integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==", + "dependencies": { + "adler-32": "~1.3.0", + "cfb": "~1.2.1", + "codepage": "~1.15.0", + "crc-32": "~1.2.1", + "ssf": "~0.11.2", + "wmf": "~1.0.1", + "word": "~0.3.0" + }, + "bin": { + "xlsx": "bin/xlsx.njs" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/xml-name-validator": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", @@ -26882,9 +27506,9 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, "node_modules/yaml": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.1.tgz", - "integrity": "sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz", + "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==", "bin": { "yaml": "bin.mjs" }, @@ -26931,9 +27555,9 @@ } }, "node_modules/yoga-layout": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/yoga-layout/-/yoga-layout-3.1.0.tgz", - "integrity": "sha512-auzJ8lEovThZIpR8wLGWNo/JEj4VTO79q9/gOJ0dWb3shAYPFdX3t9VN0fC0v+jeQF77STUdCzebLwRMqzn5gQ==" + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/yoga-layout/-/yoga-layout-3.2.1.tgz", + "integrity": "sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ==" }, "node_modules/zoom-level": { "version": "2.5.0", diff --git a/apps/OpenSign/package.json b/apps/OpenSign/package.json index 0a1850179..301c49d72 100644 --- a/apps/OpenSign/package.json +++ b/apps/OpenSign/package.json @@ -4,16 +4,16 @@ "private": true, "dependencies": { "@formkit/auto-animate": "^0.8.2", - "@lottiefiles/dotlottie-react": "^0.10.0", + "@lottiefiles/dotlottie-react": "^0.12.3", "@pdf-lib/fontkit": "^1.1.1", "@radix-ui/themes": "^3.1.6", - "@react-pdf/renderer": "^4.1.4", - "@reduxjs/toolkit": "^2.3.0", - "axios": "^1.7.7", + "@react-pdf/renderer": "^4.1.6", + "@reduxjs/toolkit": "^2.5.1", + "axios": "^1.7.9", "file-saver": "^2.0.5", - "i18next": "^23.16.5", - "i18next-browser-languagedetector": "^8.0.0", - "i18next-http-backend": "^2.6.2", + "i18next": "^23.16.8", + "i18next-browser-languagedetector": "^8.0.2", + "i18next-http-backend": "^3.0.1", "jszip": "^3.10.1", "jwt-decode": "^4.0.0", "moment": "^2.30.1", @@ -23,29 +23,30 @@ "print-js": "^1.6.0", "radix-ui": "^1.0.1", "react": "^18.2.0", - "react-bootstrap": "^2.10.5", - "react-confetti": "^6.1.0", + "react-bootstrap": "^2.10.9", + "react-confetti": "^6.2.2", "react-cookie": "^7.2.2", - "react-datepicker": "^7.5.0", + "react-datepicker": "^7.6.0", "react-dnd": "^16.0.1", "react-dnd-html5-backend": "^16.0.1", - "react-dnd-multi-backend": "^8.0.3", + "react-dnd-multi-backend": "^9.0.0", "react-dnd-touch-backend": "^16.0.1", "react-dom": "^18.2.0", "react-gtm-module": "^2.0.11", "react-helmet": "^6.1.0", - "react-i18next": "^15.1.1", + "react-i18next": "^15.4.0", "react-konva": "^18.2.10", - "react-pdf": "^9.1.1", + "react-pdf": "^9.2.1", "react-quill-new": "^3.3.3", - "react-redux": "^9.1.2", - "react-rnd": "^10.4.13", - "react-router-dom": "^6.28.0", + "react-redux": "^9.2.0", + "react-rnd": "^10.4.14", + "react-router": "^7.1.5", "react-scripts": "5.0.1", "react-scrollbars-custom": "^4.1.1", - "react-select": "^5.8.3", - "react-signature-canvas": "^1.0.6", + "react-select": "^5.10.0", + "react-signature-canvas": "^1.0.7", "react-syntax-highlighter": "^15.6.1", + "react-timezone-select": "^3.2.8", "react-tooltip": "^5.28.0", "react-web-share": "^2.0.2", "reactour": "^1.19.4", @@ -55,17 +56,16 @@ "serve": "^14.2.4", "styled-components": "^5.3.0", "web-vitals": "^4.2.4", - "ws": "^8.18.0" + "ws": "^8.18.0", + "xlsx": "^0.18.5" }, "scripts": { - "build-webpack": "webpack --config webpack.config.js", - "build": "npm run version && npm run build-webpack && react-scripts build", - "build-watch": "webpack --config webpack.config.js --watch", + "build": "npm run version && react-scripts build", "start-dev": "react-scripts start", "start": "serve -s build", "version": "curl -s https://api.github.com/repos/opensignlabs/opensign/releases/latest | grep '\"tag_name\":' | awk -F '\"' '{print $4}' > ./public/version.txt", "version-win": "powershell -Command \"Invoke-RestMethod -Uri 'https://api.github.com/repos/opensignlabs/opensign/releases/latest' | Select-Object -ExpandProperty tag_name | Out-File -FilePath ./public/version.txt\"", - "build-win": "npm run version-win && npm run build-webpack && react-scripts build", + "build-win": "npm run version-win && react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject", "release": "standard-version", @@ -95,29 +95,29 @@ } }, "devDependencies": { - "@babel/core": "^7.26.0", - "@babel/preset-env": "^7.26.0", - "@babel/preset-react": "^7.25.9", - "@babel/runtime-corejs2": "^7.26.0", + "@babel/core": "^7.26.8", + "@babel/preset-env": "^7.26.8", + "@babel/preset-react": "^7.26.3", + "@babel/runtime-corejs2": "^7.26.7", "autoprefixer": "^10.4.20", "babel-loader": "^9.2.1", "clean-webpack-plugin": "^4.0.0", "commitizen": "^4.3.1", - "concurrently": "^9.1.0", + "concurrently": "^9.1.2", "css-loader": "^7.1.2", - "daisyui": "^4.12.14", - "dotenv": "^16.4.5", + "daisyui": "^4.12.23", + "dotenv": "^16.4.7", "dotenv-webpack": "^8.1.0", - "eslint": "^9.14.0", - "eslint-plugin-prettier": "^5.2.1", - "eslint-plugin-react": "^7.37.2", - "lint-staged": "^15.2.10", + "eslint": "^9.20.0", + "eslint-plugin-prettier": "^5.2.3", + "eslint-plugin-react": "^7.37.4", + "lint-staged": "^15.4.3", "mini-css-extract-plugin": "^2.9.2", - "postcss": "^8.4.49", - "prettier": "^3.3.3", + "postcss": "^8.5.1", + "prettier": "^3.5.0", "pretty-quick": "^4.0.0", - "tailwindcss": "^3.4.15", - "terser-webpack-plugin": "^5.3.10", + "tailwindcss": "^3.4.17", + "terser-webpack-plugin": "^5.3.11", "webpack-cli": "^5.1.4" }, "overrides": { @@ -127,4 +127,4 @@ "engines": { "node": "18 || 20 || 22" } -} +} \ No newline at end of file diff --git a/apps/OpenSign/public/favicon.ico b/apps/OpenSign/public/favicon.ico old mode 100755 new mode 100644 diff --git a/apps/OpenSign/public/index.html b/apps/OpenSign/public/index.html index d46cbe9d2..aa6140e7a 100644 --- a/apps/OpenSign/public/index.html +++ b/apps/OpenSign/public/index.html @@ -3,7 +3,7 @@ - + @@ -15,6 +15,6 @@ OpenSign™ -
+
\ No newline at end of file diff --git a/apps/OpenSign/public/locales/de/translation.json b/apps/OpenSign/public/locales/de/translation.json new file mode 100644 index 000000000..86962189d --- /dev/null +++ b/apps/OpenSign/public/locales/de/translation.json @@ -0,0 +1,837 @@ +{ + "header-news": "Neue Funktion: Benutzer des Teams-Plans können jetzt ihre eigenen AWS S3-Buckets für die Dateispeicherung integrieren", + "header-news-btn": "Jetzt einrichten", + "create-account": "Konto erstellen", + "login": "Anmelden", + "language": "Sprache", + "name": "Name", + "phone": "Telefon", + "phone-optional": "optional", + "email": "E-Mail", + "company": "Unternehmen", + "job-title": "Berufsbezeichnung", + "profile": "Profil", + "log-out": "Abmelden", + "is-email-verified": "Ist E-Mail verifiziert", + "public-profile": "Öffentliches Profil", + "tagline": "Slogan", + "has-requested-you-to-sign": "hat Sie gebeten, zu unterschreiben", + "has-requested-you-to-review-and-sign": "hat Sie gebeten, zu prüfen und zu unterschreiben", + "input-required": "Bitte füllen Sie dieses Feld aus.", + "sort-order": { + "Ascending": "Aufsteigend", + "Descending": "Absteigend", + "Name": "Name", + "Date": "Datum" + }, + "context-menu": { + "Download": "Herunterladen", + "Rename": "Umbenennen", + "Move": "Verschieben", + "Delete": "Löschen" + }, + "action": "Aktion", + "add": "Hinzufügen", + "add-new-folder": "Neuen Ordner hinzufügen", + "disable-documentId": "DocumentId deaktivieren", + "edit": "Bearbeiten", + "change-password": "Passwort ändern", + "save": "Speichern", + "cancel": "Abbrechen", + "upgrade-now": "Jetzt upgraden", + "upgrade-to": "Upgrade zu", + "plan": "Plan", + "subscribe-card-teamplan": "Entfesseln Sie die volle Kraft der Zusammenarbeit! Erstellen Sie unbegrenzt Organisationen, Teams und Hierarchien. Teilen Sie Vorlagen nahtlos zwischen Teams und weisen Sie benutzerdefinierte Benutzerrollen zu. Optimieren Sie Ihren Workflow noch heute!", + "subscribe-card-plan": "Entsperren Sie Premium-Funktionen ab nur {{premiumPrice}}/Monat. Genießen Sie eine verbesserte Leistung und zahlen Sie nur {{addonPrice}} pro zusätzlichem Credit nach den enthaltenen Premium-Credits.", + "user-name-limit-char": "Um einen Benutzernamen mit weniger als 8 Zeichen zu haben, abonnieren Sie bitte.", + "tour-content": "Nicht erneut anzeigen", + "pro": "PRO", + "team": "TEAM", + "user": "Benutzer", + "docs": "Dokumente", + "session-expired": "Ihre Sitzung ist abgelaufen.", + "public-profile-help": "Dies ist Ihre öffentliche URL. Kopieren oder teilen Sie sie mit dem Unterzeichner, und Sie können alle öffentlich eingestellten Vorlagen sehen.", + "tagline-help": "Dieser Slogan wird in Ihrem öffentlichen OpenSign-Profil angezeigt, z. B. https://opensign.me/alex", + "welcome": "Willkommen zurück!", + "Login-to-your-account": "Melden Sie sich bei Ihrem Konto an", + "password": "Passwort", + "forgot-password": "Passwort vergessen?", + "loading": "Wird geladen...", + "of": "von", + "sign-SSO": "Mit SSO anmelden", + "login-page": "Anmeldeseite", + "or": "ODER", + "signup-page": "Registrierungsseite", + "password-length": "Das Passwort sollte 8 Zeichen lang sein", + "password-case": "Das Passwort sollte einen Großbuchstaben, einen Kleinbuchstaben und eine Zahl enthalten", + "password-special-char": "Das Passwort sollte ein Sonderzeichen enthalten", + "agreee": "Ich stimme den", + "term": "Nutzungsbedingungen zu", + "subscribe-to-opensign": "Abonnieren Sie den OpenSign-Newsletter", + "register": "Registrieren", + "sidebar": { + "Dashboard": "Armaturenbrett", + "Sign yourself": "Selbst unterschreiben", + "Request signatures": "Signaturen anfordern", + "Templates": "Vorlagen", + "Templates-Children": { + "Create template": "Vorlage erstellen", + "Manage templates": "Vorlagen verwalten", + "Embedding": "Einbetten" + }, + "OpenSign™ Drive": "OpenSign™ drive", + "Documents": "Dokumente", + "Reports": "Berichte", + "Documents-Children": { + "Need your sign": "Benötigt Ihre Unterschrift", + "In Progress": "In Bearbeitung", + "Completed": "Abgeschlossen", + "Drafts": "Entwürfe", + "Declined": "Abgelehnt", + "Expired": "Abgelaufen" + }, + "Contactbook": "Kontaktbuch", + "Settings": "Einstellungen", + "Settings-Children": { + "My Signature": "Meine Unterschrift", + "API Token": "API-Token", + "Webhook": "Webhook", + "Preferences": "Einstellungen", + "Teams": "Teams", + "Team-update-successfully": "Team erfolgreich aktualisiert.", + "Users": "Benutzer" + } + }, + "dashboard-card": { + "Need your Signature": "Benötigt Ihre Unterschrift", + "Out for signatures": "Ausstehende Signaturen" + }, + "report-name": { + "Draft Documents": "Entwurfsdokumente", + "Need your sign": "Benötigt Ihre Unterschrift", + "In-progress documents": "Dokumente in Bearbeitung", + "Completed Documents": "Abgeschlossene Dokumente", + "Declined Documents": "Abgelehnte Dokumente", + "Expired Documents": "Abgelaufene Dokumente", + "Recently sent for signatures": "Kürzlich für Signaturen versendet", + "Recent signature requests": "Kürzliche Signaturanfragen", + "Drafts": "Entwürfe", + "Contactbook": "Kontaktbuch", + "Templates": "Vorlagen", + "Teams": "Teams", + "Users": "Benutzer" + }, + "btnLabel": { + "sign": "unterschreiben", + "Sign": "UNTERSCHREIBEN", + "Resend": "Erneut senden", + "Rename": "Umbenennen", + "Revoke": "Widerrufen", + "Delete": "Löschen", + "Use": "Verwenden", + "Quick send": "Schnell senden", + "Edit": "Bearbeiten", + "Share with team": "Mit Team teilen", + "Share": "Teilen", + "View": "Ansehen", + "option": "Option", + "Embed": "Einbetten", + "Copy TemplateId": "Vorlagen-ID kopieren", + "Copy Public URL": "Öffentliche URL kopieren", + "extend-expiry-date": "Ablaufdatum verlängern", + "Duplicate Template": "Vorlage duplizieren", + "Duplicate": "Duplikat" + }, + "report-heading": { + "Sr.No": "Nr.", + "Title": "Titel", + "Email": "E-Mail", + "Phone": "Telefon", + "File": "Datei", + "Owner": "Besitzer", + "Signers": "Unterzeichner", + "Note": "Notiz", + "Folder": "Ordner", + "Reason": "Grund", + "Parent Team": "Übergeordnetes Team", + "Active": "Aktiv", + "Role": "Rolle", + "Team": "Team", + "Name": "Name", + "Status": "Status", + "created-date": "Erstellungsdatum", + "Type": "Typ", + "Logs": "Protokolle", + "Expiry-date": "Ablaufdatum" + }, + "report-help": { + "Draft Documents": "Dies sind Dokumente, die Sie begonnen, aber noch nicht zum Versenden fertiggestellt haben.", + "Need your sign": "Dies ist eine Liste von Dokumenten, die auf Ihre Unterschrift warten.", + "In-progress documents": "Dies ist eine Liste von Dokumenten, die Sie anderen Parteien zur Unterschrift gesendet haben.", + "Completed Documents": "Dies ist eine Liste von Dokumenten, die von allen Parteien unterzeichnet wurden.", + "Declined Documents": "Dies ist eine Liste von Dokumenten, die von einem der Unterzeichner abgelehnt wurden.", + "Expired Documents": "Dies ist eine Liste von Dokumenten, deren Ablaufdatum erreicht wurde.", + "Contactbook": "Dies ist eine Liste von Kontakten/Unterzeichnern, die Sie hinzugefügt haben. Diese erscheinen als Vorschläge, wenn Sie neue Unterzeichner hinzufügen möchten.", + "Templates": "Dies ist eine Liste von Vorlagen, die Ihnen zur Verfügung stehen, um Dokumente zu erstellen. Sie können die Schaltfläche 'Verwenden' anklicken, um ein neues Dokument mit einer Vorlage zu erstellen, das Dokument zu ändern und Unterzeichner im nächsten Schritt hinzuzufügen." + }, + "form-name": { + "Sign Yourself": "Selbst unterschreiben", + "Request Signatures": "Signaturen anfordern", + "New Template": "Neue Vorlage" + }, + "file-type": "pdf, png, jpg, jpeg", + "docx": "docx", + "file-selected": "Datei ausgewählt", + "template-title": "Vorlagentitel", + "document-title": "Dokumenttitel", + "description": "Beschreibung", + "time-to-complete": "Bearbeitungszeit (Tage)", + "send-in-order": "In der Reihenfolge senden", + "send-in-order-help": { + "p1": "Wählen Sie aus, wie Sie die Unterzeichnungsanfragen an die Dokumentenunterzeichner senden möchten:", + "p2": "Wenn Sie diese Option auswählen, wird die Unterzeichnungsanfrage zunächst an den ersten Unterzeichner gesendet. Sobald dieser seine Aufgabe abgeschlossen hat, erhält der nächste Unterzeichner in der Reihenfolge die Anfrage. Dieser Prozess setzt sich fort, bis alle Unterzeichner das Dokument unterschrieben haben. Diese Methode stellt sicher, dass das Dokument in einer bestimmten Reihenfolge unterzeichnet wird.", + "p3": "Wenn Sie diese Option auswählen, werden die Signaturlinks gleichzeitig an alle Unterzeichner gesendet. Jeder Unterzeichner kann das Dokument nach Belieben unterzeichnen, unabhängig davon, ob andere Unterzeichner ihre Unterschriften abgeschlossen haben. Diese Methode ist schneller, erzwingt jedoch keine Reihenfolge unter den Teilnehmern.", + "p4": "Wählen Sie die Option, die am besten zu den Anforderungen Ihrer Dokumentenverarbeitung passt." + }, + "no": "Nein", + "auto-reminder": "Automatische Erinnerung", + "remind-once": "Einmal erinnern alle (Tage)", + "next": "Weiter", + "select-folder": "Ordner auswählen", + "OpenSign-drive": "OpenSign™ Drive", + "drive-document-status": { + "Completed": "Abgeschlossen", + "Declined": "Abgelehnt", + "Draft": "Entwurf", + "Expired": "Abgelaufen", + "In Progress": "In Bearbeitung" + }, + "select-folder-help": "Wenn Sie keinen Ordner auswählen, wird Ihr unterzeichnetes Dokument im Hauptordner des OpenSign-Drives gespeichert.", + "no-data": "Keine Daten gefunden", + "save-here": "Hier speichern", + "back": "Zurück", + "add-folder": "Ordner hinzufügen", + "create-folder": "Ordner erstellen", + "parent-folder": "Übergeordneter Ordner", + "create": "Erstellen", + "signers": "Unterzeichner", + "signers-help": "Beginnen Sie mit der Eingabe eines Kontaktnamens, um vorgeschlagene Unterzeichner aus Ihren gespeicherten Kontakten zu sehen, oder fügen Sie neue hinzu. Ordnen Sie die Reihenfolge der Unterzeichner, indem Sie sie in der gewünschten Reihenfolge hinzufügen. Verwenden Sie die '+'-Schaltfläche, um Unterzeichner hinzuzufügen, und 'x', um sie zu entfernen. Jeder Unterzeichner erhält eine E-Mail-Aufforderung, das Dokument in der aufgelisteten Reihenfolge zu unterzeichnen.", + "bcc-help": "Beginnen Sie mit der Eingabe des Namens eines Kontakts, um Vorschläge aus Ihren gespeicherten Kontakten anzuzeigen oder neue hinzuzufügen. Verwenden Sie die Schaltfläche '+', um einen Benutzer hinzuzufügen, und das 'x', um ihn zu entfernen. Die E-Mail des ausgewählten Benutzers wird als Bcc (Blindkopie) hinzugefügt. Jeder Benutzer erhält eine E-Mail-Benachrichtigung, sobald das Dokument fertig ist.", + "add-signer": "Unterzeichner hinzufügen", + "contact-not-found": "Kontakt nicht gefunden", + "add-yourself": "Sich selbst hinzufügen", + "submit": "Absenden", + "reset": "Zurücksetzen", + "my-signature": "Meine Unterschrift", + "signature": "Unterschrift", + "upload-image": "Bild hochladen", + "clear": "Löschen", + "upload-signature/Image": "Bitte Unterschrift/Bild hochladen", + "initials": "Initialen", + "API": "API", + "api-token": "API-Token", + "regenerate-token": "Live-Token neu generieren", + "generate-token": "Live-Token generieren", + "view-docs": "Dokumentation ansehen", + "generate-token-alert": "Sind Sie sicher, dass Sie das Token neu generieren möchten? Das alte Token wird ablaufen.", + "yes": "Ja", + "copied": "Kopiert", + "something-went-wrong-mssg": "Etwas ist schiefgelaufen. Bitte versuchen Sie es später erneut.", + "token-generated": "Token erfolgreich generiert.", + "webhook": "Webhook", + "update-webhook": "Webhook aktualisieren", + "add-webhook": "Webhook hinzufügen", + "webhook-added": "Webhook erfolgreich hinzugefügt.", + "team-disabled": "Team deaktiviert", + "Team enabled": "Team aktiviert", + "are-you-sure": "Sind Sie sicher, dass Sie", + "disable": "deaktivieren", + "enable": "aktivieren", + "this-team": "dieses Team möchten?", + "edit-team": "Team bearbeiten", + "name-of-team": "Name des Teams", + "prev": "Zurück", + "no-data-avaliable": "Keine Daten verfügbar", + "add-team": "Team hinzufügen", + "page-not-found": "Seite nicht gefunden", + "users-from-teams": "Benutzer aus Teams", + "user-status": "Benutzerstatus", + "activate": "aktivieren", + "deactivate": "deaktivieren", + "this-user": "diesen Benutzer", + "delete-user": "Benutzer löschen", + "delete": "löschen", + "add-user": "Benutzer hinzufügen", + "password-generateed": "Das Passwort wird nur einmal generiert; stellen Sie sicher, dass Sie es kopieren.", + "Team status": "Teamstatus", + "user-deactivated": "Benutzer deaktiviert.", + "user-activated": "Benutzer aktiviert.", + "public": "Öffentlich", + "download": "Herunterladen", + "view": "Ansehen", + "make-template-public": "Vorlage öffentlich machen", + "make-template-private": "Vorlage privat machen", + "make-template-public-alert": "Sind Sie sicher, dass Sie diese Vorlage öffentlich machen möchten?", + "make-template-private-alert": "Sind Sie sicher, dass Sie diese Vorlage privat machen möchten? Dadurch wird sie aus Ihrem öffentlichen Profil entfernt.", + "public-role": "Öffentliche Rolle", + "public-url": "Öffentliches Profil", + "embed-template": "Vorlage einbetten", + "public-url-copy": "Hier ist Ihre öffentliche URL: ", + "public-url-copy-mssg": "Kopieren oder teilen Sie diese URL, und Sie können alle öffentlich eingestellten Vorlagen sehen.", + "add-public-url-alert": "Sie können Ihr öffentliches OpenSign-Profil generieren", + "share-with-alert": "Sie können eine Vorlage nicht teilen, wenn Rollen bereits Kontakte zugewiesen haben. Entfernen Sie bitte alle Kontaktzuweisungen von den Rollen, bevor Sie die Vorlage teilen.", + "share-with": "Teilen mit", + "team-not-found": "Team nicht gefunden", + "roles": "Rollen", + "delete-document": "Dokument löschen", + "delete-document-alert": "Sind Sie sicher, dass Sie dieses Dokument löschen möchten?", + "quick-send": "Schnell senden", + "add-new": "Neu hinzufügen", + "send": "Senden", + "quick-send-alert-1": "Alle Rollen in diesem Dokument sind derzeit mit Kontakten verknüpft. Um Kopien dieser Vorlage schnell an mehrere Unterzeichner zu senden, stellen Sie sicher, dass mindestens eine Rolle keinem Kontakt zugeordnet ist.", + "quick-send-alert-2": "Bitte stellen Sie sicher, dass für alle Empfänger mindestens ein Signatur-Widget hinzugefügt wurde.", + "quick-send-alert-3": "Bitte fügen Sie mindestens eine Rolle zu dieser Vorlage hinzu, um Kopien davon schnell an mehrere Unterzeichner zu senden.", + "quick-send-alert-4": "Das Limit für Schnellsendungen wurde erreicht.", + "copy-link": "Link kopieren", + "copy": "Kopieren", + "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}}.", + "subject": "Betreff", + "body": "Inhalt", + "add-contact": "Kontakt hinzufügen", + "edit-contact": "Kontakt bearbeiten", + "add-signer-alert": "Kontakt existiert bereits! Bitte wählen Sie ihn aus dem Dropdown-Menü 'Unterzeichner' aus.", + "record-delete-alert": "Datensatz erfolgreich gelöscht!", + "record-revoke-alert": "Datensatz erfolgreich widerrufen!", + "mail-sent-alert": "E-Mail erfolgreich gesendet.", + "document-sent-alert": "Dokument erfolgreich gesendet!", + "template-share-alert": "Vorlage erfolgreich geteilt.", + "template-public-alert-1": "Sie haben die Vorlage erfolgreich öffentlich gemacht.", + "template-public-alert-2": "Sie haben die Vorlage erfolgreich privat gemacht.", + "template-public-alert-3": "Sie müssen eine Rolle für die öffentlichen Unterzeichner auswählen.", + "template-public-alert-4": "Bitte stellen Sie sicher, dass für alle Unterzeichner mindestens ein Signatur-Widget hinzugefügt wurde.", + "template-public-alert-5": "Da für diese Vorlage das Senden in Reihenfolge aktiviert ist, muss die öffentliche Rolle oben positioniert sein.", + "template-public-alert-6": "Bitte verknüpfen Sie Unterzeichner mit allen Rollen, außer mit der öffentlichen Rolle.", + "template-public-alert-7": "Bitte weisen Sie mindestens eine öffentliche Rolle zu, um diese Vorlage öffentlich zu machen.", + "loader": "Das könnte etwas Zeit in Anspruch nehmen", + "pages": "Seiten", + "document-signed": "Dokument unterzeichnet", + "close": "Schließen", + "validation-alert": "Validierungswarnung", + "validate-alert-mssg": "Die Eingabe erfüllt nicht die Kriterien des regulären Ausdrucks.", + "otp-verification": "OTP-Verifizierung", + "enter-otp": "OTP eingeben", + "verify": "Verifizieren", + "verify-email-1": "E-Mail verifizieren", + "resend": "Erneut senden", + "contact-details": "Kontaktdetails", + "verify-email": "Bitte verifizieren Sie Ihre E-Mail!", + "send-otp": "OTP senden", + "otp-placeholder": "Verifizierungscode aus der E-Mail eingeben", + "loading-doc": "Dokument wird geladen...", + "widgets-name": { + "signature": "Unterschrift", + "stamp": "Stempel", + "initials": "Initialen", + "name": "Name", + "job title": "Berufsbezeichnung", + "company": "Unternehmen", + "date": "Datum", + "text": "Text", + "text input": "Texteingabe", + "checkbox": "Checkbox", + "dropdown": "Dropdown", + "radio button": "Radiobutton", + "image": "Bild", + "email": "E-Mail" + }, + "fields": "Felder", + "recipients": "Empfänger", + "please-add": "Bitte fügen Sie hinzu", + "signed-by": "Unterzeichnet von", + "more": "mehr", + "sent": "gesendet", + "print": "Drucken", + "certificate": "Zertifikat", + "decline": "Ablehnen", + "finish": "Fertigstellen", + "mail": "E-Mail", + "sign-now": "Jetzt unterzeichnen", + "successfully-signed": "Erfolgreich unterzeichnet!", + "email-mssg": "Empfänger, die hier hinzugefügt werden, erhalten eine Kopie des unterzeichneten Dokuments.", + "email-error-1": "Bitte geben Sie eine korrekte E-Mail-Adresse an.", + "email-error-2": "Sie können nur an maximal zehn Empfänger gleichzeitig senden.", + "Email-verified-alert-1": "E-Mail wurde verifiziert.", + "Email-verified-alert-2": "E-Mail wurde bereits verifiziert.", + "upload-stamp-image": "Stempelbild hochladen", + "draw": "Zeichnen", + "type": "Schreiben", + "color-type": { + "red": "rot", + "blue": "blau", + "black": "schwarz", + "yellow": "gelb" + }, + "my-initials": "Meine Initialen", + "upload": "Hochladen", + "initial-teb": "Initialen", + "signature-tab": "Unterschrift", + "initial-alert": "Meine Initiale nicht gefunden", + "copy-title": "Widget kopieren zu", + "contact-delete-alert": "Sind Sie sicher, dass Sie diesen Kontakt löschen möchten?", + "reset-password-alert-1": "Ein Link zum Zurücksetzen des Passworts wurde an Ihre E-Mail-Adresse gesendet.", + "reset-password-alert-2": "Bitte richten Sie den E-Mail-Adapter ein.", + "reset-password-alert-3": "Setzen Sie Ihr Passwort zurück", + "faild-animation": "Animation konnte nicht geladen werden", + "apply": "Anwenden", + "copy-type": { + "All pages": "Alle Seiten", + "All pages but last": "Alle Seiten außer der letzten", + "All pages but first": "Alle Seiten außer der ersten", + "Next to current widget": "Neben dem aktuellen Widget" + }, + "options": "Optionen", + "minimun-check": "Minimale Anzahl", + "maximum-check": "Maximale Anzahl", + "default-value": "Standardwert", + "select": "Auswählen", + "read-only": "Nur lesen", + "hide-labels": "Labels ausblenden", + "checkbox": "Checkbox", + "alert": "Warnung", + "zoom-in": "Vergrößern", + "zoom-out": "Verkleinern", + "document-signed-alert": "Herzlichen Glückwunsch! 🎉 Dieses Dokument wurde erfolgreich von Ihnen unterzeichnet!", + "otp-sent-alert": "OTP wurde an Ihre E-Mail gesendet", + "fields-required": "Erforderliche Felder", + "signature-widget-alert-1": "Bitte stellen Sie sicher, dass mindestens ein Signatur-Widget hinzugefügt wurde", + "signature-widget-alert-2": "Bitte stellen Sie sicher, dass alle Felder korrekt ausgefüllt sind und die Anforderungen erfüllen.", + "encrypted-pdf-alert": "Derzeit werden verschlüsselte PDF-Dateien nicht unterstützt.", + "encrypted-pdf-alert-1": "Das Passwort der PFX-Datei ist ungültig.", + "user-not-exist": "Benutzer existiert nicht", + "template-role-alert": "Bitte fügen Sie zuerst Rollen hinzu", + "create-document": "Dokument erstellen", + "template-created-alert": "Möchten Sie ein Dokument mit der gerade erstellten Vorlage erstellen?", + "signers-alert": "Unterzeichner-Warnung", + "template-creation-alert-1": "Bitte wählen Sie einen Unterzeichner aus, um Platzhalter hinzuzufügen!", + "ok": "OK", + "radio-group": "Radiogruppe", + "dropdown-options": "Dropdown-Optionen", + "add-role": "Rolle hinzufügen", + "role-ex": "z. B.: Kunde, Personalabteilung, Direktor, Manager, Student, etc.", + "add/choose-signer": "Unterzeichner hinzufügen/auswählen", + "choose-from-contacts": "Aus Kontakten auswählen", + "select-signer": "Bitte Unterzeichner auswählen", + "edit-template": "Vorlage bearbeiten", + "widget-info": "Widget-Info", + "validation": "Validierung", + "invalid-default-value": "Ungültiger Standardwert", + "hint": "Hinweis", + "color": "Farbe", + "role-help": { + "p1": "Was sind Vorlagenrollen?", + "p2": "Beginnen Sie damit, jede Rolle zu definieren, die für die Fertigstellung des Dokuments erforderlich ist. Überlegen Sie, welche Parteien in den Unterschriftsprozess einbezogen sind und welche Aufgaben sie haben. Häufige Rollen sind z. B. Personalabteilung für interne Dokumente, Kunde für Vereinbarungen oder Anbieter für Geschäftsvereinbarungen.", + "p3": "Warum Benutzer an bestimmte Rollen vorab anhängen?", + "p4": "Für Rollen, die regelmäßig dieselbe Person betreffen (z. B. die Unterschrift des CEOs bei Mitarbeiterangebotsschreiben), können Sie einen Benutzer in der Vorlage vorab an eine Rolle anhängen. Dieser Schritt ist optional, aber empfohlen für Effizienz und Konsistenz.", + "p5": "Wann lege ich den Benutzer für jede Rolle fest?", + "p6": "Wenn Sie ein Dokument aus Ihrer Vorlage erstellen, werden Sie aufgefordert, Benutzer an jede definierte Rolle anzuhängen. Wenn eine Rolle bereits einen Benutzer hat, wird diese vorausgefüllt, kann aber vor dem Versand des Dokuments geändert werden." + }, + "add-recipients": "Empfänger hinzufügen", + "loading-mssg": "Das könnte etwas Zeit in Anspruch nehmen", + "send-mail": "E-Mail senden", + "signature-field-widget": "Für jeden Benutzer muss mindestens ein Signaturfeld hinzugefügt werden. Sie haben keine Signaturfelder für {{signersName}} hinzugefügt", + "placeholder-alert-1": "Bitte stellen Sie sicher, dass für alle Empfänger mindestens ein Signatur-Widget hinzugefügt wurde.", + "placeholder-alert-2": "Bitte bestätigen Sie, dass Sie das Textfeld ausgefüllt haben.", + "placeholder-alert-3": "Sind Sie sicher, dass Sie dieses Dokument zur Unterzeichnung senden möchten?", + "placeholder-alert-4": "Sie haben erfolgreich E-Mails an alle Empfänger gesendet!", + "placeholder-mail-alert": "Sie haben erfolgreich eine E-Mail an {{name}} gesendet. Die nachfolgenden Unterzeichner erhalten eine E-Mail, sobald {{name}} das Dokument unterzeichnet.", + "placeholder-alert-5": "Möchten Sie die Dokumente jetzt unterschreiben?", + "placeholder-alert-6": "Bitte richten Sie den E-Mail-Adapter ein, um E-Mails zu senden!", + "placeholder-alert-7": "Bitte wählen Sie einen Unterzeichner aus, um Platzhalter hinzuzufügen!", + "email-subject": "E-Mail-Betreff", + "email-body": "E-Mail-Inhalt", + "email-placeholder": "E-Mail-Text eingeben", + "reset-to-default": "Auf Standard zurücksetzen", + "cutomize-email": "E-Mail anpassen", + "upgrade-to-customize-email": "Upgrade, um E-Mails anzupassen", + "sign-url": "Signatur-URL", + "mails-sent": "E-Mails gesendet", + "mail-not-delivered": "E-Mail nicht zugestellt", + "document-alert": "Dokument-Warnung", + "owner-subscription-expired": "Das Abonnement des Besitzers ist abgelaufen.", + "subscription-expired": "Abonnement abgelaufen", + "alert-message": "Warnmeldung", + "document-decline": "Dokument ablehnen", + "decline-alert-1": "Sind Sie sicher, dass Sie dieses Dokument ablehnen möchten?", + "decline-alert-2": "Sie haben dieses Dokument abgelehnt!", + "decline-alert-3": "Sie können dieses Dokument nicht unterschreiben, da es abgelehnt/widerrufen wurde.", + "sign here": "Hier unterschreiben", + "guest-email-alert": "Ein Verifizierungscode wurde an Ihre E-Mail gesendet", + "get-otp-alert": "Sie erhalten einen Verifizierungscode per E-Mail", + "user-already-exist": "Benutzer existiert bereits.", + "server-error": "Interner Serverfehler!", + "fill-required-details!": "Bitte füllen Sie die erforderlichen Felder aus!", + "sign-up-form": "Registrierungsformular", + "sign-up": "Registrieren", + "folder-already-exist!": "Ordner existiert bereits!", + "please-select-position!": "Bitte Position auswählen!", + "default-sign-alert": "Möchten Sie wirklich alle angeforderten {{widgetsType}}-Widgets automatisch anmelden?", + "Your-Signature": "Ihre Unterschrift", + "auto-sign-all": "Alles automatisch unterschreiben", + "generating-certificate": "Zertifikat wird generiert", + "pdf-download": "PDF herunterladen", + "generate-certificate-alert": "Ihr Abschlusszertifikat wird gerade generiert. Bitte warten Sie einen Moment. Wenn der Download nicht bald beginnt, klicken Sie erneut auf die Schaltfläche.", + "generate-certificate-err": "Wir haben derzeit ein Problem mit der Zertifikatserstellung. Bitte versuchen Sie es später erneut", + "folder-already-exist": "Ordner existiert bereits!", + "folder-created-successfully": "Ordner erfolgreich erstellt!", + "fill-folder-name": "Bitte Ordnernamen eingeben", + "already-exists-this-username": "Ein Benutzer mit diesem Benutzernamen existiert bereits!", + "verification-code-sent": "Verifizierungs-Mail wurde an Ihre E-Mail gesendet!", + "registered-user-successfully": "Benutzer erfolgreich registriert.", + "role-not-found": "Rolle nicht gefunden.", + "do-not-access": "Sie haben keinen Zugriff. Bitte kontaktieren Sie den Administrator.", + "add-admin": "Admin hinzufügen", + "opensign-setup": "OpenSign-Einrichtung", + "join-discord": "Treten Sie unserem Discord-Server bei", + "admin-already-exist": "Admin existiert bereits.", + "password-update-alert-1": "Passwort erfolgreich aktualisiert.", + "password-update-alert-2": "Ihr aktuelles Passwort fehlt oder ist falsch.", + "password-update-alert-3": "Ihr aktuelles Passwort fehlt oder ist falsch.", + "password-update-alert-4": "Ihr Passwort und die Bestätigung stimmen nicht überein.", + "current-password": "Aktuelles Passwort", + "new-password": "Neues Passwort", + "confirm-password": "Passwort bestätigen", + "file-alert-1": "Die ausgewählte Datei ist zu groß. Bitte wählen Sie eine Datei, die kleiner als", + "file-alert-2": "Bitte Datei auswählen.", + "file-alert-3": "Bitte warten, während das Dokument hochgeladen wird.", + "enter-pdf-password": "PDF-Passwort eingeben", + "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!", + "enter-otp-alert": "Bitte OTP eingeben!", + "get-verification-code": "Verifizierungscode erhalten", + "get-verification-code-2": "Sie erhalten einen Verifizierungscode per E-Mail", + "enter-verification-code": "Verifizierungscode eingeben", + "provide-your-details": "Bitte geben Sie Ihre Daten an", + "provide-email": "Bitte E-Mail angeben.", + "additional-info": "Zusätzliche Informationen", + "signature-saved-alert": "Unterschrift erfolgreich gespeichert.", + "saved-successfully": "Erfolgreich gespeichert.", + "fill-field": "Bitte dieses Feld ausfüllen", + "error-template": "Fehler: Vorlage nicht gefunden!", + "error": "Fehler", + "invalid-document": "Fehler: ungültiges Dokument!", + "document-not-found": "Dokument nicht gefunden!", + "document-signed-alert-1": "Sie haben das Dokument erfolgreich unterzeichnet. Sie können eine Kopie des teilweise unterzeichneten Dokuments herunterladen oder drucken. Eine Kopie des digital signierten Dokuments und des Abschlusszertifikats wird per E-Mail an den Besitzer und alle Unterzeichner gesendet, sobald alle unterzeichnet haben.", + "encrypted-pdf-not-support": "Derzeit werden verschlüsselte PDF-Dateien nicht unterstützt.", + "document-signed-alert-4": "Herzlichen Glückwunsch! 🎉 Dieses Dokument wurde erfolgreich von allen Teilnehmern unterzeichnet!", + "document-signed-alert-5": "Dieses Dokument wurde von allen Unterzeichnern unterzeichnet.", + "document-signed-alert-6": "Dieses Dokument wurde von einem oder mehreren Empfängern abgelehnt.", + "document-signed-alert-7": "Dieses Dokument ist nicht mehr verfügbar.", + "document-signed-alert-8": "Das Dokument wurde bereits zum Unterzeichnen versendet.", + "yet-to-sign": "Noch zu unterzeichnen", + "validation-alert-1": "Die Eingabe erfüllt nicht die Kriterien des regulären Ausdrucks.", + "account-already-exists": "Konto existiert bereits!", + "choose-password": "Passwort wählen", + "enter-password": "Passwort eingeben", + "sure": "Sicher", + "subscribed-alert": "Sie haben diesen Plan bereits abonniert!", + "monthly": "Monatlich", + "yearly-upto": "Jährlich (bis zu 66 % Rabatt)", + "billed-yearly": "Jährlich abgerechnet", + "billed-monthly": "Monatlich abgerechnet", + "plansubscription-1": "Hosten Sie es selbst kostenlos", + "visit-github": "Besuchen Sie Github", + "user-already-exist-name": "Ein Benutzer mit diesem Benutzernamen existiert bereits!", + "do-not-access-contact-admin": "Sie haben keinen Zugriff, bitte kontaktieren Sie den Administrator.", + "filed-required-correctly": "Bitte füllen Sie die erforderlichen Details korrekt aus.", + "admin-created": "Admin erstellt", + "invalid-masterkey": "Ungültiger Hauptschlüssel", + "opensign-Setup": "OpenSign-Einrichtung", + "master-key": "Hauptschlüssel", + "profile-update-alert": "Profil erfolgreich aktualisiert.", + "date": "Datum", + "report-not-found": "Bericht nicht gefunden", + "please-wait": "Bitte warten", + "select-foler": "Ordner auswählen", + "generated-on": "Erstellt am", + "text-field": "Textfeld", + "font-size": "Schriftgröße", + "widget-status": { + "Required": "Erforderlich", + "Optional": "Optional" + }, + "all-right": "Alle Rechte vorbehalten", + "version": "version", + "social-media": { + "github": "Github", + "linked-in": "LinkedIn", + "twitter": "Twitter", + "discord": "Discord" + }, + "tour-mssg": { + "home-layout-1": "Sie haben sich erfolgreich angemeldet! Werfen wir einen Blick darauf.", + "home-layout-2": "Um Dokumente zum Selbstunterzeichnen hochzuladen oder um Unterschriften anderer anzufordern, wählen Sie einfach die entsprechenden Schaltflächen.", + "home-layout-3": "Sie sind bereit, OpenSign zu verwenden! Wenn Sie Unterstützung benötigen, kontaktieren Sie uns gerne.", + "generate-token": "Jetzt upgraden, um ein Produktions-API-Token zu generieren.", + "opensign-drive-1": "Klicken Sie auf die Breadcrumb-Links, um einfach durch die Ordnerhierarchie zu navigieren und die Dokumente in jedem Ordner anzuzeigen.", + "opensign-drive-2": "Klicken Sie auf die Schaltfläche Hinzufügen, um einen neuen Ordner oder ein neues Dokument zu erstellen.", + "opensign-drive-3": "Sortieren Sie Ihre Dokumente nach Datum oder Name über dieses Menü.", + "opensign-drive-4": "Klicken Sie auf dieses Menü, um die Dokumente in der Listenansicht anzuzeigen.", + "opensign-drive-5": "Die Dokumentenliste wird entsprechend der ausgewählten Sortieroption angezeigt. Symbole neben jedem Dokument zeigen den aktuellen Status an.", + "opensign-drive-6": "Klicken Sie mit der rechten Maustaste auf ein Dokument, um Optionen wie Herunterladen, Umbenennen, Verschieben und Löschen anzuzeigen. Klicken Sie auf das Dokument, um es zu öffnen.", + "opensign-drive-7": "Klicken Sie mit der rechten Maustaste auf einen Ordner, um Optionen anzuzeigen. Wählen Sie Umbenennen, um den Namen des Ordners zu ändern, oder klicken Sie auf den Ordner, um seinen Inhalt anzuzeigen.", + "pdf-request-file-1": "Liste der Unterzeichner, die das Dokument noch unterschreiben müssen.", + "pdf-request-file-2": "Klicken Sie auf die Platzhalter im Dokument, um zu unterschreiben. Sie sehen dann Optionen, Ihre Unterschrift zu zeichnen, einzugeben oder ein Bild hochzuladen.", + "pdf-request-file-3": "Klicken Sie auf die Schaltflächen Ablehnen oder Fertig stellen, um durch Ihr Dokument zu navigieren. Verwenden Sie das Auslassungsmenü für weitere Optionen, einschließlich der Schaltfläche Herunterladen.", + "pdf-request-file-4": "Liste der Unterzeichner, die das Dokument bereits unterzeichnet haben.", + "pdf-request-file-5": "Sie können auf Automatisch alles unterschreiben klicken, um automatisch an allen für Sie vorgesehenen Stellen zu unterschreiben. Überprüfen Sie das Dokument gründlich, bevor Sie diese Schaltfläche verwenden.", + "pdf-request-file-6": "Bitte füllen Sie die Felder auf Seite {{pagenumbers}} aus, die alle zur einfachen Identifizierung in der gleichen Farbe hervorgehoben sind.", + "placeholder-sign-1": "Wählen Sie einen Empfänger aus dieser Liste aus, um einen Platzhalter hinzuzufügen, an dem er unterschreiben soll. Der Platzhalter wird in der gleichen Farbe wie der Empfängername angezeigt, sobald Sie ihn im Dokument ablegen.", + "placeholder-sign-2": "Das Klicken auf die Schaltfläche 'Empfänger hinzufügen' ermöglicht es Ihnen, weitere Unterzeichner hinzuzufügen.", + "placeholder-sign-3": "Klicken Sie auf diese Schaltfläche, um weitere Empfänger/Unterzeichner zum Dokument hinzuzufügen.", + "placeholder-sign-4": "Ziehen Sie ein Feld in das Dokument oder klicken Sie darauf, um es hinzuzufügen.", + "placeholder-sign-5": "Der PDF-Inhaltsbereich zeigt bereits die vorhandenen Platzhalter der Vorlage an. Diese Platzhalter entsprechen der Farbe des Empfängernamens, um sie leicht erkennbar zu machen.", + "placeholder-sign-6": "Mit einem Klick auf 'Weiter' wird das Dokument gespeichert. Im nächsten Schritt können Sie die E-Mails, die an die Empfänger versendet werden sollen, anpassen oder die Signaturlinks kopieren und diese selbst mit den Empfängern teilen.", + "redirect": "Klicken Sie auf die Schaltfläche 'Verwenden', um ein neues Dokument aus einer bestehenden Vorlage zu erstellen.", + "bulksend": "Um schnell mehrere Dokumente mithilfe einer vorhandenen Vorlage zu versenden, indem Sie einfach die E-Mail-Adressen der Empfänger erstellen, klicken Sie auf die Schaltfläche ‚Massenversand‘", + "option": "Dieses Menü zeigt weitere Optionen wie Bearbeiten und Löschen. Verwenden Sie die Schaltfläche 'Bearbeiten', um Unterzeichnerrollen hinzuzufügen, Felder zu ändern und Ihre Vorlage zu aktualisieren. Änderungen gelten für alle zukünftigen Dokumente, die aus dieser Vorlage erstellt werden, wirken sich jedoch nicht auf vorhandene Dokumente aus. Verwenden Sie die Schaltfläche 'Löschen', um die Vorlage zu entfernen.", + "signyour-self-1": "Wählen und ziehen Sie Ihre bevorzugten Widgets auf das PDF, um Ihr Dokument vor dem Unterzeichnen anzupassen. Wählen Sie die perfekten Stellen für jede Anpassung aus, um das Dokument an Ihre Bedürfnisse anzupassen.", + "signyour-self-2": "Ziehen Sie ein Widget irgendwo in diesen Bereich. Sie können es später in der Größe ändern und verschieben.", + "template-placeholder-1": "Das Klicken auf die Schaltfläche 'Rolle hinzufügen' ermöglicht es Ihnen, verschiedene Unterzeichnerrollen hinzuzufügen. Sie können Benutzern diese Rollen in den folgenden Schritten zuweisen.", + "template-placeholder-2": "Sobald Rollen hinzugefügt wurden, wählen Sie eine Rolle aus der Liste aus, um einen Platzhalter hinzuzufügen, an dem der Unterzeichner unterschreiben soll. Der Platzhalter wird in der gleichen Farbe wie der Rollenname angezeigt, sobald Sie ihn im Dokument ablegen.", + "template-placeholder-3": "Ziehen Sie ein Feld in das Dokument oder klicken Sie darauf, um es hinzuzufügen.", + "template-placeholder-4": "Ziehen Sie den Platzhalter für eine Rolle an eine beliebige Stelle im Dokument. Denken Sie daran, dass er in der gleichen Farbe wie der Name des Empfängers angezeigt wird, um die Zuordnung zu erleichtern.", + "template-placeholder-5": "Das Klicken auf 'Weiter' speichert die aktuelle Vorlage. Nach dem Speichern werden Sie gefragt, ob Sie ein neues Dokument aus dieser Vorlage erstellen möchten.", + "webhook-1": "Jetzt upgraden, um einen Webhook einzurichten", + "Need your Signature": "Das Klicken auf diese Karte führt Sie zu einer Liste der Dokumente, die auf Ihre Überprüfung warten.", + "Out for signatures": "Das Klicken auf diese Karte führt Sie zu einer Liste der Dokumente, die auf eine Signatur warten.", + "Recent signature requests": "Dies ist eine Liste von Dokumenten, die auf Ihre Unterschrift warten.", + "Recently sent for signatures": "Dies ist eine Liste von Dokumenten, die Sie an andere Parteien zur Unterschrift gesendet haben.", + "Drafts": "Dies sind Dokumente, die Sie begonnen, aber noch nicht zum Versenden fertiggestellt haben.", + "public-template": "Dieses Video zeigt Ihnen, wie Sie Ihr personalisiertes öffentliches Profil einrichten, z. B. 'https://opensign.me/Ihr-Benutzername'. Sie lernen auch, wie Sie Ihren Slogan anpassen und Ihre Vorlagen für öffentliche Signaturen verfügbar machen.", + "allowModify-widgets": "Sie können jedes dieser Felder per Drag & Drop in das Dokument ziehen, zusätzlich zu den Feldern, die der Dokumentersteller bereits für Sie festgelegt hat." + }, + "enter-email-plaholder": "E-Mail-Adresse hinzufügen und Enter drücken", + "success-email-alert": "E-Mail erfolgreich gesendet!", + "expired-doc-title": "Abgelaufenes Dokument", + "expired-on-mssg": "Dieses Dokument ist am {{expiredDate}} abgelaufen und nicht mehr verfügbar zum Unterzeichnen.", + "signature-validate-alert": "Bitte bestätigen Sie, dass Sie mindestens {{minRequiredCount}} Kontrollkästchen ausgewählt haben.", + "signature-validate-alert-2": "Stellen Sie sicher, dass dieses Feld korrekt ausgefüllt ist und alle Anforderungen erfüllt.", + "remaing-users": "Verbleibende Benutzer", + "Role": "Rolle", + "additional-users": "Bitte kaufen Sie zusätzliche Benutzer hinzu.", + "Quantity-of-users": "Anzahl der Benutzer", + "Price": "Preis", + "Total-price-for-next-time": "Gesamtpreis für das nächste Mal", + "Proceed": "Fortfahren", + "Select": "Auswählen", + "Add-seats": "Plätze hinzufügen", + "user-name-exist": "Benutzername existiert bereits", + "format": "Format", + "select-date-format": "Wählen Sie ein Datumsformat", + "quantity-of-credits": "Anzahl der Premium-Credits", + "remaining-credits": "Verfügbare Premium-Credits:", + "remaining-credits-help": "Verwenden Sie Premium-Credits für API-Dokumentensignaturen, Massenversand oder die Einbettung der OpenSign-Integration auf Ihrer Website. Sie haben {{allowedcredits}} enthaltene Credits und {{addoncredits}} zusätzlich gekaufte Credits übrig.", + "additional-credits": "Bitte kaufen Sie Premium-Credits hinzu", + "quota-err-quicksend": "Kontingent erreicht, Sie haben nicht genügend Credits.", + "buy-credits": "Premium-Credits kaufen", + "rotate-right": "Nach rechts drehen", + "rotate-left": "Nach links drehen", + "rotate-alert-mssg": "Alle Widgets auf dieser Seite gehen verloren. Sind Sie sicher, dass Sie fortfahren möchten?", + "templateid": "Vorlagen-ID", + "bulk-send-subcription-alert": "Bitte upgraden Sie auf den Professional- oder Team-Plan, um den Massenversand zu nutzen.", + "generate-test-token": "Test-Token generieren", + "regenerate-test-token": "Test-Token neu generieren", + "help-test-token": "Dieses Token kann verwendet werden, um die APIs unter https://sandbox.opensignlabs.com/api/v1 zu testen und unbegrenzt Dokumente zu signieren. Beachten Sie, dass die Sandbox-API Ihre Dokumente mit selbstsignierten Zertifikaten signiert, die möglicherweise von Adobe nicht als gültig erkannt werden. Nach Abschluss Ihrer Tests können Sie auf einen unserer kostenpflichtigen Pläne upgraden, um ein Produktionstoken zu generieren.", + "help-api-token": "Dieses Token kann verwendet werden, um auf die Produktions-APIs unter {{origin}}/api/v1 zuzugreifen. Es kann nur auf einem unserer kostenpflichtigen Pläne generiert werden.", + "reason": "Grund", + "decline-by": "Abgelehnt/widerrufen von", + "document-declined": "Dokument abgelehnt", + "public-template-mssg-1": "Um OpenSign in Ihr React- oder Next.js-Projekt zu integrieren, führen Sie einfach den folgenden Befehl aus:", + "public-template-mssg-2": "Stellen Sie sicher, dass npm oder yarn in Ihrem Projekt eingerichtet ist. Wenn Sie Yarn verwenden, können Sie npm install durch yarn add @opensign/react ersetzen.", + "public-template-mssg-3": "Benötigen Sie weitere Details oder Beispiele?", + "public-template-mssg-4": "Besuchen Sie die", + "public-template-mssg-5": " npm für die neuesten Updates, detaillierte Dokumentationen und Versionshistorie.", + "public-template-mssg-6": "Bevor Sie diesen Code-Schnipsel verwenden können, müssen Sie diese Vorlage öffentlich machen.", + "public-template-mssg-7": "Bevor Sie einen öffentlichen Link generieren können, müssen Sie diese Vorlage öffentlich machen.", + "here": "Hier", + "copy-code": "KOPIEREN", + "copied-code": "KOPIERT", + "Installation": "Installation", + "Usage": "Nutzung", + "insufficient-credits": "Nicht genügend Signatur-Credits", + "insufficient-credits-mssg": "Der Besitzer dieses Dokuments verfügt derzeit nicht über die notwendigen OpenSign-Credits, damit Sie unterzeichnen können. Bitte wenden Sie sich an den Besitzer, wenn Sie weitere Informationen benötigen.", + "angular-npm-mssg-1": "Um OpenSign in Ihr Angular-Projekt zu integrieren, führen Sie einfach den folgenden Befehl aus:", + "quota-mail-info-head": "Monatliches Limit für Signaturanfragen per E-Mail", + "quota-mail-info": "Sie können bis zu 15 Signaturanfragen per E-Mail pro Monat senden. Jetzt upgraden, um unbegrenzt Signaturanfragen direkt zu senden.", + "quota-mail-reset": "Ihre Credits für Signaturanfragen per E-Mail werden zurückgesetzt am", + "quota-mail": "Sie haben Ihr monatliches Limit von 15 Signaturanfragen per E-Mail erreicht. Jetzt upgraden, um weiter E-Mails direkt zu senden.", + "quota-mail-tip": "Tipp: Sie können weiterhin <1>unbegrenzt Dokumente signieren, indem Sie die Signaturanfragelinks manuell teilen.", + "quota-mail-head": "Kontingent erreicht", + "unauthorized-modal": "Sie haben keine Berechtigung, diese Aktion auszuführen. Bitte kontaktieren Sie {{adminEmail}}.", + "sent-this-month": "Diesen Monat gesendet", + "available-seats": "Verfügbare Plätze", + "buy-users": "Weitere Benutzer kaufen", + "isenable-otp": "OTP-Verifizierung aktivieren", + "isenable-otp-help": { + "p1": "Möchten Sie den Verifizierungsprozess mit einem einmaligen Passwort (OTP) aktivieren?", + "p2": "Wenn Sie diese Option auswählen, wird die OTP-Verifizierung aktiviert. Benutzer erhalten einen Verifizierungscode per E-Mail, den sie eingeben müssen, um das Dokument zu unterzeichnen.", + "p3": "Wenn Sie diese Option deaktivieren, können Benutzer das Dokument direkt ohne zusätzliche Schritte unterzeichnen.", + "p4": "Bitte wählen Sie die Option, die am besten zu Ihren Anforderungen für die Dokumentenunterzeichnung passt." + }, + "advanced-options": "Erweiterte Optionen", + "hide-advanced-options": "Erweiterte Optionen ausblenden", + "download-files": "Dateien herunterladen", + "download-pdf": "PDF herunterladen", + "pdf-certificate": "PDF + Zertifikat herunterladen", + "document-logs": "Dokumentenprotokolle", + "server-down": "Verbindung zum OpenSign-Server nicht möglich. Wenn Sie OpenSign selbst hosten, stellen Sie bitte sicher, dass alle Schritte in der Dokumentation korrekt befolgt wurden. Wenn Sie OpenSign lokal ausführen, verwenden Sie möglicherweise eine falsche Portnummer.", + "admin-exists": "Admin existiert bereits. Bitte melden Sie sich mit den Admin-Anmeldedaten an, um Benutzer zu verwalten.", + "enable-tour": "Tour aktivieren", + "istourenabled-help": { + "p1": "Dies aktiviert eine geführte Tour für Unterzeichner, die während des Unterzeichnungsprozesses Anweisungen gibt.", + "p2": "Dies deaktiviert die geführte Tour, wodurch ein schneller, ununterbrochener Unterzeichnungsprozess gewährleistet wird.", + "p3": "Tipp: Wenn Ihre Unterzeichner mit OpenSign vertraut sind und es häufig verwenden, können Sie die geführte Tour deaktivieren, um ein nahtloses Erlebnis zu gewährleisten. Wählen Sie die Option, die am besten zu Ihren Anforderungen passt." + }, + "form-title-1": "Dokumentenfluss-Einstellungen", + "form-title-2": "Sicherheitseinstellungen", + "public-tour-message": "Die Vorlage muss öffentlich sein, bevor Sie einen teilbaren Link generieren können.", + "add-user-template": "Sie müssen eine Rolle hinzufügen, bevor Sie Felder dafür hinzufügen können.", + "pdf-uncompatible": "Dieses PDF ist nicht kompatibel mit OpenSign. Bitte kontaktieren Sie ", + "text-field-tour": "Felder vom Typ 'Text' müssen im Voraus ausgefüllt werden, bevor das Dokument versendet wird. Wenn Sie möchten, dass die Unterzeichner Eingaben machen, verwenden Sie das Feld 'Texteingabe'.", + "attach-signer-tour": "Sie müssen einen Unterzeichner jeder Rolle zuweisen. Dies können Sie durch Klicken auf dieses Symbol tun. Sobald Sie einen Unterzeichner auswählen, wird er allen Feldern der zugehörigen Rolle zugewiesen, die in derselben Farbe erscheinen.", + "allowed-signature-types": "Erlaubte Signaturtypen", + "at-least-one-signature-type": "Mindestens ein Signaturtyp sollte aktiviert sein.", + "expect-default-one-signature-type": "Bitte aktivieren Sie einen zusätzlichen Signaturtyp neben dem Standard.", + "add-signer-note": "Hinweis - Dieser Kontakt wird zu Ihrer Kontaktliste hinzugefügt", + "allowed-signature-types-help": { + "p1": "Diese Signaturpräferenz steuert, welche Signaturoptionen Ihren Unterzeichnern zur Verfügung stehen. Nur die Signaturtypen, die Sie auswählen, werden im Signatur-Widget angezeigt, wenn ein Dokument unterzeichnet wird. Wenn Sie beispielsweise nur die Option 'Zeichnen' in den Einstellungen auswählen, sieht Ihr Unterzeichner nur die Option 'Zeichnen' im Signatur-Widget, während die anderen drei Optionen nicht verfügbar sind.", + "l1": "Erstellen Sie eine handschriftliche Signatur direkt auf dem Bildschirm mit Ihrem Finger oder einem Stift.", + "l2": "Geben Sie Ihren Namen ein und wählen Sie aus verschiedenen Schriftarten, um eine Signatur zu erstellen.", + "l3": "Laden Sie eine vorhandene digitale Version Ihrer Signatur hoch.", + "l4": "Verwenden Sie einen voreingestellten Signaturstil, der unter 'Meine Signatur' in Ihren Einstellungen gespeichert ist." + }, + "notify-on-signatures": "Benachrichtigen bei Signaturen", + "notify-on-signatures-help": { + "p1": "Der Ersteller des Dokuments erhält eine E-Mail-Benachrichtigung, sobald ein Unterzeichner das Dokument unterschreibt.", + "note": "Hinweis: Unabhängig von dieser Einstellung wird immer eine Abschluss-E-Mail mit dem signierten Dokument und dem Abschlusszertifikat im Anhang an alle Unterzeichner und den Dokumentbesitzer gesendet." + }, + "expiry-date": "Ablaufdatum", + "expiry-date-updated": "Das Ablaufdatum wurde erfolgreich auf {{newexpirydate}} verlängert.", + "expiry-date-error": "Bitte geben Sie ein neues Ablaufdatum an, das nach dem aktuellen liegt.", + "duplicate-template-alert": "Sind Sie sicher, dass Sie eine Kopie dieser Vorlage erstellen möchten?", + "duplicate-template-created": "Kopie der Vorlage erfolgreich erstellt.", + "delete-page": "Seite löschen", + "merge-pdf": "PDFs zusammenführen", + "add-pages": "Seiten hinzufügen", + "delete-alert": "Einzelne Seite kann nicht gelöscht werden.", + "delete-alert-2": "Sind Sie sicher, dass Sie diese Seite löschen möchten?", + "delete-note": "Hinweis: Sobald Sie diese Seite löschen, kann dies nicht rückgängig gemacht werden.", + "Rotation-alert": "Seite drehen", + "bulk-import": "Massenimport", + "contacts-file": "Kontaktdatei (xlsx, csv)", + "100-records-only": "Derzeit können Sie nur bis zu 100 Datensätze importieren.", + "csv-excel-support-only": "Laden Sie eine Datei in einem der folgenden Formate hoch: CSV, XLSX oder XLS.", + "contact-imported": "{{imported}} Kontakte wurden importiert. {{failed}} Kontakte konnten nicht importiert werden.", + "invalid-data": "Ungültige Daten", + "delete-folder-alert": "Sind Sie sicher, dass Sie diesen Ordner löschen möchten?", + "delete-folder-alert-1": "Löschen nicht möglich: Der Ordner muss leer sein.", + "defaultSign-alert": "{{widgetsType}} Widgets sind nicht für die automatische Signatur verfügbar.", + "embed-heading": "OpenSign-Vorlagen einbetten", + "public-template-edit-title": "Öffentliche Vorlage bearbeiten", + "public-template-edit-mssg": "Eine öffentliche Vorlage können Sie nicht direkt bearbeiten. Um Änderungen vorzunehmen, wird die Vorlage auf privat gesetzt und Sie müssen sie anschließend wieder öffentlich machen. Möchten Sie fortfahren?", + "agree-p1": "Ich bestätige, dass ich die ", + "agree-p2": "Offenlegung elektronischer Aufzeichnungen und Signaturen", + "agree-p3": "gelesen und verstanden habe und der Verwendung elektronischer Aufzeichnungen und Signaturen zustimme.", + "agrre-button": "Zustimmen & Fortfahren", + "term-cond-title": "Allgemeine Geschäftsbedingungen", + "term-cond-h": "OFFENLEGUNG ELEKTRONISCHER AUFZEICHNUNGEN UND SIGNATUREN", + "term-cond-p1": "Diese Offenlegung elektronischer Aufzeichnungen und Signaturen ('Offenlegung') ist eine Vereinbarung zwischen dem Dokumentersteller ('Sender') und dem Unterzeichner ('Ihnen'), bereitgestellt über die OpenSign-Plattform ('Plattform'). Durch das Signieren von Dokumenten über OpenSign stimmen Sie den in dieser Offenlegung beschriebenen Bedingungen zu. Bitte lesen Sie sie sorgfältig durch, bevor Sie fortfahren.", + "term-cond-h1": "1. Zweck und Geltungsbereich", + "term-cond-p2": "Diese Offenlegung regelt die Nutzung elektronischer Aufzeichnungen und Signaturen für Dokumente, die vom Sender bereitgestellt und von Ihnen über die OpenSign-Plattform unterzeichnet werden. Mit Ihrer Zustimmung erkennen Sie an, dass:", + "term-cond-p3": "Sie Dokumente elektronisch über OpenSign empfangen und unterzeichnen werden.", + "term-cond-p4": "Ihre elektronische Signatur rechtlich bindend und einer handschriftlichen Signatur gleichgestellt ist.", + "term-cond-h2": "2. Zustimmung zur Nutzung elektronischer Aufzeichnungen und Signaturen", + "term-cond-p5": "Durch Ihre Zustimmung zu dieser Offenlegung:", + "term-cond-p6": "Erklären Sie sich einverstanden, elektronisch mit dem Sender über OpenSign zu kommunizieren, und verstehen, dass diese Zustimmung gültig ist, bis sie widerrufen wird.", + "term-cond-p7": "Stimmen Sie zu, Dokumente über OpenSign elektronisch zu prüfen, zu unterzeichnen und zurückzusenden.", + "term-cond-p8": "Diese Zustimmung gilt nur für die spezifischen Dokumente, die vom Sender bereitgestellt werden.", + "term-cond-h3": "3. Recht auf Widerruf der Zustimmung", + "term-cond-p9": "Sie haben das Recht, Ihre Zustimmung zur Nutzung elektronischer Aufzeichnungen und Unterschriften zu widerrufen, indem Sie:", + "term-cond-p10": "Den Absender direkt über die in seiner Kommunikation angegebenen Kontaktdaten kontaktieren.", + "term-cond-p11": "Den Absender vor Abschluss des Unterschriftsprozesses benachrichtigen.", + "term-cond-h4": "4. Hardware- und Softwareanforderungen", + "term-cond-p12": "Um Dokumente mit OpenSign zu unterzeichnen, benötigen Sie:", + "term-cond-p13": "Ein Gerät mit Internetzugang.", + "term-cond-p14": "Einen kompatiblen Webbrowser mit aktiviertem JavaScript.", + "term-cond-p15": "Ein E-Mail-Konto, um Benachrichtigungen und unterzeichnete Dokumente zu erhalten.", + "term-cond-p16": "Wenn sich diese Anforderungen ändern, werden Sie vom Absender oder OpenSign über die Aktualisierungen informiert.", + "term-cond-h5": "5. Aufbewahrung von Unterlagen und Anforderung von Papierkopien", + "term-cond-p17": "Sie sind dafür verantwortlich, sicherzustellen, dass Sie auf die elektronisch unterzeichneten Dokumente zugreifen und diese aufbewahren können. OpenSign stellt Tools zur Verfügung, mit denen Sie das unterzeichnete Dokument unmittelbar nach Abschluss des Unterzeichnungsprozesses herunterladen oder ausdrucken können.", + "term-cond-p18": "Wenn Sie eine Papierkopie eines elektronisch unterzeichneten Dokuments bevorzugen, können Sie diese direkt beim Absender anfordern. Der Absender kann eine angemessene Gebühr für die Bereitstellung von Papierkopien erheben, sofern dies nicht durch geltendes Recht verboten ist.", + "term-cond-h6": "6. Anerkennung und Zustimmung", + "term-cond-p19": "Durch das Fortfahren bestätigen Sie:", + "term-cond-p20": "Dass Sie in der Lage sind, elektronische Dokumente wie in dieser Offenlegung beschrieben zu öffnen und zu überprüfen.", + "term-cond-p21": "Der Nutzung elektronischer Aufzeichnungen und Unterschriften für die angegebenen Transaktionen mit dem Absender zuzustimmen.", + "term-cond-p22": "Zu verstehen, dass OpenSign eine Plattform zur Unterstützung der Transaktion ist und keine Partei der Vereinbarung ist.", + "term-cond-h7": "7. Rechtliche Wirkung", + "term-cond-p23": "Ihre durch OpenSign vermittelte elektronische Unterschrift:", + "term-cond-p24": "Entspricht den geltenden Gesetzen über elektronische Unterschriften, einschließlich, aber nicht beschränkt auf den E-SIGN Act in den Vereinigten Staaten, die EU-eIDAS-Verordnung und das indische Information Technology Act.", + "term-cond-p25": "Ist rechtlich bindend zwischen Ihnen und dem Absender für die unterzeichneten Dokumente.", + "term-cond-h8": "8. Plattformrolle und Haftungsbeschränkung", + "term-cond-p26": "OpenSign dient als Plattform zur Unterstützung elektronischer Transaktionen. Es ist nicht verantwortlich für den Inhalt, die Gültigkeit oder die Durchsetzbarkeit der vom Absender gesendeten Dokumente. Alle Streitigkeiten oder Probleme im Zusammenhang mit dem Dokument oder seiner Unterzeichnung müssen direkt zwischen Ihnen und dem Absender gelöst werden.", + "term-cond-h9": "9. Beendigung der Vereinbarung", + "term-cond-p27": "Ihre Zustimmung gilt nur für die aktuelle Transaktion, es sei denn, der Absender gibt etwas anderes an. OpenSign behält sich das Recht vor, den Zugriff auf seine Plattform bei Verstößen gegen die Nutzungsbedingungen oder Richtlinien zu beenden.", + "term-cond-p28": "Durch Auswahl von 'Ich stimme zu' bestätigen Sie, dass Sie die Bedingungen dieser Offenlegung über elektronische Aufzeichnungen und Unterschriften verstanden haben und diesen zustimmen sowie der elektronischen Unterzeichnung der vom Absender über OpenSign bereitgestellten Dokumente zustimmen.", + "term-cond-p29": "Wenn Sie Fragen zu dieser Offenlegung haben, kontaktieren Sie den Absender direkt. Für technischen Support mit OpenSign besuchen Sie", + "term-cond-p30": "oder senden Sie eine E-Mail an", + "js-snippet-msg": "Um OpenSign-Vorlagen in Ihre HTML-Websites oder Landingpages zu integrieren, können Sie den folgenden Code verwenden:", + "js-snippet-msg-1": "Die TemplateId erhalten Sie von der", + "js-snippet-msg-2": "Vorlagen verwalten", + "js-snippet-msg-3": "Seite.", + "agrrement-alert": "Um fortzufahren, müssen Sie der Offenlegung über elektronische Aufzeichnungen und Unterschriften zustimmen.", + "webhook-already-exists": "Die URL existiert bereits! Bitte versuchen Sie eine andere.", + "webhook-must-be-secure": "Die Webhook-URL muss sicher sein und https:// verwenden.", + "provide-test-token": "Bitte generieren Sie einen API-Test-Token.", + "invalid-redirect-url": "Bitte geben Sie eine gültige Weiterleitungs-URL an.", + "auto-sign-mssg": "Alles automatisch unterzeichnen", + "already-exist-signer": "Der ausgewählte Unterzeichner ist bereits in der Empfängerliste vorhanden.", + "change-signer": "Unterzeichner ändern", + "signyour-self-button": "Verwenden Sie diese Option, um das Dokument selbst zu unterschreiben, ohne andere hinzuzufügen.", + "requestsign-button": "Verwenden Sie diese Option, um Unterschriften von anderen und sich selbst anzufordern.", + "signyour-self-description": "Verwenden Sie dieses Formular, um das Dokument selbst zu unterschreiben, ohne andere hinzuzufügen.", + "requestsign-description": "Verwenden Sie dieses Formular, um Unterschriften von anderen und sich selbst anzufordern.", + "template-form-description": "Verwenden Sie dieses Formular, um wiederverwendbare Vorlagen für Ihre Dokumente zu erstellen.", + "allow-modify": "Änderungen erlauben", + "allow-modify-help": { + "p1": "Möchten Sie während des Unterzeichnungsprozesses Änderungen am Dokument erlauben?", + "p2": "Durch Auswahl dieser Option können Unterzeichner zusätzliche Elemente wie Unterschriften, Initialen, Stempel oder Texte zu den vorhandenen Widgets hinzufügen.", + "p3": "Durch Auswahl dieser Option wird verhindert, dass Unterzeichner während des Unterzeichnungsprozesses Ergänzungen zum Dokument vornehmen." + }, + "signature-setting": "Signatur-Einstellungen", + "activation-key": "Aktivierungsschlüssel", + "paid-selfhost-help": "Bitte kontaktieren Sie OpenSign für weitere Informationen unter ", + "remaining-credits-selfhost-help": "Verwenden Sie Premium-Credits für API-Dokumentensignaturen, den Massenversand und die OpenSign-Integration auf Ihrer Website. Sie haben {{allowedcredits}} enthaltene Credits und {{addoncredits}} zusätzlich gekaufte Credits übrig.", + "signature-type": "Ihre Signatur", + "initial-type": "Ihre Initialen", + "redirect-url": "Weiterleitungs-URL", + "bulk-send": "Massenversand", + "select-timezone": "Wählen Sie Ihre Zeitzone", + "current-time": "Aktuelle Uhrzeit", + "email-help": "Aus Sicherheitsgründen dürfen Sie die E-Mail-Adresse nicht ändern. Bitte erstellen Sie ein weiteres kostenloses Konto mit der neuen E-Mail-Adresse.", + "doc-sent": "Dokument erfolgreich gesendet.", + "no-signer": "Entfernen", + "and": "und", + "make-public": "Öffentlich machen", + "general": "Allgemein", + "request-email": "Anfrage-E-Mail", + "completion-email": "Abschluss-E-Mail", + "variables-use": "Zu verwendende Variablen", + "send-to-sign": "hat Sie gebeten zu unterschreiben", + "use-template": "Vorlage verwenden", + "contact-already-exists": "Der Kontakt existiert bereits." +} diff --git a/apps/OpenSign/public/locales/en/translation.json b/apps/OpenSign/public/locales/en/translation.json index 40d56f9f4..63553ab2e 100644 --- a/apps/OpenSign/public/locales/en/translation.json +++ b/apps/OpenSign/public/locales/en/translation.json @@ -1,7 +1,7 @@ { "header-news": "New feature: Teams plan users can now integrate their own AWS S3 buckets for file storage", - "header-news-btn": "Setup Now", - "create-account": "Create Account", + "header-news-btn": "Setup now", + "create-account": "Create account", "login": "Login", "language": "Language", "name": "Name", @@ -12,7 +12,7 @@ "job-title": "Job title", "profile": "Profile", "log-out": "Log Out", - "is-email-verified": "Is Email verified", + "is-email-verified": "Is email verified", "public-profile": "Public profile", "tagline": "Tagline ", "has-requested-you-to-sign": "has requested you to sign", @@ -33,15 +33,15 @@ "action": "Action", "add": "Add", "add-new-folder": "Add a new folder", - "disable-documentId": "Disable DocumentId", + "disable-documentId": "Disable documentId", "edit": "Edit", - "change-password": "Change Password", + "change-password": "Change password", "save": "Save", "cancel": "Cancel", "upgrade-now": "Upgrade now", "upgrade-to": "Upgrade to", "plan": "Plan", - "subscribe-card-teamplan":"Unlock the full power of collaboration! Create unlimited organizations, teams, and hierarchies. Share templates seamlessly across teams and assign custom user roles. Elevate your workflow today!", + "subscribe-card-teamplan": "Unlock the full power of collaboration! Create unlimited organizations, teams, and hierarchies. Share templates seamlessly across teams and assign custom user roles. Elevate your workflow today!", "subscribe-card-plan": "Unlock premium features starting at just {{premiumPrice}}/month. Enjoy enhanced performance and only {{addonPrice}} per additional credit after your included premium credits.", "user-name-limit-char": "To have a username less than 8 character please subscribe", "tour-content": "Don't show this again", @@ -51,15 +51,15 @@ "docs": "Docs", "session-expired": "Your session has expired.", "public-profile-help": "This is your public URL. Copy or share it with the signer, and you will be able to see all your publicly set templates.", - "tagline-help": "This Tagline will appear on your OpenSign public profile for ex. https://opensign.me/alex", - "welcome": "Welcome Back!", + "tagline-help": "This tagline will appear on your OpenSign public profile for ex. https://opensign.me/alex", + "welcome": "Welcome back!", "Login-to-your-account": "Login to your account", "password": "Password", - "forgot-password": "Forgot Password?", + "forgot-password": "Forgot password?", "loading": "Loading...", "of": "of", "sign-SSO": "Sign in with SSO", - "login-page": "Login Page", + "login-page": "Login P+age", "or": "OR", "signup-page": "Signup page", "password-length": "Password should be 8 characters long", @@ -76,23 +76,25 @@ "Templates": "Templates", "Templates-Children": { "Create template": "Create template", - "Manage templates": "Manage templates" + "Manage templates": "Manage templates", + "Embedding": "Embedding" }, - "OpenSign™ Drive": "OpenSign™ Drive", + "OpenSign™ Drive": "OpenSign™ drive", "Reports": "Reports", - "Reports-Children": { + "Documents": "Documents", + "Documents-Children": { "Need your sign": "Need your sign", - "In Progress": "In Progress", + "In Progress": "In progress", "Completed": "Completed", "Drafts": "Drafts", "Declined": "Declined", - "Expired": "Expired", - "Contactbook": "Contactbook" + "Expired": "Expired" }, + "Contactbook": "Contactbook", "Settings": "Settings", "Settings-Children": { - "My Signature": "My Signature", - "API Token": "API Token", + "My Signature": "My signature", + "API Token": "API token", "Webhook": "Webhook", "Preferences": "Preferences", "Teams": "Teams", @@ -101,16 +103,16 @@ } }, "dashboard-card": { - "Need your Signature": "Need your Signature", - "Out for signatures": "Out for Signatures" + "Need your Signature": "Need your signature", + "Out for signatures": "Out for signatures" }, "report-name": { - "Draft Documents": "Draft Documents", + "Draft Documents": "Draft documents", "Need your sign": "Need your sign", "In-progress documents": "In-progress documents", - "Completed Documents": "Completed Documents", - "Declined Documents": "Declined Documents", - "Expired Documents": "Expired Documents", + "Completed Documents": "Completed documents", + "Declined Documents": "Declined documents", + "Expired Documents": "Expired documents", "Recently sent for signatures": "Recently sent for signatures", "Recent signature requests": "Recent signature requests", "Drafts": "Drafts", @@ -123,6 +125,7 @@ "sign": "sign", "Sign": "SIGN", "Resend": "Resend", + "Rename": "Rename", "Revoke": "Revoke", "Delete": "Delete", "Use": "Use", @@ -133,9 +136,11 @@ "View": "View", "option": "Option", "Embed": "Embed", - "Copy TemplateId":"Copy TemplateId", - "Copy Public URL":"Copy Public URL", - "extend-expiry-date": "Extend expiry date" + "Copy TemplateId": "Copy TemplateId", + "Copy Public URL": "Copy public URL", + "extend-expiry-date": "Extend expiry date", + "Duplicate Template": "Duplicate template", + "Duplicate": "Duplicate" }, "report-heading": { "Sr.No": "Sr.No", @@ -148,16 +153,16 @@ "Note": "Note", "Folder": "Folder", "Reason": "Reason", - "Parent Team": "Parent Team", + "Parent Team": "Parent team", "Active": "Active", "Role": "Role", "Team": "Team", "Name": "Name", "Status": "Status", - "created-date": "Created Date", + "created-date": "Created date", "Type": "Type", "Logs": "Logs", - "Expiry-date": "Expiry Date" + "Expiry-date": "Expiry date" }, "report-help": { "Draft Documents": "These are documents you have started but have not finalized for sending.", @@ -170,18 +175,18 @@ "Templates": "This is a list of templates that are available to you for creating documents. You can click the 'use' button to create a new document using a template, modify the document & add signers in the next step." }, "form-name": { - "Sign Yourself": "Sign Yourself", - "Request Signatures": "Request Signatures", - "New Template": "New Template" + "Sign Yourself": "Sign yourself", + "Request Signatures": "Request signatures", + "New Template": "New template" }, "file-type": "pdf, png, jpg, jpeg", "docx": "docx", "file-selected": "file selected", - "template-title": "Template Title", - "document-title": "Document Title", + "template-title": "Template title", + "document-title": "Document title", "description": "Description", - "time-to-complete": "Time To Complete (Days)", - "send-in-order": "Send In Order", + "time-to-complete": "Time to complete (Days)", + "send-in-order": "Send in order", "send-in-order-help": { "p1": "Choose how you want the signing requests to be sent to the document signers:", "p2": "Selecting this option will send the signing request to the first signer initially. Once the first signer completes their part, the next signer in the sequence will receive the request. This process continues until all signers have signed the document. This method ensures that the document is signed in a specific order.", @@ -192,49 +197,50 @@ "auto-reminder": "Auto reminder", "remind-once": " Remind once in every (Days)", "next": "Next", - "select-folder": "Select Folder", - "OpenSign-drive": "OpenSign™ Drive", + "select-folder": "Select folder", + "OpenSign-drive": "OpenSign™ drive", "drive-document-status": { "Completed": "Completed", "Declined": "Declined", "Draft": "Draft", "Expired": "Expired", - "In Progress": "In Progress" + "In Progress": "In progress" }, "select-folder-help": "If you do not select a folder, your signed document will be saved in the Main OpenSign drive folder.", "no-data": "No data found", - "save-here": "Save Here", + "save-here": "Save here", "back": "Back", "add-folder": "Add folder", - "create-folder": "Create Folder", - "parent-folder": "Parent Folder", + "create-folder": "Create folder", + "parent-folder": "Parent folder", "create": "Create", "signers": "Signers", "signers-help": "Begin typing a contact's name to see suggested signers from your saved contacts or add new ones. Arrange the signing order by adding signers in the desired sequence. Use the '+' button to include signers and the 'x' to remove them. Each signer will receive an email prompt to sign the document in the order listed.", + "bcc-help": "Start typing a contact's name to see suggestions from your saved contacts or add new ones. Use the '+' button to add a user and the 'x' to remove them. The selected user's email will be added as a Bcc (blind carbon copy). Each user will receive an email notification once the document is completed.", "add-signer": "Add Signer", "contact-not-found": "Contact not found", - "add-yourself": "Add Yourself", + "add-yourself": "Add yourself", "submit": "Submit", "reset": "Reset", - "my-signature": "My Signature", + "my-signature": "My signature", "signature": "Signature", "upload-image": " Upload image", "clear": "Clear", "upload-signature/Image": "Please upload signature/Image", "initials": "Initials", "API": "API", - "api-token": "API Token", - "regenerate-token": "Regenerate Live Token", - "generate-token": "Generate Live Token", - "view-docs": "View Docs", + "api-token": "API token", + "regenerate-token": "Regenerate live token", + "generate-token": "Generate live token", + "view-docs": "View docs", "generate-token-alert": "Are you sure you want to regenerate token it will expire old token?", "yes": "Yes", "copied": "Copied", "something-went-wrong-mssg": "Something went wrong, please try again later.", "token-generated": "Token generated successfully.", "webhook": "Webhook", - "update-webhook": "Update Webhook", - "add-webhook": "Add Webhook", + "update-webhook": "Update webhook", + "add-webhook": "Add webhook", "webhook-added": "Webhook added successfully.", "team-disabled": "Team disabled", "Team enabled": "Team enabled", @@ -242,20 +248,20 @@ "disable": "disable", "enable": "enable", "this-team": " this team?", - "edit-team": "Edit Team", - "name-of-team": "Name of Team", + "edit-team": "Edit team", + "name-of-team": "Name of team", "prev": "Prev", - "no-data-avaliable": "No Data Available", - "add-team": "Add Team", - "page-not-found": "Page Not Found", + "no-data-avaliable": "No data available", + "add-team": "Add team", + "page-not-found": "Page not found", "users-from-teams": "users from Teams", "user-status": "User status", "activate": "activate", "deactivate": "deactivate", "this-user": " this user", - "delete-user": "Delete User", + "delete-user": "Delete user", "delete": "delete", - "add-user": "Add User", + "add-user": "Add user", "password-generateed": "Password will only be generated once; make sure to copy it.", "Team status": "Team status", "user-deactivated": "User deactivated.", @@ -269,15 +275,15 @@ "make-template-private-alert": "Are you sure you want to make this template private? This will remove it from your public profile.", "public-role": "Public role", "public-url": "Public profile", - "embed-template": "Embed Template", + "embed-template": "Embed template", "public-url-copy": "Here’s your public URL: ", - "public-url-copy-mssg":"Copy it or share it with the signer, and you will be able to see all your publicly set templates.", - "add-public-url-alert": "Please complete your OpenSign public profile setup. Once done, you’ll be able to make templates public. This process only needs to be completed once.", + "public-url-copy-mssg": "Copy it or share it with the signer, and you will be able to see all your publicly set templates.", + "add-public-url-alert": "You can generate your OpenSign public profile", "share-with-alert": "You cannot share a template if any roles already have contacts assigned. Please remove all contact assignments from the roles before sharing the template.", "share-with": "Share with", "team-not-found": "Team not found", "roles": "Roles", - "delete-document": "Delete Document", + "delete-document": "Delete document", "delete-document-alert": "Are you sure you want to delete this document?", "quick-send": "Quick send", "add-new": "Add new", @@ -290,11 +296,12 @@ "copy": "Copy", "revoke-document": "Revoke document", "revoke-document-alert": "Are you sure you want to revoke this document?", - "resend-mail": "Resend Mail", + "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}}.", "subject": "Subject", "body": "Body", - "add-contact": "Add Contact", + "add-contact": "Add contact", + "edit-contact": "Edit contact", "add-signer-alert": "Contact already exist! Please select it from ‘Signers’ dropdown", "record-delete-alert": "Record deleted successfully!", "record-revoke-alert": "Record revoked successfully!", @@ -319,11 +326,11 @@ "verify": "Verify", "verify-email-1": "Verify email", "resend": "Resend", - "contact-details": "Contact Details", + "contact-details": "Contact details", "verify-email": "Please verify your email !", "send-otp": " Send OTP", "otp-placeholder": "Enter verification code received over email", - "loading-doc": "Loading Document..", + "loading-doc": "Loading document..", "widgets-name": { "signature": "signature", "stamp": "stamp", @@ -351,7 +358,7 @@ "decline": "Decline", "finish": "Finish", "mail": "Mail", - "sign-now": "Sign Now", + "sign-now": "Sign now", "successfully-signed": "Successfully signed!", "email-mssg": " Recipients added here will get a copy of the signed document.", "email-error-1": " please provide correct email address", @@ -367,11 +374,11 @@ "black": "black", "yellow": "yellow" }, - "my-initials": "My Initials", + "my-initials": "My initials", "upload": "Upload", "initial-teb": "Initials", "signature-tab": "Signature", - "your-signature": "Your signature", + "initial-alert": "My initial not found", "copy-title": "Copy widget to", "contact-delete-alert": "Are you sure you want to delete this contact?", "reset-password-alert-1": "Reset password link has been sent to your email id", @@ -404,21 +411,20 @@ "encrypted-pdf-alert": "Currently encrypted pdf files are not supported.", "encrypted-pdf-alert-1": "PFX file password is invalid.", "user-not-exist": "User does not exist", - "template-signature-field": "Please add at least one signature field for all roles.", "template-role-alert": "Please add roles first", - "create-document": "Create Document", - "template-created-alert": "Do you want to create a document using the template you just created ?", + "create-document": "Create document", + "template-created-alert": "What would you like to do with the template you just created? ", "signers-alert": "signers alert", "template-creation-alert-1": "Please select signer for add placeholder!", "ok": "Ok", "radio-group": "Radio group", "dropdown-options": "Dropdown options", - "add-role": "Add Role", + "add-role": "Add role", "role-ex": " e.g: Customer, Hr, Director, Manager, Student, etc", - "add/choose-signer": "Add/Choose Signer", + "add/choose-signer": "Add/Choose signer", "choose-from-contacts": "Choose from contacts", "select-signer": " Please select signer", - "edit-template": "Edit Template", + "edit-template": "Edit template", "widget-info": "Widget info", "validation": "Validation", "invalid-default-value": "invalid default value", @@ -435,23 +441,25 @@ "add-recipients": "Add recipients", "loading-mssg": "This might take some time", "send-mail": "Send Mail", + "signature-field-widget": "A minimum of one signature field must be added for each user. You have not added signature fields for {{signersName}}", "placeholder-alert-1": "Please ensure there's at least one signature widget added for all recipients.", "placeholder-alert-2": "Please confirm that you have filled the text field.", "placeholder-alert-3": " Are you sure you want to send out this document for signatures?", "placeholder-alert-4": "You have successfully sent mails to all recipients!", - "placeholder-alert-5": "Do you want to sign documents right now ?", + "placeholder-mail-alert": "You have successfully sent email to {{name}}. Subsequent signers will get email(s) once {{name}} signs the document", + "placeholder-alert-5": "Do you want to sign the document right now?", "placeholder-alert-6": "Please setup mail adapter to send mail!", "placeholder-alert-7": "Please select signer for add placeholder!", "email-subject": "email subject", "email-body": "email body", "email-placeholder": "add body of email", "reset-to-default": "Reset to default", - "cutomize-email": "Cutomize Email", + "cutomize-email": "Cutomize email", "upgrade-to-customize-email": "Upgrade to customize Email", "sign-url": "Sign url", - "mails-sent": "Mails sent", + "mails-sent": "Mails Sent", "mail-not-delivered": "Mail not delivered", - "document-alert": "Document Alert", + "document-alert": "Document alert", "owner-subscription-expired": "Owner's subscription has expired.", "subscription-expired": "Subscription Expired", "alert-message": "Alert message", @@ -469,12 +477,13 @@ "sign-up": "Sign up", "folder-already-exist!": "folder already exist!", "please-select-position!": "please select position!", - "default-sign-alert": "Are you sure you want to auto sign at requested all locations?", - "Your-Signature": "Your Signature", - "auto-sign-all": "Auto Sign All", + "default-sign-alert": "Are you sure you want to auto-sign all requested {{widgetsType}} widgets?", + "Your-Signature": "Your signature", + "auto-sign-all": "Auto sign all", "generating-certificate": "Generating certificate", - "pdf-download": "PDF Download", + "pdf-download": "PDF download", "generate-certificate-alert": " Your completion certificate is being generated. Please wait momentarily. If the download doesn't start shortly, click the button again.", + "generate-certificate-err": "We are currently experiencing an issue with certificate generation. Please try again later.", "folder-already-exist": "Folder already exist!", "folder-created-successfully": "Folder created successfully!", "fill-folder-name": "Please fill folder name", @@ -484,32 +493,33 @@ "role-not-found": "Role not found.", "do-not-access": "You don't have access, please contact the admin.", "add-admin": "Add admin", - "opensign-setup": "OpenSign Setup", + "opensign-setup": "OpenSign setup", "join-discord": "Join our discord server", "admin-already-exist": "Admin already exist.", "password-update-alert-1": "Password updated successfully.", "password-update-alert-2": "Your current password is missing or incorrect.", "password-update-alert-3": "Your current password is missing or incorrect.", "password-update-alert-4": "Your password and confirmation password do not match.", - "current-password": "Current Password", - "new-password": "New Password", - "confirm-password": "Confirm Password", + "current-password": "Current password", + "new-password": "New password", + "confirm-password": "Confirm password", "file-alert-1": "The selected file size is too large. Please select a file less than", "file-alert-2": "Please select file.", "file-alert-3": "Please wait while the document is being uploaded.", - "enter-pdf-password": "Enter Pdf Password", + "enter-pdf-password": "Enter Pdf password", "correct-password": "Please provide correct password", "decrypting-pdf": " Decrypting pdf please wait...", - "invalid-otp": "Invalid Otp", + "invalid-otp": "Invalid otp", "user-not-found": "User not found!", - "enter-otp-alert": "Please Enter OTP!", + "enter-otp-alert": "Please enter OTP!", "get-verification-code": "Get verification code", "get-verification-code-2": "You will get a verification code via Email", - "enter-verification-code": "Enter Verification Code", + "enter-verification-code": "Enter verification code", "provide-your-details": "Provide your details", "provide-email": "Please provide email.", - "additional-info": "Additional Info", + "additional-info": "Additional info", "signature-saved-alert": "Signature saved successfully.", + "saved-successfully": "Saved successfully.", "fill-field": "Please fill out this field", "error-template": "Error: Template not found!", "error": "Error", @@ -525,8 +535,8 @@ "yet-to-sign": "Yet to sign", "validation-alert-1": "The input does not meet the criteria set by the regular expression.", "account-already-exists": "Account already exists!", - "choose-password": "Choose Password", - "enter-password": "Enter Password", + "choose-password": "Choose password", + "enter-password": "Enter password", "sure": "sure", "subscribed-alert": "You have already subscribed to plan!", "monthly": "Monthly", @@ -540,21 +550,21 @@ "filed-required-correctly": "Please fill required details correctly.", "admin-created": "Admin created", "invalid-masterkey": "Invalid masterkey", - "opensign-Setup": "OpenSign Setup", + "opensign-Setup": "OpenSign setup", "master-key": " Master key", "profile-update-alert": "Profile updated successfully.", "date": "Date", - "report-not-found": "Report Not Found", + "report-not-found": "Report not found", "please-wait": "please wait", - "select-foler": "Select Folder", - "generated-on": "Generated On", + "select-foler": "Select folder", + "generated-on": "Generated on", "text-field": "Text field", "font-size": "Font size", "widget-status": { "Required": "Required", "Optional": "Optional" }, - "all-right": "All Rights Reserved", + "all-right": "All rights reserved", "version": "version", "social-media": { "github": "Github", @@ -576,18 +586,19 @@ "opensign-drive-7": "Right-click on any folder to see options. Choose ‘Rename’ to change the folder’s name or click on the folder to navigate through its contents.", "pdf-request-file-1": "List of signers who still need to sign the document .", "pdf-request-file-2": "Click any of the placeholders appearing on the document to sign. You will then see options to draw your signature, type it, or upload an image .", - "pdf-request-file-3": "Click the Back, Decline, or Finish buttons to navigate your document. Use the ellipsis menu for additional options, including the Download button .", + "pdf-request-file-3": "Click Decline, or Finish buttons to navigate your document. Use the ellipsis menu for additional options, including the Download button .", "pdf-request-file-4": "List of signers who have already signed the document .", "pdf-request-file-5": "You can click 'Auto Sign All' to automatically sign at all the locations meant to be signed by you. Make sure that you review the document properly before you click this button .", + "pdf-request-file-6": "Please complete the fields on page number {{pagenumbers}}, all highlighted in the same color for easy identification.", "placeholder-sign-1": "Select a recipient from this list to add a place-holder where he is supposed to sign.The placeholder will appear in the same colour as the recipient name once you drop it on the document.", "placeholder-sign-2": "Clicking 'Add recipients' button will allow you to add more signers.", "placeholder-sign-3": "Click this button to add more recipients/signers to the document.", "placeholder-sign-4": "Drag or click on a field to add it to the document.", "placeholder-sign-5": "The PDF content area already displays the template's existing placeholders. For your convenience, these placeholders will match the color of the recipient's name, making them easily identifiable.", - "placeholder-sign-6": "Clicking 'Send' will save the document. In the next step you can customize the emails to be sent out to the recipients or copy the signing links and share those with the recipients yourself.", + "placeholder-sign-6": "Clicking 'Next' will save the document. In the next step you can customize the emails to be sent out to the recipients or copy the signing links and share those with the recipients yourself.", "report-1": "Click the 'Add' button to create a new template. Templates are reusable documents designed to quickly generate new documents with the same structure and varying signers. For example, an HR template for onboarding could have predefined roles like ‘HR Manager’ and ‘New Employee’. Each time you use the template, you can assign the ‘New Employee’ role to different incoming staff members, while the ‘HR Manager’ role remains constant, facilitating a seamless onboarding process for each recruit. ", "redirect": "Click the 'Use' button to create a new document from an existing template.", - "bulksend": "To quickly create and send multiple documents using an existing template, click the 'Quick Send' button.", + "bulksend": "To quickly send multiple documents using an existing template by just creating the recipient email addresses, click the 'Bulk Send' button.", "option": "This menu reveals more options such as Edit & Delete. Use the 'Edit' button to add signer roles, modify fields, and update your template. Changes will apply to all future documents created from this template but won’t affect existing documents.Use the Delete button you can delete template. ", "signyour-self-1": "Select and drag your preferred widgets onto the PDF to customize your document before signing. Choose the perfect spots for each modification to tailor the document to your needs.", "signyour-self-2": "Drag and drop anywhere in this area. You can resize and move it later.", @@ -602,11 +613,12 @@ "Recent signature requests": "This is a list of documents that are waiting for your signature.", "Recently sent for signatures": "This is a list of documents you've sent to other parties for signature.", "Drafts": "This are documents you have started but have not finalized for sending.", - "public-template": "This video demonstrates how to set up your personalized public profile, such as ‘https://opensign.me/your-username’. You’ll also learn how to customize your tagline and make your templates available for public signing." - }, + "public-template": "This video demonstrates how to set up your personalized public profile, such as ‘https://opensign.me/your-username’. You’ll also learn how to customize your tagline and make your templates available for public signing.", + "allowModify-widgets": "You can drag and drop any of these fields onto the document, in addition to the fields already designated for you by the document creator." + }, "enter-email-plaholder": "Add an email address and hit enter", "success-email-alert": "Email sent successfully!", - "expired-doc-title": "Expired Document", + "expired-doc-title": "Expired document", "expired-on-mssg": "This document expired on {{expiredDate}} and is no longer available to sign.", "signature-validate-alert": "Please confirm that you have selected at least {{minRequiredCount}} checkboxes.", "signature-validate-alert-2": "Ensure this field is accurately filled and meets all requirements.", @@ -618,51 +630,53 @@ "Total-price-for-next-time": "Total price for next time", "Proceed": "Proceed", "Select": "Select", - "Add-seats": "Add Seats", + "Add-seats": "Add seats", "user-name-exist": "user name already exist", "format": "format", "select-date-format": "Select a date format", "quantity-of-credits": "Quantity of premium credits", "remaining-credits": "Premium credits available:", - "remaining-credits-help":"Use premium credits for API document signing, bulk sending, or embedding OpenSign integration on your website. You have {{allowedcredits}} included credits and {{addoncredits}} additional purchased credits remaining.", + "remaining-credits-help": "Use premium credits for API document signing, bulk sending, or embedding OpenSign integration on your website. You have {{allowedcredits}} included credits and {{addoncredits}} additional purchased credits remaining.", "additional-credits": "Please purchase premium credits", - "quota-err-quicksend": "Quota Reached, You don't have enough credits.", - "buy-credits": "Buy Premium Credits", - "rotate-right":"Rotate right", - "rotate-left":"Rotate left", - "rotate-alert-mssg":"All widgets on this page will be lost. Are you sure you want to proceed?", - "templateid":"Template-Id", - "bulk-send-subcription-alert":"Please upgrade to Professional or Team plan to use bulk send.", - "generate-test-token":"Generate Test Token", - "regenerate-test-token":"Regenerate Test Token", - "help-test-token":"This token can be used to test the APIs at the https://sandbox.opensignlabs.com/api/v1 endpoint, allowing you to conduct unlimited document signatures. Please note that the sandbox API will sign your documents with self-signed certificates, which may not be recognized as valid by Adobe. Once you’ve completed your testing, you can upgrade to one of our paid plans to generate a production token.", - "help-api-token":"This token can be used to access the production APIs at the {{origin}}/api/v1 endpoint. It can only be generated on one of our paid plans.", - "reason":"Reason", - "decline-by":"Declined/revoked by", + "quota-err-quicksend": "Quota reached, you don't have enough credits.", + "buy-credits": "Buy premium credits", + "rotate-right": "Rotate right", + "rotate-left": "Rotate left", + "rotate-alert-mssg": "All widgets on this page will be lost. Are you sure you want to proceed?", + "templateid": "Template-Id", + "bulk-send-subcription-alert": "Please upgrade to Professional or Team plan to use bulk send.", + "generate-test-token": "Generate test token", + "regenerate-test-token": "Regenerate test token", + "help-test-token": "This token can be used to test the APIs at the https://sandbox.opensignlabs.com/api/v1 endpoint, allowing you to conduct unlimited document signatures. Please note that the sandbox API will sign your documents with self-signed certificates, which may not be recognized as valid by Adobe. Once you’ve completed your testing, you can upgrade to one of our paid plans to generate a production token.", + "help-api-token": "This token can be used to access the production APIs at the {{origin}}/api/v1 endpoint. It can only be generated on one of our paid plans.", + "reason": "Reason", + "decline-by": "Declined/revoked by", "document-declined": "Document declined", - "public-template-mssg-1":"To integrate OpenSign into your React or Next.js project, simply run the following command:", - "public-template-mssg-2" :"Ensure you have npm or yarn set up in your project. If you’re using Yarn, you can replace npm install with yarn add @opensign/react.", - "public-template-mssg-3" :"Need more details or examples?", + "public-template-mssg-1": "To integrate OpenSign into your React or Next.js project, simply run the following command:", + "public-template-mssg-2": "Ensure you have npm or yarn set up in your project. If you’re using Yarn, you can replace npm install with yarn add @opensign/react.", + "public-template-mssg-3": "Need more details or examples?", "public-template-mssg-4": "Visit the", "public-template-mssg-5": " npm for the latest updates, detailed documentation, and version history.", - "public-template-mssg-6" :"Before you can use this code snippet, you must make this template public.", - "copy-code":"COPY", - "copied-code":"COPIED", - "Installation":"Installation", - "Usage" :"Usage", - "insufficient-credits":"Insufficient Signing Credits", - "insufficient-credits-mssg":"The owner of this document currently lacks the necessary OpenSign credits for you to sign. Please reach out to the owner if you require further details.", + "public-template-mssg-6": "Before you can use this code snippet, you must make this template public.", + "public-template-mssg-7": "Before you can generate a public link you must make this template public.", + "here": "here", + "copy-code": "COPY", + "copied-code": "COPIED", + "Installation": "Installation", + "Usage": "Usage", + "insufficient-credits": "Insufficient signing credits", + "insufficient-credits-mssg": "The owner of this document currently lacks the necessary OpenSign credits for you to sign. Please reach out to the owner if you require further details.", "angular-npm-mssg-1": "To integrate OpenSign into your Angular project, simply run the following command:", - "quota-mail-info-head":"Monthly request signatures email limit", + "quota-mail-info-head": "Monthly request signatures email limit", "quota-mail-info": "You can send upto 15 signature request emails every month. Upgrade now to send unlimited signing requests directly.", "quota-mail-reset": "Your signature request email credits will be reset on", "quota-mail": "You've reached your limit of 15 signature request emails for this month. Upgrade now to continue sending emails directly.", - "quota-mail-tip":"Tip: You can still sign <1>unlimited documents by manually sharing the signing request links.", - "quota-mail-head":"Quota Reached", - "unauthorized-modal":"You don't have permission to perform this action, please contact {{adminEmail}}.", - "sent-this-month":"Sent this month", - "available-seats":"Available seats", - "buy-users":"Buy more users", + "quota-mail-tip": "Tip: You can still sign <1>unlimited documents by manually sharing the signing request links.", + "quota-mail-head": "Quota reached", + "unauthorized-modal": "You don't have permission to perform this action, please contact {{adminEmail}}.", + "sent-this-month": "Sent this month", + "available-seats": "Available seats", + "buy-users": "Buy more users", "isenable-otp": "Enable OTP verification", "isenable-otp-help": { "p1": "Would you like to enable the verification process using a one-time password (OTP)?", @@ -670,31 +684,31 @@ "p3": "Selecting this option will disable OTP verification, allowing users to sign the document directly without additional steps.", "p4": "Please choose the option that best suits your document signing requirements." }, - "advanced-options":"Advanced options", - "hide-advanced-options":"Hide Advanced options", - "download-files":"Download files", - "download-pdf":"Download Pdf", - "pdf-certificate":"Download Pdf + Certificate", - "document-logs":"Document logs", + "advanced-options": "Advanced options", + "hide-advanced-options": "Hide advanced options", + "download-files": "Download files", + "download-pdf": "Download pdf", + "pdf-certificate": "Download pdf + Certificate", + "document-logs": "Document logs", "server-down": "Unable to connect to the OpenSign server. If you are self-hosting OpenSign, please ensure that all the steps in the documentation have been followed correctly. If you're running OpenSign locally, you might be accessing it through an incorrect port number.", "admin-exists": "Admin already exists. Please login to the application using admin credentials in order to manage users.", - "enable-tour":"Enable Tour", - "istourenabled-help":{ - "p1":"This will enable a guided tour for signers, providing instructions during the signing process.", - "p2":"This will disable the guided tour, ensuring a faster, uninterrupted signing experience.", - "p3":"Tip: If your signers are familiar with OpenSign and frequently use it, you may want to disable the guided tour for a more seamless experience. Choose the option that best fits your document signing needs." - }, - "form-title-1":"Document Flow Setting", - "form-title-2":"Security Settings", - "public-tour-message":"The template needs to be public before you can generate a shareable link.", + "enable-tour": "Enable tour", + "istourenabled-help": { + "p1": "This will enable a guided tour for signers, providing instructions during the signing process.", + "p2": "This will disable the guided tour, ensuring a faster, uninterrupted signing experience.", + "p3": "Tip: If your signers are familiar with OpenSign and frequently use it, you may want to disable the guided tour for a more seamless experience. Choose the option that best fits your document signing needs." + }, + "form-title-1": "Document flow setting", + "form-title-2": "Security settings", + "public-tour-message": "The template needs to be public before you can generate a shareable link.", "add-user-template": "You need to add a role before you can add fields for it.", "pdf-uncompatible": "This pdf is not compatible with opensign, please contact ", - "text-field-tour":"Fields of type 'Text' must be filled in advance before the document is sent. If you need the signers to provide input, use the 'Text Input' field instead.", - "attach-signer-tour":"You need to attach a Signer to every role. You can do that by clicking this icon. Once you select a Signer it will be attached to all the fields associated with that role which appear in the same colour.", + "text-field-tour": "Fields of type 'Text' must be filled in advance before the document is sent. If you need the signers to provide input, use the 'Text Input' field instead.", + "attach-signer-tour": "You need to attach a Signer to every role. You can do that by clicking this icon. Once you select a Signer it will be attached to all the fields associated with that role which appear in the same colour.", "allowed-signature-types": "Allowed signature types", "at-least-one-signature-type": "At least one signature type should be enabled.", - "expect-default-one-more-signature-type": "Please enable one additional signature type apart from the default.", - "add-signer-note": "Note - This contact will be added to your contact list", + "expect-default-one-signature-type": "Please enable one additional signature type apart from the default.", + "add-signer-note": "Note - This contact will be saved to your Contacts", "allowed-signature-types-help": { "p1": "This signature preference controls which signing options are available to your signers. Only the signature types you select will appear in the signature widget when a document is signed. For example, if you choose only the 'Draw' option in preferences, your signer will see only the 'Draw' option in the signature widget, while the other three options will not be available.", "l1": "Create a handwritten signature directly on the screen using your finger or a stylus.", @@ -705,9 +719,120 @@ "notify-on-signatures": "Notify on signatures", "notify-on-signatures-help": { "p1": "The document creator will receive an email notification whenever a signer signs the document.", - "note": "Note: Notification email will not be sent for the last signer, as the document creator will receive a completion email instead." + "note": "Note: Regardless of this setting, a completion email with the signed document and completion certificate attached is always sent to all signers and the document owner." }, - "expiry-date": "Expiry Date", + "expiry-date": "Expiry date", "expiry-date-updated": "The expiry date has been successfully extended to {{newexpirydate}}", - "expiry-date-error": "Please provide a new expiry date that is later than the current one" + "expiry-date-error": "Please provide a new expiry date that is later than the current one", + "duplicate-template-alert": "Are you sure you want to create a duplicate of this template?", + "duplicate-template-created": "Duplicate template created successfully.", + "delete-page": "Delete page", + "merge-pdf": "Merge pdf", + "add-pages": "Add pages", + "delete-alert": "Can not delete single page", + "delete-alert-2": "Are you sure you want to delete this page?", + "delete-note": "Note: Once you delete this page, you cannot undo.", + "Rotation-alert": "Rotate page", + "bulk-import": "Bulk import", + "contacts-file": "Contacts file (xlsx, csv)", + "100-records-only": "Currently you can only import up to 100 records.", + "csv-excel-support-only": "Upload a file in one of the following formats: CSV, XLSX or XLS.", + "contact-imported": "{{imported}} contacts were imported. {{failed}} contacts failed to import.", + "invalid-data": "Invalid data", + "delete-folder-alert": "Are you sure you want to delete this Folder ?", + "delete-folder-alert-1": "Unable to delete: The folder must be empty.", + "defaultSign-alert": "{{widgetsType}} widgets are not available for auto sign.", + "embed-heading": "Embed OpenSign Templates", + "public-template-edit-title": "Edit Public Template", + "public-template-edit-mssg": "You cannot edit a public template directly. To make changes, the template will be set to private, and you'll need to make it public again afterward. Do you want to continue?", + "agree-p1": "I confirm that I have read and understood the ", + "agree-p2": "Electronic Record and Signature Disclosure", + "agree-p3": "and consent to use electronic records and signatures.", + "agrre-button": " Agree & Continue", + "term-cond-title": "Terms and conditions", + "term-cond-h": "ELECTRONIC RECORD AND SIGNATURE DISCLOSURE", + "term-cond-p1": "This Electronic Record and Signature Disclosure ('Disclosure') is an agreement between the Document Creator ('Sender') and the Signer ('You'), facilitated through the OpenSign platform ('Platform'). By signing documents via OpenSign, you agree to the terms outlined in this Disclosure. Please read it carefully before proceeding.", + "term-cond-h1": "1. Purpose and Scope", + "term-cond-p2": "This Disclosure governs the use of electronic records and signatures for documents sent by the Sender and signed by You through the OpenSign platform. By agreeing, You acknowledge that:", + "term-cond-p3": "You will receive and sign documents electronically via OpenSign.", + "term-cond-p4": "Your electronic signature is legally binding and equivalent to a handwritten signature.", + "term-cond-h2": "2. Consent to Use Electronic Records and Signatures", + "term-cond-p5": "By agreeing to this Disclosure:", + "term-cond-p6": "You consent to transact electronically with the Sender using OpenSign and understand that this consent is valid until withdrawn.", + "term-cond-p7": "You agree to review, sign, and return documents electronically using OpenSign.", + "term-cond-p8": "This consent applies only to the specific document(s) provided by the Sender.", + "term-cond-h3": "3. Right to Withdraw Consent", + "term-cond-p9": "You have the right to withdraw your consent to use electronic records and signatures by:", + "term-cond-p10": "Contacting the Sender directly using the contact information provided in their communication.", + "term-cond-p11": "Notifying the Sender before completing the signing process.", + "term-cond-h4": "4. Hardware and Software Requirements", + "term-cond-p12": "To sign documents using OpenSign, You must have:", + "term-cond-p13": "A device with internet access.", + "term-cond-p14": "A compatible web browser with JavaScript enabled.", + "term-cond-p15": "An email account to receive notifications and signed documents.", + "term-cond-p16": "If these requirements change, the Sender or OpenSign will notify You of the updates.", + "term-cond-h5": "5. Retention of Records and Request for Paper Copies", + "term-cond-p17": "You are responsible for ensuring You can access and retain the electronically signed document(s). OpenSign provides tools to download or print the signed document immediately after the signing process is complete.", + "term-cond-p18": "If You prefer a paper copy of any electronically signed document, You may request it directly from the Sender. The Sender may charge a reasonable fee for providing paper copies unless prohibited by applicable law.", + "term-cond-h6": "6. Acknowledgment and Agreement", + "term-cond-p19": "By proceeding, You:", + "term-cond-p20": "Confirm that You can access and review electronic documents as described in this Disclosure.", + "term-cond-p21": "Agree to use electronic records and signatures for the specified transaction(s) with the Sender.", + "term-cond-p22": "Understand that OpenSign is a platform facilitating the transaction and is not a party to the agreement.", + "term-cond-h7": "7. Legal Effect", + "term-cond-p23": "Your electronic signature facilitated through OpenSign:", + "term-cond-p24": "Complies with applicable electronic signature laws, including but not limited to the E-SIGN Act in the United States, the EU eIDAS Regulation, and India’s Information Technology Act.", + "term-cond-p25": "Is legally binding between You and the Sender for the signed document(s).", + "term-cond-h8": "8. Platform Role and Limitation of Liability", + "term-cond-p26": "OpenSign serves as a platform to facilitate electronic transactions. It is not responsible for the content, validity, or enforceability of the documents sent by the Sender. Any disputes or issues related to the document or its signing must be resolved directly between You and the Sender.", + "term-cond-h9": "9. Termination of Agreement", + "term-cond-p27": "Your consent applies only to the current transaction unless otherwise specified by the Sender. OpenSign reserves the right to terminate access to its platform for violations of its Terms of Service or policies.", + "term-cond-p28": "By selecting 'I Agree,' You confirm that You understand and agree to the terms of this Electronic Record and Signature Disclosure and consent to electronically sign the document(s) provided by the Sender through OpenSign.", + "term-cond-p29": "If You have questions about this Disclosure, contact the Sender directly. For technical support with OpenSign, visit", + "term-cond-p30": "or email", + "js-snippet-msg": "To integrate OpenSign Templates into your HTML websites or landing pages, you can use below code:", + "js-snippet-msg-1": "You can get the TemplateId from the", + "js-snippet-msg-2": "Manage Templates", + "js-snippet-msg-3": "page.", + "agrrement-alert": "To proceed, you must consent to the electronic record and signature disclosure.", + "webhook-already-exists": "The URL already exists! Please try a different one.", + "webhook-must-be-secure": "The webhook URL must be secure and use https://", + "provide-test-token": "Please generate api test token", + "invalid-redirect-url": "Please provide valid redirect url.", + "auto-sign-mssg": "Auto sign all", + "already-exist-signer": "The selected signer is already present", + "change-signer": "Change signer", + "signyour-self-button": "Use this option to sign the document yourself without adding others", + "requestsign-button": "Use this option to request signatures from others and yourself together.", + "signyour-self-description": "Use this form to sign the document yourself without adding others", + "requestsign-description": "Use this form to request signatures from others and yourself together.", + "template-form-description": "Use this form to create reusable templates for your documents.", + "allow-modify": " Allow modifications", + "allow-modify-help": { + "p1": "Do you want to allow modifications to the document during the signing process?", + "p2": "Selecting this option permits signers to add additional elements, such as signatures, initials, stamps, or text, on top of the existing widgets.", + "p3": "Selecting this option restricts signers from making any additions to the document during the signing process." + }, + "signature-setting": "Signature settings", + "activation-key": "Activation key", + "paid-selfhost-help": "Please contact to opensign for more info at ", + "remaining-credits-selfhost-help": "Use premium credits for API document signing, bulk sending OpenSign integration on your website. You have {{allowedcredits}} included credits and {{addoncredits}} additional purchased credits remaining.", + "signature-type": "Your signature", + "initial-type": "Your initials", + "redirect-url": "Redirect url", + "bulk-send": "Bulk send", + "select-timezone": "Select your Timezone", + "current-time": "Current time", + "email-help": "You are not allowed to change email address due to security reasons. Please create another free account using the new email address.", + "doc-sent": "Document sent successfully.", + "no-signer": "Remove", + "and": "and", + "make-public": "Make public", + "general": "General", + "request-email": "Request Email", + "completion-email": "Completion Email", + "variables-use": "Variables to use", + "send-to-sign": "has requested you to sign", + "use-template": "Use Template", + "contact-already-exists": "contact already exists." } diff --git a/apps/OpenSign/public/locales/es/translation.json b/apps/OpenSign/public/locales/es/translation.json index bb0ed8987..47956255c 100644 --- a/apps/OpenSign/public/locales/es/translation.json +++ b/apps/OpenSign/public/locales/es/translation.json @@ -76,19 +76,21 @@ "Templates": "Plantillas", "Templates-Children": { "Create template": "Crear plantilla", - "Manage templates": "Administrar plantillas" + "Manage templates": "Administrar plantillas", + "Embedding": "Incrustar" }, "OpenSign™ Drive": "OpenSign™ Drive", "Reports": "Reportes", - "Reports-Children": { + "Documents": "Documentos", + "Documents-Children": { "Need your sign": "Necesitan tu firma", "In Progress": "En progreso", "Completed": "Completado", "Drafts": "Borradores", "Declined": "Rechazados", - "Expired": "Expirados", - "Contactbook": "Agenda de contactos" + "Expired": "Expirados" }, + "Contactbook": "Agenda de contactos", "Settings": "Ajustes", "Settings-Children": { "My Signature": "Mi firma", @@ -123,6 +125,7 @@ "sign": "firmar", "Sign": "FIRMAR", "Resend": "Reenviar", + "Rename": "Renombrar", "Revoke": "Revocar", "Delete": "Eliminar", "Use": "Usar", @@ -135,7 +138,9 @@ "Embed": "Incrustar", "Copy TemplateId": "Copiar ID de plantilla", "Copy Public URL": "Copiar URL pública", - "extend-expiry-date": "Ampliar fecha de caducidad" + "extend-expiry-date": "Date d'expiration", + "Duplicate Template": "Plantilla duplicada", + "Duplicate": "Duplicada" }, "report-heading": { "Sr.No": "Nº", @@ -211,12 +216,14 @@ "create": "Crear", "signers": "Firmantes", "signers-help": "Empieza a escribir el nombre de un contacto para ver los firmantes sugeridos entre tus contactos guardados o añade otros nuevos. Organiza el orden de firma añadiendo firmantes en la secuencia deseada. Utiliza el botón «+» para añadir nuevos firmantes y la «X» para quitar todos. Cada firmante recibirá una solicitud por correo electrónico para que firme el documento según el orden indicado.", + "bcc-help": "Empieza a escribir el nombre de un contacto para ver sugerencias de tus contactos guardados o agregar nuevos. Usa el botón '+' para añadir un usuario y el botón 'x' para eliminarlo. El correo electrónico del usuario seleccionado se añadirá como Bcc (copia oculta). Cada usuario recibirá una notificación por correo electrónico una vez que el documento esté completado.", "add-signer": "Añadir firmante", "contact-not-found": "Contacto no encontrado", "add-yourself": "Añadirte a ti mismo", "submit": "Enviar", "reset": "Volver a empezar", "my-signature": "Mi firma", + "initial-alert": "Mi inicial no encontrada", "signature": "Firma", "upload-image": " Subir imagen", "clear": "Limpiar", @@ -272,7 +279,7 @@ "embed-template": "Insertar plantilla", "public-url-copy": "Aquí está tu URL pública: ", "public-url-copy-mssg": "Cópiala o compártela con el firmante y podrás ver todas tus plantillas públicas.", - "add-public-url-alert": "Por favor, completa la configuración de tu perfil público OpenSign. Una vez terminado, podrás crear plantillas públicas. Este proceso solo necesita ser completado una vez.", + "add-public-url-alert": "Puedes generar tu perfil público OpenSign", "share-with-alert": "No puedes compartir una plantilla si alguno de los roles ya tiene contactos asignados. Elimina todas las asignaciones de contactos de los roles antes de compartir la plantilla.", "share-with": "Compartir con", "team-not-found": "Equipo no encontrado", @@ -295,6 +302,7 @@ "subject": "Asunto", "body": "Cuerpo", "add-contact": "Agregar contacto", + "edit-contact": "Editar contacto", "add-signer-alert": "¡El contacto ya existe! Selecciónelo en el menú desplegable 'Firmantes'", "record-delete-alert": "¡Entrada eliminada exitosamente!", "record-revoke-alert": "¡Entrada revocada exitosamente!", @@ -404,10 +412,9 @@ "encrypted-pdf-alert": "Actualmente los archivos PDF encriptados no están soportados.", "encrypted-pdf-alert-1": "La contraseña del archivo PFX es inválida.", "user-not-exist": "El usuario no existe", - "template-signature-field": "Por favor, agrega al menos un campo de firma para todos los roles.", "template-role-alert": "Por favor, primero agrega roles", "create-document": "Crear documento", - "template-created-alert": "¿Quieres crear un documento usando la plantilla que acabas de crear?", + "template-created-alert": "¿Qué te gustaría hacer con la plantilla que acabas de crear?", "signers-alert": "alerta de firmantes", "template-creation-alert-1": "¡Por favor, selecciona un firmante para agregar un marcador de posición!", "ok": "OK", @@ -439,6 +446,7 @@ "placeholder-alert-2": "Por favor, confirma que hayas rellenado el campo de texto.", "placeholder-alert-3": " ¿En definitiva quieres enviar este documento para ser firmado?", "placeholder-alert-4": "¡Has enviado exitosamente correos a todos los destinatarios!", + "placeholder-mail-alert": "Has enviado un correo electrónico con éxito a {{name}}. Los siguientes firmantes recibirán un correo electrónico una vez que {{name}} firme el documento.", "placeholder-alert-5": "¿Quieres firmar documentos ahora mismo?", "placeholder-alert-6": "¡Por favor, configura el adaptador de correo para enviar correos!", "placeholder-alert-7": "¡Por favor, selecciona un firmante para agregar un marcador de posición!", @@ -469,12 +477,13 @@ "sign-up": "Registrarse", "folder-already-exist!": "¡la carpeta ya existe!", "please-select-position!": "¡por favor, selecciona una posición!", - "default-sign-alert": "¿En definitiva quieres firmar automáticamente en todos los lugares solicitados?", + "default-sign-alert": "¿Está seguro de que desea iniciar sesión automáticamente en todos los {{widgetsType}} widgets solicitados?", "Your-Signature": "Tu firma", "auto-sign-all": "Firmar todo automáticamente", "generating-certificate": "Generando certificado", "pdf-download": "Descargar PDF", "generate-certificate-alert": " Tu certificado de finalización se está generando. Por favor, espera un momento. Si la descarga no inicia pronto, presiona el botón otra vez.", + "generate-certificate-err": "Estamos experimentando un problema al generar el certificado. Por favor, inténtelo de nuevo más tarde.", "folder-already-exist": "¡La carpeta ya existe!", "folder-created-successfully": "¡Carpeta creada exitosamente!", "fill-folder-name": "Por favor, rellena el nombre de la carpeta", @@ -510,6 +519,7 @@ "provide-email": "Por favor, proporciona un correo.", "additional-info": "Información adicional", "signature-saved-alert": "Firma guardada exitosamente.", + "saved-successfully": "Guardado con éxito.", "fill-field": "Por favor, rellena este campo", "error-template": "Error: ¡Plantilla no encontrada!", "error": "Error", @@ -576,18 +586,19 @@ "opensign-drive-7": "Haz clic con el botón derecho en cualquier carpeta para ver las opciones. Elige «Renombrar» para cambiar el nombre de la carpeta o haz clic en ella para navegar por su contenido.", "pdf-request-file-1": "Lista de firmantes que todavía tienen que firmar este documento.", "pdf-request-file-2": "Haz clic en cualquiera de los marcadores de posición que aparecen en el documento para firmar. A continuación, verás opciones para dibujar tu firma, escribirla o subir una imagen .", - "pdf-request-file-3": "Haz clic en los botones «Atrás», «Rechazar» o «Finalizar» para navegar por el documento. Utiliza el menú de tres puntos para ver otras opciones, como el botón «Descargar».", + "pdf-request-file-3": "Haga clic en los botones Rechazar o Finalizar para navegar por el documento. Utilice el menú de puntos suspensivos para ver opciones adicionales, incluido el botón Descargar.", "pdf-request-file-4": "Lista de firmantes que ya han firmado el documento.", "pdf-request-file-5": "Puedes hacer clic en «Firmar todo automáticamente» para firmar de manera automática en todos los lugares que deban ser firmados por ti. Asegúrate de revisar correctamente el documento antes de hacer clic en ese botón.", + "pdf-request-file-6": "Por favor, complete los campos en la página {{pagenumbers}}, todos resaltados con el mismo color para facilitar la identificación.", "placeholder-sign-1": "Selecciona un destinatario de esta lista para agregar un marcador de posición dónde este destinatario tendrá que firmar. El marcador de posición aparecerá con el mismo color que el nombre del destinatario una vez lo sueltes en el documento.", "placeholder-sign-2": "Hacer clic en el botón «Agregar destinatarios» te permitirá añadir más firmantes.", "placeholder-sign-3": "Haz clic en este botón para agregar más destinatarios/firmantes al documento.", "placeholder-sign-4": "Arrastra o haz clic en un capo para agregarlo al documento.", "placeholder-sign-5": "El área de contenido del PDF ya muestra los marcadores de posición existentes en la plantilla. Para tu comodidad, estos marcadores de posición coincidirán con el color del nombre del destinatario, haciéndolos fácilmente identificables.", - "placeholder-sign-6": "Hacer clic en «Enviar» guardará el documento. En el siguiente paso podrás personalizar los correos que serán enviados a los destinatarios o copiar los enlaces para firmar y compartirlos con los destinatarios por tu cuenta.", + "placeholder-sign-6": "Al hacer clic en 'Siguiente' se guardará el documento. En el siguiente paso, puede personalizar los correos electrónicos que se enviarán a los destinatarios o copiar los enlaces de firma y compartirlos usted mismo con los destinatarios.", "report-1": "Haz clic en el botón «Agregar» para crear una nueva plantilla. Las plantillas son documentos reusables diseñados para generar rápidamente nuevos documentos con la misma estructura pero diferentes firmantes. Por ejemplo, una plantilla de RR.HH. para el proceso de incorporación podría tener roles predefinidos como «Director de RR.HH.» y «Nuevo empleado». Cada vez que utilices la plantilla, puedes asignar el rol de «Nuevo empleado» a los distintos miembros del personal que se incorporen, mientras que el rol de « Director de RR.HH.» permanece constante, lo que facilita un proceso de incorporación fluido para cada persona contratada.", "redirect": "Haz clic en el botón «Usar» para crear un nuevo documento desde una plantilla existente.", - "bulksend": "Para crear y enviar rápidamente múltiples documentos usando una plantilla existente, haz clic en el botón «Envío rápido».", + "bulksend": "Para enviar rápidamente múltiples documentos utilizando una plantilla existente creando simplemente las direcciones de correo electrónico de los destinatarios, haz clic en el botón 'Envío Masivo'.", "option": "Este menú revela más opciones como «Editar» y «Eliminar». Usa el botón «Editar» para agregar roles, modificar campos y actualizar tu plantilla. Los cambios aplicarán para todos los documentos futuros que sean creados usando esta plantilla pero no afectarán a los documentos ya existentes. Con el botón «Eliminar» puedes eliminar la plantilla.", "signyour-self-1": "Para personalizar el documento antes de que sea firmado, selecciona y arrastra al documento los widgets que prefieras. Escoge el espacio perfecto para cada modificación para adaptar el documento a tus necesidades.", "signyour-self-2": "Arrastra y suelta en cualquier lugar de esta área. Después podrás cambiar el tamaño y moverlo.", @@ -602,7 +613,8 @@ "Recent signature requests": "Esta es una lista de documentos que esperan por tu firma.", "Recently sent for signatures": "Esta es una lista de documentos que has enviado a otras partes para que sea firmado.", "Drafts": "Estos son documentos que has empezado pero que todavía no finalizas para su envío.", - "public-template": "Este video muestra cómo puedes configurar tu perfil público personalizado, como «https://opensign.me/tu-nombre-de-usuario». También aprenderás cómo personalizar tu eslogan y cómo hacer tus plantillas disponibles para su firmado público." + "public-template": "Este video muestra cómo puedes configurar tu perfil público personalizado, como «https://opensign.me/tu-nombre-de-usuario». También aprenderás cómo personalizar tu eslogan y cómo hacer tus plantillas disponibles para su firmado público.", + "allowModify-widgets": "Puede arrastrar y soltar cualquiera de estos campos en el documento, además de los campos ya designados para usted por el creador del documento" }, "enter-email-plaholder": "Agrega una dirección de correo y presiona «Enter»", "success-email-alert": "¡Correo enviado exitosamente!", @@ -646,6 +658,8 @@ "public-template-mssg-4": "Visita la", "public-template-mssg-5": " «npm» para las últimas actualizaciones, documentación detallada e historial de versiones.", "public-template-mssg-6": "Antes de que puedas usar este fragmento de código, debes convertir esta plantilla en pública.", + "public-template-mssg-7": "Antes de poder generar un enlace público, debes hacer que esta plantilla sea pública.", + "here": "aquí", "copy-code": "COPIAR", "copied-code": "COPIADO", "Installation": "Instalación", @@ -682,19 +696,19 @@ "add-user-template": "Es necesario agregar un rol antes de poder agregarle campos.", "pdf-uncompatible": "Este pdf no es compatible con opensign, comuníquese con ", "enable-tour": "Habilitar recorrido", - "istourenabled-help":{ + "istourenabled-help": { "p1": "Esto permitirá realizar una visita guiada para los firmantes, brindando instrucciones durante el proceso de firma.", "p2": "Esto desactivará la visita guiada, lo que garantizará una experiencia de firma más rápida e ininterrumpida.", "p3": "Consejo: si sus firmantes están familiarizados con OpenSign y lo utilizan con frecuencia, es posible que desee desactivar la visita guiada para disfrutar de una experiencia más fluida. Elija la opción que mejor se adapte a sus necesidades de firma de documentos" - }, + }, "form-title-1": "Configuración del flujo de documentos", "form-title-2": "Configuración de seguridad", - "text-field-tour":"Los campos de tipo 'Texto' deben completarse con anticipación antes de enviar el documento. Si necesita que los firmantes proporcionen información, utilice el campo 'Entrada de texto'", - "attach-signer-tour" :"Debe adjuntar un firmante a cada función. Puede hacerlo haciendo clic en este icono. Una vez que seleccione un Firmante, se adjuntará a todos los campos asociados con ese rol que aparecen en el mismo color.", + "text-field-tour": "Los campos de tipo 'Texto' deben completarse con anticipación antes de enviar el documento. Si necesita que los firmantes proporcionen información, utilice el campo 'Entrada de texto'", + "attach-signer-tour": "Debe adjuntar un firmante a cada función. Puede hacerlo haciendo clic en este icono. Una vez que seleccione un Firmante, se adjuntará a todos los campos asociados con ese rol que aparecen en el mismo color.", "allowed-signature-types": "Tipos de firma permitidos", "at-least-one-signature-type": "Se debe habilitar al menos un tipo de firma.", "expect-default-one-signature-type": "Habilite un tipo de firma adicional aparte del predeterminado.", - "add-signer-note": "Nota - Este contacto se agregará a su lista de contactos", + "add-signer-note": "Nota - Este contacto se guardará en sus Contactos", "allowed-signature-types-help": { "p1": "Esta preferencia de firma controla qué opciones de firma están disponibles para sus firmantes. Solo los tipos de firma que seleccione aparecerán en el widget de firma cuando se firme un documento. Por ejemplo, si elige sólo la opción 'Draw' en las preferencias, su firmante verá sólo la opción 'Draw' en el widget de firma, mientras que las otras tres opciones no estarán disponibles.", "l1": "Cree una firma manuscrita directamente en la pantalla usando su dedo o un lápiz.", @@ -705,9 +719,120 @@ "notify-on-signatures": "Notificar sobre firmas", "notify-on-signatures-help": { "p1": "El creador del documento recibirá una notificación por correo electrónico cada vez que un firmante firme el documento.", - "note": "Nota: No se enviará un correo electrónico de notificación al último firmante, ya que el creador del documento recibirá un correo electrónico de finalización." + "note": "Nota: Independientemente de esta configuración, siempre se envía un correo electrónico de finalización con el documento firmado y el certificado de finalización adjunto a todos los firmantes y al propietario del documento." }, "expiry-date": "Date d'expiration", "expiry-date-updated": "La fecha de vencimiento se ha extendido con éxito hasta el {{newexpirydate}}", - "expiry-date-error": "Proporcione una nueva fecha de vencimiento que sea posterior a la actual" + "expiry-date-error": "Proporcione una nueva fecha de vencimiento que sea posterior a la actual", + "duplicate-template-alert": "¿Está seguro de que desea crear un duplicado de esta plantilla?", + "duplicate-template-created": "Plantilla duplicada creada correctamente.", + "delete-page": "eliminar página", + "merge-pdf": "fusionar pdf", + "add-pages": "Agregar páginas", + "delete-alert": "No se puede eliminar una sola página", + "delete-alert-2": "¿Está seguro de que desea eliminar esta página?", + "delete-note": "Nota: una vez que elimines esta página, no podrás deshacerla", + "Rotation-alert": "Girar página", + "bulk-import": "Importación masiva", + "contacts-file": "Archivo de contactos (xlsx, csv)", + "100-records-only": "Currently you can only import up to 100 records.", + "csv-excel-support-only": "Cargue un archivo en uno de los siguientes formatos: CSV, XLSX o XLS.", + "contact-imported": "Se importaron {{imported}} contactos. {{failed}} contactos no pudieron importarse.", + "invalid-data": "Datos no válidos", + "delete-folder-alert": "¿Está seguro de que desea eliminar este Carpeta?", + "delete-folder-alert-1": "No se puede eliminar: la carpeta debe estar vacía", + "defaultSign-alert": "Los widgets {{widgetsType}} no están disponibles para la firma automática", + "embed-heading": "Incrustar plantillas de OpenSign", + "public-template-edit-title": "Editar plantilla pública", + "public-template-edit-mssg": "No puede editar una plantilla pública directamente. Para realizar cambios, la plantilla se configurará como privada y luego tendrás que volver a hacerla pública. ¿Quieres continuar?", + "agree-p1": "Confirmo que he leído y comprendido el ", + "agree-p2": "Registro Electrónico y Divulgación de Firma", + "agree-p3": "y consentimiento para utilizar registros y firmas electrónicas.", + "agrre-button": "Aceptar y continuar", + "term-cond-title": "Términos y condiciones", + "term-cond-h": "DIVULGACIÓN DE REGISTRO ELECTRÓNICO Y FIRMA", + "term-cond-p1": "Esta Divulgación de Firma y Registro Electrónico ('Divulgación') es un acuerdo entre el Creador del Documento ('Remitente') y el Firmante ('Usted'), facilitado a través de la plataforma OpenSign ('Plataforma'). Al firmar documentos a través de OpenSign, usted acepta los términos descritos en esta Divulgación. Léala detenidamente antes de continuar.", + "term-cond-h1": "1. Objet et portée", + "term-cond-p2": "Esta Divulgación rige el uso de registros y firmas electrónicas para los documentos enviados por el Remitente y firmados por Usted a través de la plataforma OpenSign. Al aceptar, Usted reconoce que:", + "term-cond-p3": "Recibirá y firmará documentos electrónicamente a través de OpenSign.", + "term-cond-p4": "Su firma electrónica es jurídicamente vinculante y equivalente a una firma manuscrita.", + "term-cond-h2": "2. Consentimiento para el uso de registros y firmas electrónicas", + "js-snippet-msg-2": "Administrar plantillas", + "js-snippet-msg-3": "página.", + "term-cond-p5": "Al aceptar esta Divulgación:", + "term-cond-p6": "Usted acepta realizar transacciones electrónicas con el Remitente utilizando OpenSign y comprende que este consentimiento es válido hasta que se retire.", + "term-cond-p7": "Usted acepta revisar, firmar y devolver documentos electrónicamente utilizando OpenSign.", + "term-cond-p8": "Este consentimiento se aplica únicamente a los documentos específicos proporcionados por el Remitente.", + "term-cond-h3": "3. Derecho a retirar el consentimiento", + "term-cond-p9": "Tiene derecho a retirar su consentimiento para el uso de registros y firmas electrónicas mediante:", + "term-cond-p10": "Contactar directamente con el Remitente utilizando la información de contacto proporcionada en su comunicación.", + "term-cond-p11": "Notificar al remitente antes de completar el proceso de firma.", + "term-cond-h4": "4. Requisitos de hardware y software", + "term-cond-p12": "Para firmar documentos usando OpenSign, debe tener:", + "term-cond-p13": "Un dispositivo con acceso a Internet.", + "term-cond-p14": "Un navegador web compatible con JavaScript habilitado.", + "term-cond-p15": "Una cuenta de correo electrónico para recibir notificaciones y documentos firmados.", + "term-cond-p16": "Si estos requisitos cambian, el Remitente u OpenSign le notificarán las actualizaciones.", + "term-cond-h5": "5. Conservación de registros y solicitud de copias en papel", + "term-cond-p17": "Usted es responsable de garantizar que pueda acceder y conservar los documentos firmados electrónicamente. OpenSign proporciona herramientas para descargar o imprimir el documento firmado inmediatamente después de que se complete el proceso de firma.", + "term-cond-p18": "Si prefiere una copia en papel de cualquier documento firmado electrónicamente, puede solicitarla directamente al Remitente. El Remitente puede cobrar una tarifa razonable por proporcionar copias en papel, a menos que lo prohíba la ley aplicable.", + "term-cond-h6": "6. Reconocimiento y Acuerdo", + "term-cond-p19": "Al continuar, usted:", + "term-cond-p20": "Confirme que puede acceder y revisar documentos electrónicos como se describe en esta Divulgación.", + "term-cond-p21": "Acepta utilizar registros y firmas electrónicas para las transacciones especificadas con el Remitente.", + "term-cond-p22": "Comprenda que OpenSign es una plataforma que facilita la transacción y no es parte del acuerdo.", + "term-cond-h7": "7. Efecto jurídico", + "term-cond-p23": "Tu firma electrónica facilitada a través de OpenSign:", + "term-cond-p24": "Cumple con las leyes de firma electrónica aplicables, incluidas, entre otras, la Ley E-SIGN de ​​los Estados Unidos, el Reglamento eIDAS de la UE y la Ley de tecnología de la información de la India", + "term-cond-p25": "Es legalmente vinculante entre Usted y el Remitente para los documentos firmados", + "term-cond-h8": "8. Platform Role and Limitation of Liability", + "term-cond-p26": "OpenSign sirve como plataforma para facilitar transacciones electrónicas. No es responsable del contenido, validez o aplicabilidad de los documentos enviados por el Remitente. Cualquier disputa o problema relacionado con el documento o su firma debe resolverse directamente entre Usted y el Remitente.", + "term-cond-h9": "9. Terminación del Acuerdo", + "term-cond-p27": "Su consentimiento se aplica únicamente a la transacción actual a menos que el Remitente especifique lo contrario. OpenSign se reserva el derecho de cancelar el acceso a su plataforma por violaciones de sus Términos de Servicio o políticas.", + "term-cond-p28": "Al seleccionar 'Acepto', usted confirma que comprende y acepta los términos de este Registro electrónico y Divulgación de firma y acepta firmar electrónicamente los documentos proporcionados por el Remitente a través de OpenSign.", + "term-cond-p29": "Si tiene preguntas sobre esta Divulgación, comuníquese directamente con el Remitente. Para obtener soporte técnico con OpenSign, visite", + "term-cond-p30": "o correo electrónico", + "js-snippet-msg": "Para integrar plantillas OpenSign en sus sitios web HTML o páginas de destino, puede utilizar el siguiente código:", + "js-snippet-msg-1": "Puede obtener el TemplateId en la página Administrar plantillas", + "agrrement-alert": "Para continuar, debe consentir la divulgación de registros y firmas electrónicas.", + "webhook-already-exists": "¡La URL ya existe! Pruebe con uno diferente.", + "webhook-must-be-secure": "La URL del webhook debe ser segura y utilizar https://", + "provide-test-token": "Por favor genere un token de prueba de API", + "invalid-redirect-url": "Proporcione una URL de redireccionamiento válida.", + "auto-sign-mssg": "firmar automáticamente todo", + "already-exist-signer": "El firmante seleccionado ya está presente en la lista de destinatarios", + "allow-modify": "Permitir modificaciones", + "allow-modify-help": { + "p1": "¿Desea permitir modificaciones al documento durante el proceso de firma?", + "p2": "Seleccionar esta opción permite a los firmantes agregar elementos adicionales, como firmas, iniciales, sellos o texto, sobre los widgets existentes.", + "p3": "Seleccionar esta opción restringe a los firmantes de realizar cualquier adición al documento durante el proceso de firma." + }, + "signature-setting": "Configuración de firmas", + "signyour-self-button": "Utilice este formulario para crear plantillas reutilizables para sus documentos.", + "requestsign-button": "Utilice esta opción para solicitar firmas de otras personas y de usted mismo en conjunto.", + "signyour-self-description": "Utilice este formulario para firmar el documento usted mismo sin agregar otros.", + "requestsign-description": "Utilice este formulario para solicitar firmas de otras personas y de usted mismo en conjunto.", + "template-form-description": "Utilice este formulario para crear plantillas reutilizables para sus documentos.", + "change-signer": "Cambiar firmante", + "activation-key": "Clave de activación", + "paid-selfhost-help": "Por favor, póngase en contacto con OpenSign para más información en ", + "remaining-credits-selfhost-help": "Use créditos premium para firmar documentos mediante la API, enviar en masa e integrar OpenSign en su sitio web. Tiene {{allowedcredits}} créditos incluidos y {{addoncredits}} créditos adicionales comprados restantes.", + "signature-type": "Tu firma", + "initial-type": "Tus iniciales", + "redirect-url": "URL de redireccionamiento", + "bulk-send": "envío masivo", + "select-timezone": "Seleccione su zona horaria", + "current-time": "Hora actual", + "email-help": "No se permite cambiar la dirección de correo electrónico por razones de seguridad. Por favor, cree otra cuenta gratuita utilizando la nueva dirección de correo electrónico.", + "doc-sent": "Documento enviado con éxito.", + "no-signer": "Eliminar", + "and": "y", + "make-public": "Hacer público", + "general": "General", + "request-email": "Correo de solicitud", + "completion-email": "Correo de finalización", + "variables-use": "Variables para usar", + "send-to-sign": "le ha solicitado que firme", + "use-template": "Usar plantilla", + "contact-already-exists": "El contacto ya existe." } diff --git a/apps/OpenSign/public/locales/fr/translation.json b/apps/OpenSign/public/locales/fr/translation.json index eb515ef3e..a8cef679c 100644 --- a/apps/OpenSign/public/locales/fr/translation.json +++ b/apps/OpenSign/public/locales/fr/translation.json @@ -42,7 +42,7 @@ "upgrade-to": "Mettre à niveau vers", "pro": "PRO", "plan": "Offre", - "subscribe-card-teamplan":"Libérez toute la puissance de la collaboration ! Créez un nombre illimité d'organisations, d'équipes et de hiérarchies. Partagez des modèles de manière transparente entre les équipes et attribuez des rôles d'utilisateur personnalisés. Améliorez votre flux de travail dès aujourd'hui !", + "subscribe-card-teamplan": "Libérez toute la puissance de la collaboration ! Créez un nombre illimité d'organisations, d'équipes et de hiérarchies. Partagez des modèles de manière transparente entre les équipes et attribuez des rôles d'utilisateur personnalisés. Améliorez votre flux de travail dès aujourd'hui !", "subscribe-card-plan": "Débloquez des fonctionnalités premium à partir de seulement {{premiumPrice}}/mois. Bénéficiez de performances améliorées et de seulement {{addonPrice}} par crédit supplémentaire après vos crédits premium inclus.", "user-name-limit-char": "Pour avoir un nom d'utilisateur de moins de 8 caractères s'il vous plaît s'abonner", "tour-content": "Ne plus afficher", @@ -76,19 +76,21 @@ "Templates": "Modèles", "Templates-Children": { "Create template": "Créer un modèle", - "Manage templates": "Gérer les modèles" + "Manage templates": "Gérer les modèles", + "Embedding": "Intégration" }, "OpenSign™ Drive": "Lecteur OpenSign™", "Reports": "Rapports", - "Reports-Children": { + "Documents": "Documents", + "Documents-Children": { "Need your sign": "Besoin de votre signature", "In Progress": "En cours", "Completed": "Complété", "Drafts": "Brouillons", "Declined": "Signature refusé", - "Expired": "Expiré", - "Contactbook": "Carnet de contacts" + "Expired": "Expiré" }, + "Contactbook": "Carnet de contacts", "Settings": "Paramètres", "Settings-Children": { "My Signature": "Ma signature", @@ -144,6 +146,7 @@ "btnLabel": { "sign": "Signer", "Resend": "Relancer", + "Rename": "Renommer", "Revoke": "Révoquer", "Delete": "Supprimer", "Use": "Utiliser", @@ -155,8 +158,10 @@ "option": "Option", "Embed": "Intégrer", "Copy TemplateId": "Copier l'ID du modèle", - "Copy Public URL":"Copier l'URL publique", - "extend-expiry-date": "Prolonger la date d'expiration" + "Copy Public URL": "Copier l'URL publique", + "extend-expiry-date": "Prolonger la date d'expiration", + "Duplicate Template": "dupliquer le modèle", + "Duplicate": "Double" }, "report-help": { "Draft Documents": "Il s'agit de documents que vous avez commencés mais que vous n'avez pas finalisés pour envoi.", @@ -210,12 +215,14 @@ "create": "Créer", "signers": "Signataires", "signers-help": "Commencez à saisir le nom d'un contact pour voir les signataires suggérés par vos contacts enregistrés ou en ajouter de nouveaux. Organisez l'ordre de signature en ajoutant des signataires dans l'ordre souhaité. Utilisez le bouton « + » pour inclure les signataires et le « x » pour les supprimer. Chaque signataire recevra un e-mail invité à signer le document dans l'ordre indiqué.", + "bcc-help": "Commencez à taper le nom d’un contact pour voir les suggestions parmi vos contacts enregistrés ou en ajouter de nouveaux. Utilisez le bouton '+' pour ajouter un utilisateur et le bouton 'x' pour le supprimer. L’adresse e-mail de l’utilisateur sélectionné sera ajoutée en Bcc (copie carbone invisible). Chaque utilisateur recevra une notification par e-mail une fois le document terminé.", "add-signer": "Ajouter un signataire", "contact-not-found": "Contact introuvable", "add-yourself": "Ajoutez-vous", "submit": "Soumettre", "reset": "Réinitialiser", "my-signature": "Ma signature", + "initial-alert": "Mon initiale introuvable", "signature": "Signature", "upload-image": "Télécharger une image", "clear": "Vider", @@ -260,7 +267,7 @@ "user-deactivated": "Utilisateur désactivé.", "user-activated": "Activé par l'utilisateur.", "public": "Public", - "download": "Téléchargement", + "download": "Télécharger", "view": "voir", "make-template-public": "Rendre le modèle public", "make-template-private": "Rendre le modèle privé", @@ -271,7 +278,7 @@ "embed-template": "Intégrer le modèle", "public-url-copy": "Voici votre URL publique : ", "public-url-copy-mssg": "copiez-la ou partagez-le avec le signataire et vous pouvoir voir tous vos paramètres publics modèles.", - "add-public-url-alert": "Veuillez terminer la configuration de votre profil public OpenSign. Une fois cela fait, vous pourrez rendre les modèles publics. Ce processus ne doit être effectué qu’une seule fois.", + "add-public-url-alert": "Vous pouvez générer votre profil public OpenSign", "share-with-alert": "Vous ne pouvez pas partager un modèle si des contacts sont déjà attribués à des rôles. Veuillez supprimer toutes les attributions de contacts des rôles avant de partager le modèle.", "share-with": "Partager avec", "team-not-found": "Équipe introuvable", @@ -294,6 +301,7 @@ "subject": "Sujet", "body": "Corps", "add-contact": "Ajouter le contact", + "edit-contact": "Modifier le contact", "add-signer-alert": "Le contact existe déjà ! Veuillez le sélectionner dans la liste déroulante 'Signataires'", "record-delete-alert": "Enregistrement supprimé avec succès !", "record-revoke-alert": " Enregistrement révoqué avec succès ! ", @@ -403,10 +411,9 @@ "encrypted-pdf-alert": "Les fichiers PDF actuellement cryptés ne sont pas pris en charge.", "encrypted-pdf-alert-1": "Le mot de passe du fichier PFX n'est pas valide.", "user-not-exist": "L'utilisateur n'existe pas", - "template-signature-field": "Veuillez ajouter au moins un champ de signature pour tous les rôles.", "template-role-alert": "Veuillez d'abord ajouter des rôles", "create-document": "Créer un document", - "template-created-alert": "Voulez-vous créer un document en utilisant le modèle que vous vient de créer ?", + "template-created-alert": "Que voulez-vous faire avec le modèle que vous venez de créer ?", "signers-alert": "alerte des signataires", "template-creation-alert-1": "Veuillez sélectionner le signataire pour ajouter un espace réservé !", "ok": "D'accord", @@ -438,6 +445,7 @@ "placeholder-alert-2": "Veuillez confirmer que vous avez rempli le champ de texte.", "placeholder-alert-3": "Etes-vous sûr de vouloir envoyer ce document pour signature ? ", "placeholder-alert-4": "Vous avez envoyé avec succès des mails à tous les", + "placeholder-mail-alert": "Vous avez envoyé un e-mail avec succès à {{name}}. Les signataires suivants recevront un e-mail une fois que {{name}} aura signé le document.", "placeholder-alert-5": "Voulez-vous signer des documents maintenant ?", "placeholder-alert-6": "Veuillez configurer l'adaptateur de messagerie pour envoyer du courrier !", "placeholder-alert-7": "Veuillez sélectionner le signataire pour ajouter un espace réservé !", @@ -468,12 +476,13 @@ "sign-up": "S'inscrire", "folder-already-exist!": "le dossier existe déjà !", "please-select-position!": "Veuillez sélectionner un poste !", - "default-sign-alert": "Êtes-vous sûr de vouloir vous connecter automatiquement à tous les emplacements demandés ? ", + "default-sign-alert": "Êtes-vous sûr de vouloir vous connecter automatiquement à tous les widgets {{widgetsType}} ?", "Your-Signature": "Votre signature", "auto-sign-all": "Tout signer automatiquement", "generating-certificate": "Génération du certificat", - "pdf-download": "Téléchargement PDF", + "pdf-download": "Télécharger PDF", "generate-certificate-alert": " Votre certificat d'achèvement est en cours de génération. Veuillez patienter quelques instants. Si le téléchargement ne démarre pas sous peu, cliquez à nouveau sur le bouton. ", + "generate-certificate-err": "Nous rencontrons actuellement un problème lors de la génération du certificat. Veuillez réessayer plus tard.", "folder-already-exist": "Le dossier existe déjà !", "folder-created-successfully": "Dossier créé avec succès !", "fill-folder-name": "Veuillez indiquer le nom du dossier", @@ -509,6 +518,7 @@ "provide-email": "Veuillez fournir un e-mail.", "additional-info": "Information additionnelle", "signature-saved-alert": "Signature enregistrée avec succès.", + "saved-successfully": "Enregistré avec succès.", "fill-field": "Veuillez remplir ce champ", "error-template": "Erreur : modèle introuvable ! ", "error": "Erreur", @@ -575,18 +585,19 @@ "opensign-drive-7": "Faites un clic droit sur n'importe quel dossier pour voir les options. Choisissez 'Renommer' pour changer le nom du dossier ou cliquez sur le dossier pour naviguer dans son contenu.", "pdf-request-file-1": "Liste des signataires qui doivent encore signer le document.", "pdf-request-file-2": "Cliquez sur l'un des espaces réservés apparaissant sur le document pour signer. Vous verrez alors des options pour dessiner votre signature, la saisir ou télécharger une image.", - "pdf-request-file-3": "Cliquez sur les boutons Précédent, Refuser ou Terminer pour parcourir votre document. Utilisez le menu points de suspension pour des options supplémentaires, notamment le bouton Télécharger.", + "pdf-request-file-3": "Cliquez sur les boutons Refuser ou Terminer pour parcourir votre document. Utilisez le menu à points de suspension pour des options supplémentaires, notamment le bouton Télécharger.", "pdf-request-file-4": "Liste des signataires ayant déjà signé le document.", "pdf-request-file-5": "Vous pouvez cliquer sur 'Signer automatiquement tout' pour signer automatiquement à tous les emplacements que vous êtes censé signer. Assurez-vous de lire correctement le document avant de cliquer sur ce bouton.", + "pdf-request-file-6": "Veuillez remplir les champs à la page {{pagenumbers}}, tous mis en évidence avec la même couleur pour une identification facile.", "placeholder-sign-1": "Sélectionnez un destinataire dans cette liste pour ajouter un espace réservé à l'endroit où il est censé signer. L'espace réservé apparaîtra de la même couleur que le nom du destinataire une fois que vous le déposerez sur le document.", "placeholder-sign-2": "Cliquer sur le bouton 'Ajouter des destinataires' vous permettra d'ajouter plus de signataires.", "placeholder-sign-3": "Cliquez sur ce bouton pour ajouter plus de destinataires/signataires au document", "placeholder-sign-4": "Faites glisser ou cliquez sur un champ pour l'ajouter au document.", "placeholder-sign-5": "La zone de contenu PDF affiche déjà les espaces réservés existants du modèle. Pour votre commodité, ces espaces réservés correspondront à la couleur du nom du destinataire, ce qui les rendra facilement identifiables.", - "placeholder-sign-6": "Cliquer sur 'Envoyer' enregistrera le document. À l'étape suivante, vous pourrez personnaliser les e-mails à envoyer aux destinataires ou copier les liens de signature et les partager vous-même avec les destinataires.", + "placeholder-sign-6": "En cliquant sur 'Suivant', le document sera enregistré. À l'étape suivante, vous pouvez personnaliser les e-mails à envoyer aux destinataires ou copier les liens de signature et les partager vous-même avec les destinataires.", "report-1": "Cliquez sur le bouton 'Ajouter' pour créer un nouveau modèle. Les modèles sont des documents réutilisables conçus pour générer rapidement de nouveaux documents avec la même structure et différents signataires. Par exemple, un modèle RH pour l'intégration peut avoir des rôles prédéfinis tels que 'Responsable RH' et ' Nouvel employé'. Chaque fois que vous utilisez le modèle, vous pouvez attribuer le rôle 'Nouvel employé' à différents membres du personnel entrants, tandis que le rôle 'Responsable RH' reste constant, facilitant ainsi un processus d'intégration fluide pour chaque recrue", "redirect": "Cliquez sur le bouton 'Utiliser' pour créer un nouveau document à partir d'un modèle existant.", - "bulksend": "Pour créer et envoyer rapidement plusieurs documents à l'aide d'un modèle existant, cliquez sur le bouton 'Envoi rapide'.", + "bulksend": "Pour envoyer rapidement plusieurs documents en utilisant un modèle existant en créant simplement les adresses e-mail des destinataires, cliquez sur le bouton 'Envoi en masse'.", "option": "Ce menu révèle plus d'options telles que Modifier et Supprimer. Utilisez le bouton « Modifier » pour ajouter des rôles de signataire, modifier les champs et mettre à jour votre modèle. Les modifications s'appliqueront à tous les futurs documents créés à partir de ce modèle mais n'affecteront pas les documents existants. Utilisez le bouton Supprimer, vous pouvez supprimer le modèle ", "signyour-self-1": "Sélectionnez et faites glisser vos widgets préférés sur le PDF pour personnaliser votre document avant de le signer. Choisissez les endroits parfaits pour chaque modification afin d'adapter le document à vos besoins.", "signyour-self-2": "Faites glisser et déposer n'importe où dans cette zone. Vous pourrez la redimensionner et la déplacer plus tard.", @@ -601,7 +612,8 @@ "Recent signature requests": "Voici une liste de documents qui attendent votre signature.", "Recently sent for signatures": "Il s'agit d'une liste de documents que vous avez envoyés à d'autres parties pour signature.", "Drafts": "Il s'agit de documents que vous avez commencés mais que vous n'avez pas finalisés pour envoi.", - "public-template": "Cette vidéo montre comment configurer votre profil public personnalisé, tel que 'https://opensign.me/your-username'. Vous apprendrez également comment personnaliser votre slogan et rendre vos modèles disponibles pour la signature publique." + "public-template": "Cette vidéo montre comment configurer votre profil public personnalisé, tel que 'https://opensign.me/your-username'. Vous apprendrez également comment personnaliser votre slogan et rendre vos modèles disponibles pour la signature publique.", + "allowModify-widgets": "Vous pouvez faire glisser et déposer n'importe lequel de ces champs sur le document, en plus des champs déjà désignés pour vous par le créateur du document." }, "enter-email-plaholder": "Ajoutez une adresse email et appuyez sur Entrée", "success-email-alert": "E-mail envoyé avec succès!", @@ -621,47 +633,49 @@ "Add-seats": "Ajouter des sièges", "format": "format", "select-date-format": "Sélectionnez un format de date", - "quantity-of-credits":"Quantité de crédits de prime", - "remaining-credits":"Crédits premium disponibles :", - "additional-credits":"Veuillez acheter des crédits premium", - "remaining-credits-help":"Utilisez des crédits premium pour la signature de documents API, l'envoi groupé ou l'intégration d'OpenSign sur votre site Web. Il vous reste {{allowedcredits}} crédits inclus et {{addoncredits}} crédits achetés supplémentaires.", + "quantity-of-credits": "Quantité de crédits de prime", + "remaining-credits": "Crédits premium disponibles :", + "additional-credits": "Veuillez acheter des crédits premium", + "remaining-credits-help": "Utilisez des crédits premium pour la signature de documents API, l'envoi groupé ou l'intégration d'OpenSign sur votre site Web. Il vous reste {{allowedcredits}} crédits inclus et {{addoncredits}} crédits achetés supplémentaires.", "quota-err-quicksend": "Quota atteint, vous n'avez pas assez de crédits.", "buy-credits": "Acheter des crédits premium", - "rotate-right" :"Faire pivoter à droite", - "rotate-left" :"Faire pivoter à gauche", - "rotate-alert-mssg" :"Tous les widgets de cette page seront perdus. Êtes-vous sûr de vouloir continuer ?", - "templateid":"ID de modèle", - "bulk-send-subcription-alert":"Veuillez passer au forfait Professionnel ou Équipe pour utiliser Quicksend.", + "rotate-right": "Faire pivoter à droite", + "rotate-left": "Faire pivoter à gauche", + "rotate-alert-mssg": "Tous les widgets de cette page seront perdus. Êtes-vous sûr de vouloir continuer ?", + "templateid": "ID de modèle", + "bulk-send-subcription-alert": "Veuillez passer au forfait Professionnel ou Équipe pour utiliser Quicksend.", "generate-test-token": "Générer jeton de test", - "regenerate-test-token":"Régénérer le jeton de test", - "help-test-token":"Ce jeton peut être utilisé pour tester les API au niveau du point de terminaison https://sandbox.opensignlabs.com/api/v1, vous permettant ainsi d'effectuer un nombre illimité de signatures de documents. Veuillez noter que l'API sandbox signera vos documents avec des certificats auto-signés, qui peuvent ne pas être reconnus comme valides par Adobe. Une fois vos tests terminés, vous pouvez passer à l’un de nos forfaits payants pour générer un jeton de production.", - "help-api-token":"Ce jeton peut être utilisé pour accéder aux API de production au point de terminaison {{origin}}/api/v1. Il ne peut être généré que sur l'un de nos forfaits payants.", - "reason" :"Raison", - "decline-by" :"Refusé/révoqué par", - "document-declined":"document refusé", - "public-template-mssg-1" :"Pour intégrer OpenSign dans votre projet React ou Next.js, exécutez simplement la commande suivante :", - "public-template-mssg-2" :"Assurez-vous que npm ou Yarn est configuré dans votre projet. Si vous utilisez Yarn, vous pouvez remplacer npm install par Yarn Add @opensign/react.", - "public-template-mssg-3" :"Besoin de plus de détails ou d'exemples ?", + "regenerate-test-token": "Régénérer le jeton de test", + "help-test-token": "Ce jeton peut être utilisé pour tester les API au niveau du point de terminaison https://sandbox.opensignlabs.com/api/v1, vous permettant ainsi d'effectuer un nombre illimité de signatures de documents. Veuillez noter que l'API sandbox signera vos documents avec des certificats auto-signés, qui peuvent ne pas être reconnus comme valides par Adobe. Une fois vos tests terminés, vous pouvez passer à l’un de nos forfaits payants pour générer un jeton de production.", + "help-api-token": "Ce jeton peut être utilisé pour accéder aux API de production au point de terminaison {{origin}}/api/v1. Il ne peut être généré que sur l'un de nos forfaits payants.", + "reason": "Raison", + "decline-by": "Refusé/révoqué par", + "document-declined": "document refusé", + "public-template-mssg-1": "Pour intégrer OpenSign dans votre projet React ou Next.js, exécutez simplement la commande suivante :", + "public-template-mssg-2": "Assurez-vous que npm ou Yarn est configuré dans votre projet. Si vous utilisez Yarn, vous pouvez remplacer npm install par Yarn Add @opensign/react.", + "public-template-mssg-3": "Besoin de plus de détails ou d'exemples ?", "public-template-mssg-4": "Visitez le", - "public-template-mssg-5": "npm pour les dernières mises à jour, une documentation détaillée et l'historique des versions.", - "public-template-mssg-6":"Avant de pouvoir utiliser cet extrait de code, vous devez rendre ce modèle public.", - "copy-code":"COPIE", - "copied-code":"COPIÉ", - "Installation":"Installation", - "Usage" :"Usage", - "insufficient-credits":"Crédits de signature insuffisants", - "insufficient-credits-mssg" :"Le propriétaire de ce document ne dispose actuellement pas des crédits OpenSign nécessaires pour que vous puissiez le signer. Veuillez contacter le propriétaire si vous avez besoin de plus de détails.", - "angular-npm-mssg-1" :"Pour intégrer OpenSign dans votre projet Angular, exécutez simplement la commande suivante :", - "quota-mail-info-head":"Limite mensuelle d'e-mails de signatures de demandes", + "public-template-mssg-5": "npm pour les dernières mises à jour, une documentation détaillée et l'historique des versions.", + "public-template-mssg-6": "Avant de pouvoir utiliser cet extrait de code, vous devez rendre ce modèle public.", + "public-template-mssg-7": "Avant de pouvoir générer un lien public, vous devez rendre ce modèle public.", + "here": "ici", + "copy-code": "COPIE", + "copied-code": "COPIÉ", + "Installation": "Installation", + "Usage": "Usage", + "insufficient-credits": "Crédits de signature insuffisants", + "insufficient-credits-mssg": "Le propriétaire de ce document ne dispose actuellement pas des crédits OpenSign nécessaires pour que vous puissiez le signer. Veuillez contacter le propriétaire si vous avez besoin de plus de détails.", + "angular-npm-mssg-1": "Pour intégrer OpenSign dans votre projet Angular, exécutez simplement la commande suivante :", + "quota-mail-info-head": "Limite mensuelle d'e-mails de signatures de demandes", "quota-mail-info": "Vous pouvez envoyer jusqu'à 15 e-mails de demande de signature chaque mois. Mettez à niveau maintenant pour envoyer directement des demandes de signature illimitées.", "quota-mail-reset": "Les crédits de votre email de demande de signature seront réinitialisés le", "quota-mail": "Vous avez atteint votre limite de 15 e-mails de demande de signature pour ce mois. Mettez à niveau maintenant pour continuer à envoyer des e-mails directement.", - "quota-mail-tip-tip":"Astuce : Vous pouvez toujours signer un nombre <1>illimité de documents en partageant manuellement les liens de demande de signature.", - "quota-mail-head":"Quota atteint", - "unauthorized-modal":"Vous n'êtes pas autorisé à effectuer cette action, veuillez contacter {{adminEmail}}.", - "sent-this-month":"envoyé ce mois-ci", - "available-seats":"Disponible sièges", - "buy-users":"Acheter plus d'utilisateurs", + "quota-mail-tip-tip": "Astuce : Vous pouvez toujours signer un nombre <1>illimité de documents en partageant manuellement les liens de demande de signature.", + "quota-mail-head": "Quota atteint", + "unauthorized-modal": "Vous n'êtes pas autorisé à effectuer cette action, veuillez contacter {{adminEmail}}.", + "sent-this-month": "envoyé ce mois-ci", + "available-seats": "Disponible sièges", + "buy-users": "Acheter plus d'utilisateurs", "isenable-otp": "Activer la vérification OTP", "isenable-otp-help": { "p1": "Souhaitez-vous activer le processus de vérification à l'aide d'un mot de passe à usage unique (OTP)?", @@ -669,31 +683,31 @@ "p3": "La sélection de cette option désactivera la vérification OTP, permettant aux utilisateurs de signer le document directement sans étapes supplémentaires.", "p4": "Veuillez choisir l'option qui correspond le mieux à vos exigences en matière de signature de documents." }, - "advanced-options":"Options avancées", + "advanced-options": "Options avancées", "hide-advanced-options": "Masquer les options avancées", - "download-files" :"Télécharger des fichiers", - "download-pdf" :"Télécharger le PDF", - "pdf-certificate" :"Télécharger Pdf + Certificat", - "document-logs":"Journaux de documents", + "download-files": "Télécharger des fichiers", + "download-pdf": "Télécharger le PDF", + "pdf-certificate": "Télécharger Pdf + Certificat", + "document-logs": "Journaux de documents", "server-down": "Impossible de se connecter au serveur OpenSign. Si vous hébergez vous-même OpenSign, veuillez vous assurer que toutes les étapes de la documentation ont été correctement suivies. Si vous exécutez OpenSign localement, vous y accédez peut-être via un numéro de port incorrect.", "admin-exists": "L'administrateur existe déjà. Veuillez vous connecter à l'application en utilisant les informations d'identification de l'administrateur afin de gérer les utilisateurs.", "enable-tour": "Activer la visite", - "istourenabled-otp-help":{ + "istourenabled-otp-help": { "p1": "Cela permettra une visite guidée pour les signataires, fournissant des instructions pendant le processus de signature.", "p2": "Cela désactivera la visite guidée, garantissant ainsi une expérience de signature plus rapide et ininterrompue.", - "p3": "Conseil : si vos signataires connaissent OpenSign et l'utilisent fréquemment, vous souhaiterez peut-être désactiver la visite guidée pour une expérience plus fluide. Choisissez l'option qui correspond le mieux à vos besoins en matière de signature de documents." + "p3": "Conseil : si vos signataires connaissent OpenSign et l'utilisent fréquemment, vous souhaiterez peut-être désactiver la visite guidée pour une expérience plus fluide. Choisissez l'option qui correspond le mieux à vos besoins en matière de signature de documents." }, - "form-title-1": "Paramètre du flux de documents", - "form-title-2": "Paramètre de sécurité", + "form-title-1": "Paramètre du flux de documents", + "form-title-2": "Paramètre de sécurité", "public-tour-message": "Le modèle doit être public avant que vous puissiez générer un lien partageable.", - "add-user-template":"Vous devez ajouter un rôle avant de pouvoir lui ajouter des champs. ", - "pdf-uncompatible":"Ce pdf n'est pas compatible avec opensign, veuillez contacter ", - "text-field-tour" :"Les champs de type 'Texte' doivent être remplis à l'avance avant l'envoi du document. Si vous avez besoin que les signataires fournissent des informations, utilisez plutôt le champ 'Saisie de texte'.", - "attach-signer-tour" :"Vous devez associer un signataire à chaque rôle. Vous pouvez le faire en cliquant sur cette icône. Une fois que vous avez sélectionné un signataire, il sera attaché à tous les champs associés à ce rôle qui apparaissent dans la même couleur.", + "add-user-template": "Vous devez ajouter un rôle avant de pouvoir lui ajouter des champs. ", + "pdf-uncompatible": "Ce pdf n'est pas compatible avec opensign, veuillez contacter ", + "text-field-tour": "Les champs de type 'Texte' doivent être remplis à l'avance avant l'envoi du document. Si vous avez besoin que les signataires fournissent des informations, utilisez plutôt le champ 'Saisie de texte'.", + "attach-signer-tour": "Vous devez associer un signataire à chaque rôle. Vous pouvez le faire en cliquant sur cette icône. Une fois que vous avez sélectionné un signataire, il sera attaché à tous les champs associés à ce rôle qui apparaissent dans la même couleur.", "allowed-signature-types": "Types de signature autorisés", "at-least-one-signature-type": "Au moins un type de signature doit être activé.", "expect-default-one-signature-type": "Veuillez activer un type de signature supplémentaire en plus de celui par défaut.", - "add-signer-note": "Remarque - Ce contact sera ajouté à votre liste de contacts", + "add-signer-note": "Remarque - Ce contact sera enregistré dans vos contacts", "allowed-signature-types-help": { "p1": "Cette préférence de signature contrôle les options de signature disponibles pour vos signataires. Seuls les types de signature que vous sélectionnez apparaîtront dans le widget de signature lorsqu'un document est signé. Par exemple, si vous choisissez uniquement l'option 'Draw' dans les préférences, votre signataire ne verra que l'option 'Draw' dans le widget de signature, tandis que les trois autres options ne seront pas disponibles.", "l1": "Créez une signature manuscrite directement sur l'écran à l'aide de votre doigt ou d'un stylet.", @@ -704,9 +718,120 @@ "notify-on-signatures": "Notifier les signatures", "notify-on-signatures-help": { "p1": "Le créateur du document recevra une notification par e-mail chaque fois qu'un signataire signera le document.", - "note": "Remarque : L'e-mail de notification ne sera pas envoyé pour le dernier signataire, car le créateur du document recevra à la place un e-mail de fin." + "note": "Remarque: Quel que soit ce paramètre, un e-mail d'achèvement contenant le document signé et le certificat d'achèvement en pièce jointe est toujours envoyé à tous les signataires et au propriétaire du document." }, "expiry-date": "Fecha de caducidad", - "expiry-date-updated": "La fecha de vencimiento se ha extendido con éxito hasta el {{newexpirydate}}", - "expiry-date-error": "Veuillez fournir une nouvelle date d'expiration postérieure à la date actuelle" + "expiry-date-updated": "La date d'expiration a été prolongée avec succès jusqu'au {{newexpirydate}}", + "expiry-date-error": "Veuillez fournir une nouvelle date d'expiration postérieure à la date actuelle", + "duplicate-template-alert": "Êtes-vous sûr de vouloir créer une copie de ce modèle ?", + "duplicate-template-created": "Modèle en double créé avec succès.", + "delete-page": "supprimer la page", + "merge-pdf": "Fusionner le pdf", + "add-pages": "Ajouter des pages", + "delete-alert": "Impossible de supprimer une seule page", + "delete-alert-2": "Etes-vous sûr de vouloir supprimer cette page ?", + "delete-note": "Remarque : une fois cette page supprimée, vous ne pouvez plus l'annuler", + "Rotation-alert": "Faire pivoter la page", + "bulk-import": "Importation en masse", + "contacts-file": "Fichier de contacts (xlsx, csv)", + "100-records-only": "Actuellement, vous ne pouvez importer que 100 enregistrements.", + "csv-excel-support-only": "Veuillez télécharger un fichier dans l'un des formats suivants : CSV, XLSX ou XLS.", + "contact-imported": "{{imported}} contacts ont été importés. {{failed}} contacts n'ont pas pu être importés.", + "invalid-data": "Données invalides", + "delete-folder-alert": "Êtes-vous sûr de vouloir supprimer ce Dossier ?", + "delete-folder-alert-1": "Impossible de supprimer : le dossier doit être vide.", + "defaultSign-alert": "Les widgets {{widgetsType}} ne sont pas disponibles pour la signature automatique.", + "embed-heading": "Intégrer des modèles OpenSign", + "public-template-edit-title": "Modifier le modèle public", + "public-template-edit-mssg": "Vous ne pouvez pas modifier directement un modèle public. Pour apporter des modifications, le modèle sera défini comme privé et vous devrez ensuite le rendre à nouveau public. Voulez-vous continuer ?", + "agree-p1": "Je confirme avoir lu et compris les ", + "agree-p2": "Divulgation des enregistrements électroniques et des signatures", + "agree-p3": "et consentez à l'utilisation d'enregistrements et de signatures électroniques.", + "agrre-button": " Accepter et continuer ", + "term-cond-title": "Termes et conditions", + "term-cond-h": "DIVULGATION D'ENREGISTREMENT ÉLECTRONIQUE ET DE SIGNATURE", + "term-cond-p1": "Cette divulgation d'enregistrement électronique et de signature (' Divulgation ') est un accord entre le créateur du document (' Expéditeur ') et le signataire (' Vous '), facilité via la plateforme OpenSign (' Plateforme '). En signant des documents via OpenSign, vous acceptez les conditions décrites dans cette divulgation. Veuillez la lire attentivement avant de continuer.", + "term-cond-h1": "1. Objet et portée", + "term-cond-p2": "Cette divulgation régit l'utilisation d'enregistrements et de signatures électroniques pour les documents envoyés par l'expéditeur et signés par vous via la plateforme OpenSign. En acceptant, vous reconnaissez que :", + "term-cond-p3": "Vous recevrez et signerez des documents électroniquement via OpenSign.", + "term-cond-p4": "Votre signature électronique est juridiquement contraignante et équivaut à une signature manuscrite.", + "js-snippet-msg-2": "Gérer les modèles", + "js-snippet-msg-3": "page.", + "term-cond-h2": "2. Consentement à l'utilisation d'enregistrements et de signatures électroniques", + "term-cond-p5": "En acceptant cette divulgation :", + "term-cond-p6": "Vous consentez à effectuer des transactions électroniques avec l'expéditeur en utilisant OpenSign et comprenez que ce consentement est valable jusqu'à son retrait.", + "term-cond-p7": "Vous acceptez de consulter, de signer et de renvoyer des documents par voie électronique à l'aide d'OpenSign.", + "term-cond-p8": "Ce consentement s'applique uniquement au(x) document(s) spécifique(s) fourni(s) par l'Expéditeur.", + "term-cond-h3": "3. Droit de retirer le consentement", + "term-cond-p9": "Vous avez le droit de retirer votre consentement à l'utilisation d'enregistrements et de signatures électroniques en :", + "term-cond-p10": "Contacter directement l'expéditeur en utilisant les coordonnées fournies dans sa communication.", + "term-cond-p11": "Notifier l'expéditeur avant de terminer le processus de signature.", + "term-cond-h4": "4. Configuration matérielle et logicielle requise", + "term-cond-p12": "Pour signer des documents avec OpenSign, vous devez avoir :", + "term-cond-p13": "Un appareil avec accès à Internet.", + "term-cond-p14": "Un navigateur Web compatible avec JavaScript activé.", + "term-cond-p15": "Un compte email pour recevoir des notifications et des documents signés.", + "term-cond-p16": "Si ces exigences changent, l'expéditeur ou OpenSign vous informera des mises à jour.", + "term-cond-h5": "5. Conservation des dossiers et demande de copies papier", + "term-cond-p17": "Vous êtes responsable de vous assurer que vous pouvez accéder et conserver le(s) document(s) signé(s) électroniquement. OpenSign fournit des outils pour télécharger ou imprimer le document signé immédiatement une fois le processus de signature terminé.", + "term-cond-p18": "Si vous préférez une copie papier de tout document signé électroniquement, vous pouvez la demander directement à l'expéditeur. L'expéditeur peut facturer des frais raisonnables pour la fourniture de copies papier, sauf interdiction par la loi applicable.", + "term-cond-h6": "6. Reconnaissance et accord", + "term-cond-p19": "En procédant, Vous :", + "term-cond-p20": "Confirmez que vous pouvez accéder et consulter les documents électroniques comme décrit dans cette divulgation.", + "term-cond-p21": "Accepter d'utiliser des enregistrements et des signatures électroniques pour la ou les transactions spécifiées avec l'expéditeur.", + "term-cond-p22": "Comprenez qu'OpenSign est une plateforme facilitant la transaction et n'est pas partie à l'accord.", + "term-cond-h7": "7. Effet juridique", + "term-cond-p23": "Votre signature électronique facilitée grâce à OpenSign :", + "term-cond-p24": "Conforme aux lois applicables sur les signatures électroniques, y compris, mais sans s'y limiter, la loi E-SIGN aux États-Unis, le règlement eIDAS de l'UE et la loi indienne sur les technologies de l'information.", + "term-cond-p25": "Est juridiquement contraignant entre vous et l'expéditeur pour le(s) document(s) signé(s).", + "term-cond-h8": "8. Rôle de la plateforme et limitation de responsabilité", + "term-cond-p26": "OpenSign sert de plateforme pour faciliter les transactions électroniques. Il n'est pas responsable du contenu, de la validité ou du caractère exécutoire des documents envoyés par l'expéditeur. Tout litige ou problème lié au document ou à sa signature doit être résolu directement entre vous et l'expéditeur. Expéditeur.", + "term-cond-h9": "9. Résiliation du Contrat", + "term-cond-p27": "Votre consentement s'applique uniquement à la transaction en cours, sauf indication contraire de la part de l'expéditeur. OpenSign se réserve le droit de mettre fin à l'accès à sa plateforme en cas de violation de ses conditions d'utilisation ou de ses politiques.", + "term-cond-p28": "En sélectionnant J'accepte, vous confirmez que vous comprenez et acceptez les termes de cette divulgation d'enregistrement électronique et de signature et consentez à signer électroniquement le(s) document(s) fourni(s) par l'expéditeur via OpenSign.", + "term-cond-p29": "Si vous avez des questions sur cette divulgation, contactez directement l'expéditeur. Pour obtenir une assistance technique avec OpenSign, visitez", + "term-cond-p30": "ou par email", + "js-snippet-msg": "Pour intégrer des modèles OpenSign dans vos sites Web ou pages de destination HTML, vous pouvez utiliser le code ci-dessous :", + "js-snippet-msg-1": "Vous pouvez obtenir le TemplateId à partir de la page Gérer les modèles.", + "agrrement-alert": "Pour procéder, vous devez consentir à la divulgation des enregistrements et signatures électroniques.", + "webhook-already-exists": "L'URL existe déjà ! Veuillez en essayer un autre.", + "webhook-must-be-secure": "L'URL du webhook doit être sécurisée et utiliser https://", + "provide-test-token": "Veuillez générer un jeton de test API", + "invalid-redirect-url": "Veuillez fournir une URL de redirection valide.", + "auto-sign-mssg": "Tout signer automatiquement", + "already-exist-signer": "Le signataire sélectionné est déjà présent dans la liste des destinataires", + "allow-modify": "Autoriser les modifications", + "allow-modify-help": { + "p1": "Souhaitez-vous autoriser les modifications du document pendant le processus de signature ?", + "p2": "Sélectionner cette option permet aux signataires d'ajouter des éléments supplémentaires, tels que des signatures, des initiales, des tampons ou du texte, par-dessus les widgets existants.", + "p3": "Sélectionner cette option empêche les signataires d'apporter des ajouts au document pendant le processus de signature." + }, + "signature-setting": "Paramètres de signature", + "change-signer": "Changer de signataire", + "signyour-self-button": "Utilisez cette option pour signer le document vous-même sans en ajouter d'autres.", + "requestsign-button": "Utilisez cette option pour demander les signatures des autres et de vous-même.", + "signyour-self-description": "Utilisez ce formulaire pour signer le document vous-même sans en ajouter d'autres.", + "requestsign-description": "Utilisez ce formulaire pour demander les signatures des autres et de vous-même.", + "template-form-description": "Utilisez ce formulaire pour créer des modèles réutilisables pour vos documents.", + "activation-key": "Clé d'activation", + "paid-selfhost-help": "Veuillez contacter OpenSign pour plus d'informations à l'adresse ", + "remaining-credits-selfhost-help": "Utilisez des crédits premium pour la signature de documents via l'API, l'envoi en masse et l'intégration d'OpenSign sur votre site web. Vous avez {{allowedcredits}} crédits inclus et {{addoncredits}} crédits supplémentaires achetés restants.", + "signature-type": "Votre signature", + "initial-type": "Vos initiales", + "redirect-url": "URL de redirection", + "bulk-send": "Envoi groupé", + "select-timezone": "Sélectionnez votre fuseau horaire", + "current-time": "Heure actuelle", + "email-help": "Vous n'êtes pas autorisé à changer d'adresse e-mail pour des raisons de sécurité. Veuillez créer un autre compte gratuit en utilisant la nouvelle adresse e-mail.", + "doc-sent": "Document envoyé avec succès.", + "no-signer": "Supprimer", + "and": "et", + "make-public": "Rendre public", + "general": "Général", + "request-email": "E-mail de demande", + "completion-email": "E-mail de finalisation", + "variables-use": "Variables à utiliser", + "send-to-sign": "vous a demandé de signer", + "use-template": "Utiliser le modèle", + "contact-already-exists": "Le contact existe déjà." } diff --git a/apps/OpenSign/public/locales/it/translation.json b/apps/OpenSign/public/locales/it/translation.json new file mode 100644 index 000000000..0e845776e --- /dev/null +++ b/apps/OpenSign/public/locales/it/translation.json @@ -0,0 +1,837 @@ +{ + "header-news": "Nuova funzionalità: Gli utenti del piano Teams possono ora integrare i propri bucket AWS S3 per l'archiviazione dei file", + "header-news-btn": "Configura Ora", + "create-account": "Crea Account", + "login": "Accedi", + "language": "Lingua", + "name": "Nome", + "phone": "Telefono", + "phone-optional": "facoltativo", + "email": "Email", + "company": "Azienda", + "job-title": "Titolo professionale", + "profile": "Profilo", + "log-out": "Disconnetti", + "is-email-verified": "Email verificata", + "public-profile": "Profilo pubblico", + "tagline": "Slogan", + "has-requested-you-to-sign": "ha richiesto la tua firma", + "has-requested-you-to-review-and-sign": "ha richiesto la tua revisione e firma", + "input-required": "Per favore, compila questo campo.", + "sort-order": { + "Ascending": "Crescente", + "Descending": "Decrescente", + "Name": "Nome", + "Date": "Data" + }, + "context-menu": { + "Download": "Scarica", + "Rename": "Rinomina", + "Move": "Sposta", + "Delete": "Elimina" + }, + "action": "Azione", + "add": "Aggiungi", + "add-new-folder": "Aggiungi una nuova cartella", + "disable-documentId": "Disabilita DocumentId", + "edit": "Modifica", + "change-password": "Cambia Password", + "save": "Salva", + "cancel": "Annulla", + "upgrade-now": "Aggiorna ora", + "upgrade-to": "Aggiorna a", + "plan": "Piano", + "subscribe-card-teamplan": "Sblocca tutto il potenziale della collaborazione! Crea organizzazioni, team e gerarchie illimitati. Condividi modelli senza problemi tra i team e assegna ruoli personalizzati agli utenti. Migliora il tuo flusso di lavoro oggi stesso!", + "subscribe-card-plan": "Sblocca le funzionalità premium a partire da soli {{premiumPrice}}/mese. Approfitta di prestazioni migliorate e paga solo {{addonPrice}} per ogni credito aggiuntivo dopo quelli inclusi.", + "user-name-limit-char": "Per un nome utente con meno di 8 caratteri, abbonati", + "tour-content": "Non mostrare più", + "pro": "PRO", + "team": "TEAM", + "user": "Utente", + "docs": "Documenti", + "session-expired": "La tua sessione è scaduta.", + "public-profile-help": "Questo è il tuo URL pubblico. Copialo o condividilo con il firmatario, e potrai visualizzare tutti i tuoi modelli pubblici.", + "tagline-help": "Questo slogan apparirà nel tuo profilo pubblico OpenSign, es. https://opensign.me/alex", + "welcome": "Bentornato!", + "Login-to-your-account": "Accedi al tuo account", + "password": "Password", + "forgot-password": "Password dimenticata?", + "loading": "Caricamento...", + "of": "di", + "sign-SSO": "Accedi con SSO", + "login-page": "Pagina di accesso", + "or": "O", + "signup-page": "Pagina di registrazione", + "password-length": "La password deve contenere almeno 8 caratteri", + "password-case": "La password deve contenere una lettera maiuscola, una minuscola e un numero", + "password-special-char": "La password deve contenere un carattere speciale", + "agreee": "Accetto i", + "term": "Termini di servizio", + "subscribe-to-opensign": "Iscriviti alla newsletter di OpenSign", + "register": "Registrati", + "sidebar": { + "Dashboard": "Dashboard", + "Sign yourself": "Firma tu stesso", + "Request signatures": "Richiedi firme", + "Templates": "Modelli", + "Templates-Children": { + "Create template": "Crea modello", + "Manage templates": "Gestisci modelli", + "Embedding": "Incorporazione" + }, + "OpenSign™ Drive": "OpenSign™ Drive", + "Reports": "Report", + "Documents": "Documenti", + "Documents-Children": { + "Need your sign": "Necessita della tua firma", + "In Progress": "In corso", + "Completed": "Completati", + "Drafts": "Bozze", + "Declined": "Rifiutati", + "Expired": "Scaduti" + }, + "Contactbook": "Rubrica", + "Settings": "Impostazioni", + "Settings-Children": { + "My Signature": "La mia firma", + "API Token": "Token API", + "Webhook": "Webhook", + "Preferences": "Preferenze", + "Teams": "Team", + "Team-update-successfully": "Team aggiornato con successo.", + "Users": "Utenti" + } + }, + "dashboard-card": { + "Need your Signature": "Necessita della tua firma", + "Out for signatures": "In attesa di firme" + }, + "report-name": { + "Draft Documents": "Documenti in bozza", + "Need your sign": "Necessita della tua firma", + "In-progress documents": "Documenti in corso", + "Completed Documents": "Documenti completati", + "Declined Documents": "Documenti rifiutati", + "Expired Documents": "Documenti scaduti", + "Recently sent for signatures": "Inviati recentemente per firme", + "Recent signature requests": "Richieste di firma recenti", + "Drafts": "Bozze", + "Contactbook": "Rubrica", + "Templates": "Modelli", + "Teams": "Team", + "Users": "Utenti" + }, + "btnLabel": { + "sign": "firma", + "Sign": "FIRMA", + "Resend": "Reinvia", + "Rename": "Rinominare", + "Revoke": "Revoca", + "Delete": "Elimina", + "Use": "Usa", + "Quick send": "Invio rapido", + "Edit": "Modifica", + "Share with team": "Condividi con il team", + "Share": "Condividi", + "View": "Visualizza", + "option": "Opzione", + "Embed": "Incorpora", + "Copy TemplateId": "Copia TemplateId", + "Copy Public URL": "Copia URL pubblico", + "extend-expiry-date": "Estendi data di scadenza", + "Duplicate Template": "Duplica modello", + "Duplicate": "Duplica" + }, + "report-heading": { + "Sr.No": "Nr.", + "Title": "Titolo", + "Email": "Email", + "Phone": "Telefono", + "File": "File", + "Owner": "Proprietario", + "Signers": "Firmatari", + "Note": "Nota", + "Folder": "Cartella", + "Reason": "Motivo", + "Parent Team": "Team genitore", + "Active": "Attivo", + "Role": "Ruolo", + "Team": "Team", + "Name": "Nome", + "Status": "Stato", + "created-date": "Data di creazione", + "Type": "Tipo", + "Logs": "Log", + "Expiry-date": "Data di scadenza" + }, + "report-help": { + "Draft Documents": "Questi sono documenti che hai iniziato ma non hai ancora finalizzato per l'invio.", + "Need your sign": "Questa è una lista di documenti in attesa della tua firma.", + "In-progress documents": "Questa è una lista di documenti che hai inviato ad altre parti per la firma.", + "Completed Documents": "Questa è una lista di documenti firmati da tutte le parti.", + "Declined Documents": "Questa è una lista di documenti rifiutati da uno dei firmatari.", + "Expired Documents": "Questa è una lista di documenti che hanno raggiunto la data di scadenza.", + "Contactbook": "Questa è una lista di contatti/firmatari aggiunti da te. Appariranno come suggerimenti quando provi ad aggiungere firmatari a un nuovo documento.", + "Templates": "Questa è una lista di modelli disponibili per creare documenti. Puoi fare clic sul pulsante 'Usa' per creare un nuovo documento utilizzando un modello, modificare il documento e aggiungere firmatari nel passaggio successivo." + }, + "form-name": { + "Sign Yourself": "Firma tu stesso", + "Request Signatures": "Richiedi firme", + "New Template": "Nuovo modello" + }, + "file-type": "pdf, png, jpg, jpeg", + "docx": "docx", + "file-selected": "file selezionato", + "template-title": "Titolo del modello", + "document-title": "Titolo del documento", + "description": "Descrizione", + "time-to-complete": "Tempo per completare (giorni)", + "send-in-order": "Invia in ordine", + "send-in-order-help": { + "p1": "Scegli come desideri inviare le richieste di firma ai firmatari del documento:", + "p2": "Selezionando questa opzione, la richiesta di firma verrà inviata inizialmente al primo firmatario. Una volta che il primo firmatario avrà completato la propria parte, il successivo nella sequenza riceverà la richiesta. Questo processo continua fino a quando tutti i firmatari hanno firmato il documento. Questo metodo garantisce che il documento venga firmato in un ordine specifico.", + "p3": "Selezionando questa opzione, i link di firma verranno inviati a tutti i firmatari contemporaneamente. Ogni firmatario può firmare il documento a sua discrezione, indipendentemente dal fatto che altri firmatari abbiano completato le firme. Questo metodo è più veloce ma non impone un ordine di firma tra i partecipanti.", + "p4": "Seleziona l'opzione che meglio si adatta alle esigenze del tuo processo documentale." + }, + "no": "No", + "auto-reminder": "Promemoria automatico", + "remind-once": "Ricorda una volta ogni (giorni)", + "next": "Avanti", + "select-folder": "Seleziona cartella", + "OpenSign-drive": "OpenSign™ Drive", + "drive-document-status": { + "Completed": "Completato", + "Declined": "Rifiutato", + "Draft": "Bozza", + "Expired": "Scaduto", + "In Progress": "In corso" + }, + "select-folder-help": "Se non selezioni una cartella, il tuo documento firmato verrà salvato nella cartella principale di OpenSign drive.", + "no-data": "Nessun dato trovato", + "save-here": "Salva qui", + "back": "Indietro", + "add-folder": "Aggiungi cartella", + "create-folder": "Crea cartella", + "parent-folder": "Cartella principale", + "create": "Crea", + "signers": "Firmatari", + "signers-help": "Inizia a digitare il nome di un contatto per vedere i firmatari suggeriti dai tuoi contatti salvati o aggiungerne di nuovi. Organizza l'ordine di firma aggiungendo firmatari nella sequenza desiderata. Usa il pulsante '+' per includere firmatari e 'x' per rimuoverli. Ogni firmatario riceverà una notifica via email per firmare il documento nell'ordine elencato.", + "bcc-help": "it-Start it-typing it-a it-contact's it-name it-to it-see it-suggestions it-from it-your it-saved it-contacts it-or it-add it-new it-ones. it-Use it-the '+' it-button it-to it-add it-a it-user it-and it-the 'x' it-to it-remove it-them. it-The it-selected it-user's it-email it-will it-be it-added it-as it-a it-Bcc (it-blind it-carbon it-copy). it-Each it-user it-will it-receive it-an it-email it-notification it-once it-the it-document it-is it-completed.", + "add-signer": "Aggiungi firmatario", + "contact-not-found": "Contatto non trovato", + "add-yourself": "Aggiungi te stesso", + "submit": "Invia", + "reset": "Reimposta", + "my-signature": "La mia firma", + "signature": "Firma", + "upload-image": "Carica immagine", + "clear": "Chiara", + "upload-signature/Image": "Carica firma/immagine", + "initials": "Iniziali", + "API": "API", + "api-token": "Token API", + "regenerate-token": "Rigenera token live", + "generate-token": "Genera token live", + "view-docs": "Visualizza documenti", + "generate-token-alert": "Sei sicuro di voler rigenerare il token? Questo invaliderà il vecchio token.", + "yes": "Sì", + "copied": "Copiato", + "something-went-wrong-mssg": "Qualcosa è andato storto, riprova più tardi.", + "token-generated": "Token generato con successo.", + "webhook": "Webhook", + "update-webhook": "Aggiorna Webhook", + "add-webhook": "Aggiungi Webhook", + "webhook-added": "Webhook aggiunto con successo.", + "team-disabled": "Team disabilitato", + "Team enabled": "Team abilitato", + "are-you-sure": "Sei sicuro di voler", + "disable": "disabilitare", + "enable": "abilitare", + "this-team": "questo team?", + "edit-team": "Modifica Team", + "name-of-team": "Nome del Team", + "prev": "Precedente", + "no-data-avaliable": "Nessun dato disponibile", + "add-team": "Aggiungi Team", + "page-not-found": "Pagina non trovata", + "users-from-teams": "utenti dai Team", + "user-status": "Stato utente", + "activate": "attiva", + "deactivate": "disattiva", + "this-user": "questo utente", + "delete-user": "Elimina utente", + "delete": "elimina", + "add-user": "Aggiungi utente", + "password-generateed": "La password verrà generata solo una volta; assicurati di copiarla.", + "Team status": "Stato del Team", + "user-deactivated": "Utente disattivato.", + "user-activated": "Utente attivato.", + "public": "Pubblico", + "download": "Scarica", + "view": "Visualizza", + "make-template-public": "Rendi il modello pubblico", + "make-template-private": "Rendi il modello privato", + "make-template-public-alert": "Sei sicuro di voler rendere pubblico questo modello?", + "make-template-private-alert": "Sei sicuro di voler rendere privato questo modello? Questo lo rimuoverà dal tuo profilo pubblico.", + "public-role": "Ruolo pubblico", + "public-url": "Profilo pubblico", + "embed-template": "Incorpora Modello", + "public-url-copy": "Ecco il tuo URL pubblico: ", + "public-url-copy-mssg": "Copialo o condividilo con il firmatario; potrai vedere tutti i tuoi modelli impostati come pubblici.", + "add-public-url-alert": "Completa la configurazione del tuo profilo pubblico OpenSign. Dopo, potrai rendere i modelli pubblici. Questo processo è necessario solo una volta.", + "share-with-alert": "Non puoi condividere un modello se alcuni ruoli hanno già contatti assegnati. Rimuovi tutte le assegnazioni di contatti dai ruoli prima di condividere il modello.", + "share-with": "Condividi con", + "team-not-found": "Team non trovato", + "roles": "Ruoli", + "delete-document": "Elimina documento", + "delete-document-alert": "Sei sicuro di voler eliminare questo documento?", + "quick-send": "Invio rapido", + "add-new": "Aggiungi nuovo", + "send": "Invia", + "quick-send-alert-1": "Tutti i ruoli in questo documento sono attualmente collegati a contatti. Per inviare rapidamente copie di questo modello a più firmatari, assicurati che almeno un ruolo non sia collegato a nessun contatto.", + "quick-send-alert-2": "Assicurati che ci sia almeno un widget firma aggiunto per tutti i destinatari.", + "quick-send-alert-3": "Aggiungi almeno un ruolo a questo modello per 'invio rapido' a più firmatari.", + "quick-send-alert-4": "Limite di invio rapido raggiunto.", + "copy-link": "Copia link", + "copy": "Copia", + "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}}.", + "subject": "Oggetto", + "body": "Corpo del messaggio", + "add-contact": "Aggiungi contatto", + "edit-contact": "Modifica contatto", + "add-signer-alert": "Il contatto esiste già! Selezionalo dal menu a tendina ‘Firmatari’.", + "record-delete-alert": "Record eliminato con successo!", + "record-revoke-alert": "Record revocato con successo!", + "mail-sent-alert": "Email inviata con successo.", + "document-sent-alert": "Documento inviato con successo!", + "template-share-alert": "Modello condiviso con successo.", + "template-public-alert-1": "Hai reso pubblico il modello con successo.", + "template-public-alert-2": "Hai reso privato il modello con successo.", + "template-public-alert-3": "Devi selezionare un ruolo per i firmatari pubblici.", + "template-public-alert-4": "Assicurati che ci sia almeno un widget firma aggiunto per tutti i firmatari.", + "template-public-alert-5": "Poiché questo modello ha l'invio in ordine abilitato, il ruolo pubblico deve essere posizionato in cima.", + "template-public-alert-6": "Assegna firmatari a tutti i ruoli tranne che per l'utente ruolo pubblico.", + "template-public-alert-7": "Assegna almeno un ruolo pubblico per rendere questo modello pubblico.", + "loader": "Questo potrebbe richiedere del tempo.", + "pages": "Pagine", + "document-signed": "Documento firmato", + "close": "Chiudi", + "validation-alert": "Avviso di validazione", + "validate-alert-mssg": "L'input non soddisfa i criteri impostati dall'espressione regolare.", + "otp-verification": "Verifica OTP", + "enter-otp": "Inserisci OTP", + "verify": "Verifica", + "verify-email-1": "Verifica email", + "resend": "Reinvia", + "contact-details": "Dettagli contatto", + "verify-email": "Verifica la tua email!", + "send-otp": "Invia OTP", + "otp-placeholder": "Inserisci il codice di verifica ricevuto via email", + "loading-doc": "Caricamento del documento...", + "widgets-name": { + "signature": "firma", + "stamp": "timbro", + "initials": "iniziali", + "name": "nome", + "job title": "titolo lavorativo", + "company": "azienda", + "date": "data", + "text": "testo", + "text input": "campo di testo", + "checkbox": "casella di controllo", + "dropdown": "menu a tendina", + "radio button": "pulsante di opzione", + "image": "immagine", + "email": "email" + }, + "fields": "Campi", + "recipients": "Destinatari", + "please-add": "Aggiungi un", + "signed-by": "Firmato da", + "more": "altro", + "sent": "inviato", + "print": "Stampa", + "certificate": "Certificato", + "decline": "Rifiuta", + "finish": "Completa", + "mail": "Email", + "sign-now": "Firma ora", + "successfully-signed": "Firmato con successo!", + "email-mssg": "I destinatari aggiunti qui riceveranno una copia del documento firmato.", + "email-error-1": "fornisci un indirizzo email corretto", + "email-error-2": "Puoi inviare solo a dieci destinatari alla volta.", + "Email-verified-alert-1": "Email verificata.", + "Email-verified-alert-2": "Email già verificata.", + "upload-stamp-image": "Carica immagine timbro", + "draw": "Disegno", + "type": "Digitata", + "color-type": { + "red": "rosso", + "blue": "blu", + "black": "nero", + "yellow": "giallo" + }, + "my-initials": "Le mie iniziali", + "upload": "Caricamento", + "initial-teb": "Iniziali", + "signature-tab": "Firma", + "your-signature": "La tua firma", + "copy-title": "Copia widget in", + "contact-delete-alert": "Sei sicuro di voler eliminare questo contatto?", + "reset-password-alert-1": "Il link per reimpostare la password è stato inviato al tuo indirizzo email", + "reset-password-alert-2": "Si prega di configurare l'adattatore email", + "reset-password-alert-3": "Reimposta la tua password", + "faild-animation": "Caricamento animazione non riuscito", + "apply": "Applica", + "copy-type": { + "All pages": "Tutte le pagine", + "All pages but last": "Tutte le pagine tranne l'ultima", + "All pages but first": "Tutte le pagine tranne la prima", + "Next to current widget": "Accanto al widget corrente" + }, + "options": "Opzioni", + "minimun-check": "Controllo minimo", + "maximum-check": "Controllo massimo", + "default-value": "Valore predefinita", + "select": "Seleziona", + "read-only": "È solo lettura", + "hide-labels": "Nascondi etichette", + "checkbox": "Casella di controllo", + "alert": "Avviso", + "zoom-in": "Ingrandisci", + "zoom-out": "Riduci", + "document-signed-alert": "Congratulazioni! 🎉 Questo documento è stato firmato con successo da te!", + "otp-sent-alert": "OTP inviato alla tua email", + "fields-required": "Campi richiesti", + "signature-widget-alert-1": "Assicurati che sia stato aggiunto almeno un widget per la firma", + "signature-widget-alert-2": "Assicurati che tutti i campi siano compilati correttamente e soddisfino tutti i requisiti.", + "encrypted-pdf-alert": "Attualmente i file PDF crittografati non sono supportati.", + "encrypted-pdf-alert-1": "La password del file PFX non è valida.", + "user-not-exist": "L'utente non esiste", + "template-role-alert": "Aggiungi prima i ruoli", + "create-document": "Crea Documento", + "template-created-alert": "Cosa vorresti fare con il modello che hai appena creato?", + "signers-alert": "Avviso firmatari", + "template-creation-alert-1": "Seleziona il firmatario per aggiungere un segnaposto!", + "ok": "Ok", + "radio-group": "Gruppo radio", + "dropdown-options": "Opzioni a discesa", + "add-role": "Aggiungi Ruolo", + "role-ex": "es: Cliente, HR, Direttore, Manager, Studente, ecc.", + "add/choose-signer": "Aggiungi/Scegli Firmatario", + "choose-from-contacts": "Scegli dai contatti", + "select-signer": "Seleziona il firmatario", + "edit-template": "Modifica Modello", + "widget-info": "Informazioni Widget", + "validation": "Validazione", + "invalid-default-value": "Valore predefinita non valido", + "hint": "Suggerimento", + "color": "Colore", + "role-help": { + "p1": "Cosa sono i ruoli del modello?", + "p2": "Inizia specificando ogni ruolo necessario per completare il documento. Pensa alle parti coinvolte nel processo di firma e alle loro responsabilità. I ruoli comuni includono HR per documenti interni, Cliente per accordi o Fornitore per accordi commerciali.", + "p3": "Perché pre-assegnare utenti a determinati ruoli?", + "p4": "Per ruoli che coinvolgono sempre la stessa persona (es. la firma del CEO sulle lettere di offerta ai dipendenti), puoi pre-assegnare un utente a un ruolo nel modello. Questo passaggio è facoltativo ma consigliato per efficienza e coerenza nei documenti.", + "p5": "Quando specifico l'utente associato a ciascun ruolo?", + "p6": "Quando crei un documento dal tuo modello, ti verrà chiesto di assegnare utenti a ciascun ruolo definito. Se un ruolo ha già un utente associato, sarà precompilato, ma puoi modificarlo se necessario prima di inviare il documento." + }, + "add-recipients": "Aggiungi destinatari", + "loading-mssg": "Questo potrebbe richiedere del tempo", + "send-mail": "Invia Mail", + "placeholder-alert-1": "Assicurati che sia stato aggiunto almeno un widget per la firma per tutti i destinatari.", + "placeholder-alert-2": "Conferma di aver compilato il campo di testo.", + "placeholder-alert-3": "Sei sicuro di voler inviare questo documento per le firme?", + "placeholder-alert-4": "Hai inviato con successo le mail a tutti i destinatari!", + "placeholder-mail-alert": "Hai inviato con successo un'e-mail a {{name}}. I firmatari successivi riceveranno un'e-mail una volta che {{name}} avrà firmato il documento.", + "placeholder-alert-5": "Vuoi firmare i documenti ora?", + "placeholder-alert-6": "Configura l'adattatore email per inviare mail!", + "placeholder-alert-7": "Seleziona il firmatario per aggiungere un segnaposto!", + "email-subject": "Oggetto email", + "email-body": "Corpo email", + "email-placeholder": "aggiungi corpo dell'email", + "reset-to-default": "Reimposta predefinita", + "cutomize-email": "Personalizza Email", + "upgrade-to-customize-email": "Aggiorna per personalizzare l'Email", + "sign-url": "URL Firma", + "mails-sent": "Mail inviate", + "mail-not-delivered": "Mail non consegnata", + "document-alert": "Avviso Documento", + "owner-subscription-expired": "L'abbonamento del proprietario è scaduto.", + "subscription-expired": "Abbonamento Scaduto", + "alert-message": "Messaggio di avviso", + "document-decline": "Documento rifiutato", + "decline-alert-1": "Sei sicuro di voler rifiutare questo documento?", + "decline-alert-2": "Hai rifiutato questo documento!", + "decline-alert-3": "Non puoi firmare questo documento poiché è stato rifiutato/revocato.", + "sign here": "Firma qui", + "guest-email-alert": "Il codice di verifica è stato inviato alla tua email", + "get-otp-alert": "Riceverai un codice di verifica tramite Email", + "user-already-exist": "L'utente esiste già.", + "server-error": "Errore interno del server!", + "fill-required-details!": "Compila i dettagli richiesti!", + "sign-up-form": "Modulo di registrazione", + "sign-up": "Registrati", + "folder-already-exist!": "La cartella esiste già!", + "please-select-position!": "Seleziona la posizione!", + "default-sign-alert": "Sei sicuro di voler firmare automaticamente in tutte le posizioni richieste?", + "Your-Signature": "La tua Firma", + "auto-sign-all": "Firma tutto automaticamente", + "generating-certificate": "Generazione certificato", + "pdf-download": "Scarica PDF", + "generate-certificate-alert": "Il certificato di completamento è in fase di generazione. Attendi momentaneamente. Se il download non inizia a breve, fai clic nuovamente sul pulsante.", + "generate-certificate-err": "Stiamo attualmente riscontrando un problema con la generazione del certificato. Per favore riprova più tardi.", + "folder-already-exist": "La cartella esiste già!", + "folder-created-successfully": "Cartella creata con successo!", + "fill-folder-name": "Compila il nome della cartella", + "already-exists-this-username": "Un utente con questo nome utente esiste già!", + "verification-code-sent": "Una mail di verifica è stata inviata al tuo indirizzo email!", + "registered-user-successfully": "Utente registrato con successo.", + "role-not-found": "Ruolo non trovato.", + "do-not-access": "Non hai accesso, contatta l'amministratore.", + "add-admin": "Aggiungi amministratore", + "opensign-setup": "Configurazione OpenSign", + "join-discord": "Unisciti al nostro server Discord", + "admin-already-exist": "L'amministratore esiste già.", + "password-update-alert-1": "Password aggiornata con successo.", + "password-update-alert-2": "La tua password attuale manca o è errata.", + "password-update-alert-3": "La tua password attuale è mancante o errata.", + "password-update-alert-4": "La tua password e la password di conferma non corrispondono.", + "current-password": "Password attuale", + "new-password": "Nuova Password", + "confirm-password": "Conferma Password", + "file-alert-1": "La dimensione del file selezionato è troppo grande. Seleziona un file inferiore a", + "file-alert-2": "Seleziona un file.", + "file-alert-3": "Attendi mentre il documento viene caricato.", + "enter-pdf-password": "Inserisci la password del PDF", + "correct-password": "Fornisci la password corretta", + "decrypting-pdf": "Decrittazione PDF, attendi...", + "invalid-otp": "OTP non valido", + "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", + "enter-verification-code": "Inserisci il codice di verifica", + "provide-your-details": "Fornisci i tuoi dettagli", + "provide-email": "Fornisci l'email.", + "additional-info": "Informazioni aggiuntive", + "signature-saved-alert": "Firma salvata con successo.", + "saved-successfully": "Salvato con successo.", + "fill-field": "Compila questo campo", + "error-template": "Errore: Modello non trovato!", + "error": "Errore", + "invalid-document": "Errore: documento non valido!", + "document-not-found": "Documento non trovato!", + "document-signed-alert-1": "Hai firmato con successo il documento. Puoi scaricare o stampare una copia del documento parzialmente firmato. Una copia del documento firmato digitalmente e del certificato di completamento verrà inviata al proprietario e a tutti i firmatari via email una volta che tutti avranno firmato.", + "encrypted-pdf-not-support": "Attualmente i file PDF crittografati non sono supportati.", + "document-signed-alert-4": "Congratulazioni! 🎉 Questo documento è stato firmato con successo da tutti i partecipanti!", + "document-signed-alert-5": "Questo documento è stato firmato da tutti i firmatari.", + "document-signed-alert-6": "Questo documento è stato rifiutato da uno o più destinatari.", + "document-signed-alert-7": "Questo documento non è più disponibile.", + "document-signed-alert-8": "Il documento è già stato inviato per la firma.", + "yet-to-sign": "Ancora da firmare", + "validation-alert-1": "L'input non soddisfa i criteri impostati dall'espressione regolare.", + "account-already-exists": "L'account esiste già!", + "choose-password": "Scegli Password", + "enter-password": "Inserisci Password", + "sure": "sicuro", + "subscribed-alert": "Hai già sottoscritto il piano!", + "monthly": "Mensile", + "yearly-upto": "Annuale (fino al 66% di sconto)", + "billed-yearly": "Fatturato annualmente", + "billed-monthly": "Fatturato mensilmente", + "plansubscription-1": "Ospitalo tu stesso gratuitamente", + "visit-github": "Visita Github", + "user-already-exist-name": "Esiste già un utente con questo nome utente!", + "do-not-access-contact-admin": "Non hai accesso, contatta l'amministratore.", + "filed-required-correctly": "Compila i dettagli richiesti correttamente.", + "admin-created": "Amministratore creato", + "invalid-masterkey": "Masterkey non valida", + "opensign-Setup": "Configurazione OpenSign", + "master-key": "Chiave principale", + "profile-update-alert": "Profilo aggiornato con successo.", + "date": "Data", + "report-not-found": "Report non trovato", + "please-wait": "attendere prego", + "select-foler": "Seleziona cartella", + "generated-on": "Generato il", + "text-field": "Campo di testo", + "font-size": "Dimensione carattere", + "widget-status": { + "Required": "Richiesto", + "Optional": "Opzionale" + }, + "all-right": "Tutti i diritti riservati", + "version": "versione", + "social-media": { + "github": "Github", + "linked-in": "LinkedIn", + "twitter": "Twitter", + "discord": "Discord" + }, + "tour-mssg": { + "home-layout-1": "Accesso effettuato con successo! Diamo un'occhiata.", + "home-layout-2": "Per caricare documenti da firmare personalmente o richiedere le firme di altri, seleziona semplicemente i pulsanti corrispondenti.", + "home-layout-3": "Sei pronto per iniziare a usare OpenSign! Se hai bisogno di supporto, contattaci pure.", + "generate-token": "Esegui l'upgrade ora per generare un token API di produzione.", + "opensign-drive-1": "Fai clic sui collegamenti breadcrumb per navigare facilmente attraverso la gerarchia delle cartelle e visualizzare i documenti in ciascuna cartella.", + "opensign-drive-2": "Fai clic sul pulsante aggiungi per creare una nuova cartella o documento.", + "opensign-drive-3": "Ordina i tuoi documenti per data o nome utilizzando questo menu.", + "opensign-drive-4": "Fai clic su questo menu per visualizzare i documenti in modalità elenco.", + "opensign-drive-5": "L'elenco dei documenti è visualizzato in base all'opzione di ordinamento selezionata. Le icone accanto a ciascun documento indicano il suo stato attuale.", + "opensign-drive-6": "Fai clic con il tasto destro su un documento per vedere opzioni come Scarica, Rinomina, Sposta e Elimina. Fai clic sul documento per aprirlo.", + "opensign-drive-7": "Fai clic con il tasto destro su qualsiasi cartella per vedere le opzioni. Scegli 'Rinomina' per cambiare il nome della cartella o fai clic sulla cartella per navigare nei suoi contenuti.", + "pdf-request-file-1": "Elenco dei firmatari che devono ancora firmare il documento.", + "pdf-request-file-2": "Fai clic su uno dei segnaposto che appaiono sul documento per firmare. Vedrai poi le opzioni per disegnare la tua firma, digitarla o caricare un'immagine.", + "pdf-request-file-3": "Clicca sui pulsanti Rifiuta o Fine per navigare nel tuo documento. Usa il menu con i puntini di sospensione per opzioni aggiuntive, incluso il pulsante Scarica.", + "pdf-request-file-4": "Elenco dei firmatari che hanno già firmato il documento.", + "pdf-request-file-5": "Puoi fare clic su 'Firma Tutto Automaticamente' per firmare automaticamente in tutte le posizioni previste per te. Assicurati di esaminare attentamente il documento prima di fare clic su questo pulsante.", + "pdf-request-file-6": "Si prega di completare i campi alla pagina {{pagenumbers}}, tutti evidenziati con lo stesso colore per una facile identificazione.", + "placeholder-sign-1": "Seleziona un destinatario da questo elenco per aggiungere un segnaposto dove deve firmare. Il segnaposto apparirà dello stesso colore del nome del destinatario una volta posizionato sul documento.", + "placeholder-sign-2": "Facendo clic sul pulsante 'Aggiungi destinatari' potrai aggiungere più firmatari.", + "placeholder-sign-3": "Fai clic su questo pulsante per aggiungere altri destinatari/firmatari al documento.", + "placeholder-sign-4": "Trascina o fai clic su un campo per aggiungerlo al documento.", + "placeholder-sign-5": "L'area del contenuto PDF visualizza già i segnaposti esistenti del modello. Per tua comodità, questi segnaposti corrisponderanno al colore del nome del destinatario, rendendoli facilmente identificabili.", + "placeholder-sign-6": "Facendo clic su 'Invia' il documento verrà salvato. Nel passaggio successivo potrai personalizzare le email da inviare ai destinatari o copiare i link di firma e condividerli direttamente con i destinatari.", + "report-1": "Fai clic sul pulsante 'Aggiungi' per creare un nuovo modello. I modelli sono documenti riutilizzabili progettati per generare rapidamente nuovi documenti con la stessa struttura e firmatari diversi. Ad esempio, un modello HR per l'onboarding potrebbe avere ruoli predefinita come ‘Responsabile HR’ e ‘Nuovo Dipendente’. Ogni volta che usi il modello, puoi assegnare il ruolo ‘Nuovo Dipendente’ a membri dello staff in arrivo, mentre il ruolo ‘Responsabile HR’ rimane costante, facilitando un processo di onboarding fluido per ogni nuovo assunto.", + "redirect": "Fai clic sul pulsante 'Usa' per creare un nuovo documento da un modello esistente.", + "bulksend": "Per inviare rapidamente più documenti utilizzando un modello esistente creando semplicemente gli indirizzi e-mail dei destinatari, fai clic sul pulsante 'Invio Multiplo'.", + "option": "Questo menu rivela altre opzioni come Modifica ed Elimina. Usa il pulsante 'Modifica' per aggiungere ruoli di firmatari, modificare i campi e aggiornare il modello. Le modifiche si applicheranno a tutti i futuri documenti creati da questo modello ma non influiranno sui documenti esistenti. Usa il pulsante Elimina per eliminare il modello.", + "signyour-self-1": "Seleziona e trascina i widget preferiti sul PDF per personalizzare il documento prima di firmarlo. Scegli i punti perfetti per ogni modifica per adattare il documento alle tue esigenze.", + "signyour-self-2": "Trascina e rilascia ovunque in quest'area. Puoi ridimensionarlo e spostarlo in seguito.", + "template-placeholder-1": "Facendo clic sul pulsante 'Aggiungi ruolo' potrai aggiungere vari ruoli di firmatari. Puoi assegnare utenti a ciascun ruolo nei passaggi successivi.", + "template-placeholder-2": "Una volta aggiunti i ruoli, seleziona un ruolo dall'elenco per aggiungere un segnaposto dove deve firmare. Il segnaposto apparirà dello stesso colore del nome del ruolo una volta posizionato sul documento.", + "template-placeholder-3": "Trascina o fai clic su un campo per aggiungerlo al documento.", + "template-placeholder-4": "Trascina il segnaposto per un ruolo ovunque sul documento. Ricorda, apparirà dello stesso colore del nome del destinatario per un facile riferimento.", + "template-placeholder-5": "Facendo clic su 'Avanti' il modello corrente verrà memorizzato. Dopo averlo salvato, ti verrà chiesto di creare un nuovo documento da questo modello, se lo desideri.", + "webhook-1": "Esegui l'upgrade ora per configurare il webhook.", + "Need your Signature": "Facendo clic su questa scheda, accederai all'elenco dei documenti in attesa della tua revisione.", + "Out for signatures": "Facendo clic su questa scheda, accederai all'elenco dei documenti in attesa di firma.", + "Recent signature requests": "Questo è un elenco di documenti che aspettano la tua firma.", + "Recently sent for signatures": "Questo è un elenco di documenti che hai inviato ad altre parti per la firma.", + "Drafts": "Questi sono documenti che hai iniziato ma non hai finalizzato per l'invio.", + "public-template": "Questo video dimostra come configurare il tuo profilo pubblico personalizzato, come ‘https://opensign.me/tuo-username’. Imparerai anche come personalizzare il tuo slogan e rendere i tuoi modelli disponibili per la firma pubblica.", + "allowModify-widgets": "È possibile trascinare e rilasciare uno qualsiasi di questi campi nel documento, oltre ai campi già designati dal creatore del documento." + }, + "enter-email-plaholder": "Aggiungi un indirizzo email e premi invio", + "success-email-alert": "Email inviata con successo!", + "expired-doc-title": "Documento Scaduto", + "expired-on-mssg": "Questo documento è scaduto il {{expiredDate}} e non è più disponibile per la firma.", + "signature-validate-alert": "Conferma di aver selezionato almeno {{minRequiredCount}} caselle di controllo.", + "signature-validate-alert-2": "Assicurati che questo campo sia compilato correttamente e soddisfi tutti i requisiti.", + "remaing-users": "Utenti rimanenti", + "Role": "Ruolo", + "additional-users": "Acquista utenti aggiuntivi.", + "Quantity-of-users": "Quantità di utenti", + "Price": "Prezzo", + "Total-price-for-next-time": "Prezzo totale per la prossima volta", + "Proceed": "Procedi", + "Select": "Seleziona", + "Add-seats": "Aggiungi Posti", + "user-name-exist": "Il nome utente esiste già", + "format": "formato", + "select-date-format": "Seleziona un formato data", + "quantity-of-credits": "Quantità di crediti premium", + "remaining-credits": "Crediti premium disponibili:", + "remaining-credits-help": "Usa i crediti premium per firmare documenti API, invii in massa o per integrare OpenSign nel tuo sito web. Hai a disposizione {{allowedcredits}} crediti inclusi e {{addoncredits}} crediti acquistati aggiuntivi rimanenti.", + "additional-credits": "Acquista crediti premium", + "quota-err-quicksend": "Quota raggiunta, non hai abbastanza crediti.", + "buy-credits": "Acquista Crediti Premium", + "rotate-right": "Ruota a destra", + "rotate-left": "Ruota a sinistra", + "rotate-alert-mssg": "Tutti i widget su questa pagina andranno persi. Sei sicuro di voler procedere?", + "templateid": "ID Modello", + "bulk-send-subcription-alert": "Esegui l'upgrade al piano Professionale o Team per utilizzare l'invio in massa.", + "generate-test-token": "Genera Token di Test", + "regenerate-test-token": "Rigenera Token di Test", + "help-test-token": "Questo token può essere utilizzato per testare le API all'endpoint https://sandbox.opensignlabs.com/api/v1, consentendoti di firmare documenti illimitati. Nota che le API sandbox firmeranno i tuoi documenti con certificati autofirmati, che potrebbero non essere riconosciuti come validi da Adobe. Una volta completati i test, puoi eseguire l'upgrade a uno dei nostri piani a pagamento per generare un token di produzione.", + "help-api-token": "Questo token può essere utilizzato per accedere alle API di produzione all'endpoint {{origin}}/api/v1. Può essere generato solo su uno dei nostri piani a pagamento.", + "reason": "Motivo", + "decline-by": "Rifiutato/revocato da", + "document-declined": "Documento rifiutato", + "public-template-mssg-1": "Per integrare OpenSign nel tuo progetto React o Next.js, esegui semplicemente il seguente comando:", + "public-template-mssg-2": "Assicurati di avere npm o yarn configurato nel tuo progetto. Se usi Yarn, puoi sostituire npm install con yarn add @opensign/react.", + "public-template-mssg-3": "Hai bisogno di maggiori dettagli o esempi?", + "public-template-mssg-4": "Visita il", + "public-template-mssg-5": " npm per gli aggiornamenti più recenti, documentazione dettagliata e cronologia delle versioni.", + "public-template-mssg-6": "Prima di poter utilizzare questo frammento di codice, devi rendere questo modello pubblico.", + "public-template-mssg-7": "Prima di poter generare un link pubblico, devi rendere questo modello pubblico.", + "here": "Qui", + "copy-code": "COPIA", + "copied-code": "COPIATO", + "Installation": "Installazione", + "Usage": "Utilizzo", + "insufficient-credits": "Crediti di firma insufficienti", + "insufficient-credits-mssg": "Il proprietario di questo documento non dispone attualmente dei crediti OpenSign necessari affinché tu possa firmare. Contatta il proprietario per ulteriori dettagli.", + "angular-npm-mssg-1": "Per integrare OpenSign nel tuo progetto Angular, esegui semplicemente il seguente comando:", + "quota-mail-info-head": "Limite mensile email per richieste di firma", + "quota-mail-info": "Puoi inviare fino a 15 email di richiesta di firma ogni mese. Passa al piano superiore per inviare richieste di firma illimitate direttamente.", + "quota-mail-reset": "I tuoi crediti email per richieste di firma saranno ripristinati il", + "quota-mail": "Hai raggiunto il limite di 15 email di richiesta di firma per questo mese. Passa al piano superiore per continuare a inviare email direttamente.", + "quota-mail-tip": "Suggerimento: Puoi comunque firmare <1>documenti illimitati condividendo manualmente i link per le richieste di firma.", + "quota-mail-head": "Quota Raggiunta", + "unauthorized-modal": "Non hai l'autorizzazione per eseguire questa azione, contatta {{adminEmail}}.", + "sent-this-month": "Inviati questo mese", + "available-seats": "Posti disponibili", + "buy-users": "Acquista più utenti", + "isenable-otp": "Abilita verifica OTP", + "isenable-otp-help": { + "p1": "Vuoi abilitare il processo di verifica tramite password monouso (OTP)?", + "p2": "Selezionando questa opzione, abiliterai la verifica OTP. Gli utenti riceveranno un codice di verifica via email che dovranno inserire per firmare il documento.", + "p3": "Selezionando questa opzione, disabiliterai la verifica OTP, consentendo agli utenti di firmare il documento direttamente senza passaggi aggiuntivi.", + "p4": "Scegli l'opzione che meglio si adatta alle tue esigenze di firma dei documenti." + }, + "advanced-options": "Opzioni avanzate", + "hide-advanced-options": "Nascondi opzioni avanzate", + "download-files": "Scarica file", + "download-pdf": "Scarica Pdf", + "pdf-certificate": "Scarica Pdf + Certificato", + "document-logs": "Log del documento", + "server-down": "Impossibile connettersi al server OpenSign. Se stai ospitando OpenSign autonomamente, assicurati che tutti i passaggi nella documentazione siano stati seguiti correttamente. Se stai eseguendo OpenSign localmente, potresti accedervi tramite un numero di porta errato.", + "admin-exists": "L'amministratore esiste già. Accedi all'applicazione utilizzando le credenziali di amministratore per gestire gli utenti.", + "enable-tour": "Abilita tour", + "istourenabled-help": { + "p1": "Questo abiliterà un tour guidato per i firmatari, fornendo istruzioni durante il processo di firma.", + "p2": "Questo disabiliterà il tour guidato, garantendo un'esperienza di firma più veloce e senza interruzioni.", + "p3": "Suggerimento: Se i tuoi firmatari sono familiari con OpenSign e lo usano frequentemente, potresti voler disabilitare il tour guidato per un'esperienza più fluida. Scegli l'opzione che meglio si adatta alle tue esigenze di firma dei documenti." + }, + "form-title-1": "Impostazioni del flusso del documento", + "form-title-2": "Impostazioni di sicurezza", + "public-tour-message": "Il modello deve essere pubblico prima di poter generare un link condivisibile.", + "add-user-template": "Devi aggiungere un ruolo prima di poter aggiungere i campi per esso.", + "pdf-uncompatible": "Questo PDF non è compatibile con OpenSign, contatta ", + "text-field-tour": "I campi di tipo 'Testo' devono essere compilati in anticipo prima che il documento venga inviato. Se hai bisogno che i firmatari forniscano un input, usa invece il campo 'Testo di input'.", + "attach-signer-tour": "Devi allegare un firmatario a ogni ruolo. Puoi farlo cliccando su questa icona. Una volta selezionato un firmatario, sarà associato a tutti i campi associati a quel ruolo che appariranno dello stesso colore.", + "allowed-signature-types": "Tipi di firma consentiti", + "at-least-one-signature-type": "Almeno un tipo di firma deve essere abilitato.", + "expect-default-one-more-signature-type": "Abilita un tipo di firma aggiuntivo oltre al tipo predefinita.", + "add-signer-note": "Nota - Questo contatto verrà aggiunto alla tua lista di contatti", + "allowed-signature-types-help": { + "p1": "Questa preferenza di firma controlla le opzioni di firma disponibili per i tuoi firmatari. Solo i tipi di firma che selezioni appariranno nel widget di firma quando un documento viene firmato. Ad esempio, se scegli solo l'opzione 'Disegna' nelle preferenze, il tuo firmatario vedrà solo l'opzione 'Disegna' nel widget di firma, mentre gli altri tre tipi non saranno disponibili.", + "l1": "Crea una firma scritta a mano direttamente sullo schermo utilizzando il dito o una penna digitale.", + "l2": "Inserisci il tuo nome e scegli tra vari stili di font per creare una firma.", + "l3": "Carica una versione digitale esistente della tua firma.", + "l4": "Usa uno stile di firma preimpostato salvato sotto 'La mia firma' nelle tue impostazioni." + }, + "notify-on-signatures": "Notifica sulle firme", + "notify-on-signatures-help": { + "p1": "Il creatore del documento riceverà una notifica via email ogni volta che un firmatario firma il documento.", + "note": "Nota: L'email di notifica non verrà inviata per l'ultimo firmatario, poiché il creatore del documento riceverà invece un'email di completamento." + }, + "expiry-date": "Data di scadenza", + "expiry-date-updated": "La data di scadenza è stata estesa con successo a {{newexpirydate}}", + "expiry-date-error": "Fornisci una nuova data di scadenza successiva a quella attuale", + "duplicate-template-alert": "Sei sicuro di voler creare un duplicato di questo modello?", + "duplicate-template-created": "Modello duplicato creato con successo.", + "delete-page": "Elimina pagina", + "merge-pdf": "Unisci PDF", + "add-pages": "Aggiungi pagine", + "delete-alert": "Non è possibile eliminare una singola pagina", + "delete-alert-2": "Sei sicuro di voler eliminare questa pagina?", + "delete-note": "Nota: Una volta eliminata questa pagina, non potrai annullare l'operazione.", + "Rotation-alert": "Ruota pagina", + "bulk-import": "Importazione massiva", + "contacts-file": "File contatti (xlsx, csv)", + "100-records-only": "Attualmente puoi importare solo fino a 100 record.", + "csv-excel-support-only": "Carica un file nei seguenti formati: CSV, XLSX o XLS.", + "contact-imported": "{{imported}} contatti importati. {{failed}} contatti non sono stati importati.", + "invalid-data": "Dati non validi", + "delete-folder-alert": "Sei sicuro di voler eliminare questa cartella?", + "delete-folder-alert-1": "Impossibile eliminare: la cartella deve essere vuota.", + "defaultSign-alert": "I widget {{widgetsType}} non sono disponibili per la firma automatica.", + "embed-heading": "Incorpora modelli OpenSign", + "public-template-edit-title": "Modifica Modello Pubblico", + "public-template-edit-mssg": "Non puoi modificare direttamente un modello pubblico. Per apportare modifiche, il modello sarà impostato come privato e dovrai renderlo pubblico di nuovo successivamente. Vuoi continuare?", + "agree-p1": "Confermo di aver letto e compreso il", + "agree-p2": "Divulgazione sulle registrazioni e firme elettroniche", + "agree-p3": "e acconsento all'uso di registrazioni e firme elettroniche.", + "agrre-button": "Accetta e Continua", + "term-cond-title": "Termini e Condizioni", + "term-cond-h": "DIVULGAZIONE SULLE REGISTRAZIONI E FIRME ELETTRONICHE", + "term-cond-p1": "Questa Divulgazione sulle Registrazioni e Firme Elettroniche ('Divulgazione') è un accordo tra il Creatore del Documento ('Mittente') e il Firmatario ('Tu'), facilitato tramite la piattaforma OpenSign ('Piattaforma'). Firmando documenti tramite OpenSign, accetti i termini descritti in questa Divulgazione. Ti preghiamo di leggerla attentamente prima di procedere.", + "term-cond-h1": "1. Scopo e ambito", + "term-cond-p2": "Questa Divulgazione regola l'uso di registrazioni e firme elettroniche per i documenti inviati dal Mittente e firmati da Te tramite la piattaforma OpenSign. Accettando, riconosci che:", + "term-cond-p3": "Riceverai e firmerai documenti elettronicamente tramite OpenSign.", + "term-cond-p4": "La tua firma elettronica è legalmente vincolante ed equivalente a una firma manoscritta.", + "term-cond-h2": "2. Consenso all'uso di registrazioni e firme elettroniche", + "term-cond-p5": "Accettando questa Divulgazione:", + "term-cond-p6": "Consenti di effettuare transazioni elettroniche con il Mittente utilizzando OpenSign e comprendi che questo consenso è valido fino a revoca.", + "term-cond-p7": "Accetti di rivedere, firmare e restituire documenti elettronicamente utilizzando OpenSign.", + "term-cond-p8": "Questo consenso si applica solo ai documenti specifici forniti dal Mittente.", + "term-cond-h3": "3. Diritto di revoca del consenso", + "term-cond-p9": "Hai il diritto di ritirare il tuo consenso all'uso di registrazioni elettroniche e firme contattando direttamente il mittente tramite le informazioni di contatto fornite nella loro comunicazione.", + "term-cond-p10": "Contattando il mittente direttamente utilizzando le informazioni di contatto fornite nella loro comunicazione.", + "term-cond-p11": "Notificando il mittente prima di completare il processo di firma.", + "term-cond-h4": "4. Requisiti hardware e software", + "term-cond-p12": "Per firmare documenti utilizzando OpenSign, devi avere:", + "term-cond-p13": "Un dispositivo con accesso a Internet.", + "term-cond-p14": "Un browser web compatibile con JavaScript abilitato.", + "term-cond-p15": "Un account email per ricevere notifiche e documenti firmati.", + "term-cond-p16": "Se questi requisiti cambiano, il mittente o OpenSign ti notificheranno gli aggiornamenti.", + "term-cond-h5": "5. Conservazione dei documenti e richiesta di copie cartacee", + "term-cond-p17": "Sei responsabile di assicurarti di poter accedere e conservare il documento(i) firmato(i) elettronicamente. OpenSign fornisce strumenti per scaricare o stampare il documento firmato subito dopo che il processo di firma è completo.", + "term-cond-p18": "Se preferisci una copia cartacea di qualsiasi documento firmato elettronicamente, puoi richiederla direttamente al mittente. Il mittente può addebitare una tariffa ragionevole per fornire copie cartacee, salvo quanto vietato dalla legge applicabile.", + "term-cond-h6": "6. Riconoscimento e Accordo", + "term-cond-p19": "Procedendo, confermi che:", + "term-cond-p20": "Confermi di poter accedere e rivedere i documenti elettronici come descritto in questa divulgazione.", + "term-cond-p21": "Accetti di utilizzare registrazioni elettroniche e firme per le transazioni specificate con il mittente.", + "term-cond-p22": "Comprendi che OpenSign è una piattaforma che facilita la transazione e non è parte dell'accordo.", + "term-cond-h7": "7. Effetto Legale", + "term-cond-p23": "La tua firma elettronica facilitata tramite OpenSign:", + "term-cond-p24": "Rispetta le leggi applicabili sulle firme elettroniche, inclusa, ma non limitata alla Legge E-SIGN negli Stati Uniti, al Regolamento eIDAS dell'UE e alla Legge sull'Information Technology in India.", + "term-cond-p25": "È legalmente vincolante tra te e il mittente per il/i documento(i) firmato(i).", + "term-cond-h8": "8. Ruolo della piattaforma e limitazione di responsabilità", + "term-cond-p26": "OpenSign funge da piattaforma per facilitare le transazioni elettroniche. Non è responsabile del contenuto, della validità o dell'applicabilità dei documenti inviati dal mittente. Eventuali controversie o problemi relativi al documento o alla sua firma devono essere risolti direttamente tra te e il mittente.", + "term-cond-h9": "9. Risoluzione dell'accordo", + "term-cond-p27": "Il tuo consenso si applica solo alla transazione corrente, salvo diverso accordo da parte del mittente. OpenSign si riserva il diritto di terminare l'accesso alla sua piattaforma per violazioni dei suoi Termini di servizio o delle politiche.", + "term-cond-p28": "Selezionando 'Accetto', confermi di aver compreso e accettato i termini di questa divulgazione delle registrazioni elettroniche e delle firme e acconsenti a firmare elettronicamente il/i documento(i) fornito(i) dal mittente tramite OpenSign.", + "term-cond-p29": "Se hai domande su questa divulgazione, contatta direttamente il mittente. Per supporto tecnico con OpenSign, visita", + "term-cond-p30": "o invia una email a", + "js-snippet-msg": "Per integrare i modelli OpenSign nel tuo sito web HTML o nelle tue pagine di destinazione, puoi usare il codice qui sotto:", + "js-snippet-msg-1": "Puoi ottenere il TemplateId dalla", + "js-snippet-msg-2": "pagina di gestione modelli", + "js-snippet-msg-3": "pagina.", + "agrrement-alert": "Per procedere, devi acconsentire alla divulgazione delle registrazioni elettroniche e delle firme.", + "webhook-already-exists": "L'URL esiste già! Prova con uno diverso.", + "webhook-must-be-secure": "L'URL del webhook deve essere sicuro e utilizzare https://", + "provide-test-token": "Si prega di generare il token di test API", + "invalid-redirect-url": "Si prega di fornire un URL di reindirizzamento valido.", + "auto-sign-mssg": "Firma automatica per tutti", + "already-exist-signer": "Il firmatario selezionato è già presente nell'elenco dei destinatari", + "change-signer": "Cambia firmatario", + "signyour-self-button": "Usa questa opzione per firmare il documento da solo senza aggiungere altri.", + "requestsign-button": "Usa questa opzione per richiedere firme da altri e da te stesso insieme.", + "signyour-self-description": "Usa questo modulo per firmare il documento da solo senza aggiungere altri.", + "requestsign-description": "Usa questo modulo per richiedere firme da altri e da te stesso insieme.", + "template-form-description": "Usa questo modulo per creare modelli riutilizzabili per i tuoi documenti.", + "allow-modify": "Consenti Modifiche", + "allow-modify-help": { + "p1": "Vuoi consentire modifiche al documento durante il processo di firma?", + "p2": "Selezionando questa opzione, i firmatari possono aggiungere elementi aggiuntivi, come firme, iniziali, timbri o testo, sopra i widget esistenti.", + "p3": "Selezionando questa opzione, i firmatari non potranno apportare alcuna aggiunta al documento durante il processo di firma." + }, + "signature-setting": "Impostazioni Firma", + "activation-key": "Chiave di attivazione", + "paid-selfhost-help": "Si prega di contattare OpenSign per ulteriori informazioni all'indirizzo ", + "remaining-credits-selfhost-help": "Utilizza i crediti premium per la firma di documenti tramite API, l'invio in massa e l'integrazione di OpenSign sul tuo sito web. Hai {{allowedcredits}} crediti inclusi e {{addoncredits}} crediti aggiuntivi acquistati rimanenti.", + "signature-type": "La tua firma", + "initial-type": "Le tue iniziali", + "redirect-url": "URL di reindirizzamento", + "bulk-send": "Invio in blocco", + "select-timezone": "Seleziona il tuo fuso orario", + "current-time": "Ora corrente", + "email-help": "Non ti è permesso cambiare l'indirizzo email per motivi di sicurezza. Ti preghiamo di creare un altro account gratuito utilizzando il nuovo indirizzo email.", + "doc-sent": "Documento inviato con successo.", + "no-signer": "Rimuovi", + "and": "e", + "make-public": "Rendere pubblico", + "general": "Generale", + "request-email": "Email di richiesta", + "completion-email": "Email di completamento", + "variables-use": "Variabili da utilizzare", + "send-to-sign": "ha richiesto la tua firma", + "use-template": "Usa modello", + "contact-already-exists": "Il contatto esiste già." +} diff --git a/apps/OpenSign/public/logo192.png b/apps/OpenSign/public/logo192.png old mode 100755 new mode 100644 diff --git a/apps/OpenSign/public/logo512.png b/apps/OpenSign/public/logo512.png old mode 100755 new mode 100644 diff --git a/apps/OpenSign/public/version.txt b/apps/OpenSign/public/version.txt index 10830af0c..7e416bca6 100644 Binary files a/apps/OpenSign/public/version.txt and b/apps/OpenSign/public/version.txt differ diff --git a/apps/OpenSign/src/App.js b/apps/OpenSign/src/App.js index 74c468f15..fafc9398f 100644 --- a/apps/OpenSign/src/App.js +++ b/apps/OpenSign/src/App.js @@ -1,5 +1,5 @@ import React, { useState, useEffect, lazy } from "react"; -import { Routes, Route, BrowserRouter } from "react-router-dom"; +import { Routes, Route, BrowserRouter } from "react-router"; import { pdfjs } from "react-pdf"; import Login from "./pages/Login"; import Form from "./pages/Form"; @@ -15,28 +15,20 @@ import DraftDocument from "./components/pdf/DraftDocument"; import PlaceHolderSign from "./pages/PlaceHolderSign"; import PdfRequestFiles from "./pages/PdfRequestFiles"; import LazyPage from "./primitives/LazyPage"; -import { isEnableSubscription } from "./constant/const"; -import SSOVerify from "./pages/SSOVerify"; import Loader from "./primitives/Loader"; -import TeamList from "./pages/TeamList"; import UserList from "./pages/UserList"; import { serverUrl_fn } from "./constant/appinfo"; +import DocSuccessPage from "./pages/DocSuccessPage"; const DebugPdf = lazy(() => import("./pages/DebugPdf")); const ForgetPassword = lazy(() => import("./pages/ForgetPassword")); const GuestLogin = lazy(() => import("./pages/GuestLogin")); -const Pgsignup = lazy(() => import("./pages/Pgsignup")); -const Subscriptions = lazy(() => import("./pages/PlanSubscriptions")); const ChangePassword = lazy(() => import("./pages/ChangePassword")); const UserProfile = lazy(() => import("./pages/UserProfile")); -const Signup = lazy(() => import("./pages/Signup")); const Opensigndrive = lazy(() => import("./pages/Opensigndrive")); const ManageSign = lazy(() => import("./pages/Managesign")); -const GenerateToken = lazy(() => import("./pages/GenerateToken")); -const Webhook = lazy(() => import("./pages/Webhook")); const AddAdmin = lazy(() => import("./pages/AddAdmin")); const UpdateExistUserAdmin = lazy(() => import("./pages/UpdateExistUserAdmin")); const Preferences = lazy(() => import("./pages/Preferences")); - pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/legacy/build/pdf.worker.min.mjs`; const AppLoader = () => { return ( @@ -74,11 +66,6 @@ function App() { }> } /> - {isEnableSubscription && ( - } /> - )} - {!isEnableSubscription && ( - <> } @@ -87,8 +74,6 @@ function App() { path="/upgrade-2.1" element={} /> - - )} }> } /> - {isEnableSubscription && ( - <> - } - /> - } - /> - - )} }> } /> - {/* recipient signature route with no rowlevel data using docId from url */} } /> - {isEnableSubscription && ( - <> - } /> - } - /> - } - /> - - )} } /> } /> - } /> + } /> } /> diff --git a/apps/OpenSign/src/assets/images/checkmark.png b/apps/OpenSign/src/assets/images/checkmark.png deleted file mode 100644 index 10a3aaf16..000000000 Binary files a/apps/OpenSign/src/assets/images/checkmark.png and /dev/null differ diff --git a/apps/OpenSign/src/assets/images/enterprise.png b/apps/OpenSign/src/assets/images/enterprise.png deleted file mode 100644 index 37d639f38..000000000 Binary files a/apps/OpenSign/src/assets/images/enterprise.png and /dev/null differ diff --git a/apps/OpenSign/src/assets/images/free.png b/apps/OpenSign/src/assets/images/free.png deleted file mode 100644 index 16abf972a..000000000 Binary files a/apps/OpenSign/src/assets/images/free.png and /dev/null differ diff --git a/apps/OpenSign/src/assets/images/login_img.svg b/apps/OpenSign/src/assets/images/login_img.svg index 305bd652c..a5b486ed9 100644 --- a/apps/OpenSign/src/assets/images/login_img.svg +++ b/apps/OpenSign/src/assets/images/login_img.svg @@ -1,184 +1,184 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/OpenSign/src/assets/images/professional.png b/apps/OpenSign/src/assets/images/professional.png deleted file mode 100644 index 149e721ea..000000000 Binary files a/apps/OpenSign/src/assets/images/professional.png and /dev/null differ diff --git a/apps/OpenSign/src/assets/images/teams.png b/apps/OpenSign/src/assets/images/teams.png deleted file mode 100644 index c13971fc3..000000000 Binary files a/apps/OpenSign/src/assets/images/teams.png and /dev/null differ diff --git a/apps/OpenSign/src/components/AddSigner.js b/apps/OpenSign/src/components/AddSigner.js index 66508cd92..ca605b626 100644 --- a/apps/OpenSign/src/components/AddSigner.js +++ b/apps/OpenSign/src/components/AddSigner.js @@ -109,7 +109,8 @@ const AddSigner = (props) => { if (props.details) { props.details({ value: parseData[props.valueKey], - label: parseData[props.displayKey] + label: parseData[props.displayKey], + email: parseData?.Email }); } if (props.closePopup) { @@ -155,7 +156,8 @@ const AddSigner = (props) => { if (props.details) { props.details({ value: parseData[props.valueKey], - label: parseData[props.displayKey] + label: parseData[props.displayKey], + email: parseData?.Email }); } if (props.closePopup) { @@ -211,7 +213,7 @@ const AddSigner = (props) => { )}
-

{t("add-signer-note")}

+

{t("add-signer-note")}

{isUserExist && (
{ - const { t } = useTranslation(); - const [formdata, setFormdata] = useState({ - name: "", - team: "" - }); - const [isLoader, setIsLoader] = useState(false); - const [teamList, setTeamList] = useState([]); - useEffect(() => { - getTeamList(); - }, []); - - const getTeamList = async () => { - setIsLoader(true); - try { - const teams = await Parse.Cloud.run("getteams", { active: true }); - const teamRes = JSON.parse(JSON.stringify(teams)); - if (teamRes.length > 0) { - const _teamRes = JSON.parse(JSON.stringify(teamRes)); - const allUsersteam = _teamRes.find((x) => x.Name === "All Users"); - if (allUsersteam) { - setFormdata({ team: allUsersteam.objectId }); - } - setTeamList(_teamRes); - } - } catch (err) { - console.log("Err in fetch top level teamList", err); - } finally { - setIsLoader(false); - } - }; - - const handleDropdown = (e) => { - setFormdata((prev) => ({ ...prev, [e.target.name]: e.target.value })); - }; - // Define a function to handle form submission - const handleSubmit = async (e) => { - e.preventDefault(); - e.stopPropagation(); - // Extracting values except for the 'name' key - let updatedAncestors = []; - if (formdata.team) { - const Ancestors = teamList.find( - (x) => x.objectId === formdata.team - )?.Ancestors; - if (Ancestors && Ancestors.length > 0) { - updatedAncestors = Ancestors.map((x) => ({ - __type: "Pointer", - className: "contracts_Teams", - objectId: x.objectId - })); - } else { - const AllUser = teamList.find((x) => x.objectId === "All Users"); - updatedAncestors = [ - AllUser, - { - __type: "Pointer", - className: "contracts_Teams", - objectId: formdata.team - } - ]; - } - } - try { - setIsLoader(true); - let data = { Name: formdata.name }; - if (updatedAncestors.length > 0) { - const ParentId = updatedAncestors[updatedAncestors.length - 1]; - data["ParentId"] = ParentId?.objectId; - data["Ancestors"] = updatedAncestors; - } - const newTeamRes = await Parse.Cloud.run("addteam", data); - // console.log("teamRes ", newTeamRes); - if (updatedAncestors.length > 0) { - const ParentId = teamList.find((x) => x.objectId === formdata.team); - props.handleTeamInfo({ - objectId: newTeamRes.id, - Name: formdata.name, - ParentId: ParentId, - Ancestors: updatedAncestors, - IsActive: true - }); - } else { - props.handleTeamInfo({ - objectId: newTeamRes.id, - Name: formdata.name, - ParentId: "", - Ancestors: "", - IsActive: true - }); - } - if (props.closePopup) { - props.closePopup(); - } - setFormdata({ name: "", team: { name: "", objectId: "" } }); - props.setIsAlert({ type: "success", msg: "Team created successfully." }); - } catch (err) { - console.log("err in save team", err); - if (err.code === 137) { - props.setIsAlert({ type: "danger", msg: "Teams already exists." }); - } else if (err.code === 102) { - props.setIsAlert({ type: "warning", msg: "Provide team name." }); - } else { - props.setIsAlert({ type: "danger", msg: "Something went wrong." }); - } - } finally { - setTimeout(() => props.setIsAlert({ type: "success", msg: "" }), 1500); - setIsLoader(false); - } - }; - - // Define a function to handle the "add yourself" checkbox - const handleReset = () => { - setFormdata({ - name: "", - team: { name: "", objectId: "" } - }); - }; - const handleChange = (e) => { - setFormdata((prev) => ({ ...prev, [e.target.name]: e.target.value })); - }; - - return ( -
- - {isLoader && ( - <div className="absolute w-full h-full inset-0 flex justify-center items-center bg-base-content/30 z-50"> - <Loader /> - </div> - )} - <div className="w-full mx-auto"> - <form onSubmit={handleSubmit}> - {/* <h1 className="text-[20px] font-semibold mb-4">Add User</h1> */} - <div className="mb-3"> - <label - htmlFor="name" - className="block text-xs text-gray-700 font-semibold" - > - {t("name")} - <span className="text-[red] text-[13px]"> *</span> - </label> - <input - type="text" - name="name" - value={formdata.name} - onChange={(e) => handleChange(e)} - onInvalid={(e) => e.target.setCustomValidity(t("input-required"))} - onInput={(e) => e.target.setCustomValidity("")} - required - className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" - /> - </div> - <div className="mb-3"> - <label - htmlFor="phone" - className="block text-xs text-gray-700 font-semibold" - > - {t("report-heading.Parent Team")} - </label> - <select - value={formdata.team} - onChange={(e) => handleDropdown(e)} - name="team" - className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs" - > - {teamList.length > 0 && - teamList.map((x) => ( - <option key={x.objectId} value={x.objectId}> - {x.Name} - </option> - ))} - </select> - </div> - <div className="flex items-center mt-3 gap-2 text-white"> - <button type="submit" className="op-btn op-btn-primary"> - {t("submit")} - </button> - <div - type="button" - onClick={() => handleReset()} - className="op-btn op-btn-secondary" - > - {t("reset")} - </div> - </div> - </form> - </div> - </div> - ); -}; - -export default AddTeam; diff --git a/apps/OpenSign/src/components/AddUser.js b/apps/OpenSign/src/components/AddUser.js index 2f2035233..4b48c9ba4 100644 --- a/apps/OpenSign/src/components/AddUser.js +++ b/apps/OpenSign/src/components/AddUser.js @@ -2,8 +2,13 @@ import React, { useEffect, useState } from "react"; import Parse from "parse"; import Title from "./Title"; import Loader from "../primitives/Loader"; -import { copytoData, fetchSubscriptionInfo } from "../constant/Utils"; -import { emailRegex, isEnableSubscription } from "../constant/const"; +import { + copytoData, + usertimezone +} from "../constant/Utils"; +import { + emailRegex, +} from "../constant/const"; import { useTranslation } from "react-i18next"; function generatePassword(length) { const characters = @@ -27,74 +32,23 @@ const AddUser = (props) => { password: "", role: "" }); - const [amount, setAmount] = useState({ quantity: 1, price: 0 }); - const [planInfo, setPlanInfo] = useState({ - priceperUser: 0, - price: 0, - totalAllowedUser: 0, - adminId: "" - }); const [isFormLoader, setIsFormLoader] = useState(false); - const [isLoader, setIsLoader] = useState(false); const [teamList, setTeamList] = useState([]); - const [allowedUser, setAllowedUser] = useState(0); - const [err, setErr] = useState(""); const role = ["OrgAdmin", "Editor", "User"]; - const extUser = - localStorage.getItem("Extand_Class") && - JSON.parse(localStorage.getItem("Extand_Class"))?.[0]; useEffect(() => { getTeamList(); // eslint-disable-next-line }, []); const getTeamList = async () => { - if (isEnableSubscription) { - try { - setIsLoader(true); - const resSub = await fetchSubscriptionInfo(); - if (!resSub.error) { - setPlanInfo((prev) => ({ - ...prev, - priceperUser: resSub.price, - totalAllowedUser: resSub.totalAllowedUser, - adminId: resSub.adminId - })); - setAmount((prev) => ({ ...prev, price: resSub.price })); - const res = await Parse.Cloud.run("allowedusers"); - if (props.setFormHeader) { - if (res > 0) { - props.setFormHeader(t("add-user")); - } else { - props.setFormHeader( - resSub.adminId !== extUser?.objectId - ? "Unauthorized" - : t("Add-seats") - ); - } - } - setAllowedUser(res); - } else { - setAllowedUser(0); - } - } catch (err) { - setAllowedUser(0); - console.log("Err in alloweduser", err); - setErr(err.message); - } finally { - setIsLoader(false); - } - } setFormdata((prev) => ({ ...prev, password: generatePassword(12) })); const teamRes = await Parse.Cloud.run("getteams", { active: true }); if (teamRes.length > 0) { const _teamRes = JSON.parse(JSON.stringify(teamRes)); setTeamList(_teamRes); - if (!isEnableSubscription) { const allUserId = _teamRes.find((x) => x.Name === "All Users")?.objectId || ""; setFormdata((prev) => ({ ...prev, team: allUserId })); - } } }; const checkUserExist = async () => { @@ -161,7 +115,10 @@ const AddUser = (props) => { objectId: localStorage.getItem("TenantId") }); } - + const timezone = usertimezone; + if (timezone) { + extUser.set("Timezone", timezone); + } try { const _users = Parse.Object.extend("User"); const _user = new _users(); @@ -305,37 +262,6 @@ const AddUser = (props) => { props.setIsAlert({ type: "success", msg: t("copied") }); setTimeout(() => props.setIsAlert({ type: "success", msg: "" }), 1500); // Reset copied state after 1.5 seconds }; - const handlePricePerUser = (e) => { - const quantity = e.target.value; - const price = e.target?.value > 0 ? planInfo.priceperUser * quantity : 0; - setAmount((prev) => ({ ...prev, quantity: quantity, price: price })); - }; - const handleAddOnSubmit = async (e) => { - e.preventDefault(); - e.stopPropagation(); - setIsFormLoader(true); - try { - const resAddon = await Parse.Cloud.run("buyaddonusers", { - users: amount.quantity - }); - if (resAddon) { - const _resAddon = JSON.parse(JSON.stringify(resAddon)); - if (_resAddon.status === "success") { - setAllowedUser(amount.quantity); - setPlanInfo((obj) => ({ ...obj, totalAllowedUser: _resAddon.addon })); - } - if (props.handleBuyUsers) { - props.handleBuyUsers(amount.quantity, _resAddon.addon); - } - } - } catch (err) { - console.log("Err in buy addon", err); - props.setIsAlert({ type: "danger", msg: t("something-went-wrong-mssg") }); - } finally { - setTimeout(() => props.setIsAlert({ type: "success", msg: "" }), 2000); - setIsFormLoader(false); - } - }; return ( <div className="shadow-md rounded-box my-[1px] p-3 bg-base-100 relative"> <Title title={t("add-user")} /> @@ -344,232 +270,126 @@ const AddUser = (props) => { <Loader /> </div> )} - {!isLoader ? ( - <> - {err ? ( - <div className="flex justify-center items-center h-[70px] text-[18px]"> - {err} - </div> - ) : ( - <div className="w-full mx-auto"> - {!isEnableSubscription || allowedUser > 0 ? ( - <form onSubmit={handleSubmit}> - {isEnableSubscription && ( - <p className="flex justify-center mb-1"> - {t("remaing-users")}{" "} - <span - className={`${ - allowedUser < 2 ? "op-text-accent" : "op-text-primary" - } font-medium ml-1`} - > - {allowedUser} {t("of")} {planInfo.totalAllowedUser} - </span> - </p> - )} - <div className="mb-3"> - <label - htmlFor="name" - className="block text-xs text-gray-700 font-semibold" - > - {t("name")} - <span className="text-[red] text-[13px]"> *</span> - </label> - <input - type="text" - name="name" - value={formdata.name} - onChange={(e) => handleChange(e)} - onInvalid={(e) => - e.target.setCustomValidity(t("input-required")) - } - onInput={(e) => e.target.setCustomValidity("")} - required - className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" - /> - </div> - <div className="mb-3"> - <label - htmlFor="email" - className="block text-xs text-gray-700 font-semibold" - > - {t("email")} - <span className="text-[red] text-[13px]"> *</span> - </label> - <input - type="email" - name="email" - value={formdata.email} - onChange={(e) => handleChange(e)} - required - onInvalid={(e) => - e.target.setCustomValidity(t("input-required")) - } - onInput={(e) => e.target.setCustomValidity("")} - className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" - /> - </div> - <div className="mb-3"> - <label className="block text-xs text-gray-700 font-semibold"> - {t("password")} - </label> - <div className="flex justify-between items-center op-input op-input-bordered op-input-sm text-base-content w-full h-full text-[13px]"> - <div className="break-all">{formdata?.password}</div> - <i - onClick={() => copytoclipboard(formdata?.password)} - className="fa-light fa-copy rounded-full hover:bg-base-300 p-[8px] cursor-pointer " - ></i> - </div> - <div className="text-[12px] ml-2 mb-0 text-[red] select-none"> - {t("password-generateed")} - </div> - </div> - <div className="mb-3"> - <label - htmlFor="phone" - className="block text-xs text-gray-700 font-semibold" - > - {t("phone")} - {/* <span className="text-[red] text-[13px]"> *</span> */} - </label> - {/* added hint for phone number being optional */} - <input - type="text" - name="phone" - placeholder={t("phone-optional")} - value={formdata.phone} - onChange={(e) => handleChange(e)} - className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" - /> - </div> - {isEnableSubscription && ( - <div className="mb-3"> - <label - htmlFor="phone" - className="block text-xs text-gray-700 font-semibold" - > - {t("team")} - <span className="text-[red] text-[13px]"> *</span> - </label> - <select - name="team" - value={formdata.team} - onChange={(e) => handleChange(e)} - className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs" - onInvalid={(e) => - e.target.setCustomValidity(t("input-required")) - } - onInput={(e) => e.target.setCustomValidity("")} - required - > - <option defaultValue={""} value={""}> - {t("Select")} - </option> - {teamList.length > 0 && - teamList.map((x) => ( - <option key={x.objectId} value={x.objectId}> - {x.Name} - </option> - ))} - </select> - </div> - )} - <div className="mb-3"> - <label - htmlFor="phone" - className="block text-xs text-gray-700 font-semibold" - > - {t("Role")} - <span className="text-[red] text-[13px]"> *</span> - </label> - <select - value={formdata.role} - onChange={(e) => handleChange(e)} - name="role" - className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs" - onInvalid={(e) => - e.target.setCustomValidity(t("input-required")) - } - onInput={(e) => e.target.setCustomValidity("")} - required - > - <option defaultValue={""} value={""}> - {t("Select")} - </option> - {role.length > 0 && - role.map((x) => ( - <option key={x} value={x}> - {x} - </option> - ))} - </select> - </div> - <div className="flex items-center mt-3 gap-2 text-white"> - <button type="submit" className="op-btn op-btn-primary"> - {t("submit")} - </button> - <div - type="button" - onClick={() => handleReset()} - className="op-btn op-btn-secondary" - > - {t("cancel")} - </div> - </div> - </form> - ) : ( - <> - {planInfo.adminId !== extUser?.objectId ? ( - <div className="mb-3 mt-1 flex justify-center text-center items-center font-medium break-all"> - {t("unauthorized-modal", { - adminEmail: extUser?.TenantId?.EmailAddress - })} - </div> - ) : ( - <form onSubmit={handleAddOnSubmit}> - <p className="flex justify-center text-center mx-2 mb-3 text-base op-text-accent font-medium"> - {t("additional-users")} - </p> - <div className="mb-3 flex justify-between"> + <div className="w-full mx-auto"> + <form onSubmit={handleSubmit}> + <div className="mb-3"> <label - htmlFor="quantity" + htmlFor="name" className="block text-xs text-gray-700 font-semibold" > - {t("Quantity-of-users")} + {t("name")} <span className="text-[red] text-[13px]"> *</span> </label> <input - type="number" - name="quantity" - value={amount.quantity} - onChange={(e) => handlePricePerUser(e)} - className="w-1/4 op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content text-xs" + type="text" + name="name" + value={formdata.name} + onChange={(e) => handleChange(e)} + onInvalid={(e) => + e.target.setCustomValidity(t("input-required")) + } + onInput={(e) => e.target.setCustomValidity("")} required + className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" /> </div> - <div className="mb-3 flex justify-between"> - <label className="block text-xs text-gray-700 font-semibold"> - {t("Price")} (1 * {planInfo.priceperUser}) + <div className="mb-3"> + <label + htmlFor="email" + className="block text-xs text-gray-700 font-semibold" + > + {t("email")} + <span className="text-[red] text-[13px]"> *</span> </label> - <div className="w-1/4 flex justify-center items-center text-sm"> - USD {amount.price} + <input + type="email" + name="email" + value={formdata.email} + onChange={(e) => handleChange(e)} + required + onInvalid={(e) => + e.target.setCustomValidity(t("input-required")) + } + onInput={(e) => e.target.setCustomValidity("")} + className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" + /> + </div> + <div className="mb-3"> + <label className="block text-xs text-gray-700 font-semibold"> + {t("password")} + </label> + <div className="flex justify-between items-center op-input op-input-bordered op-input-sm text-base-content w-full h-full text-[13px]"> + <div className="break-all">{formdata?.password}</div> + <i + onClick={() => copytoclipboard(formdata?.password)} + className="fa-light fa-copy rounded-full hover:bg-base-300 p-[8px] cursor-pointer " + ></i> + </div> + <div className="text-[12px] ml-2 mb-0 text-[red] select-none"> + {t("password-generateed")} + </div> + </div> + <div className="mb-3"> + <label + htmlFor="phone" + className="block text-xs text-gray-700 font-semibold" + > + {t("phone")} + {/* <span className="text-[red] text-[13px]"> *</span> */} + </label> + <input + type="text" + name="phone" + placeholder={t("phone-optional")} + value={formdata.phone} + onChange={(e) => handleChange(e)} + className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" + /> + </div> + <div className="mb-3"> + <label + htmlFor="phone" + className="block text-xs text-gray-700 font-semibold" + > + {t("Role")} + <span className="text-[red] text-[13px]"> *</span> + </label> + <select + value={formdata.role} + onChange={(e) => handleChange(e)} + name="role" + className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs" + onInvalid={(e) => + e.target.setCustomValidity(t("input-required")) + } + onInput={(e) => e.target.setCustomValidity("")} + required + > + <option defaultValue={""} value={""}> + {t("Select")} + </option> + {role.length > 0 && + role.map((x) => ( + <option key={x} value={x}> + {x} + </option> + ))} + </select> + </div> + <div className="flex items-center mt-3 gap-2 text-white"> + <button type="submit" className="op-btn op-btn-primary"> + {t("submit")} + </button> + <div + type="button" + onClick={() => handleReset()} + className="op-btn op-btn-secondary" + > + {t("cancel")} </div> </div> - <hr className="text-base-content mb-3" /> - <button className="op-btn op-btn-primary w-full"> - {t("Proceed")} - </button> </form> - )} - </> - )} - </div> - )} - </> - ) : ( - <div className="w-full h-[200px] inset-0 flex justify-center items-center z-50"> - <Loader /> - </div> - )} + </div> </div> ); }; diff --git a/apps/OpenSign/src/components/BulkSendUi.js b/apps/OpenSign/src/components/BulkSendUi.js index cd0596d41..7990015bd 100644 --- a/apps/OpenSign/src/components/BulkSendUi.js +++ b/apps/OpenSign/src/components/BulkSendUi.js @@ -3,38 +3,18 @@ import axios from "axios"; import SuggestionInput from "./shared/fields/SuggestionInput"; import Loader from "../primitives/Loader"; import { useTranslation } from "react-i18next"; -import Parse from "parse"; -import ModalUi from "../primitives/ModalUi"; -import { emailRegex, isEnableSubscription } from "../constant/const"; -import { fetchSubscription } from "../constant/Utils"; -import { useNavigate } from "react-router-dom"; +import { + emailRegex, +} from "../constant/const"; const BulkSendUi = (props) => { const { t } = useTranslation(); - const navigate = useNavigate(); const [forms, setForms] = useState([]); - const [formId, setFormId] = useState(2); const formRef = useRef(null); const [scrollOnNextUpdate, setScrollOnNextUpdate] = useState(false); const [isSubmit, setIsSubmit] = useState(false); - const [allowedForm, setAllowedForm] = useState(0); const [isSignatureExist, setIsSignatureExist] = useState(); const [isBulkAvailable, setIsBulkAvailable] = useState(false); - const quantityList = [500, 1000, 5000, 50000]; - const [amount, setAmount] = useState({ - price: (75.0).toFixed(2), - quantity: 500, - priceperbulksend: 0.15, - totalcredits: 0 - }); - const [isQuotaReached, setIsQuotaReached] = useState(false); const [isLoader, setIsLoader] = useState(false); - const [isFreePlan, setIsFreePlan] = useState(false); - const [admin, setAdmin] = useState({ - objectId: "", - email: "", - isAdmin: true - }); - const allowedSigners = 50; useEffect(() => { signatureExist(); // eslint-disable-next-line react-hooks/exhaustive-deps @@ -42,75 +22,7 @@ const BulkSendUi = (props) => { //function to check atleast one signature field exist const signatureExist = async () => { - if (isEnableSubscription) { - setIsLoader(true); - try { - const subscription = await fetchSubscription(); - const extUser = - localStorage.getItem("Extand_Class") && - JSON.parse(localStorage.getItem("Extand_Class"))?.[0]; - if ( - subscription?.adminId && - extUser?.objectId === subscription?.adminId - ) { - setAdmin((obj) => ({ - ...obj, - objectId: subscription?.adminId, - isAdmin: true - })); - } else { - setAdmin((obj) => ({ - ...obj, - isAdmin: false, - email: extUser?.TenantId?.EmailAddress - })); - } - setAdmin((obj) => ({ ...obj, objectId: subscription?.adminId })); - if (subscription?.plan === "freeplan") { - setIsFreePlan(true); - } - const token = props.jwttoken - ? { jwttoken: props.jwttoken } - : { "X-Parse-Session-Token": localStorage.getItem("accesstoken") }; - const axiosres = await axios.post( - `${localStorage.getItem("baseUrl")}functions/allowedcredits`, - {}, - { - headers: { - "Content-Type": "application/json", - "X-Parse-Application-Id": localStorage.getItem("parseAppId"), - ...token - } - } - ); - const resCredits = axiosres.data && axiosres.data.result; - if (resCredits) { - const allowedcredits = resCredits?.allowedcredits || 0; - const addoncredits = resCredits?.addoncredits || 0; - const totalcredits = allowedcredits + addoncredits; - if (totalcredits > 0) { - if (subscription?.plan !== "freeplan") { - setIsBulkAvailable(true); - } - } - setAmount((obj) => ({ ...obj, totalcredits: totalcredits })); - } - const getPlaceholder = props?.Placeholders; - const checkIsSignatureExistt = getPlaceholder?.every((placeholderObj) => - placeholderObj?.placeHolder?.some((holder) => - holder?.pos?.some((posItem) => posItem?.type === "signature") - ) - ); - setIsSignatureExist(checkIsSignatureExistt); - setIsLoader(false); - } catch (err) { - setIsLoader(false); - alert(t("something-went-wrong-mssg")); - console.log("Err", err); - } - } else { setIsBulkAvailable(true); - setAdmin((obj) => ({ ...obj, isAdmin: true })); const getPlaceholder = props?.Placeholders; const checkIsSignatureExistt = getPlaceholder?.every((placeholderObj) => placeholderObj?.placeHolder?.some((holder) => @@ -119,7 +31,6 @@ const BulkSendUi = (props) => { ); setIsSignatureExist(checkIsSignatureExistt); setIsLoader(false); - } }; useEffect(() => { if (scrollOnNextUpdate && formRef.current) { @@ -150,8 +61,6 @@ const BulkSendUi = (props) => { } }); setForms((prevForms) => [...prevForms, { Id: 1, fields: users }]); - const totalForms = Math.floor(allowedSigners / users?.length); - setAllowedForm(totalForms); } })(); // eslint-disable-next-line @@ -165,38 +74,6 @@ const BulkSendUi = (props) => { setForms(newForms); }; - const handleAddForm = (e) => { - e.preventDefault(); - // Check if the quick send limit has been reached - if (isEnableSubscription && forms.length >= amount.totalcredits) { - setIsQuotaReached(true); - } else { - if (forms?.length < allowedForm) { - if (props?.Placeholders.length > 0) { - let newForm = []; - props?.Placeholders?.forEach((element) => { - if (!element.signerObjId) { - newForm = [ - ...newForm, - { - fieldId: element.Id, - email: "", - label: element.Role, - signer: {} - } - ]; - } - }); - setForms([...forms, { Id: formId, fields: newForm }]); - } - setFormId(formId + 1); - setScrollOnNextUpdate(true); - } else { - // If the limit has been reached, throw an error with the appropriate message - alert(t("quick-send-alert-4")); - } - } - }; const handleRemoveForm = (index) => { const updatedForms = forms.filter((_, i) => i !== index); @@ -285,16 +162,15 @@ const BulkSendUi = (props) => { }; const batchQuery = async (Documents) => { - const token = props.jwttoken - ? { jwttoken: props.jwttoken } - : { "X-Parse-Session-Token": localStorage.getItem("accesstoken") }; + const token = + { "X-Parse-Session-Token": localStorage.getItem("accesstoken") }; const functionsUrl = `${localStorage.getItem( "baseUrl" )}functions/batchdocuments`; const headers = { "Content-Type": "application/json", "X-Parse-Application-Id": localStorage.getItem("parseAppId"), - ...token + ...token, }; const params = { Documents: JSON.stringify(Documents) }; try { @@ -310,51 +186,6 @@ const BulkSendUi = (props) => { setIsSubmit(false); } }; - const handleAddOnQuickSubmit = async (e) => { - e.preventDefault(); - e.stopPropagation(); - setIsSubmit(true); - try { - const resAddon = await Parse.Cloud.run("buycredits", { - credits: amount.quantity - }); - if (resAddon) { - const _resAddon = JSON.parse(JSON.stringify(resAddon)); - if (_resAddon.status === "success") { - setIsBulkAvailable(true); - handleCloseQuotaReached(); - setAmount((obj) => ({ - ...obj, - quantity: 500, - priceperbulksend: 0.15, - price: (75.0).toFixed(2), - totalcredits: obj?.totalcredits + _resAddon.addon - })); - } - } - } catch (err) { - console.log("Err in buy addon", err); - alert(t("something-went-wrong-mssg")); - } finally { - setIsSubmit(false); - } - }; - const handlePricePerQuick = async (e) => { - const quantity = e.target?.value; - const price = - quantity > 0 - ? (Math.round(quantity * amount.priceperbulksend * 100) / 100).toFixed( - 2 - ) - : 500 * amount.priceperbulksend; - setAmount((prev) => ({ ...prev, quantity: quantity, price: price })); - }; - const handleCloseQuotaReached = () => { - setIsQuotaReached(false); - }; - const handleNavigation = () => { - navigate("/subscription"); - }; return ( <> {isLoader ? ( @@ -374,7 +205,7 @@ const BulkSendUi = (props) => { isSignatureExist ? ( <> {props.Placeholders?.some((x) => !x.signerObjId) ? ( - <div> + <> <form onSubmit={handleSubmit}> <div className="min-h-max max-h-[250px] overflow-y-auto"> {forms?.map((form, index) => ( @@ -400,7 +231,6 @@ const BulkSendUi = (props) => { fieldIndex ) } - jwttoken={props?.jwttoken} /> </div> ))} @@ -417,15 +247,6 @@ const BulkSendUi = (props) => { ))} </div> <div className="flex flex-col mx-4 mb-4 gap-3"> - {isEnableSubscription && ( - <button - onClick={handleAddForm} - className="op-btn op-btn-primary focus:outline-none" - > - <i className="fa-light fa-plus"></i>{" "} - <span>{t("add-new")}</span> - </button> - )} <button type="submit" className="op-btn op-btn-accent focus:outline-none" @@ -435,23 +256,7 @@ const BulkSendUi = (props) => { </button> </div> </form> - <ModalUi - isOpen={isQuotaReached} - handleClose={() => handleCloseQuotaReached()} - > - <div className="p-4 flex justify-center items-center flex-col gap-y-3"> - <p className="text-center text-base-content"> - {t("quota-err-quicksend")} - </p> - <button - onClick={() => setIsBulkAvailable(false)} - className=" op-btn op-btn-primary w-[200px]" - > - {t("buy-credits")} - </button> - </div> - </ModalUi> - </div> + </> ) : ( <div className="text-black p-3 bg-white w-full text-sm md:text-base flex justify-center items-center"> {t("quick-send-alert-1")} @@ -471,68 +276,6 @@ const BulkSendUi = (props) => { </> ) : ( <> - {isFreePlan ? ( - <div className="w-full h-[130px] flex flex-col justify-center items-center text-center p-4"> - <p className="text-base font-medium mb-2.5"> - {t("bulk-send-subcription-alert")} - </p> - <button - onClick={() => handleNavigation()} - className="op-btn op-btn-primary" - > - {t("upgrade-now")} - </button> - </div> - ) : ( - <> - {admin?.isAdmin ? ( - <form onSubmit={handleAddOnQuickSubmit} className="p-3"> - <p className="flex justify-center text-center mx-2 mb-3 text-base op-text-accent font-medium"> - {t("additional-credits")} - </p> - <div className="mb-3 flex justify-between"> - <label - htmlFor="quantity" - className="block text-xs text-gray-700 font-semibold" - > - {t("quantity-of-credits")} - <span className="text-[red] text-[13px]">*</span> - </label> - <select - value={amount.quantity} - onChange={(e) => handlePricePerQuick(e)} - name="quantity" - className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-1/4 text-xs" - required - > - {quantityList.length > 0 && - quantityList.map((x) => ( - <option key={x} value={x}> - {x} - </option> - ))} - </select> - </div> - <div className="mb-3 flex justify-between"> - <label className="block text-xs text-gray-700 font-semibold"> - {t("Price")} (1 * {amount.priceperbulksend}) - </label> - <div className="w-1/4 flex justify-center items-center text-sm"> - USD {amount.price} - </div> - </div> - <hr className="text-base-content mb-3" /> - <button className="op-btn op-btn-primary w-full mt-2"> - {t("Proceed")} - </button> - </form> - ) : ( - <div className="mx-8 mt-4 mb-8 flex justify-center text-center items-center font-medium break-all"> - {t("unauthorized-modal", { adminEmail: admin?.email })} - </div> - )} - </> - )} </> )} </> diff --git a/apps/OpenSign/src/components/EditContactForm.js b/apps/OpenSign/src/components/EditContactForm.js new file mode 100644 index 000000000..f1e1df425 --- /dev/null +++ b/apps/OpenSign/src/components/EditContactForm.js @@ -0,0 +1,126 @@ +import React, { useEffect, useState } from "react"; +import Loader from "../primitives/Loader"; +import { useTranslation } from "react-i18next"; +import Parse from "parse"; +const EditContactForm = (props) => { + const { t } = useTranslation(); + const [isLoader, setIsLoader] = useState(false); + const [formData, setFormData] = useState({ Name: "", Email: "", Phone: "" }); + useEffect(() => { + if (props.contact?.Email) { + setFormData((prev) => ({ ...prev, ...props.contact })); + } + }, [props.contact]); + const handleChange = (e) => { + if (e.target.name === "Email") { + setFormData((prev) => ({ + ...prev, + [e.target.name]: e.target.value?.toLowerCase()?.replace(/\s/g, "") + })); + } else { + setFormData((prev) => ({ ...prev, [e.target.name]: e.target.value })); + } + }; + const handleSubmit = async (e) => { + e.preventDefault(); + e.stopPropagation(); + if (props.handleEditContact) { + try { + setIsLoader(true); + const params = { + contactId: props.contact.objectId, + name: formData.Name, + email: formData.Email, + phone: formData.Phone, + tenantId: localStorage.getItem("TenantId") + }; + const res = await Parse.Cloud.run("editcontact", params); + const updateContact = { + ...res, + Name: formData.Name, + Email: formData.Email, + Phone: formData.Phone + }; + props.handleEditContact(updateContact); + } catch (err) { + console.log("err in edit contact ", err); + if (err.code === 137) { + alert(t("contact-already-exists")); + } else { + alert(t("something-went-wrong-mssg")); + } + } finally { + setIsLoader(false); + props.handleClose && props.handleClose(); + } + } + }; + return ( + <div className="h-full p-[20px]"> + {isLoader && ( + <div className="fixed inset-0 flex justify-center items-center bg-black bg-opacity-30"> + <Loader /> + </div> + )} + <div className="w-full mx-auto p-2 text-base-content"> + <form onSubmit={handleSubmit}> + <div className="mb-3"> + <label htmlFor="name" className="block text-xs font-semibold"> + {t("name")} + <span className="text-[red] text-[13px]"> *</span> + </label> + <input + type="text" + id="name" + name="Name" + value={formData.Name} + onChange={(e) => handleChange(e)} + onInput={(e) => e.target.setCustomValidity("")} + onInvalid={(e) => e.target.setCustomValidity(t("input-required"))} + className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" + required + /> + </div> + <div className="mb-3"> + <label htmlFor="email" className="block text-xs font-semibold"> + {t("email")} + <span className="text-[red] text-[13px]"> *</span> + </label> + <input + type="email" + id="email" + name="Email" + value={formData.Email} + onChange={(e) => handleChange(e)} + onInput={(e) => e.target.setCustomValidity("")} + onInvalid={(e) => e.target.setCustomValidity(t("input-required"))} + className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" + required + /> + </div> + <div className="mb-3"> + <label htmlFor="phone" className="block text-xs font-semibold"> + {t("phone")} + </label> + <input + type="text" + id="phone" + name="Phone" + value={formData.Phone} + onChange={(e) => handleChange(e)} + className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" + placeholder={t("phone-optional")} + /> + </div> + <div className="mt-4 flex gap-x-2 justify-start"> + <button type="submit" className="op-btn op-btn-primary"> + {t("submit")} + </button> + </div> + </form> + </div> + </div> + ); +}; + +export default EditContactForm; diff --git a/apps/OpenSign/src/components/Header.js b/apps/OpenSign/src/components/Header.js index 2b8118b9b..c7753cd45 100644 --- a/apps/OpenSign/src/components/Header.js +++ b/apps/OpenSign/src/components/Header.js @@ -1,44 +1,26 @@ import React, { useState, useEffect } from "react"; import dp from "../assets/images/dp.png"; import FullScreenButton from "./FullScreenButton"; -import { useNavigate } from "react-router-dom"; +import { useNavigate } from "react-router"; import Parse from "parse"; import { useWindowSize } from "../hook/useWindowSize"; import { - checkIsSubscribed, - formatDate, getAppLogo, openInNewTab, saveLanguageInLocal } from "../constant/Utils"; -import { isEnableSubscription, isStaging } from "../constant/const"; -import { validplan } from "../json/plansArr"; import { useTranslation } from "react-i18next"; -import ModalUi from "../primitives/ModalUi"; -import QuotaCard from "../primitives/QuotaCard"; - const Header = ({ showSidebar, setIsMenu }) => { const { t, i18n } = useTranslation(); const navigate = useNavigate(); const { width } = useWindowSize(); - const current_notification_version = "1"; // Update this with each new feature release - // Get the dismissed version from local storage - const dismissedVersion = localStorage.getItem("notificationDismissedVersion"); const username = localStorage.getItem("username") || ""; const image = localStorage.getItem("profileImg") || dp; const [isOpen, setIsOpen] = useState(false); - const [isSubscribe, setIsSubscribe] = useState(true); - const [isTeam, setIsTeam] = useState({ plan: "", isValid: false }); const [applogo, setAppLogo] = useState( localStorage.getItem("appLogo") || " " ); - const [emailUsed, setEmailUsed] = useState(0); - const [isModal, setIsModal] = useState(false); - const [emailResetDate, setEmailResetDate] = useState(""); - const [showNotification, setShowNotification] = useState( - (!dismissedVersion || dismissedVersion !== current_notification_version) && - true - ); + const toggleDropdown = () => { setIsOpen(!isOpen); if (width <= 768) { @@ -46,45 +28,16 @@ const Header = ({ showSidebar, setIsMenu }) => { } }; useEffect(() => { - checkSubscription(); + initializeHead(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - async function checkSubscription() { - if (isEnableSubscription) { - const subscribe = await checkIsSubscribed(); - if (subscribe.isValid) { - const applogo = await getAppLogo(); - if (applogo?.logo) { - setAppLogo(applogo?.logo); - } else { - setAppLogo(localStorage.getItem("appLogo") || ""); - } - } - setIsTeam(subscribe); - setIsSubscribe(subscribe.isValid); - try { - const extUser = await Parse.Cloud.run("getUserDetails"); - const MonthlyFreeEmails = extUser?.get("MonthlyFreeEmails") || 0; - setEmailUsed(MonthlyFreeEmails); - if (extUser) { - const _extUser = JSON.parse(JSON.stringify(extUser)); - if (_extUser?.LastEmailCountReset?.iso) { - const resetDate = formatDate(_extUser?.LastEmailCountReset?.iso); - setEmailResetDate(resetDate); - } - localStorage.setItem("Extand_Class", JSON.stringify([_extUser])); - } - } catch (err) { - console.log("err in while fetching monthlyfreeEmails", err); - } - } else { + async function initializeHead() { const applogo = await getAppLogo(); if (applogo?.logo) { setAppLogo(applogo?.logo); } else { setAppLogo(localStorage.getItem("appLogo") || ""); } - } } const closeDropdown = async () => { @@ -128,56 +81,9 @@ const Header = ({ showSidebar, setIsMenu }) => { document.removeEventListener("click", closeMenuOnOutsideClick); }; }, [isOpen]); - const handleConsoleRedirect = () => { - if (isStaging) { - window.open(" https://staging-console.opensignlabs.com/"); - } else { - window.open("https://console.opensignlabs.com/"); - } - }; - const handleNavigation = () => { - navigate("/subscription"); - }; - const handleMailUsed = () => { - setIsModal(!isModal); - }; - // Handle dismissing the notification - const dismissNotification = () => { - // Store the current version as dismissed in local storage - localStorage.setItem( - "notificationDismissedVersion", - current_notification_version - ); - setShowNotification(false); - }; - const handleSetupNowNavigation = () => { - const url = isStaging - ? "https://staging-console.opensignlabs.com/fileadapter" - : "https://console.opensignlabs.com/fileadapter"; - openInNewTab(url); - }; return ( <div> - {isEnableSubscription && showNotification && ( - <div className="flex justify-between items-center shadow py-1 bg-[#CAE4FA] p-1"> - <div className="text-center text-[14px] ml-auto"> - {t("header-news")} — - <span - className="cursor-pointer font-medium underline text-blue-800" - onClick={() => handleSetupNowNavigation()} - > - {" " + t("header-news-btn") + "."} - </span> - </div> - <div - className="ml-auto mr-1 cursor-pointer" - onClick={() => dismissNotification()} - > - <i className="fa-light fa-xmark"></i> - </div> - </div> - )} <div className="op-navbar bg-base-100 shadow"> <div className="flex-none"> <button @@ -197,26 +103,6 @@ const Header = ({ showSidebar, setIsMenu }) => { </div> </div> <div id="profile-menu" className="flex-none gap-2"> - {!isSubscribe && ( - <div> - <button - className="text-xs md:text-sm shadow op-btn op-btn-outline op-btn-sm md:op-btn-md op-btn-accent" - onClick={() => handleNavigation()} - > - {t("upgrade-now")} - </button> - </div> - )} - {isTeam.isValid && !validplan[isTeam.plan] && ( - <div className="w-[35px] h-[35px] bg-white rounded-full ring-[1px] ring-offset-2 ring-[#002862] text-[#002862] overflow-hidden font-semibold flex items-center justify-center"> - {t("pro")} - </div> - )} - {validplan[isTeam.plan] && ( - <div className="w-[35px] h-[35px] bg-white rounded-full ring-[1px] text-[13px] ring-offset-2 ring-[#002862] text-[#002862] overflow-hidden font-semibold flex items-center justify-center"> - {t("team")} - </div> - )} <div> <FullScreenButton /> </div> @@ -255,7 +141,9 @@ const Header = ({ showSidebar, setIsMenu }) => { </div> <ul tabIndex={0} - className="mt-3 z-[1] p-2 shadow op-menu op-menu-sm op-dropdown-content text-base-content bg-base-100 rounded-box w-52" + className={`mt-3 z-[1] p-2 shadow op-menu op-menu-sm op-dropdown-content text-base-content bg-base-100 rounded-box w-52 ${ + isOpen ? "" : "hidden" + }`} > <li onClick={() => openInNewTab("https://docs.opensignlabs.com")}> <span> @@ -282,21 +170,6 @@ const Header = ({ showSidebar, setIsMenu }) => { <i className="fa-light fa-lock"></i> {t("change-password")} </span> </li> - {isEnableSubscription && ( - <li onClick={() => handleConsoleRedirect()}> - <span> - <i className="fa-light fa-id-card"></i> Console - </span> - </li> - )} - {isEnableSubscription && isTeam?.plan === "freeplan" && ( - <li className="cursor-pointer" onClick={handleMailUsed}> - <span> - <i className="fa-light fa-envelope"></i> - {emailUsed}/15 {t("sent-this-month")} - </span> - </li> - )} <li onClick={closeDropdown}> <span> <i className="fa-light fa-arrow-right-from-bracket"></i>{" "} @@ -307,13 +180,6 @@ const Header = ({ showSidebar, setIsMenu }) => { </div> </div> </div> - <ModalUi isOpen={isModal}> - <QuotaCard - isPaidInfo={true} - handlClose={handleMailUsed} - emailResetDate={emailResetDate} - /> - </ModalUi> </div> ); }; diff --git a/apps/OpenSign/src/components/LoginFacebook.js b/apps/OpenSign/src/components/LoginFacebook.js deleted file mode 100644 index 369b91e34..000000000 --- a/apps/OpenSign/src/components/LoginFacebook.js +++ /dev/null @@ -1,220 +0,0 @@ -import React, { useState } from "react"; -import Parse from "parse"; -import Loader from "../primitives/Loader"; -import { useTranslation } from "react-i18next"; -// import FacebookLogin from "react-facebook-login"; - -const LoginFacebook = ({ - FBCred, - thirdpartyLoginfn, - thirdpartyLoader, - setThirdpartyLoader -}) => { - const { t } = useTranslation(); - const [isModal, setIsModal] = useState(false); - const [userDetails, setUserDetails] = useState({ - Phone: "", - Company: "", - Name: "", - Email: "" - }); - const [fBDetails, setFBDetails] = useState({ - Id: "", - AccessToken: "", - Name: "", - Email: "" - }); - const responseFacebook = async (response) => { - // console.log("response ", response); - if (response.userID) { - setThirdpartyLoader(true); - const details = { - Email: response.email, - Name: response.name - }; - setUserDetails({ ...userDetails, ...details }); - const fDetails = { - Id: response.userID, - AccessToken: response.accessToken, - Name: response.name, - Email: response.email - }; - setFBDetails({ ...fBDetails, ...fDetails }); - const res = await checkExtUser(fDetails); - } - }; - - const checkExtUser = async (details) => { - // const extUser = new Parse.Query("contracts_Users"); - // extUser.equalTo("Email", details.Email); - // const extRes = await extUser.first(); - const params = { email: details.Email }; - const extRes = await Parse.Cloud.run("getUserDetails", params); - // console.log("extRes ", extRes); - if (extRes) { - const params = { ...details, Phone: extRes?.get("Phone") || "" }; - const payload = await Parse.Cloud.run("facebooksign", params); - // console.log("payload ", payload); - if (payload && payload.sessiontoken) { - const billingDate = - extRes.get("Next_billing_date") && extRes.get("Next_billing_date"); - // console.log("billingDate expired", billingDate > new Date()); - const LocalUserDetails = { - name: details.Name, - email: details.Email, - phone: extRes?.get("Phone") || "", - company: extRes.get("Company") - }; - localStorage.setItem("userDetails", JSON.stringify(LocalUserDetails)); - thirdpartyLoginfn(payload.sessiontoken, billingDate); - } - return { msg: "exist" }; - } else { - setIsModal(true); - setThirdpartyLoader(false); - return { msg: "notexist" }; - } - }; - const handleSubmitbtn = async () => { - if (userDetails.Phone && userDetails.Company) { - setThirdpartyLoader(true); - const params = { ...fBDetails, Phone: userDetails?.Phone || "" }; - const payload = await Parse.Cloud.run("facebooksign", params); - // console.log("payload ", payload); - - if (payload && payload.sessiontoken) { - const params = { - userDetails: { - name: userDetails.Name, - email: userDetails.Email, - // "passsword":userDetails.Phone, - phone: userDetails?.Phone || "", - role: "contracts_User", - company: userDetails.Company - } - }; - const userSignUp = await Parse.Cloud.run("usersignup", params); - // console.log("userSignUp ", userSignUp); - if (userSignUp && userSignUp.sessionToken) { - const LocalUserDetails = { - name: userDetails.Name, - email: userDetails.Email, - phone: userDetails?.Phone || "", - company: userDetails.Company - }; - localStorage.setItem("userDetails", JSON.stringify(LocalUserDetails)); - thirdpartyLoginfn(userSignUp.sessionToken); - } else { - alert(userSignUp.message); - } - } else { - alert(t("server-error")); - } - } else { - alert(t("fill-required-details!")); - } - }; - return ( - <div className="relative"> - {thirdpartyLoader && ( - <div className="fixed flex justify-center items-center inset-0 bg-black bg-opacity-25 z-20 "> - <Loader /> - </div> - )} - {/* <FacebookLogin - appId={FBCred} - fields="name,email,picture" - callback={responseFacebook} - cssClass="btn btn-info btn-md btn-fb" - icon="fa fa-facebook-f" - /> */} - {isModal && ( - <div - className="modal fade show block z-[1]" - id="exampleModal" - tabIndex="-1" - role="dialog" - > - <div className="modal-dialog" role="document"> - <div className="modal-content"> - <div className="modal-header"> - <h5 className="modal-title">{t("sign-up-form")}</h5> - <span> - <span></span> - </span> - </div> - <div className="modal-body"> - <form> - <div className="form-group"> - <label htmlFor="Phone" className="col-form-label"> - {t("phone")}{" "} - <span className="text-[red] text-[13px]">*</span> - </label> - <input - type="tel" - className="form-control" - id="Phone" - value={userDetails.Phone} - onChange={(e) => - setUserDetails({ - ...userDetails, - Phone: e.target.value - }) - } - onInvalid={(e) => - e.target.setCustomValidity(t("input-required")) - } - onInput={(e) => e.target.setCustomValidity("")} - required - /> - </div> - <div className="form-group"> - <label htmlFor="Company" className="col-form-label"> - {t("company")}{" "} - <span className="text-[red] text-[13px]">*</span> - </label> - <input - type="text" - className="form-control" - id="Company" - value={userDetails.Company} - onChange={(e) => - setUserDetails({ - ...userDetails, - Company: e.target.value - }) - } - onInvalid={(e) => - e.target.setCustomValidity(t("input-required")) - } - onInput={(e) => e.target.setCustomValidity("")} - required - /> - </div> - <div> - <button - type="button" - onClick={() => handleSubmitbtn()} - className="btn btn-info mr-[10px]" - > - {t("sign-up")} - </button> - <button - type="button" - className="btn btn-secondary w-[90px]" - onClick={() => setIsModal(false)} - > - {t("cancel")} - </button> - </div> - </form> - </div> - </div> - </div> - </div> - )} - </div> - ); -}; - -export default LoginFacebook; diff --git a/apps/OpenSign/src/components/LoginGoogle.js b/apps/OpenSign/src/components/LoginGoogle.js deleted file mode 100644 index 498ee60e9..000000000 --- a/apps/OpenSign/src/components/LoginGoogle.js +++ /dev/null @@ -1,280 +0,0 @@ -import React, { useState, useRef } from "react"; -import Parse from "parse"; -import { jwtDecode } from "jwt-decode"; -import { useScript } from "../hook/useScript"; -import ModalUi from "../primitives/ModalUi"; -import Loader from "../primitives/Loader"; -import { useTranslation } from "react-i18next"; -import { saveLanguageInLocal } from "../constant/Utils"; -/* - * `GoogleSignInBtn`as it's name indicates it render google sign in button - * and in this `useScript` in which we have created for generate google sign button - * and when user click on sign in with google it will be verify on server side - * and then generate token - */ -const GoogleSignInBtn = ({ - GoogleCred, - thirdpartyLoginfn, - thirdpartyLoader, - setThirdpartyLoader -}) => { - const { t, i18n } = useTranslation(); - const [isModal, setIsModal] = useState(false); - const googleBtn = useRef(); - const [userDetails, setUserDetails] = useState({ - Phone: "", - Company: "", - Name: "", - Email: "", - Destination: "" - }); - const [googleDetails, setGoogleDetails] = useState({ - Id: "", - TokenId: "", - Gmail: "", - Name: "" - }); - useScript("https://accounts.google.com/gsi/client", () => { - window.google.accounts.id.initialize({ - client_id: GoogleCred, - callback: responseGoogle, - auto_select: false - }); - window.google.accounts.id.renderButton(googleBtn.current, { - theme: "outline", - size: "large", - width: "187px" - }); - }); - const clearStorage = async () => { - try { - await Parse.User.logOut(); - } catch (err) { - console.log("Err while logging out", err); - } - let baseUrl = localStorage.getItem("baseUrl"); - let appid = localStorage.getItem("parseAppId"); - let applogo = localStorage.getItem("appLogo"); - let defaultmenuid = localStorage.getItem("defaultmenuid"); - let PageLanding = localStorage.getItem("PageLanding"); - let userSettings = localStorage.getItem("userSettings"); - - localStorage.clear(); - saveLanguageInLocal(i18n); - - localStorage.setItem("baseUrl", baseUrl); - localStorage.setItem("parseAppId", appid); - localStorage.setItem("appLogo", applogo); - localStorage.setItem("defaultmenuid", defaultmenuid); - localStorage.setItem("PageLanding", PageLanding); - localStorage.setItem("userSettings", userSettings); - localStorage.setItem("baseUrl", baseUrl); - localStorage.setItem("parseAppId", appid); - }; - const responseGoogle = async (response) => { - clearStorage(); - setThirdpartyLoader(true); - // console.log("response ", response); - if (response.credential) { - const data = jwtDecode(response.credential); - // console.log("data ", data); - if (data.sub && data.email) { - const details = { Email: data.email, Name: data.name }; - setUserDetails({ ...userDetails, ...details }); - const Gdetails = { - Id: data.sub, - TokenId: response.credential, - Gmail: data.email, - Name: data.name - }; - setGoogleDetails({ ...googleDetails, ...Gdetails }); - await checkExtUser(Gdetails); - } - } - }; - const checkExtUser = async (details) => { - const params = { email: details.Gmail }; - const extRes = await Parse.Cloud.run("getUserDetails", params); - if (extRes) { - // const params = { ...details, Phone: extRes?.get("Phone") || "" }; - const params = { ...details, extUserId: extRes.objectId }; - const payload = await Parse.Cloud.run("googlesign", params); - if (payload && payload.sessiontoken) { - const LocalUserDetails = { - name: details.Name, - email: details.Gmail, - phone: payload?.phone || "", - company: payload.company - }; - localStorage.setItem("userDetails", JSON.stringify(LocalUserDetails)); - thirdpartyLoginfn(payload.sessiontoken); - } - return { msg: "exist" }; - } else { - setIsModal(true); - setThirdpartyLoader(false); - return { msg: "notexist" }; - } - }; - const handleSubmitbtn = async () => { - if (userDetails.Phone && userDetails.Company) { - setThirdpartyLoader(true); - // e.preventDefault() - // console.log("handelSubmit", userDetails); - const params = { ...googleDetails, Phone: userDetails?.Phone }; - const payload = await Parse.Cloud.run("googlesign", params); - - // console.log("payload ", payload); - if (payload && payload.sessiontoken) { - const params = { - userDetails: { - name: userDetails.Name, - email: userDetails.Email, - // "passsword":userDetails.Phone, - phone: userDetails?.Phone || "", - role: "contracts_User", - company: userDetails.Company, - jobTitle: userDetails.Destination - } - }; - const userSignUp = await Parse.Cloud.run("usersignup", params); - // console.log("userSignUp ", userSignUp); - if (userSignUp && userSignUp.sessionToken) { - const LocalUserDetails = { - name: userDetails.Name, - email: userDetails.Email, - phone: userDetails?.Phone || "", - company: userDetails.Company - // jobTitle: userDetails.JobTitle - }; - localStorage.setItem("userDetails", JSON.stringify(LocalUserDetails)); - thirdpartyLoginfn(userSignUp.sessionToken); - } else { - alert(userSignUp.message); - } - } else if ( - payload && - payload.message.replace(/ /g, "_") === "Internal_server_err" - ) { - alert(t("server-error")); - } - } else { - alert(t("fill-required-details!")); - } - }; - const handleCloseModal = async () => { - setIsModal(false); - try { - await Parse.User.logOut(); - } catch (err) { - console.log("Err while logging out", err); - } - let appdata = localStorage.getItem("userSettings"); - let applogo = localStorage.getItem("appLogo"); - let defaultmenuid = localStorage.getItem("defaultmenuid"); - let PageLanding = localStorage.getItem("PageLanding"); - let baseUrl = localStorage.getItem("baseUrl"); - let appid = localStorage.getItem("parseAppId"); - - localStorage.clear(); - saveLanguageInLocal(i18n); - localStorage.setItem("appLogo", applogo); - localStorage.setItem("defaultmenuid", defaultmenuid); - localStorage.setItem("PageLanding", PageLanding); - localStorage.setItem("userSettings", appdata); - localStorage.setItem("baseUrl", baseUrl); - localStorage.setItem("parseAppId", appid); - }; - return ( - <div className="relative"> - {thirdpartyLoader && ( - <div className="fixed flex justify-center items-center inset-0 bg-black bg-opacity-25 z-20 "> - <Loader /> - </div> - )} - <div ref={googleBtn} className="text-sm"></div> - <ModalUi showClose={false} isOpen={isModal} title={t("sign-up-form")}> - <form className="px-4 py-3 text-base-content"> - <div className="mb-3"> - <label htmlFor="Phone" className="block text-xs font-semibold"> - {t("phone")} <span className="text-[13px] text-[red]">*</span> - </label> - <input - type="tel" - className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" - id="Phone" - value={userDetails.Phone} - onChange={(e) => - setUserDetails({ - ...userDetails, - Phone: e.target.value - }) - } - onInvalid={(e) => e.target.setCustomValidity(t("input-required"))} - onInput={(e) => e.target.setCustomValidity("")} - required - /> - </div> - <div className="mb-3"> - <label htmlFor="Company" className="block text-xs font-semibold"> - {t("company")} <span className="text-[13px] text-[red]">*</span> - </label> - <input - type="text" - className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" - id="Company" - value={userDetails.Company} - onChange={(e) => - setUserDetails({ - ...userDetails, - Company: e.target.value - }) - } - onInvalid={(e) => e.target.setCustomValidity(t("input-required"))} - onInput={(e) => e.target.setCustomValidity("")} - required - /> - </div> - <div className="mb-3"> - <label htmlFor="JobTitle" className="block text-xs font-semibold"> - {t("job-title")} <span className="text-[13px] text-[red]">*</span> - </label> - <input - type="text" - className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" - id="JobTitle" - value={userDetails.Destination} - onChange={(e) => - setUserDetails({ - ...userDetails, - Destination: e.target.value - }) - } - onInvalid={(e) => e.target.setCustomValidity(t("input-required"))} - onInput={(e) => e.target.setCustomValidity("")} - required - /> - </div> - <div className="flex flex-row gap-2"> - <button - type="button" - className="op-btn op-btn-primary" - onClick={() => handleSubmitbtn()} - > - {t("sign-up")} - </button> - <button - type="button" - className="op-btn op-btn-ghost" - onClick={handleCloseModal} - > - {t("cancel")} - </button> - </div> - </form> - </ModalUi> - </div> - ); -}; - -export default GoogleSignInBtn; diff --git a/apps/OpenSign/src/components/RotateAlert.js b/apps/OpenSign/src/components/RotateAlert.js index a7448b6f1..b25c57805 100644 --- a/apps/OpenSign/src/components/RotateAlert.js +++ b/apps/OpenSign/src/components/RotateAlert.js @@ -6,22 +6,14 @@ function RotateAlert(props) { const { t } = useTranslation(); return ( <ModalUi - isOpen={props.isRotate} + isOpen={props.showRotateAlert} title={t("Rotation-alert")} - handleClose={() => props.setIsRotate({ status: false, degree: 0 })} + handleClose={() => props.setShowRotateAlert({ status: false, degree: 0 })} > - {" "} <div className="p-[20px] h-full"> <p>{t("rotate-alert-mssg")}</p> <div className="h-[1px] w-full my-[15px] bg-[#9f9f9f]"></div> <div className="flex gap-1"> - <button - onClick={() => props.setIsRotate({ status: false, degree: 0 })} - type="button" - className="op-btn op-btn-ghost shadow-md" - > - {t("no")} - </button> <button onClick={() => props.handleRemoveWidgets()} type="button" @@ -29,6 +21,15 @@ function RotateAlert(props) { > {t("yes")} </button> + <button + onClick={() => + props.setShowRotateAlert({ status: false, degree: 0 }) + } + type="button" + className="op-btn op-btn-ghost shadow-md" + > + {t("no")} + </button> </div> </div> </ModalUi> diff --git a/apps/OpenSign/src/components/dashboard/DashboardButton.js b/apps/OpenSign/src/components/dashboard/DashboardButton.js index 078475525..e1c7e3f8c 100644 --- a/apps/OpenSign/src/components/dashboard/DashboardButton.js +++ b/apps/OpenSign/src/components/dashboard/DashboardButton.js @@ -1,5 +1,5 @@ import React from "react"; -import { useNavigate } from "react-router-dom"; +import { useNavigate } from "react-router"; import { openInNewTab } from "../../constant/Utils"; import { useTranslation } from "react-i18next"; @@ -30,15 +30,27 @@ const DashboardButton = (props) => { } w-full shadow-md px-3 py-2 op-card bg-base-100`} > <div className="flex flex-row items-center"> - <span className="rounded-full bg-base-content bg-opacity-20 w-[60px] h-[60px] self-start flex justify-center items-center"> - <i - className={`${ - props.Icon ? props.Icon : "fa-light fa-info" - } text-[25px] lg:text-[30px]`} - ></i> - </span> - <div className=" text-lg ml-3 text-base-content"> + <div className="flex flex-row items-center"> + <span className="rounded-full bg-base-content bg-opacity-20 w-[60px] h-[60px] self-start flex justify-center items-center"> + <i + className={`${ + props.Icon ? props.Icon : "fa-light fa-info" + } text-[25px] lg:text-[30px]`} + ></i> + </span> + </div> + <div className="text-lg ml-3 text-base-content"> {t(`sidebar.${props.Label}`)} + {props.Label === "Sign yourself" && ( + <div className="text-gray-500 text-xs mt-1"> + {t("signyour-self-button")} + </div> + )} + {props.Label === "Request signatures" && ( + <div className="text-gray-500 text-xs mt-1"> + {t("requestsign-button")} + </div> + )} </div> </div> </div> diff --git a/apps/OpenSign/src/components/dashboard/DashboardCard.js b/apps/OpenSign/src/components/dashboard/DashboardCard.js index 378f2a4c3..8c0031b80 100644 --- a/apps/OpenSign/src/components/dashboard/DashboardCard.js +++ b/apps/OpenSign/src/components/dashboard/DashboardCard.js @@ -2,7 +2,7 @@ import React, { useState, useEffect } from "react"; import axios from "axios"; import Parse from "parse"; import getReplacedHashQuery from "../../constant/getReplacedHashQuery"; -import { useNavigate } from "react-router-dom"; +import { useNavigate } from "react-router"; import Tooltip from "../../primitives/Tooltip"; import { useTranslation } from "react-i18next"; @@ -133,7 +133,7 @@ const DashboardCard = (props) => { skip: 0, limit: 200 }; - const url = `${parseBaseUrl}/functions/getReport`; + const url = `${parseBaseUrl}functions/getReport`; await axios .post(url, params, { headers: { diff --git a/apps/OpenSign/src/components/dashboard/DashboardReport.js b/apps/OpenSign/src/components/dashboard/DashboardReport.js index ec288a4ba..b6706ebb5 100644 --- a/apps/OpenSign/src/components/dashboard/DashboardReport.js +++ b/apps/OpenSign/src/components/dashboard/DashboardReport.js @@ -36,12 +36,12 @@ function DashboardReport(props) { // below useEffect call when isNextRecord state is true and fetch next record useEffect(() => { if (isNextRecord) { - getReportData(props.Record.reportId, List.length, 200); + getReportData(props.Record.reportId, List.length, 20); } // eslint-disable-next-line }, [isNextRecord]); - const getReportData = async (id, skipUserRecord = 0, limit = 200) => { + const getReportData = async (id, skipUserRecord = 0, limit = 20) => { setIsLoader(true); const json = reportJson(id); if (json) { @@ -56,8 +56,10 @@ function DashboardReport(props) { sessiontoken: localStorage.getItem("accesstoken") }; try { - const params = { reportId: id, skip: skipUserRecord, limit: limit }; - const url = `${localStorage.getItem("baseUrl")}/functions/getReport`; + const skipRecord = id === "5Go51Q7T8r" ? 0 : skipUserRecord; + const limitRecord = id === "5Go51Q7T8r" ? 200 : limit; + const params = { reportId: id, skip: skipRecord, limit: limitRecord }; + const url = `${localStorage.getItem("baseUrl")}functions/getReport`; const res = await axios.post(url, params, { headers: headers, signal: abortController.signal // is used to cancel fetch query @@ -94,7 +96,7 @@ function DashboardReport(props) { prevRecord.length > 0 ? [...prevRecord, ...arr] : arr ); } else { - if (res.data.result.length === docPerPage) { + if (res.data.result.length >= docPerPage) { setIsMoreDocs(true); } else { setIsMoreDocs(false); diff --git a/apps/OpenSign/src/components/opensigndrive/DriveBody.js b/apps/OpenSign/src/components/opensigndrive/DriveBody.js index b198f6c4b..dca0547a5 100644 --- a/apps/OpenSign/src/components/opensigndrive/DriveBody.js +++ b/apps/OpenSign/src/components/opensigndrive/DriveBody.js @@ -2,13 +2,14 @@ import React, { useState, useEffect, useRef } from "react"; import "../../styles/opensigndrive.css"; import axios from "axios"; import * as ContextMenu from "@radix-ui/react-context-menu"; -import { useNavigate } from "react-router-dom"; +import { useNavigate } from "react-router"; import Table from "react-bootstrap/Table"; import * as HoverCard from "@radix-ui/react-hover-card"; import ModalUi from "../../primitives/ModalUi"; import FolderModal from "../shared/fields/FolderModal"; import { useTranslation } from "react-i18next"; -import { handleDownloadPdf } from "../../constant/Utils"; +import { handleDownloadPdf, isMobile } from "../../constant/Utils"; +import Parse from "parse"; function DriveBody(props) { const { t } = useTranslation(); @@ -17,7 +18,7 @@ function DriveBody(props) { const inputRef = useRef(null); const [isOpenMoveModal, setIsOpenMoveModal] = useState(false); const [selectDoc, setSelectDoc] = useState(); - const [isDeleteDoc, setIsDeleteDoc] = useState(false); + const [isDeleteDoc, setIsDeleteDoc] = useState({}); const contextMenu = [ { type: "Download", icon: "fa-light fa-arrow-down" }, { type: "Rename", icon: "fa-light fa-font" }, @@ -137,7 +138,7 @@ function DriveBody(props) { } }; - const handleMenuItemClick = async (selectType, data) => { + const handleMenuItemClick = async (selectType, data, deleteType) => { switch (selectType) { case "Download": { await handleDownloadPdf([data]); @@ -149,7 +150,7 @@ function DriveBody(props) { break; } case "Delete": { - setIsDeleteDoc(true); + setIsDeleteDoc({ status: true, deleteType }); setSelectDoc(data); break; } @@ -163,7 +164,7 @@ function DriveBody(props) { }; //function for delete document const handleDeleteDocument = async (docData) => { - setIsDeleteDoc(false); + setIsDeleteDoc({}); const docId = docData.objectId; const data = { IsArchive: true @@ -269,6 +270,50 @@ function DriveBody(props) { } }; + const checkFolderEmpty = async (docData) => { + let isEmptyFolder = true; + const query = new Parse.Query("contracts_Document"); + query.equalTo("Folder", { + __type: "Pointer", + className: "contracts_Document", + objectId: docData.objectId + }); + query.notEqualTo("IsArchive", true); + const res = await query.find(); + const jsonRes = JSON.parse(JSON.stringify(res)); + if (jsonRes && jsonRes.length > 0) { + isEmptyFolder = false; + return isEmptyFolder; + } else { + return isEmptyFolder; + } + }; + const handleDeleteFolder = async (docData) => { + setIsDeleteDoc({}); + const isEmptyFolder = await checkFolderEmpty(docData); + if (isEmptyFolder) { + const docId = docData?.objectId; + try { + const updateQuery = new Parse.Query("contracts_Document"); + const updateObj = await updateQuery.get(docId); + updateObj.set("IsArchive", true); + const res = await updateObj.save(); + if (res) { + const updatedData = props.pdfData.filter((x) => x.objectId !== docId); + props.setPdfData(updatedData); + } + } catch (err) { + console.log("Err ", err); + props.setIsAlert({ + isShow: true, + alertMessage: t("something-went-wrong-mssg") + }); + } + } else { + alert(t("delete-folder-alert-1")); + } + }; + //component to handle type of document and render according to type const handleFolderData = (data, ind, listType) => { let createddate, status, isDecline, signerExist, isComplete; @@ -311,6 +356,7 @@ function DriveBody(props) { </span> ); }; + return listType === "table" ? ( data.Type === "Folder" ? ( <tr onClick={() => handleOnclikFolder(data)}> @@ -359,7 +405,7 @@ function DriveBody(props) { ) : listType === "list" && data.Type === "Folder" ? ( <div key={ind} className="relative w-[100px] h-[100px] mx-2 my-3"> <ContextMenu.Root> - <ContextMenu.Trigger className="flex flex-col justify-center items-center"> + <ContextMenu.Trigger className="flex flex-col justify-center items-center select-none-cls"> {/* folder */} <div data-tut={props.dataTutSeventh} @@ -395,7 +441,7 @@ function DriveBody(props) { className="op-input op-input-bordered op-input-xs w-[100px] focus:outline-none hover:border-base-content text-[10px]" /> ) : ( - <span className="fileName">{data.Name}</span> + <span className="fileName select-none-cls">{data.Name}</span> )} </div> </ContextMenu.Trigger> @@ -413,13 +459,20 @@ function DriveBody(props) { <i className="fa-light fa-font mr-[8px]"></i> <span>Rename</span> </ContextMenu.Item> + <ContextMenu.Item + onClick={() => handleMenuItemClick("Delete", data, data.Type)} + className="ContextMenuItem" + > + <i className="fa-light fa-trash mr-[8px]"></i> + <span>Delete</span> + </ContextMenu.Item> </ContextMenu.Content> </ContextMenu.Portal> </ContextMenu.Root> </div> ) : ( <HoverCard.Root - open={rename ? false : undefined} + open={rename || isMobile ? false : undefined} openDelay={0} closeDelay={100} > @@ -427,7 +480,10 @@ function DriveBody(props) { <div> <ContextMenu.Root> <div className="relative w-[100px] h-[100px] mx-2 my-3"> - <ContextMenu.Trigger className="flex flex-col justify-center items-center"> + <ContextMenu.Trigger + asChild + className="flex flex-col justify-center items-center select-none-cls" + > {/* pdf */} <div data-tut={props.dataTutSixth} @@ -456,14 +512,16 @@ function DriveBody(props) { } }} onBlur={() => handledRenameDoc(data)} - onKeyDown={(e) => handleEnterPress(e, data)} + onKeyDown={(e) => handleEnterPress(e, data, data.Type)} ref={inputRef} defaultValue={renameValue} onChange={(e) => setRenameValue(e.target.value)} className="op-input op-input-bordered op-input-xs w-[100px] focus:outline-none hover:border-base-content text-[10px]" /> ) : ( - <span className="fileName">{data.Name}</span> + <span className="fileName select-none-cls"> + {data.Name} + </span> )} </div> </ContextMenu.Trigger> @@ -596,22 +654,33 @@ function DriveBody(props) { /> )} <ModalUi - isOpen={isDeleteDoc} + isOpen={isDeleteDoc.status} title={t("delete-document")} - handleClose={() => setIsDeleteDoc(false)} + handleClose={() => setIsDeleteDoc({})} > <div className="h-full p-[20px] text-base-content"> - <p>{t("delete-document-alert")}</p> + {isDeleteDoc.deleteType ? ( + <p>{t("delete-folder-alert")}</p> + ) : ( + <p>{t("delete-document-alert")}</p> + )} + <div className="h-[1px] w-full bg-[#9f9f9f] my-[15px]"></div> <button - onClick={() => handleDeleteDocument(selectDoc)} + onClick={() => { + if (isDeleteDoc.deleteType) { + handleDeleteFolder(selectDoc); + } else { + handleDeleteDocument(selectDoc); + } + }} type="button" className="op-btn op-btn-primary mr-2" > {t("yes")} </button> <button - onClick={() => setIsDeleteDoc(false)} + onClick={() => setIsDeleteDoc({})} type="button" className="op-btn op-btn-neutral" > diff --git a/apps/OpenSign/src/components/pdf/AgreementContent.js b/apps/OpenSign/src/components/pdf/AgreementContent.js new file mode 100644 index 000000000..808aad3e2 --- /dev/null +++ b/apps/OpenSign/src/components/pdf/AgreementContent.js @@ -0,0 +1,116 @@ +import React from "react"; +import { useTranslation } from "react-i18next"; +import ModalUi from "../../primitives/ModalUi"; + +function AgreementContent(props) { + const { t } = useTranslation(); + const h2Style = "text-base-content font-medium text-lg"; + const ulStyle = "list-disc px-4 py-3"; + const handleOnclick = () => { + props.setIsAgreeTour(false); + props.setIsAgree(true); + props.setIsShowAgreeTerms(false); + props.showFirstWidget(); + }; + return ( + <div> + <ModalUi + isOpen={true} + title={t("term-cond-title")} + handleClose={() => props.setIsShowAgreeTerms(false)} + > + <div className="h-[100%] p-[20px]"> + <h2 className={h2Style}>{t("term-cond-h")}</h2> + <span className="mt-2">{t("term-cond-p1")}</span> + <div className="h-[1px] bg-[#9f9f9f] w-full my-[15px]"></div> + <h2 className={h2Style}>{t("term-cond-h1")}</h2> + <span className="mt-2">{t("term-cond-p2")}</span> + <ul className={ulStyle}> + <li>{t("term-cond-p3")}</li> + <li>{t("term-cond-p4")}</li> + </ul> + <div className="h-[1px] bg-[#9f9f9f] w-full my-[15px]"></div> + <h2 className={h2Style}>{t("term-cond-h2")}</h2> + <span className="mt-2">{t("term-cond-p5")}</span> + <ul className={ulStyle}> + <li>{t("term-cond-p6")}</li> + <li>{t("term-cond-p7")}</li> + <li>{t("term-cond-p8")}</li> + </ul> + <div className="h-[1px] bg-[#9f9f9f] w-full my-[15px]"></div> + <h2 className={h2Style}>{t("term-cond-h3")}</h2> + <span className="mt-2">{t("term-cond-p9")}</span> + <ul className={ulStyle}> + <li>{t("term-cond-p10")}</li> + <li>{t("term-cond-p11")}</li> + </ul> + <div className="h-[1px] bg-[#9f9f9f] w-full my-[15px]"></div> + <h2 className={h2Style}>{t("term-cond-h4")}</h2> + <span className="mt-2">{t("term-cond-p12")}</span> + <ul className={ulStyle}> + <li>{t("term-cond-p13")}</li> + <li>{t("term-cond-p14")}</li> + <li>{t("term-cond-p15")}</li> + </ul> + <span>{t("term-cond-p16")}</span> + <div className="h-[1px] bg-[#9f9f9f] w-full my-[15px]"></div> + <h2 className={h2Style}>{t("term-cond-h5")}</h2> + <p>{t("term-cond-p17")}</p> + <p className="mt-2">{t("term-cond-p18")}</p> + <div className="h-[1px] bg-[#9f9f9f] w-full my-[15px]"></div> + <h2 className={h2Style}>{t("term-cond-h6")}</h2> + <span className="mt-2">{t("term-cond-p19")}</span> + <ul className={ulStyle}> + <li>{t("term-cond-p20")}</li> + <li>{t("term-cond-p21")}</li> + <li>{t("term-cond-p22")}</li> + </ul> + <div className="h-[1px] bg-[#9f9f9f] w-full my-[15px]"></div> + <h2 className={h2Style}>{t("term-cond-h7")}</h2> + <span className="mt-2">{t("term-cond-p23")}</span> + <ul className={ulStyle}> + <li>{t("term-cond-p24")}</li> + <li>{t("term-cond-p25")}</li> + </ul> + <div className="h-[1px] bg-[#9f9f9f] w-full my-[15px]"></div> + <h2 className={h2Style}>{t("term-cond-h8")}</h2> + <span className="mt-2">{t("term-cond-p26")}</span> + <div className="h-[1px] bg-[#9f9f9f] w-full my-[15px]"></div> + <h2 className={h2Style}>{t("term-cond-h9")}</h2> + <span className="mt-2">{t("term-cond-p27")}</span> + <div className="h-[1px] bg-[#9f9f9f] w-full my-[15px]"></div> + <span className="mt-2 font-medium">{t("term-cond-p28")}</span> + <div className="h-[1px] bg-[#9f9f9f] w-full my-[15px]"></div> + <span className="mt-2">{t("term-cond-p29")}</span> + <a + href="www.opensignlabs.com" + target="_blank" + className="text-blue-700 cursor-pointer" + > + {" "} + www.opensignlabs.com{" "} + </a> + <span>{t("term-cond-p30")}</span> + <span className="font-medium"> support@opensignlabs.com </span> + <div className="h-[1px] bg-[#9f9f9f] w-full my-[15px]"></div> + <div className="mt-6 flex justify-start gap-2"> + <button + onClick={() => handleOnclick()} + className="op-btn op-btn-primary" + > + {t("agrre-button")} + </button> + <button + className="op-btn op-btn-ghost" + onClick={() => props.setIsShowAgreeTerms(false)} + > + {t("close")} + </button> + </div> + </div> + </ModalUi> + </div> + ); +} + +export default AgreementContent; diff --git a/apps/OpenSign/src/components/pdf/AgreementSign.js b/apps/OpenSign/src/components/pdf/AgreementSign.js new file mode 100644 index 000000000..36f9715c9 --- /dev/null +++ b/apps/OpenSign/src/components/pdf/AgreementSign.js @@ -0,0 +1,71 @@ +import React, { useState } from "react"; +import { useTranslation } from "react-i18next"; +import AgreementContent from "./AgreementContent"; + +function AgreementSign(props) { + const { t } = useTranslation(); + const [isChecked, setIsChecked] = useState(false); + const [isShowAgreeTerms, setIsShowAgreeTerms] = useState(false); + + return ( + <> + <div className="op-modal op-modal-open absolute z-[448]"> + <div className="w-[95%] md:w-[60%] lg:w-[40%] op-modal-box overflow-y-auto hide-scrollbar text-sm p-4"> + <div className="flex flex-row items-center"> + <input + data-tut="IsAgree" + className="mr-3 op-checkbox op-checkbox-m" + type="checkbox" + value={isChecked} + onChange={(e) => { + setIsChecked(e.target.checked); + if (e.target.checked) { + props.setIsAgreeTour(false); + } + props.showFirstWidget(); + }} + /> + <div className="text-[11px] md:text-base"> + <span>{t("agree-p1")}</span> + <span + className="font-bold text-blue-600 cursor-pointer" + onClick={() => { + setIsShowAgreeTerms(true); + props.setIsAgreeTour(false); + }} + > + {t("agree-p2")} + </span> + <span> {t("agree-p3")}</span> + </div> + </div> + <div className="flex ml-[35px] mt-3"> + <button + onClick={() => { + if (isChecked) { + props.setIsAgreeTour(false); + props.setIsAgree(true); + } else { + props.setIsAgreeTour(true); + } + }} + className="op-btn op-btn-primary op-btn-sm w-full md:w-auto" + > + {t("agrre-button")} + </button> + </div> + </div> + </div> + {isShowAgreeTerms && ( + <AgreementContent + setIsAgreeTour={props.setIsAgreeTour} + setIsAgree={props.setIsAgree} + setIsShowAgreeTerms={setIsShowAgreeTerms} + showFirstWidget={props.showFirstWidget} + /> + )} + </> + ); +} + +export default AgreementSign; diff --git a/apps/OpenSign/src/components/pdf/DefaultSignature.js b/apps/OpenSign/src/components/pdf/DefaultSignature.js index c941bcd38..a15ad3d7f 100644 --- a/apps/OpenSign/src/components/pdf/DefaultSignature.js +++ b/apps/OpenSign/src/components/pdf/DefaultSignature.js @@ -1,41 +1,106 @@ -import React from "react"; +import React, { useState } from "react"; import { useTranslation } from "react-i18next"; function DefaultSignature(props) { const { t } = useTranslation(); - - const confirmToaddDefaultSign = () => { - if (props?.xyPostion.length > 0) { - props?.setDefaultSignAlert({ - isShow: true, - alertMessage: t("default-sign-alert") - }); + const tabName = ["my-signature", "my-initials"]; + const [activeTab, setActiveTab] = useState(0); + const confirmToaddDefaultSign = (type) => { + if (!props.isAgree) { + props.setIsAgreeTour(true); } else { - props?.setDefaultSignAlert({ - isShow: true, - alertMessage: t("please-select-position!") - }); + if (props?.xyPosition.length > 0) { + //check signature or initial widgets exist or not for auto signing + const getCurrentSignerXY = props?.xyPosition.filter( + (data) => data.Id === props.uniqueId + ); + const checkIsSignInitialExist = getCurrentSignerXY?.every( + (placeholderObj) => + placeholderObj?.placeHolder?.some((placeholder) => + placeholder?.pos?.some((posItem) => posItem?.type === type) + ) + ); + if (checkIsSignInitialExist) { + props?.setDefaultSignAlert({ + isShow: true, + alertMessage: t("default-sign-alert", { widgetsType: type }), + type: type + }); + } else { + props?.setDefaultSignAlert({ + isShow: true, + alertMessage: t("defaultSign-alert", { widgetsType: type }) + }); + } + } else { + props?.setDefaultSignAlert({ + isShow: true, + alertMessage: t("please-select-position!") + }); + } } }; return ( <div data-tut="reactourThird"> <div className="mx-2 pr-2 pt-2 pb-1 text-[15px] text-base-content font-semibold border-b-[1px] border-base-300"> - {t("signature")} + <p className="text-base-content">{t("signature")}</p> + </div> + <div className="flex justify-center items-center mt-2"> + <div role="tablist" className="op-tabs op-tabs-bordered"> + {tabName.map((tabData, ind) => ( + <div + onClick={() => setActiveTab(ind)} + key={ind} + role="tab" + className={`${ + activeTab === ind ? "op-tab-active" : "" + } op-tab flex items-center pb-10 md:pb-0`} + > + <span className="ml-1 text-[7px] font-medium md:font-normal md:text-[12px]"> + {t(`${tabData}`)} + </span> + </div> + ))} + </div> </div> <div className="flex flex-col items-center mt-[10px] font-semibold relative"> - <p className="text-base-content">{t("Your-Signature")}</p> <div className="op-card shadow-md h-[111px] w-[90%] p-2"> - <img - alt="signature" - className="w-full h-full object-contain" - src={props?.defaultSignImg} - /> + {activeTab === 0 ? ( + <img + alt="signature" + className="w-full h-full object-contain" + src={props?.defaultSignImg} + /> + ) : ( + activeTab === 1 && + (props?.myInitial ? ( + <img + alt="signature" + className="w-full h-full object-contain" + src={props?.myInitial} + /> + ) : ( + <div className="flex justify-center items-center h-full"> + <span>{t("initial-alert")}</span> + </div> + )) + )} </div> <button type="button" className="op-btn op-btn-primary op-btn-sm mt-[10px]" - onClick={() => confirmToaddDefaultSign()} - disabled={!props?.isDefault} + onClick={() => + confirmToaddDefaultSign( + activeTab === 0 ? "signature" : activeTab === 1 && "initials" + ) + } + disabled={ + activeTab === 0 && !props?.isDefault + ? true + : activeTab === 1 && !props.myInitial + ? true + : false + } > {t("auto-sign-all")} </button> diff --git a/apps/OpenSign/src/components/pdf/DraftDocument.js b/apps/OpenSign/src/components/pdf/DraftDocument.js index 6256704e5..6e03cd6e8 100644 --- a/apps/OpenSign/src/components/pdf/DraftDocument.js +++ b/apps/OpenSign/src/components/pdf/DraftDocument.js @@ -2,7 +2,7 @@ import React, { useEffect, useState } from "react"; import LoaderWithMsg from "../../primitives/LoaderWithMsg"; import { contractDocument } from "../../constant/Utils"; import HandleError from "../../primitives/HandleError"; -import { useLocation, useNavigate } from "react-router-dom"; +import { useLocation, useNavigate } from "react-router"; import { useTranslation } from "react-i18next"; function useQuery() { return new URLSearchParams(useLocation().search); diff --git a/apps/OpenSign/src/components/pdf/DropdownWidgetOption.js b/apps/OpenSign/src/components/pdf/DropdownWidgetOption.js index 697c42917..ab30287b9 100644 --- a/apps/OpenSign/src/components/pdf/DropdownWidgetOption.js +++ b/apps/OpenSign/src/components/pdf/DropdownWidgetOption.js @@ -1,8 +1,6 @@ import React, { useEffect, useState } from "react"; -import { isEnableSubscription } from "../../constant/const"; import ModalUi from "../../primitives/ModalUi"; import { radioButtonWidget } from "../../constant/Utils"; -import Upgrade from "../../primitives/Upgrade"; import { useTranslation } from "react-i18next"; import { fontColorArr, fontsizeArr } from "../../constant/Utils"; @@ -130,14 +128,6 @@ function DropdownWidgetOption(props) { setDefaultValue(""); }; - const handleSetMinMax = (e) => { - const minValue = e.target.value; - if (minValue > dropdownOptionList.length) { - return ""; - } else { - return minValue; - } - }; const handleDefaultCheck = (index) => { const getDefaultCheck = defaultCheckbox.includes(index); @@ -181,7 +171,7 @@ function DropdownWidgetOption(props) { key={index} className="flex flex-row mb-[5px] items-center" > - {props.type === "checkbox" && !props.isSignYourself && ( + {props.type === "checkbox" && props.isShowAdvanceFeature && ( <input type="checkbox" checked={handleDefaultCheck(index)} @@ -224,65 +214,6 @@ function DropdownWidgetOption(props) { onClick={handleAddInput} className="fa-light fa-square-plus text-[25px] ml-[10px] op-text-primary cursor-pointer" ></i> - {isEnableSubscription && ( - <div> - {props.type === "checkbox" && !props.isSignYourself && ( - <> - <label - className={`${ - !props.isSubscribe ? "text-[gray]" : "" - } text-[13px] font-semibold`} - > - {t("minimun-check")} - </label> - {!props.isSubscribe && isEnableSubscription && ( - <Upgrade /> - )} - <input - onInvalid={(e) => - e.target.setCustomValidity(t("input-required")) - } - onInput={(e) => e.target.setCustomValidity("")} - required - defaultValue={0} - value={minCount} - disabled={props.isSubscribe ? false : true} - onChange={(e) => { - const count = handleSetMinMax(e); - setMinCount(count); - }} - className={`${ - props.isSubscribe ? "" : "pointer-events-none" - } op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs`} - /> - <label - className={`${ - !props.isSubscribe ? "text-[gray]" : "" - } text-[13px] font-semibold`} - > - {t("maximum-check")} - </label> - <input - onInvalid={(e) => - e.target.setCustomValidity(t("input-required")) - } - onInput={(e) => e.target.setCustomValidity("")} - required - defaultValue={0} - value={maxCount} - disabled={props.isSubscribe ? false : true} - onChange={(e) => { - const count = handleSetMinMax(e); - setMaxCount(count); - }} - className={`${ - props.isSubscribe ? "" : "pointer-events-none" - } op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs`} - /> - </> - )} - </div> - )} </div> {["dropdown", radioButtonWidget].includes(props.type) && ( <> @@ -381,9 +312,11 @@ function DropdownWidgetOption(props) { ></span> </div> </div> - {["checkbox", radioButtonWidget].includes(props.type) && ( + {["checkbox", radioButtonWidget, "dropdown"].includes( + props.type + ) && ( <div className="flex flex-row gap-5 my-2 items-center text-center"> - {!props.isSignYourself && ( + {props.isShowAdvanceFeature && ( <div className="flex items-center"> <input id="isreadonly" @@ -397,26 +330,28 @@ function DropdownWidgetOption(props) { </label> </div> )} - <div className="flex items-center"> - <input - id="ishidelabel" - type="checkbox" - checked={isHideLabel} - className="op-checkbox op-checkbox-sm" - onChange={(e) => setIsHideLabel(e.target.checked)} - /> + {props.type !== "dropdown" && ( + <div className="flex items-center"> + <input + id="ishidelabel" + type="checkbox" + checked={isHideLabel} + className="op-checkbox op-checkbox-sm" + onChange={(e) => setIsHideLabel(e.target.checked)} + /> - <label className="ml-1 mb-0" htmlFor="ishidelabel"> - {t("hide-labels")} - </label> - </div> + <label className="ml-1 mb-0" htmlFor="ishidelabel"> + {t("hide-labels")} + </label> + </div> + )} </div> )} </div> <div className={`${ - props.type === "checkbox" && !props.isSignYourself + props.type === "checkbox" && props.isShowAdvanceFeature ? "mb-[15px]" : "my-[15px]" } w-full h-[1px] bg-[#9f9f9f]`} diff --git a/apps/OpenSign/src/components/pdf/EditTemplate.js b/apps/OpenSign/src/components/pdf/EditTemplate.js index e3d589de7..eef8b5c28 100644 --- a/apps/OpenSign/src/components/pdf/EditTemplate.js +++ b/apps/OpenSign/src/components/pdf/EditTemplate.js @@ -1,11 +1,17 @@ -import React, { useState, useEffect } from "react"; -import { checkIsSubscribed, getFileName } from "../../constant/Utils"; -import Upgrade from "../../primitives/Upgrade"; -import { isEnableSubscription } from "../../constant/const"; +import React, { + useState, +} from "react"; +import { + getFileName +} from "../../constant/Utils"; import { useTranslation } from "react-i18next"; import { Tooltip } from "react-tooltip"; +import SignersInput from "../shared/fields/SignersInput"; -const EditTemplate = ({ template, onSuccess, jwttoken }) => { +const EditTemplate = ({ + template, + onSuccess, +}) => { const { t } = useTranslation(); const [formData, setFormData] = useState({ Name: template?.Name || "", @@ -21,19 +27,22 @@ const EditTemplate = ({ template, onSuccess, jwttoken }) => { NotifyOnSignatures: template?.NotifyOnSignatures !== undefined ? template?.NotifyOnSignatures - : false + : false, + Bcc: template?.Bcc, + RedirectUrl: template?.RedirectUrl || "", + AllowModifications: template?.AllowModifications || false }); - const [isSubscribe, setIsSubscribe] = useState(false); - useEffect(() => { - fetchSubscription(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - const fetchSubscription = async () => { - if (isEnableSubscription) { - const subscribe = await checkIsSubscribed(jwttoken); - setIsSubscribe(subscribe.isValid); + + // `isValidURL` is used to check valid webhook url + function isValidURL(value) { + try { + const url = new URL(value); + return url.protocol === "https:" || url.protocol === "http:"; + } catch (error) { + return false; } - }; + } + const handleStrInput = (e) => { setFormData({ ...formData, [e.target.name]: e.target.value }); }; @@ -42,10 +51,15 @@ const EditTemplate = ({ template, onSuccess, jwttoken }) => { const handleSubmit = async (e) => { e.preventDefault(); e.stopPropagation(); + if (formData.RedirectUrl && !isValidURL(formData?.RedirectUrl)) { + alert(t("invalid-redirect-url")); + return; + } const isChecked = formData.SendinOrder === "true" ? true : false; const isTourEnabled = formData?.IsTourEnabled === "false" ? false : true; const AutoReminder = formData?.AutomaticReminders || false; const IsEnableOTP = formData.IsEnableOTP === "true" ? true : false; + const allowModify = formData?.AllowModifications || false; let reminderDate = {}; if (AutoReminder) { const RemindOnceInEvery = parseInt(formData?.RemindOnceInEvery); @@ -58,21 +72,26 @@ const EditTemplate = ({ template, onSuccess, jwttoken }) => { SendinOrder: isChecked, IsEnableOTP: IsEnableOTP, IsTourEnabled: isTourEnabled, + AllowModifications: allowModify, ...reminderDate }; onSuccess(data); }; - const handleAutoReminder = () => { - setFormData((prev) => ({ - ...prev, - AutomaticReminders: !formData.AutomaticReminders - })); - }; // `handleNotifySignChange` is trigger when user change radio of notify on signatures const handleNotifySignChange = (value) => { setFormData((obj) => ({ ...obj, NotifyOnSignatures: value })); }; + const handleBcc = (data) => { + if (data && data.length > 0) { + const trimEmail = data.map((item) => ({ + objectId: item?.value, + Name: item?.label, + Email: item?.email + })); + setFormData((prev) => ({ ...prev, Bcc: trimEmail })); + } + }; return ( <div className="max-h-[300px] md:max-h-[400px] overflow-y-scroll p-[10px]"> <div className="text-base-content"> @@ -154,119 +173,7 @@ const EditTemplate = ({ template, onSuccess, jwttoken }) => { </div> </div> </div> - {isEnableSubscription && ( - <div className="text-xs mt-2"> - <span - className={ - isSubscribe ? "font-semibold" : "font-semibold text-gray-300" - } - > - {t("auto-reminder")} - {!isSubscribe && isEnableSubscription && <Upgrade />} - </span> - <label - className={`${ - isSubscribe - ? "cursor-pointer" - : "pointer-events-none opacity-50" - } relative block items-center mb-0`} - > - <input - checked={formData.AutomaticReminders} - onChange={handleAutoReminder} - type="checkbox" - className="op-toggle transition-all checked:[--tglbg:#3368ff] checked:bg-white mt-2" - /> - </label> - </div> - )} - {isSubscribe && formData?.AutomaticReminders === true && ( - <div className="text-xs mt-2"> - <label className="block"> - {t("remind-once")} - <span className="text-red-500 text-[13px]">*</span> - </label> - <input - type="number" - value={formData.RemindOnceInEvery} - name="RemindOnceInEvery" - className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" - onChange={handleStrInput} - onInvalid={(e) => - e.target.setCustomValidity(t("input-required")) - } - onInput={(e) => e.target.setCustomValidity("")} - required - /> - </div> - )} - {isEnableSubscription && ( - <div className="text-xs mt-2"> - <label className="block"> - <span className={isSubscribe ? "" : " text-gray-300"}> - {t("isenable-otp")}{" "} - <a data-tooltip-id="isenableotp-tooltip" className="ml-1"> - <sup> - <i className="fa-light fa-question rounded-full border-[#33bbff] text-[#33bbff] text-[13px] border-[1px] py-[1.5px] px-[4px]"></i> - </sup> - </a>{" "} - {!isSubscribe && isEnableSubscription && <Upgrade />} - </span> - <Tooltip id="isenableotp-tooltip" className="z-50"> - <div className="max-w-[200px] md:max-w-[450px]"> - <p className="font-bold">{t("isenable-otp")}</p> - <p>{t("isenable-otp-help.p1")}</p> - <p className="p-[5px]"> - <ol className="list-disc"> - <li> - <span className="font-bold">{t("yes")}: </span> - <span>{t("isenable-otp-help.p2")}</span> - </li> - <li> - <span className="font-bold">{t("no")}: </span> - <span>{t("isenable-otp-help.p3")}</span> - </li> - </ol> - </p> - <p>{t("isenable-otp-help.p4")}</p> - </div> - </Tooltip> - </label> - <div className="flex flex-col md:flex-row md:gap-4"> - <div - className={`${ - isSubscribe ? "" : "pointer-events-none opacity-50" - } flex items-center gap-2 ml-2 mb-1`} - > - <input - type="radio" - value={"true"} - className="op-radio op-radio-xs" - name="IsEnableOTP" - checked={formData.IsEnableOTP === "true"} - onChange={handleStrInput} - /> - <div className="text-center">{t("yes")}</div> - </div> - <div - className={`${ - isSubscribe ? "" : "pointer-events-none opacity-50" - } flex items-center gap-2 ml-2 mb-1 `} - > - <input - type="radio" - value={"false"} - name="IsEnableOTP" - className="op-radio op-radio-xs" - checked={formData.IsEnableOTP === "false"} - onChange={handleStrInput} - /> - <div className="text-center">{t("no")}</div> - </div> - </div> - </div> - )} - <div className="text-xs mt-2"> + <div className="text-xs mt-3"> <label className="block"> <span> {t("enable-tour")} @@ -322,9 +229,6 @@ const EditTemplate = ({ template, onSuccess, jwttoken }) => { </div> <div className="text-xs mt-3"> <label - className={`${ - isSubscribe || !isEnableSubscription ? "" : "text-gray-300" - } block`} > {t("notify-on-signatures")} <a data-tooltip-id="nos-tooltip" className="ml-1"> @@ -332,7 +236,6 @@ const EditTemplate = ({ template, onSuccess, jwttoken }) => { <i className="fa-light fa-question rounded-full border-[#33bbff] text-[#33bbff] text-[13px] border-[1px] py-[1.5px] px-[4px]"></i> </sup> </a> - {!isSubscribe && isEnableSubscription && <Upgrade />} <Tooltip id="nos-tooltip" className="z-[999]"> <div className="max-w-[200px] md:max-w-[450px] text-[11px]"> <p className="font-bold">{t("notify-on-signatures")}</p> @@ -343,11 +246,9 @@ const EditTemplate = ({ template, onSuccess, jwttoken }) => { </label> <div className="flex flex-col md:flex-row md:gap-4"> <div - className={`${ - isSubscribe || !isEnableSubscription - ? "" - : "pointer-events-none opacity-50" - } flex items-center gap-2 ml-2 mb-1`} + className={ + "flex items-center gap-2 ml-2 mb-1" + } > <input className="mr-[2px] op-radio op-radio-xs" @@ -358,11 +259,9 @@ const EditTemplate = ({ template, onSuccess, jwttoken }) => { <div className="text-center">{t("yes")}</div> </div> <div - className={`${ - isSubscribe || !isEnableSubscription - ? "" - : "pointer-events-none opacity-50" - } flex items-center gap-2 ml-2 mb-1`} + className={ + "flex items-center gap-2 ml-2 mb-1" + } > <input className="mr-[2px] op-radio op-radio-xs" @@ -374,6 +273,27 @@ const EditTemplate = ({ template, onSuccess, jwttoken }) => { </div> </div> </div> + <div className="text-xs mt-3"> + <SignersInput + label={t("Bcc")} + initialData={template?.Bcc} + onChange={handleBcc} + helptextZindex={50} + helpText={t("bcc-help")} + isCaptureAllData + /> + </div> + <div className="text-xs mt-2"> + <label className="block">Redirect Url</label> + <input + name="RedirectUrl" + className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" + value={formData.RedirectUrl} + onChange={handleStrInput} + onInvalid={(e) => e.target.setCustomValidity(t("input-required"))} + onInput={(e) => e.target.setCustomValidity("")} + /> + </div> <div className="mt-[1rem] flex justify-start"> <button type="submit" className="op-btn op-btn-primary"> {t("submit")} diff --git a/apps/OpenSign/src/components/pdf/EditorToolbar.js b/apps/OpenSign/src/components/pdf/EditorToolbar.js index 1624ed7d2..4ebbcf75b 100644 --- a/apps/OpenSign/src/components/pdf/EditorToolbar.js +++ b/apps/OpenSign/src/components/pdf/EditorToolbar.js @@ -54,17 +54,20 @@ Quill.register(Font, true); export const module1 = { toolbar: { container: "#toolbar1", - handlers: { - undo: undoChange, - redo: redoChange - } + handlers: { undo: undoChange, redo: redoChange } }, - history: { - delay: 500, - maxStack: 100, - userOnly: true - } + history: { delay: 500, maxStack: 100, userOnly: true } }; + +// Modules object for setting up the Quill editor +export const module2 = { + toolbar: { + container: "#toolbar2", + handlers: { undo: undoChange, redo: redoChange } + }, + history: { delay: 500, maxStack: 100, userOnly: true } +}; + // Formats objects for setting up the Quill editor export const formats = [ "header", diff --git a/apps/OpenSign/src/components/pdf/EmailComponent.js b/apps/OpenSign/src/components/pdf/EmailComponent.js index bae473ecb..3b9948538 100644 --- a/apps/OpenSign/src/components/pdf/EmailComponent.js +++ b/apps/OpenSign/src/components/pdf/EmailComponent.js @@ -15,7 +15,6 @@ function EmailComponent({ sender, setIsAlert, extUserId, - activeMailAdapter, setIsDownloadModal }) { const { t } = useTranslation(); @@ -31,14 +30,14 @@ function EmailComponent({ setIsLoading(true); let sendMail; const docId = pdfDetails?.[0]?.objectId || ""; - const FileAdapterId = pdfDetails?.[0]?.FileAdapterId - ? pdfDetails?.[0]?.FileAdapterId - : ""; let presignedUrl = pdfUrl; try { const axiosRes = await axios.post( `${localStorage.getItem("baseUrl")}/functions/getsignedurl`, - { url: pdfUrl, docId: docId, fileAdapterId: FileAdapterId }, + { + url: pdfUrl, + docId: docId, + }, { headers: { "content-type": "Application/json", @@ -65,13 +64,16 @@ function EmailComponent({ const openSignUrl = "https://www.opensignlabs.com/contact-us"; const themeBGcolor = themeColor; let params = { - mailProvider: activeMailAdapter, extUserId: extUserId, pdfName: pdfName, url: presignedUrl, recipient: emailList[i], subject: `${sender.name} has signed the doc - ${pdfName}`, - from: sender.email, + replyto: + pdfDetails?.[0]?.ExtUserPtr?.Email || + "", + from: + sender.email, html: "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body> <div style='background-color:#f5f5f5;padding:20px'> <div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background-color:white;'> <div><img src=" + imgPng + @@ -182,7 +184,7 @@ function EmailComponent({ {!isAndroid && ( <button onClick={(e) => - handleToPrint(e, pdfUrl, setIsDownloading, pdfDetails) + handleToPrint(e, setIsDownloading, pdfDetails) } className="op-btn op-btn-neutral op-btn-sm text-[15px]" > diff --git a/apps/OpenSign/src/components/pdf/EmbedTab.js b/apps/OpenSign/src/components/pdf/EmbedTab.js index 65213cfaa..183a5a635 100644 --- a/apps/OpenSign/src/components/pdf/EmbedTab.js +++ b/apps/OpenSign/src/components/pdf/EmbedTab.js @@ -3,9 +3,11 @@ import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; import { tomorrow } from "react-syntax-highlighter/dist/esm/styles/prism"; import { copytoData } from "../../constant/Utils"; import { useTranslation } from "react-i18next"; +import { useNavigate } from "react-router"; function EmbedTab(props) { const { t } = useTranslation(); + const navigate = useNavigate(); const tabName = [ { title: "React/Next.js", icon: "fa-brands fa-react", color: "#61dafb" }, { title: "JavaScript", icon: "fa-brands fa-js", color: "#ffd43b" }, @@ -33,7 +35,7 @@ export default function App() { <Opensign onLoad={() => console.log("success")} onLoadError={(error) => console.log(error)} - templateId= "${props.templateId}" + templateId= "${props.templateId ? props.templateId : "#templateId"}" /> </div> ); @@ -60,7 +62,7 @@ import { OpensignComponent } from "@opensign/angular" selector:'app-root', standalone: true, imports: [OpensignComponent], - template:\`<opensign templateId="${props.templateId}" + template:\`<opensign templateId="${props.templateId ? props.templateId : "#templateId"}" (onLoad)="handleLoad()" (onLoadError)="handleError($event)" ></opensign>\`, @@ -79,9 +81,9 @@ export class AppComponent { ]; const jsCodeString = ` <script - src= "https://app.opensignlabs.com/static/js/public-template.bundle.js" + src= "${window.location.origin}/static/js/public-template.bundle.js" id="opensign-script" - templateId=${props.templateId} + templateId=${props.templateId ? props.templateId : "#templateId"} ></script> `; @@ -92,10 +94,12 @@ export class AppComponent { }; return ( - <div className="mt-4 border-t-[1px]"> - <h3 className="text-base-content font-bold text-lg pt-[15px] pb-[5px]"> - {t("embed-template")} - </h3> + <div className={`${props.templateId && "border-t-[1px] mt-4"}`}> + {props.templateId && ( + <h3 className="text-base-content font-bold text-lg pt-[15px] pb-[5px]"> + {t("embed-template")} + </h3> + )} <div className="flex justify-center items-center mt-2"> <div role="tablist" className="op-tabs op-tabs-bordered"> {tabName.map((tabData, ind) => ( @@ -128,7 +132,7 @@ export class AppComponent { {t(`${data.title}`)} </p> {ind === 0 && ( - <p className="text-[13px] mt-2"> + <p className="text-[15px] mt-2"> {t("public-template-mssg-1")} </p> )} @@ -155,8 +159,19 @@ export class AppComponent { </div> ); })} - - <p className="font-medium text-[15px]"> + {props.isEmbedPage && ( + <p className="text-[15px] my-2"> + {t("js-snippet-msg-1")} + <span + className="text-blue-600 cursor-pointer px-1" + onClick={() => navigate("/report/6TeaPr321t")} + > + {t("js-snippet-msg-2")} + </span> + <span>{t("js-snippet-msg-3")}</span> + </p> + )} + <p className="font-medium mt-3 text-[15px]"> {t("public-template-mssg-3")} </p> <p className="my-[6px]"> @@ -177,8 +192,8 @@ export class AppComponent { ) : activeTab === 1 ? ( <div className="mt-4"> <div> - {/* <p className="font-medium text-[18px]">{t(`${data.title}`)}</p> */} - + <p className="font-medium text-[18px]">{t(`Usage`)}</p> + <p className="text-[15px] my-2">{t("js-snippet-msg")}</p> <div className="relative p-1"> <div onClick={() => handleCopy(jsCodeString, 0)} @@ -199,6 +214,18 @@ export class AppComponent { {jsCodeString} </SyntaxHighlighter> </div> + {props.isEmbedPage && ( + <p className="text-[15px] my-2"> + {t("js-snippet-msg-1")} + <span + className="text-blue-600 cursor-pointer px-1" + onClick={() => navigate("/report/6TeaPr321t")} + > + {t("js-snippet-msg-2")} + </span> + <span>{t("js-snippet-msg-3")}</span> + </p> + )} </div> </div> ) : ( @@ -211,7 +238,7 @@ export class AppComponent { {t(`${data.title}`)} </p> {ind === 0 && ( - <p className="text-[13px] mt-2"> + <p className="text-[15px] mt-2"> {t("angular-npm-mssg-1")} </p> )} @@ -238,8 +265,19 @@ export class AppComponent { </div> ); })} - - <p className="font-medium text-[15px]"> + {props.isEmbedPage && ( + <p className="text-[15px] my-2"> + {t("js-snippet-msg-1")} + <span + className="text-blue-600 cursor-pointer px-1" + onClick={() => navigate("/report/6TeaPr321t")} + > + {t("js-snippet-msg-2")} + </span> + <span>{t("js-snippet-msg-3")}</span> + </p> + )} + <p className="font-medium mt-3 text-[15px]"> {t("public-template-mssg-3")} </p> <p className="my-[6px]"> diff --git a/apps/OpenSign/src/components/pdf/PdfHeader.js b/apps/OpenSign/src/components/pdf/PdfHeader.js index a5857ac04..25ae08606 100644 --- a/apps/OpenSign/src/components/pdf/PdfHeader.js +++ b/apps/OpenSign/src/components/pdf/PdfHeader.js @@ -1,8 +1,11 @@ -import React, { useState } from "react"; +import React, { useRef, useState } from "react"; import PrevNext from "./PrevNext"; import { + base64ToArrayBuffer, + deletePdfPage, handleDownloadCertificate, handleDownloadPdf, + handleRemoveWidgets, handleToPrint } from "../../constant/Utils"; import "../../styles/signature.css"; @@ -10,65 +13,92 @@ import * as DropdownMenu from "@radix-ui/react-dropdown-menu"; import ModalUi from "../../primitives/ModalUi"; import Loader from "../../primitives/Loader"; import { useTranslation } from "react-i18next"; +import { PDFDocument } from "pdf-lib"; -function Header({ - isPdfRequestFiles, - isPlaceholder, - setIsDecline, - pageNumber, - allPages, - changePage, - pdfUrl, - embedWidgetsData, - pdfDetails, - signerPos, - signersdata, - isMailSend, - alertSendEmail, - isCompleted, - isShowHeader, - decline, - currentSigner, - alreadySign, - isSignYourself, - setIsEmail, - completeBtnTitle, - setIsEditTemplate, - isPublicTemplate, - clickOnZoomIn, - clickOnZoomOut, - handleRotationFun, - isDisableRotate, - templateId, - setIsDownloadModal, - disabledBackBtn -}) { +function Header(props) { const { t } = useTranslation(); const filterPrefill = - signerPos && signerPos?.filter((data) => data.Role !== "prefill"); + props?.signerPos && + props?.signerPos?.filter((data) => data.Role !== "prefill"); const isMobile = window.innerWidth < 767; const [isDownloading, setIsDownloading] = useState(""); - const isGuestSigner = localStorage.getItem("isGuestSigner"); - const enabledBackBtn = disabledBackBtn === true ? false : true; - + const [isDeletePage, setIsDeletePage] = useState(false); + const mergePdfInputRef = useRef(null); + const enabledBackBtn = props?.disabledBackBtn === true ? false : true; //function for show decline alert const handleDeclinePdfAlert = async () => { const currentDecline = { currnt: "Sure", isDeclined: true }; - setIsDecline(currentDecline); + props?.setIsDecline(currentDecline); }; + const handleDetelePage = async () => { + props?.setIsUploadPdf && props?.setIsUploadPdf(true); + const pdfupdatedData = await deletePdfPage( + props?.pdfArrayBuffer, + props?.pageNumber + ); + if (pdfupdatedData?.totalPages === 1) { + alert(t("delete-alert")); + } else { + props?.setPdfBase64Url(pdfupdatedData.base64); + props?.setPdfArrayBuffer(pdfupdatedData.arrayBuffer); + setIsDeletePage(false); + handleRemoveWidgets( + props?.setSignerPos, + props?.signerPos, + props?.pageNumber + ); + } + }; + + const handleFileUpload = async (e) => { + const file = e.target.files[0]; + if (!file) { + alert("Please upload a valid PDF file."); + return; + } + if (!file.type.includes("pdf")) { + alert("Only PDF files are allowed."); + return; + } + try { + const uploadedPdfBytes = await file.arrayBuffer(); + const uploadedPdfDoc = await PDFDocument.load(uploadedPdfBytes, { + ignoreEncryption: true + }); + const basePdfDoc = await PDFDocument.load(props.pdfArrayBuffer); + + // Copy pages from the uploaded PDF to the base PDF + const uploadedPdfPages = await basePdfDoc.copyPages( + uploadedPdfDoc, + uploadedPdfDoc.getPageIndices() + ); + uploadedPdfPages.forEach((page) => basePdfDoc.addPage(page)); + // Save the updated PDF + const pdfBase64 = await basePdfDoc.saveAsBase64({ + useObjectStreams: false + }); + const pdfBuffer = base64ToArrayBuffer(pdfBase64); + props.setPdfArrayBuffer(pdfBuffer); + props.setPdfBase64Url(pdfBase64); + props.setIsUploadPdf && props.setIsUploadPdf(true); + mergePdfInputRef.current.value = ""; + } catch (error) { + mergePdfInputRef.current.value = ""; + console.error("Error merging PDF:", error); + } + }; + return ( <div className="flex py-[5px]"> - {isMobile && isShowHeader ? ( + {isMobile && props?.isShowHeader ? ( <div id="navbar" - className={isGuestSigner ? "stickySignerHead" : "stickyHead"} + className="stickyHead" style={{ - width: isGuestSigner - ? window.innerWidth - : window.innerWidth - 30 + "px" + width: window.innerWidth + "px" }} > - <div className="flex justify-between items-center py-[5px] px-[10px] "> + <div className="flex justify-between items-center py-[5px] pl-[10px] "> <div onClick={() => window.history.go(-2)}> <i className="fa-light fa-arrow-left text-base-content" @@ -76,14 +106,14 @@ function Header({ ></i> </div> <PrevNext - pageNumber={pageNumber} - allPages={allPages} - changePage={changePage} + pageNumber={props?.pageNumber} + allPages={props?.allPages} + changePage={props?.changePage} /> - {isCompleted || alreadySign ? ( + {props?.isCompleted || props?.alreadySign ? ( <DropdownMenu.Root> <DropdownMenu.Trigger asChild> - <div className="op-link op-link-primary no-underline text-[16px] font-semibold pr-[3px] pl-[5px]"> + <div className="op-link op-link-primary no-underline text-[16px] font-semibold px-3"> <i className="fa-light fa-ellipsis-v" aria-hidden="true" @@ -98,10 +128,14 @@ function Header({ <DropdownMenu.Item className="DropdownMenuItem" onClick={() => { - if (isCompleted) { - setIsDownloadModal(true); + if (props?.isCompleted) { + props?.setIsDownloadModal(true); } else { - handleDownloadPdf(pdfDetails, setIsDownloading); + handleDownloadPdf( + props?.pdfDetails, + setIsDownloading, + props.pdfBase64 + ); } }} > @@ -113,12 +147,12 @@ function Header({ {t("download")} </div> </DropdownMenu.Item> - {isCompleted && ( + {props?.isCompleted && ( <DropdownMenu.Item className="DropdownMenuItem" onClick={() => handleDownloadCertificate( - pdfDetails, + props?.pdfDetails, setIsDownloading ) } @@ -132,10 +166,10 @@ function Header({ </div> </DropdownMenu.Item> )} - {isSignYourself && ( + {props?.isSignYourself && ( <DropdownMenu.Item className="DropdownMenuItem" - onClick={() => setIsEmail(true)} + onClick={() => props?.setIsEmail(true)} > <div className="flex flex-row"> <i @@ -149,7 +183,7 @@ function Header({ <DropdownMenu.Item className="DropdownMenuItem" onClick={(e) => - handleToPrint(e, pdfUrl, setIsDownloading, pdfDetails) + handleToPrint(e, setIsDownloading, props?.pdfDetails) } > <div className="flex flex-row"> @@ -168,9 +202,9 @@ function Header({ {/* current signer is checking user send request and check status of pdf sign than if current user exist than show finish button else no */} - {currentSigner && ( + {props?.currentSigner && ( <div className="flex items-center" data-tut="reactourFifth"> - {decline && ( + {props?.decline && ( <div onClick={() => handleDeclinePdfAlert()} className="text-[red] border-none font-[650] text-[14px] mr-2" @@ -178,32 +212,41 @@ function Header({ {t("decline")} </div> )} - {isPlaceholder ? ( + {props?.isPlaceholder ? ( <div onClick={() => { - if (!isMailSend) { - alertSendEmail(); + if (!props?.isMailSend) { + props?.alertSendEmail(); } }} className={`${ - isMailSend ? "" : "op-link-primary" + props?.isMailSend ? "" : "op-link-primary" } op-link no-underline font-[650] text-[14px]`} data-tut="headerArea" > - {completeBtnTitle ? completeBtnTitle : t("send")} + {props?.completeBtnTitle + ? props?.completeBtnTitle + : t("send")} </div> ) : ( <div data-tut="reactourThird" - onClick={() => embedWidgetsData()} + onClick={() => props?.embedWidgetsData()} className="border-none font-[650] text-[14px] op-link op-link-primary no-underline" > {t("finish")} </div> )} + <input + type="file" + className="hidden" + accept="application/pdf" + ref={mergePdfInputRef} + onChange={handleFileUpload} + /> <DropdownMenu.Root> <DropdownMenu.Trigger asChild> - <div className="font-[650] text-[18px] px-2 ml-[4px] text-base-content no-underline"> + <div className="font-[650] text-[18px] px-3 text-base-content no-underline"> <i className="fa-light fa-ellipsis-v" aria-hidden="true" @@ -218,7 +261,11 @@ function Header({ <DropdownMenu.Item className="DropdownMenuItem" onClick={() => - handleDownloadPdf(pdfDetails, setIsDownloading) + handleDownloadPdf( + props?.pdfDetails, + setIsDownloading, + props.pdfBase64 + ) } > <div className="flex flex-row"> @@ -231,11 +278,34 @@ function Header({ </span> </div> </DropdownMenu.Item> - {!isDisableRotate && ( + {!props?.isDisablePdfEditTools && ( <> <DropdownMenu.Item className="DropdownMenuItem" - onClick={() => handleRotationFun(90)} + onClick={() => mergePdfInputRef.current.click()} + > + <div className="flex flex-row"> + <i className="fa-light fa-plus text-gray-500 2xl:text-[30px] mr-[3px]"></i> + <span className="font-[500]"> + {t("add-pages")} + </span> + </div> + </DropdownMenu.Item> + <DropdownMenu.Item + className="DropdownMenuItem" + onClick={() => setIsDeletePage(true)} + > + <div className="flex flex-row"> + <i className="fa-light fa-trash text-gray-500 2xl:text-[30px] mr-[3px]"></i> + <span className="font-[500]"> + {t("delete-page")} + </span> + </div> + </DropdownMenu.Item> + + <DropdownMenu.Item + className="DropdownMenuItem" + onClick={() => props?.handleRotationFun(90)} > <div className="flex flex-row"> <i className="fa-light fa-rotate-right text-gray-500 2xl:text-[30px] mr-[3px]"></i> @@ -246,7 +316,7 @@ function Header({ </DropdownMenu.Item> <DropdownMenu.Item className="DropdownMenuItem" - onClick={() => handleRotationFun(-90)} + onClick={() => props?.handleRotationFun(-90)} > <div className="flex flex-row"> <i className="fa-light fa-rotate-left text-gray-500 2xl:text-[30px] mr-[3px]"></i> @@ -260,7 +330,7 @@ function Header({ <DropdownMenu.Item className="DropdownMenuItem" - onClick={() => clickOnZoomIn()} + onClick={() => props?.clickOnZoomIn()} > <div className="flex flex-row"> <i className="fa-light fa-magnifying-glass-plus text-gray-500 2xl:text-[30px] mr-[3px]"></i> @@ -269,7 +339,7 @@ function Header({ </DropdownMenu.Item> <DropdownMenu.Item className="DropdownMenuItem" - onClick={() => clickOnZoomOut()} + onClick={() => props?.clickOnZoomOut()} > <div className="flex flex-row"> <i className="fa-light fa-magnifying-glass-minus text-gray-500 2xl:text-[30px] mr-[3px]"></i> @@ -283,11 +353,11 @@ function Header({ </DropdownMenu.Root> </div> )} - {isPublicTemplate && ( + {props?.isPublicTemplate && ( <div data-tut="reactourThird" - onClick={() => embedWidgetsData()} - className="border-none font-[650] text-[14px] op-link op-link-primary no-underline" + onClick={() => props?.embedWidgetsData()} + className="border-none font-[650] text-[14px] pr-2 op-link op-link-primary no-underline" > {t("sign-now")} </div> @@ -299,25 +369,27 @@ function Header({ ) : ( <div className="flex flex-wrap justify-between items-center w-full gap-y-1 ml-1"> <PrevNext - pageNumber={pageNumber} - allPages={allPages} - changePage={changePage} + pageNumber={props?.pageNumber} + allPages={props?.allPages} + changePage={props?.changePage} /> - {isPlaceholder ? ( + {props?.isPlaceholder ? ( <> <div className="flex mx-[100px] lg:mx-0 order-last lg:order-none"> - {!isMailSend && - signersdata.length > 0 && - signersdata.length !== filterPrefill.length && ( + {!props?.isMailSend && + props?.signersdata.length > 0 && + props?.signersdata.length !== filterPrefill.length && ( <div> {filterPrefill.length === 0 ? ( <span className="text-[13px] text-[#f5405e]"> - {t("add")} {signersdata.length - filterPrefill.length}{" "} + {t("add")}{" "} + {props?.signersdata.length - filterPrefill.length}{" "} {t("recipients")} {t("widgets-name.signature")} </span> ) : ( <span className="text-[13px] text-[#f5405e]"> - {t("add")} {signersdata.length - filterPrefill.length}{" "} + {t("add")}{" "} + {props?.signersdata.length - filterPrefill.length}{" "} {t("more")} {t("recipients")} {t("widgets-name.signature")} </span> @@ -326,9 +398,9 @@ function Header({ )} </div> <div className="flex"> - {setIsEditTemplate && ( + {props?.setIsEditTemplate && ( <button - onClick={() => setIsEditTemplate(true)} + onClick={() => props?.setIsEditTemplate(true)} className="outline-none border-none text-center mr-[3px]" > <i className="fa-light fa-gear fa-lg"></i> @@ -344,25 +416,25 @@ function Header({ </button> )} <button - disabled={isMailSend && true} + disabled={props?.isMailSend && true} data-tut="headerArea" className="op-btn op-btn-primary op-btn-sm mr-[3px]" - onClick={() => alertSendEmail()} + onClick={() => props?.alertSendEmail()} > - {completeBtnTitle - ? completeBtnTitle - : isMailSend + {props?.completeBtnTitle + ? props?.completeBtnTitle + : props?.isMailSend ? t("sent") : t("send")} </button> </div> </> - ) : isPdfRequestFiles ? ( - alreadySign ? ( + ) : props?.isPdfRequestFiles || props?.isSelfSign ? ( + props?.alreadySign || (props?.isSelfSign && props?.isCompleted) ? ( <div className="flex flex-row"> <button onClick={(e) => - handleToPrint(e, pdfUrl, setIsDownloading, pdfDetails) + handleToPrint(e, setIsDownloading, props?.pdfDetails) } type="button" className="op-btn op-btn-neutral op-btn-sm mr-[3px] shadow" @@ -373,11 +445,14 @@ function Header({ ></i> <span className="hidden lg:block">{t("print")}</span> </button> - {isCompleted && ( + {props?.isCompleted && ( <button type="button" onClick={() => - handleDownloadCertificate(pdfDetails, setIsDownloading) + handleDownloadCertificate( + props?.pdfDetails, + setIsDownloading + ) } className="op-btn op-btn-secondary op-btn-sm mr-[3px] shadow" > @@ -392,10 +467,14 @@ function Header({ type="button" className="op-btn op-btn-primary op-btn-sm mr-[3px] shadow" onClick={() => { - if (isCompleted) { - setIsDownloadModal(true); + if (props?.isCompleted) { + props?.setIsDownloadModal(true); } else { - handleDownloadPdf(pdfDetails, setIsDownloading); + handleDownloadPdf( + props?.pdfDetails, + setIsDownloading, + props.pdfBase64 + ); } }} > @@ -408,21 +487,26 @@ function Header({ </div> ) : ( <div className="flex" data-tut="reactourFifth"> - {!templateId && ( - <button - onClick={() => window.history.go(-2)} - type="button" - className="op-btn op-btn-ghost op-btn-sm mr-[3px]" - > - {t("back")} - </button> - )} - {currentSigner && ( + {(!props?.templateId && !props?.isSelfSign) || + (!props.isGuestSignFlow && ( + <button + onClick={() => window.history.go(-2)} + type="button" + className="op-btn op-btn-ghost op-btn-sm mr-[3px]" + > + {t("back")} + </button> + ))} + {props?.currentSigner && ( <> - {templateId && ( + {props?.templateId && ( <button onClick={() => - handleDownloadPdf(pdfDetails, setIsDownloading) + handleDownloadPdf( + props?.pdfDetails, + setIsDownloading, + props.pdfBase64 + ) } type="button" className="op-btn op-btn-ghost op-btn-sm mr-[3px]" @@ -430,42 +514,51 @@ function Header({ <span className="hidden lg:block">{t("download")}</span> </button> )} - <button - className="op-btn op-btn-secondary op-btn-sm mr-[3px] shadow" - onClick={() => handleDeclinePdfAlert()} - > - {t("decline")} - </button> - <button - type="button" - className="op-btn op-btn-primary op-btn-sm mr-[3px] shadow" - onClick={() => embedWidgetsData()} - > - {t("finish")} - </button> - {!templateId && ( + {!props?.isSelfSign && ( + <button + className="op-btn op-btn-secondary op-btn-sm mr-[3px] shadow" + onClick={() => handleDeclinePdfAlert()} + > + {t("decline")} + </button> + )} + {!props?.templateId && ( <button type="button" - className="op-btn op-btn-neutral op-btn-sm mr-[3px] shadow" + className="op-btn op-btn-ghost op-btn-sm mr-[3px]" onClick={() => - handleDownloadPdf(pdfDetails, setIsDownloading) + handleDownloadPdf( + props?.pdfDetails, + setIsDownloading, + props.pdfBase64 + ) } > <i className="fa-light fa-arrow-down font-semibold lg:hidden"></i> <span className="hidden lg:block">{t("download")}</span> </button> )} + <button + type="button" + className="op-btn op-btn-primary op-btn-sm mr-[3px] shadow" + onClick={() => props?.embedWidgetsData()} + > + {t("finish")} + </button> </> )} </div> ) - ) : isCompleted ? ( + ) : props?.isCompleted ? ( <div className="flex flex-row"> - {isCompleted && ( + {props?.isCompleted && ( <button type="button" onClick={() => - handleDownloadCertificate(pdfDetails, setIsDownloading) + handleDownloadCertificate( + props?.pdfDetails, + setIsDownloading + ) } className="op-btn op-btn-secondary op-btn-sm gap-0 font-medium text-[12px] mr-[3px] shadow" > @@ -477,7 +570,7 @@ function Header({ )} <button onClick={(e) => - handleToPrint(e, pdfUrl, setIsDownloading, pdfDetails) + handleToPrint(e, setIsDownloading, props?.pdfDetails) } type="button" className="op-btn op-btn-neutral op-btn-sm gap-0 font-medium text-[12px] mr-[3px] shadow" @@ -488,9 +581,7 @@ function Header({ <button type="button" className="op-btn op-btn-primary op-btn-sm gap-0 font-medium text-[12px] mr-[3px] shadow" - onClick={() => { - setIsDownloadModal(true); - }} + onClick={() => props?.setIsDownloadModal(true)} > <i className="fa-light fa-download" aria-hidden="true"></i> <span className="hidden lg:block ml-1">{t("download")}</span> @@ -498,18 +589,18 @@ function Header({ <button type="button" className="op-btn op-btn-info op-btn-sm gap-0 font-medium text-[12px] mr-[3px] shadow" - onClick={() => setIsEmail(true)} + onClick={() => props?.setIsEmail(true)} > <i className="fa-light fa-envelope" aria-hidden="true"></i> <span className="hidden lg:block ml-1">{t("mail")}</span> </button> </div> - ) : isPublicTemplate ? ( + ) : props?.isPublicTemplate ? ( <div className="flex"> <button type="button" className="op-btn op-btn-primary op-btn-sm shadow" - onClick={() => embedWidgetsData()} + onClick={() => props?.embedWidgetsData()} > {t("sign-now")} </button> @@ -526,7 +617,7 @@ function Header({ <button type="button" className="op-btn op-btn-primary op-btn-sm mr-[3px]" - onClick={() => embedWidgetsData()} + onClick={() => props?.embedWidgetsData()} > {t("finish")} </button> @@ -540,17 +631,47 @@ function Header({ </div> )} <ModalUi - isOpen={isDownloading === "certificate"} + isOpen={ + isDownloading === "certificate" || isDownloading === "certificate_err" + } title={ - isDownloading === "certificate" + isDownloading === "certificate" || isDownloading === "certificate_err" ? t("generating-certificate") : t("pdf-download") } handleClose={() => setIsDownloading("")} > <div className="p-3 md:p-5 text-[13px] md:text-base text-center text-base-content"> - {isDownloading === "certificate"}{" "} - <p>{t("generate-certificate-alert")}</p> + {isDownloading === "certificate" ? ( + <p>{t("generate-certificate-alert")}</p> + ) : ( + <p>{t("generate-certificate-err")}</p> + )} + </div> + </ModalUi> + <ModalUi + isOpen={isDeletePage} + title={t("delete-page")} + handleClose={() => setIsDeletePage(false)} + > + <div className="h-[100%] p-[20px]"> + <p className="font-medium">{t("delete-alert-2")}</p> + <p className="pt-3">{t("delete-note")}</p> + <div className="h-[1px] bg-[#9f9f9f] w-full my-[15px]"></div> + <button + onClick={() => handleDetelePage()} + type="button" + className="op-btn op-btn-primary" + > + {t("yes")} + </button> + <button + onClick={() => setIsDeletePage(false)} + type="button" + className="op-btn op-btn-ghost" + > + {t("no")} + </button> </div> </ModalUi> </div> diff --git a/apps/OpenSign/src/components/pdf/PdfZoom.js b/apps/OpenSign/src/components/pdf/PdfZoom.js index c315a16da..746139ba4 100644 --- a/apps/OpenSign/src/components/pdf/PdfZoom.js +++ b/apps/OpenSign/src/components/pdf/PdfZoom.js @@ -1,47 +1,176 @@ -import React from "react"; +import React, { useRef, useState } from "react"; import { useTranslation } from "react-i18next"; +import { + base64ToArrayBuffer, + deletePdfPage, + handleRemoveWidgets +} from "../../constant/Utils"; +import ModalUi from "../../primitives/ModalUi"; +import { PDFDocument } from "pdf-lib"; function PdfZoom(props) { const { t } = useTranslation(); + const mergePdfInputRef = useRef(null); + const [isDeletePage, setIsDeletePage] = useState(false); + const handleDetelePage = async () => { + props.setIsUploadPdf && props.setIsUploadPdf(true); + try { + const pdfupdatedData = await deletePdfPage( + props.pdfArrayBuffer, + props.pageNumber + ); + if (pdfupdatedData?.totalPages === 1) { + alert(t("delete-alert")); + } else { + props.setPdfBase64Url(pdfupdatedData.base64); + props.setPdfArrayBuffer(pdfupdatedData.arrayBuffer); + setIsDeletePage(false); + handleRemoveWidgets( + props.setSignerPos, + props.signerPos, + props.pageNumber + ); + props.setAllPages(pdfupdatedData.remainingPages || 1); + if (props.allPages === props.pageNumber) { + props.setPageNumber(props.pageNumber - 1); + } else if (props.allPages > 2) { + props.setPageNumber(props.pageNumber); + } + } + } catch (e) { + console.log("error in delete pdf page", e); + } + }; + const handleFileUpload = async (e) => { + const file = e.target.files[0]; + if (!file) { + alert("Please upload a valid PDF file."); + return; + } + if (!file.type.includes("pdf")) { + alert("Only PDF files are allowed."); + return; + } + try { + const uploadedPdfBytes = await file.arrayBuffer(); + const uploadedPdfDoc = await PDFDocument.load(uploadedPdfBytes, { + ignoreEncryption: true + }); + const basePdfDoc = await PDFDocument.load(props.pdfArrayBuffer); + + // Copy pages from the uploaded PDF to the base PDF + const uploadedPdfPages = await basePdfDoc.copyPages( + uploadedPdfDoc, + uploadedPdfDoc.getPageIndices() + ); + uploadedPdfPages.forEach((page) => basePdfDoc.addPage(page)); + // Save the updated PDF + const pdfBase64 = await basePdfDoc.saveAsBase64({ + useObjectStreams: false + }); + const pdfBuffer = base64ToArrayBuffer(pdfBase64); + props.setPdfArrayBuffer(pdfBuffer); + props.setPdfBase64Url(pdfBase64); + props.setIsUploadPdf && props.setIsUploadPdf(true); + mergePdfInputRef.current.value = ""; + } catch (error) { + mergePdfInputRef.current.value = ""; + console.error("Error merging PDF:", error); + } + }; return ( - <span className="hidden md:flex flex-col gap-1 text-center md:w-[5%] mt-[43px] 2xl:mt-[63px]"> - <span - className="bg-gray-50 px-[4px] 2xl:px-[15px] 2xl:py-[10px] cursor-pointer" - onClick={() => props.clickOnZoomIn()} - title={t("zoom-in")} - > - <i className="fa-light fa-magnifying-glass-plus text-gray-500 2xl:text-[30px]"></i> + <> + <span className="hidden md:flex flex-col gap-1 text-center md:w-[5%] mt-[42px]"> + {!props.isDisableEditTools && ( + <> + <span + className="bg-gray-50 px-[4px] 2xl:py-[10px] cursor-pointer" + onClick={() => mergePdfInputRef.current.click()} + title={t("add-pages")} + > + <input + type="file" + className="hidden" + accept="application/pdf" + ref={mergePdfInputRef} + onChange={handleFileUpload} + /> + <i className="fa-light fa-plus text-gray-500 2xl:text-[25px]"></i> + </span> + <span + className="bg-gray-50 px-[4px] 2xl:py-[10px] cursor-pointer" + onClick={() => setIsDeletePage(true)} + title={t("delete-page")} + > + <i className="fa-light fa-trash text-gray-500 2xl:text-[25px]"></i> + </span> + </> + )} + <span + className="bg-gray-50 px-[4px] 2xl:py-[10px] cursor-pointer" + onClick={() => props.clickOnZoomIn()} + title={t("zoom-in")} + > + <i className="fa-light fa-magnifying-glass-plus text-gray-500 2xl:text-[25px]"></i> + </span> + + {!props.isDisableEditTools && ( + <> + <span + className="bg-gray-50 px-[4px] 2xl:py-[10px] cursor-pointer" + onClick={() => props.handleRotationFun(90)} + title={t("rotate-right")} + > + <i className="fa-light fa-rotate-right text-gray-500 2xl:text-[25px]"></i> + </span> + <span + className="bg-gray-50 px-[4px] 2xl:py-[10px] cursor-pointer" + title={t("rotate-left")} + onClick={() => props.handleRotationFun(-90)} + > + <i className="fa-light fa-rotate-left text-gray-500 2xl:text-[25px]"></i> + </span> + </> + )} + <span + className="bg-gray-50 px-[4px] 2xl:py-[10px]" + onClick={() => props.clickOnZoomOut()} + style={{ + cursor: props.zoomPercent > 0 ? "pointer" : "default" + }} + title={t("zoom-out")} + > + <i className="fa-light fa-magnifying-glass-minus text-gray-500 2xl:text-[30px]"></i> + </span> </span> - {!props?.isDisableRotate && ( - <> - <span - className="bg-gray-50 px-[4px] 2xl:px-[15px] 2xl:py-[10px] cursor-pointer" - onClick={() => props.handleRotationFun(90)} - title={t("rotate-right")} - > - <i className="fa-light fa-rotate-right text-gray-500 2xl:text-[30px]"></i> - </span> - <span - className="bg-gray-50 px-[4px] 2xl:px-[15px] 2xl:py-[10px] cursor-pointer" - title={t("rotate-left")} - onClick={() => props.handleRotationFun(-90)} - > - <i className="fa-light fa-rotate-left text-gray-500 2xl:text-[30px]"></i> - </span> - </> - )} - <span - className="bg-gray-50 px-[4px] 2xl:px-[15px] 2xl:py-[10px]" - onClick={() => props.clickOnZoomOut()} - style={{ - cursor: props.zoomPercent > 0 ? "pointer" : "default" - }} - title={t("zoom-out")} + + <ModalUi + isOpen={isDeletePage} + title={t("delete-page")} + handleClose={() => setIsDeletePage(false)} > - <i className="fa-light fa-magnifying-glass-minus text-gray-500 2xl:text-[30px]"></i> - </span> - </span> + <div className="h-[100%] p-[20px]"> + <p className="font-medium">{t("delete-alert-2")}</p> + <p className="pt-3">{t("delete-note")}</p> + <div className="h-[1px] bg-[#9f9f9f] w-full my-[15px]"></div> + <button + onClick={() => handleDetelePage()} + type="button" + className="op-btn op-btn-primary" + > + {t("yes")} + </button> + <button + onClick={() => setIsDeletePage(false)} + type="button" + className="op-btn op-btn-ghost ml-1" + > + {t("no")} + </button> + </div> + </ModalUi> + </> ); } diff --git a/apps/OpenSign/src/components/pdf/Placeholder.js b/apps/OpenSign/src/components/pdf/Placeholder.js index 30ca1f529..5e800a330 100644 --- a/apps/OpenSign/src/components/pdf/Placeholder.js +++ b/apps/OpenSign/src/components/pdf/Placeholder.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from "react"; +import React, { useState, useEffect, useRef } from "react"; import BorderResize from "./BorderResize"; import PlaceholderBorder from "./PlaceholderBorder"; import { Rnd } from "react-rnd"; @@ -8,7 +8,8 @@ import { fontsizeArr, getContainerScale, handleCopyNextToWidget, - isTabAndMobile, + handleCopySignUrl, + handleHeighlightWidget, onChangeInput, radioButtonWidget, textInputWidget, @@ -93,11 +94,16 @@ const getDefaultdate = (selectedDate, format = "dd-MM-yyyy") => { const getDefaultFormat = (dateFormat) => dateFormat || "MM/dd/yyyy"; function Placeholder(props) { + //'isTouchDevice' is used to detect whether a device has a touchscreen or is mouse-based + const isTouchDevice = navigator.maxTouchPoints > 0; const { t } = useTranslation(); const [placeholderBorder, setPlaceholderBorder] = useState({ w: 0, h: 0 }); const [isDraggingEnabled, setDraggingEnabled] = useState(true); const [isDateModal, setIsDateModal] = useState(false); const [containerScale, setContainerScale] = useState(); + const holdTimeout = useRef(null); + const startTime = useRef(null); // Track when the user starts holdings + const [isDisableDragging, setIsDisableDragging] = useState(true); const [selectDate, setSelectDate] = useState({ date: props.pos.type === "date" @@ -128,7 +134,6 @@ function Placeholder(props) { width: null, height: null }); - useEffect(() => { const getPdfPageWidth = props.pdfOriginalWH.find( (data) => data.pageNumber === props.pageNumber @@ -164,17 +169,17 @@ function Placeholder(props) { }, [props.pos]); useEffect(() => { - const closeMenuOnOutsideClick = (e) => { - if (!isDraggingEnabled && !e.target.closest("#changeIsDragging")) { + const onOutsideClick = () => { + if (!isDraggingEnabled) { setDraggingEnabled(true); } }; - document.addEventListener("click", closeMenuOnOutsideClick); + document.addEventListener("click", onOutsideClick); return () => { // Cleanup the event listener when the component unmounts - document.removeEventListener("click", closeMenuOnOutsideClick); + document.removeEventListener("click", onOutsideClick); }; }, [isDraggingEnabled]); //function change format array list with selected date and format @@ -200,7 +205,7 @@ function Placeholder(props) { }; useEffect(() => { - if (props.isPlaceholder || props.isSignYourself) { + if (props.isPlaceholder || props.isSignYourself || props.isSelfSign) { selectDate && changeDateFormat(); } // eslint-disable-next-line react-hooks/exhaustive-deps @@ -226,29 +231,34 @@ function Placeholder(props) { if (widgetTypeExist) { setDraggingEnabled(false); } - if ((props.isNeedSign || props.isSignYourself) && !props.isDragging) { + if (props.isOpenSignPad && !props.isDragging) { if (props?.ispublicTemplate) { props.handleUserDetails(); } else { - if (props.pos.type) { - if ( - props.pos.type === "signature" || - props.pos.type === "stamp" || - props.pos.type === "image" - ) { - props.setIsSignPad(true); - props.setSignKey(props.pos.key); - props.setIsStamp(props.pos.isStamp); - } else if (props.pos.type === "initials") { - props.setIsSignPad(true); - props.setSignKey(props.pos.key); - props.setIsStamp(props.pos.isStamp); - props.setIsInitial(true); - } - } else { + if (props?.isNeedSign) { + //funcion is used to height widgets on top if two widgets on overlap + const getCurrentSignerPos = props.xyPosition.find( + (x) => x.Id === props.uniqueId + ); + const updateZindex = handleHeighlightWidget( + getCurrentSignerPos, + props.pos.key, + props.pageNumber + ); + const updatesignerPos = props.xyPosition.map((x) => + x.Id === props.uniqueId ? { ...x, placeHolder: updateZindex } : x + ); + props.setXyPosition(updatesignerPos); + } + if ( + ["signature", "stamp", "image", "initials"].includes(props.pos.type) + ) { props.setIsSignPad(true); props.setSignKey(props.pos.key); - props.setIsStamp(props.pos?.isStamp ? props.pos.isStamp : false); + props.setIsStamp(props.pos.isStamp); + } + if (props.pos.type === "initials") { + props.setIsInitial(true); } } } else if ( @@ -259,7 +269,7 @@ function Placeholder(props) { if (props.pos.key === props.selectWidgetId) { props.handleLinkUser(props.data.Id); props.setUniqueId(props.data.Id); - const checkIndex = props.xyPostion.findIndex( + const checkIndex = props.xyPosition.findIndex( (data) => data.Id === props.data.Id ); props.setIsSelectId(checkIndex || 0); @@ -285,20 +295,95 @@ function Placeholder(props) { } } }; - const handleOnClickPlaceholder = () => { + + const widgetClickHandler = () => { + //The else condition opens the signature pad if it's a request signature flow and the user clicking is identified as a signer. props.setCurrWidgetsDetails && props.setCurrWidgetsDetails(props.pos); - if (!props.isNeedSign) { - props.setWidgetType(props.pos.type); + if (props?.data?.signerObjId === props?.signerObjId && !props.isDragging) { + if (!props.isAgree && !props.isSelfSign) { + props.setIsAgreeTour && props.setIsAgreeTour(true); + } else { + handleWidgetIdandPopup(); + } + } //condition for open contact details popup when sign templet from public signing flow + else if (props?.uniqueId && props.data?.Id === props?.uniqueId) { + handleWidgetIdandPopup(); } - if (props.isNeedSign && props.data?.signerObjId === props.signerObjId) { - handleWidgetIdandPopup(); - } else if ( - props?.isNeedSign && - props?.uniqueId && - props.data?.Id === props?.uniqueId - ) { - handleWidgetIdandPopup(); - } else if (props.isPlaceholder || props.isSignYourself) { + }; + const handleOnClickPlaceholder = () => { + //condition only for request signing flow and self signing flow then apply one click copy sign url of previous drawn signature + if (props.isApplyAll) { + props.setRequestSignTour && props.setRequestSignTour(true); + let isCopySignature = false; + let existSignPosition = ""; + //condition for 'signature','initials','stamp' widgets only + if (["signature", "initials", "stamp"].includes(props.pos.type)) { + const widgetKey = props.pos.key; + let exitLoop = false; + const placeholders = props.data.placeHolder; + //check onclick current widget signature/stamp/initials signature url exist or not + placeholders?.forEach((holder) => { + holder?.pos?.forEach((posItem) => { + if (posItem.SignUrl && posItem.type === props.pos.type) { + existSignPosition = posItem; + return; // Break out of the current iteration + } + }); + if (existSignPosition) { + return; + } + }); + //case:- + //1- Open signpad once when if there are no any signature url draw + //2- If multiple signature widgets are present, clicking on the next widget should copy the signature URL from the previously drawn signature + //3- If the user attempts to edit the signature, open the signature pad to allow drawing a new signature upon clicking. + for (const placeholderObj of props.data.placeHolder || []) { + for (const posItem of placeholderObj.pos || []) { + if (posItem.key === widgetKey) { + //This condition is used to open signature pad to draw signature in some case + //case-1 : The condition (!posItem.SignUrl && !existSignPosition) checks if the current widget being clicked does not have a drawn signature and no signature URL exists for any signature widget. + //case-2 : The condition posItem.SignUrl is used to verify if the current widget already has a drawn signature and if the user is attempting to edit it + if ((!posItem.SignUrl && !existSignPosition) || posItem.SignUrl) { + exitLoop = true; + } else { + //else condition is used to copy the signature URL from the previously drawn signature + exitLoop = true; + isCopySignature = true; + break; + } + } + } + if (exitLoop) { + break; // Stop iterating through placeholders if exitLoop true + } + } + //existSignPosition.type === props.pos.type ensures that the current widget's type matches the type of the widget associated with the existing signature URL during the click event + if ( + existSignPosition.type === props.pos.type && + existSignPosition && + isCopySignature + ) { + props.setCurrWidgetsDetails && props.setCurrWidgetsDetails(props.pos); + //function to copy the signature URL from the previously drawn signature when clicking on the next widget. + handleCopySignUrl( + props.pos, //currect widget position details + existSignPosition, //exist sign url widget's position details + props.setXyPosition, //used to update Placeholders details + props.xyPosition, //keep Placeholders details + props.pageNumber, //current page number + props.signerObjId //current signer's object id + ); + existSignPosition = ""; + } else { + widgetClickHandler(); + } + } else { + widgetClickHandler(); + } + } else { + //The else condition is used to handle the case when the user clicks on a widget and open signature pad to draw sign + props.setCurrWidgetsDetails && props.setCurrWidgetsDetails(props.pos); + props.setWidgetType(props.pos.type); handleWidgetIdandPopup(); } }; @@ -321,7 +406,7 @@ function Placeholder(props) { "job title", "email" ].includes(props.pos.type) && - props.isSignYourself + (props.isSignYourself || props.isSelfSign) ) { props.handleTextSettingModal(true); } else { @@ -331,14 +416,14 @@ function Placeholder(props) { //condition for only placeholder and template flow if (props.data && props?.pos?.type !== textWidget) { props.setUniqueId(props?.data?.Id); - const checkIndex = props.xyPostion + const checkIndex = props.xyPosition .filter((data) => data.Role !== "prefill") .findIndex((data) => data.Id === props.data.Id); - props.setIsSelectId(checkIndex || 0); + props.setIsSelectId && props.setIsSelectId(checkIndex || 0); } //condition to handle in placeholder and template flow for text widget signerId for text widgets i have to set uniqueId in tempSignerId because //it does not have any signer user and any signerobjId - else if (props.data && props.pos.type === textWidget) { + else if (props.data && props.pos.type === textWidget && !props.isSelfSign) { props.setTempSignerId(props.uniqueId); props.setUniqueId(props?.data?.Id); } @@ -356,18 +441,22 @@ function Placeholder(props) { if (props.data && props?.pos?.type !== textWidget) { props.setUniqueId(props?.data?.Id); - const checkIndex = props.xyPostion + const checkIndex = props.xyPosition .filter((data) => data.Role !== "prefill") .findIndex((data) => data.Id === props.data.Id); - props.setIsSelectId(checkIndex || 0); - } else if (props.data && props.pos.type === textWidget) { + props.setIsSelectId && props.setIsSelectId(checkIndex || 0); + } else if ( + props.data && + props.pos.type === textWidget && + !props.isSelfSign + ) { props.setTempSignerId(props.uniqueId); props.setUniqueId(props?.data?.Id); } //checking widget's type and open widget copy modal for required widgets if ( - ["signature", textWidget, "stamp", "initial"].includes(props.pos.type) + ["signature", textWidget, "stamp", "initials"].includes(props.pos.type) ) { props.setIsPageCopy(true); props.setSignKey(props.pos.key); @@ -376,14 +465,26 @@ function Placeholder(props) { handleCopyNextToWidget( props.pos, props.pos.type, - props.xyPostion, + props.xyPosition, props.index, - props.setXyPostion, + props.setXyPosition, props.data && props.data?.Id ); } }; + //function to save date and format after seleted new date in response field and after finish document it should be emebed new selected date instead of current date + useEffect(() => { + if (props.pos.type === "date") { + const isDateChange = true; + const dateObj = { + date: startDate, + format: selectDate.format + }; + handleSaveDate(dateObj, isDateChange); //function to save date and format in local array + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [startDate]); //function to save date and format on local array onchange date and onclick format const handleSaveDate = (data, isDateChange) => { let updateDate = data.date; @@ -404,9 +505,9 @@ function Placeholder(props) { onChangeInput( date, props.pos.key, - props.xyPostion, + props.xyPosition, props.index, - props.setXyPostion, + props.setXyPosition, props.data && props.data.Id, false, data?.format, @@ -418,10 +519,18 @@ function Placeholder(props) { setSelectDate({ date: date, format: data?.format }); }; const PlaceholderIcon = () => { + // 1- If props.isShowBorder is true, display border's icon for all widgets. OR + // 2- Use the combination of props?.isAlllowModify and !props?.assignedWidgetId.includes(props.pos.key) to determine when to show border's icon: + // 1- When isAlllowModify is true, show border's icon. + // 2- Do not display border's icon for widgets already assigned (props.assignedWidgetId.includes(props.pos.key) is true). return ( - props.isShowBorder && ( + (props.isShowBorder || + (props?.isAlllowModify && + !props?.assignedWidgetId.includes(props.pos.key))) && ( <> - {(props.isPlaceholder || props.isSignYourself) && ( + {(props.isPlaceholder || + props.isSignYourself || + props.isSelfSign) && ( <> {/* condition to add setting icon for signyour-self flow for particular text widgets and also it have diffrent position @@ -434,7 +543,8 @@ function Placeholder(props) { "company", "job title", "email" - ].includes(props.pos.type) && props.isSignYourself ? ( + ].includes(props.pos.type) && + (props.isSignYourself || props.isSelfSign) ? ( <i onClick={(e) => { e.stopPropagation(); @@ -452,7 +562,8 @@ function Placeholder(props) { ((!props?.pos?.type && props.pos.isStamp) || (props?.pos?.type && !["date"].includes(props.pos.type) && - !props.isSignYourself)) && ( + !props.isSignYourself && + !props.isSelfSign)) && ( <i onClick={(e) => { e.stopPropagation(); @@ -472,31 +583,33 @@ function Placeholder(props) { ) )} {/* condition for usericon for all widgets except text widgets and signyour-self flow */} - {props.pos.type !== textWidget && !props.isSignYourself && ( - <i - data-tut="assignSigner" - className="fa-light fa-user icon" - onClick={(e) => { - e.stopPropagation(); - props.handleLinkUser(props.data.Id); - props.setUniqueId(props.data.Id); - const checkIndex = props.xyPostion.findIndex( - (data) => data.Id === props.data.Id - ); - props.setIsSelectId(checkIndex || 0); - }} - onTouchEnd={(e) => { - e.stopPropagation(); - props.handleLinkUser(props.data.Id); - props.setUniqueId(props.data.Id); - const checkIndex = props.xyPostion.findIndex( - (data) => data.Id === props.data.Id - ); - props.setIsSelectId(checkIndex || 0); - }} - style={{ color: "#188ae2", right: "32px", top: "-18px" }} - ></i> - )} + {props.pos.type !== textWidget && + !props.isSignYourself && + !props.isSelfSign && ( + <i + data-tut="assignSigner" + className="fa-light fa-user icon" + onClick={(e) => { + e.stopPropagation(); + props.handleLinkUser(props.data.Id); + props.setUniqueId(props.data.Id); + const checkIndex = props.xyPosition.findIndex( + (data) => data.Id === props.data.Id + ); + props.setIsSelectId(checkIndex || 0); + }} + onTouchEnd={(e) => { + e.stopPropagation(); + props.handleLinkUser(props.data.Id); + props.setUniqueId(props.data.Id); + const checkIndex = props.xyPosition.findIndex( + (data) => data.Id === props.data.Id + ); + props.setIsSelectId(checkIndex || 0); + }} + style={{ color: "#188ae2", right: "32px", top: "-18px" }} + ></i> + )} </> )} {/* setting icon only for date widgets */} @@ -510,7 +623,7 @@ function Placeholder(props) { if (props.data) { props.setSignKey(props.pos.key); props.setUniqueId(props.data.Id); - const checkIndex = props.xyPostion.findIndex( + const checkIndex = props.xyPosition.findIndex( (data) => data.Id === props.data.Id ); props.setIsSelectId(checkIndex || 0); @@ -523,7 +636,7 @@ function Placeholder(props) { if (props.data) { props.setSignKey(props.pos.key); props.setUniqueId(props.data.Id); - const checkIndex = props.xyPostion.findIndex( + const checkIndex = props.xyPosition.findIndex( (data) => data.Id === props.data.Id ); props.setIsSelectId(checkIndex || 0); @@ -647,7 +760,7 @@ function Placeholder(props) { const fontSize = (size || 12) * containerScale * props.scale; //isMinHeight to set text box minimum height if (isMinHeight) { - return fontSize * 1.2 + "px"; + return fontSize * 1.5 + "px"; } else { return fontSize + "px"; } @@ -666,7 +779,95 @@ function Placeholder(props) { return "all-scroll"; } }; + const handleDragging = () => { + //condition for request signing flow + if (props.isNeedSign) { + //enable dragging functionality only if isAlllowModify true on tab that widget and hold 1sec + if ( + props.isAlllowModify && + props?.assignedWidgetId.includes(props.pos.key) + ) { + //if 'isTouchDevice' then handle dragging functionality conditionaly + if (isTouchDevice) { + return isDisableDragging; + } else { + //no need to handle dragging functionality it auto enable and working or mouse click devices + return false; + } + } else if ( + //condition when 'isAlllowModify' is true and user add new widgets then handle dragging functionality like signyourself flow + props.isAlllowModify && + !props?.assignedWidgetId.includes(props.pos.key) + ) { + return !isDraggingEnabled; + } else { + //if 'isAlllowModify' is false then disbale dragging functionality + return true; + } + } //dragging enable in placeholder,template and not text widget flow + else if (props.isPlaceholder && ![textWidget].includes(props.pos.type)) { + return false; + } //dragging depend on 'isDraggingEnabled' variable in self sign and signyourself flow + else { + return !isDraggingEnabled; + } + }; + //function to handle widget background color + const handleBackground = () => { + if (props.data) { + if (props.isNeedSign) { + if (props.data?.Id === props?.uniqueId) { + return props.data?.blockColor + "b0"; + } else { + return "#dedddc"; + } + } else { + return props.data?.blockColor + "b0"; + } + } else { + return "rgba(203, 233, 237, 0.69)"; + } + }; + const handleTouchEnd = () => { + if (!props.isNeedSign || props.isAlllowModify) { + const holdDuration = Date.now() - startTime.current; // Calculate hold time + clearTimeout(holdTimeout.current); // Cancel timeout if touch ended early + if (holdDuration < 1000) { + try { + navigator.vibrate([]); // Cancel any ongoing vibration + } catch (e) { + console.log("error in navigator.vibrate", e); + } + } + } + if (!props.isNeedSign || props.isAlllowModify) handleOnClickPlaceholder(); + }; + const handleTouchStart = () => { + clearTimeout(holdTimeout.current); // Ensure no previous timeouts are running + startTime.current = Date.now(); // Store touch start time + + holdTimeout.current = setTimeout(() => { + //handlle vibration and tab any widget and hold for 1 sec then show border outside widget and then user can able to drag + if (isDisableDragging) { + if ( + props.isNeedSign && + props.isAlllowModify && + props?.assignedWidgetId.includes(props.pos.key) + ) { + try { + navigator.vibrate(200); // Vibrate for 200ms + } catch (e) { + console.log("error in navigator.vibrate", e); + } + setIsDisableDragging(false); + props.setSelectWidgetId(props.pos.key); + } else if (!props.isNeedSign) { + setIsDisableDragging(false); + } + } + }, 1000); // Hold for 1 second before vibrating + }; return ( <> <Rnd @@ -674,6 +875,7 @@ function Placeholder(props) { data-tut={props.pos.key === props.unSignedWidgetId ? "IsSigned" : ""} key={props.pos.key} lockAspectRatio={ + !props.isFreeResize && ![ textWidget, "email", @@ -712,11 +914,6 @@ function Placeholder(props) { style={{ border: "1px solid #007bff", borderRadius: "2px", - textAlign: - props.pos.type !== "name" && - props.pos.type !== "company" && - props.pos.type !== "job title" && - "center", cursor: getCursor(), zIndex: props.pos.type === "date" @@ -726,9 +923,9 @@ function Placeholder(props) { : props?.pos?.zIndex ? props.pos.zIndex : "5", - background: props.data - ? props.data?.blockColor + "b0" - : "rgba(203, 233, 237, 0.69)" + opacity: + props.isNeedSign && props.data?.Id !== props?.uniqueId && "0.4", + background: handleBackground() }} onDrag={() => { setDraggingEnabled(true); @@ -760,8 +957,8 @@ function Placeholder(props) { props.handleSignYourselfImageResize( ref, props.pos.key, - props.xyPostion, - props.setXyPostion, + props.xyPosition, + props.setXyPosition, props.index, containerScale, props.scale, @@ -769,17 +966,17 @@ function Placeholder(props) { props.isResize ); }} - disableDragging={ - props.isNeedSign - ? true - : props.isPlaceholder && ![textWidget].includes(props.pos.type) - ? false - : !isDraggingEnabled - } - onDragStop={(event, dragElement) => + disableDragging={handleDragging()} + onDragStop={(event, dragElement) => { + setIsDisableDragging(true); props.handleStop && - props.handleStop(event, dragElement, props.data?.Id, props.pos?.key) - } + props.handleStop( + event, + dragElement, + props.data?.Id, + props.pos?.key + ); + }} position={{ x: xPos(props.pos, props.isSignYourself), y: yPos(props.pos, props.isSignYourself) @@ -790,125 +987,106 @@ function Placeholder(props) { h: ref.offsetHeight / (props.scale * containerScale) }); }} - onClick={() => !props.isResize && handleOnClickPlaceholder()} + // onClick={() => + // !props.isResize && !isMobile && handleOnClickPlaceholder() + // } > - {props.isShowBorder && - props.pos.type !== radioButtonWidget && - props.pos.type !== "checkbox" && - props.pos.key === props.selectWidgetId ? ( + {props.pos.key === props.selectWidgetId && + ((props.isShowBorder && + ![radioButtonWidget, "checkbox"].includes(props.pos.type)) || + (props?.isAlllowModify && + !props?.assignedWidgetId.includes(props.pos.key))) ? ( <BorderResize right={-12} top={-11} pos={props.pos} posHeight={props.posHeight} - isSignYourself={props.isSignYourself} + isSignYourself={props.isSignYourself || props.isSelfSign} /> ) : props.data && props.isNeedSign && props.pos.type !== "checkbox" ? ( props.data?.signerObjId === props.signerObjId && - props.pos.type !== radioButtonWidget && - props.pos.type !== "checkbox" ? ( + ![radioButtonWidget, "checkbox"].includes(props.pos.type) ? ( <BorderResize posHeight={props.posHeight} - isSignYourself={props.isSignYourself} + isSignYourself={props.isSignYourself || props.isSelfSign} pos={props.pos} /> ) : ( <></> ) ) : ( - props.pos.type !== radioButtonWidget && - props.pos.type !== "checkbox" && + ![radioButtonWidget, "checkbox"].includes(props.pos.type) && props.pos.key === props.selectWidgetId && <BorderResize /> )} - {props.isShowBorder && props.pos.key === props.selectWidgetId && ( - <PlaceholderBorder - setDraggingEnabled={setDraggingEnabled} + {/* 1- Show a border if props.pos.key === props.selectWidgetId, indicating the current user's selected widget. + 2- If props.isShowBorder is true, display borders for all widgets. + 3- Use the combination of props?.isAlllowModify and !props?.assignedWidgetId.includes(props.pos.key) to determine when to show borders: + 1- When isAlllowModify is true, show borders. + 2- Do not display border for widgets already assigned (props.assignedWidgetId.includes(props.pos.key) is true). + */} + {props.pos.key === props.selectWidgetId && + (props.isShowBorder || + !isDisableDragging || + (props?.isAlllowModify && + !props?.assignedWidgetId.includes(props.pos.key))) && ( + <PlaceholderBorder + setDraggingEnabled={setDraggingEnabled} + pos={props.pos} + isPlaceholder={props.isPlaceholder} + getCheckboxRenderWidth={getCheckboxRenderWidth} + scale={props.scale} + containerScale={containerScale} + placeholderBorder={placeholderBorder} + /> + )} + <div + className="flex items-stretch justify-center" + style={{ + left: xPos(props.pos, props.isSignYourself), + top: yPos(props.pos, props.isSignYourself), + width: + props.pos.type === radioButtonWidget || + props.pos.type === "checkbox" + ? "auto" + : props.posWidth(props.pos, props.isSignYourself), + height: + props.pos.type === radioButtonWidget || + props.pos.type === "checkbox" + ? "auto" + : props.posHeight(props.pos, props.isSignYourself), + zIndex: "10" + }} + onTouchEnd={() => handleTouchEnd()} + onClick={() => handleOnClickPlaceholder()} + onTouchStart={() => handleTouchStart()} + > + {props.pos.key === props.selectWidgetId && <PlaceholderIcon />} + <PlaceholderType pos={props.pos} + xyPosition={props.xyPosition} + index={props.index} + setXyPosition={props.setXyPosition} + data={props.data} + setSignKey={props.setSignKey} + isShowDropdown={props?.isShowDropdown} isPlaceholder={props.isPlaceholder} - getCheckboxRenderWidth={getCheckboxRenderWidth} - scale={props.scale} - containerScale={containerScale} - placeholderBorder={placeholderBorder} + isSignYourself={props.isSignYourself} + isSelfSign={props.isSelfSign} + signerObjId={props.signerObjId} + handleUserName={props.handleUserName} + pdfDetails={props?.pdfDetails && props?.pdfDetails[0]} + isNeedSign={props.isNeedSign} + setSelectDate={setSelectDate} + selectDate={selectDate} + setValidateAlert={props.setValidateAlert} + setStartDate={setStartDate} + startDate={startDate} + handleSaveDate={handleSaveDate} + xPos={props.xPos} + calculateFont={calculateFont} /> - )} - {isTabAndMobile ? ( - <div - className="flex items-stretch justify-center" - style={{ - left: xPos(props.pos, props.isSignYourself), - top: yPos(props.pos, props.isSignYourself), - width: - props.pos.type === radioButtonWidget || - props.pos.type === "checkbox" - ? "auto" - : props.posWidth(props.pos, props.isSignYourself), - height: - props.pos.type === radioButtonWidget || - props.pos.type === "checkbox" - ? "auto" - : props.posHeight(props.pos, props.isSignYourself), - zIndex: "10" - }} - onTouchEnd={() => handleOnClickPlaceholder()} - onClick={() => handleOnClickPlaceholder()} - > - {props.pos.key === props.selectWidgetId && <PlaceholderIcon />} - - <PlaceholderType - pos={props.pos} - xyPostion={props.xyPostion} - index={props.index} - setXyPostion={props.setXyPostion} - data={props.data} - setSignKey={props.setSignKey} - isShowDropdown={props?.isShowDropdown} - isPlaceholder={props.isPlaceholder} - isSignYourself={props.isSignYourself} - signerObjId={props.signerObjId} - handleUserName={props.handleUserName} - setDraggingEnabled={setDraggingEnabled} - pdfDetails={props?.pdfDetails && props?.pdfDetails[0]} - isNeedSign={props.isNeedSign} - setSelectDate={setSelectDate} - selectDate={selectDate} - setValidateAlert={props.setValidateAlert} - setStartDate={setStartDate} - startDate={startDate} - handleSaveDate={handleSaveDate} - xPos={props.xPos} - calculateFont={calculateFont} - /> - </div> - ) : ( - <> - {props.pos.key === props.selectWidgetId && <PlaceholderIcon />} - <PlaceholderType - pos={props.pos} - xyPostion={props.xyPostion} - index={props.index} - setXyPostion={props.setXyPostion} - data={props.data} - setSignKey={props.setSignKey} - isShowDropdown={props?.isShowDropdown} - isPlaceholder={props.isPlaceholder} - isSignYourself={props.isSignYourself} - signerObjId={props.signerObjId} - handleUserName={props.handleUserName} - setDraggingEnabled={setDraggingEnabled} - pdfDetails={props?.pdfDetails && props?.pdfDetails[0]} - isNeedSign={props.isNeedSign} - setSelectDate={setSelectDate} - selectDate={selectDate} - setValidateAlert={props.setValidateAlert} - setStartDate={setStartDate} - startDate={startDate} - handleSaveDate={handleSaveDate} - xPos={props.xPos} - calculateFont={calculateFont} - /> - </> - )} + </div> </Rnd> <ModalUi isOpen={isDateModal} title={t("widget-info")} showClose={false}> <div className="h-[100%] p-[20px]"> diff --git a/apps/OpenSign/src/components/pdf/PlaceholderBorder.js b/apps/OpenSign/src/components/pdf/PlaceholderBorder.js index a451dbc83..71e9a2369 100644 --- a/apps/OpenSign/src/components/pdf/PlaceholderBorder.js +++ b/apps/OpenSign/src/components/pdf/PlaceholderBorder.js @@ -43,9 +43,9 @@ function PlaceholderBorder(props) { }; return ( <div - onMouseEnter={() => !isMobile && props?.setDraggingEnabled(true)} + onMouseEnter={() => !isMobile && props?.setDraggingEnabled(false)} onTouchEnd={() => - props.pos.type === textWidget && props?.setDraggingEnabled(true) + props.pos.type === textWidget && props?.setDraggingEnabled(false) } className="absolute inline-block w-[14px] h-[14px] border-[0.2px] overflow-hidden border-dashed" style={{ diff --git a/apps/OpenSign/src/components/pdf/PlaceholderCopy.js b/apps/OpenSign/src/components/pdf/PlaceholderCopy.js index 943da8cc0..6afb4b583 100644 --- a/apps/OpenSign/src/components/pdf/PlaceholderCopy.js +++ b/apps/OpenSign/src/components/pdf/PlaceholderCopy.js @@ -19,56 +19,89 @@ function PlaceholderCopy(props) { //function for get copy placeholder position const getCopyPlaceholderPosition = ( type, - currentPlaceholder, + newPlaceholder, newPageNumber, existPlaceholderPosition ) => { + //remove existing page position when used option copy but first or copy but last const filterPosition = existPlaceholderPosition && existPlaceholderPosition.filter( - (data) => data.xPosition !== currentPlaceholder.xPosition + (data) => data.xPosition !== newPlaceholder.xPosition ); + //first option - copy all page but not first //copy all page placeholder at requested position except first page if (newPageNumber === 1 && type === 3) { - if (filterPosition && filterPosition.length > 0) { + //when user choose this option and placed widget on first page then do not remove first page widget + //it should be copy all page included first page on same postion + if (props.pageNumber === 1) { + return { + pageNumber: newPageNumber, + pos: [...existPlaceholderPosition] + }; + } //else when user copy widget and choose this option and not at first page then copy all page but not at first + else if (filterPosition && filterPosition.length > 0) { return { pageNumber: newPageNumber, pos: [...filterPosition] }; } } + //second option - copy all page but not last //copy all page placeholder at requested position except last page else if (newPageNumber === props.allPages && type === 2) { if (existPlaceholderPosition) { + //when user choose this option and placed widget on last page then do not remove last page widget + //it should be copy all page included last page on same postion + if (props.pageNumber === props.allPages) { + return { + pageNumber: newPageNumber, + pos: [...existPlaceholderPosition] + }; + } else { + return { + pageNumber: newPageNumber, + pos: [...filterPosition] + }; + } + } + } + //this optin - copy all page with exiting widgets on same page + //copy all page placeholder at requested position with existing placeholder position + else if (existPlaceholderPosition) { + if (newPageNumber === props.pageNumber) { + return { + pageNumber: props.pageNumber, + pos: [...existPlaceholderPosition] + }; + } else { return { pageNumber: newPageNumber, - pos: [...filterPosition] + pos: [...existPlaceholderPosition, newPlaceholder] }; } } - //copy all page placeholder at requested position with existing placeholder position - else if (existPlaceholderPosition) { - return { - pageNumber: newPageNumber, - pos: [...filterPosition, currentPlaceholder] - }; - } //copy all page placeholder at requested position else { - return { - pageNumber: newPageNumber, - pos: [currentPlaceholder] - }; + if (newPageNumber === props.pageNumber) { + return { + pageNumber: props.pageNumber, + pos: [...existPlaceholderPosition] + }; + } else { + return { + pageNumber: newPageNumber, + pos: [newPlaceholder] + }; + } } }; - //function for copy placeholder as per select copy type const copyPlaceholder = (type) => { let newPlaceholderPosition = []; let newPageNumber = 1; - const signerPosition = props.xyPostion; + const signerPosition = props.xyPosition; const signerId = props.signerObjId ? props.signerObjId : props.Id; - //handle placeholder array and copy for multiple signers placeholder at requested location if (signerId) { //get current signers data @@ -90,10 +123,9 @@ function PlaceholderCopy(props) { const currentPlaceholder = placeholderPosition[0].pos.find( (position) => position.key === props.signKey ); - for (let i = 0; i < props.allPages; i++) { const newId = randomId(); - currentPlaceholder.key = newId; + const newPlaceholder = { ...currentPlaceholder, key: newId }; //get exist placeholder position for particular page const existPlaceholder = filterSignerPosition[0].placeHolder.filter( (data) => data.pageNumber === newPageNumber @@ -104,11 +136,11 @@ function PlaceholderCopy(props) { //function for get copy to requested location of placeholder position const getPlaceholderObj = getCopyPlaceholderPosition( type, - currentPlaceholder, + newPlaceholder, newPageNumber, existPlaceholderPosition ); - if (getPlaceholderObj) { + if (getPlaceholderObj?.pos) { newPlaceholderPosition.push(getPlaceholderObj); } newPageNumber++; @@ -138,13 +170,13 @@ function PlaceholderCopy(props) { const signersData = signerPosition; signersData.splice(0, signerPosition.length, ...updatedSignerPlaceholder); - props.setXyPostion(signersData); + props.setXyPosition(signersData); } //handle signyourself array and copy for single signers placeholder at requested location else { - const xyPostion = props.xyPostion; + const xyPosition = props.xyPosition; - const placeholderPosition = xyPostion.filter( + const placeholderPosition = xyPosition.filter( (data) => data.pageNumber === props.pageNumber ); //get current placeholder position data which user want to copy @@ -154,18 +186,18 @@ function PlaceholderCopy(props) { for (let i = 0; i < props.allPages; i++) { //get exist placeholder position for particular page - const existPlaceholder = xyPostion.filter( + const existPlaceholder = xyPosition.filter( (data) => data.pageNumber === newPageNumber ); const existPlaceholderPosition = existPlaceholder[0] && existPlaceholder[0].pos; const newId = randomId(); - currentPlaceholder.key = newId; + const newPlaceholder = { ...currentPlaceholder, key: newId }; //function for get copy to requested location of placeholder position const getPlaceholderObj = getCopyPlaceholderPosition( type, - currentPlaceholder, + newPlaceholder, newPageNumber, existPlaceholderPosition ); @@ -175,14 +207,14 @@ function PlaceholderCopy(props) { newPageNumber++; } - props.setXyPostion(newPlaceholderPosition); + props.setXyPosition(newPlaceholderPosition); } }; //function for getting selected type placeholder copy const handleApplyCopy = () => { if (selectCopyType === 4) { - const signerPosition = props.xyPostion; + const signerPosition = props.xyPosition; let currentXYposition; const signerId = props.signerObjId ? props.signerObjId : props.Id; if (signerId) { @@ -200,16 +232,16 @@ function PlaceholderCopy(props) { handleCopyNextToWidget( currentXYposition, props.widgetType, - props.xyPostion, + props.xyPosition, props.pageNumber, - props.setXyPostion, + props.setXyPosition, props?.Id ); } else { - const getIndex = props?.xyPostion.findIndex( + const getIndex = props?.xyPosition.findIndex( (data) => data.pageNumber === props.pageNumber ); - const placeholderPosition = props?.xyPostion[getIndex]; + const placeholderPosition = props?.xyPosition[getIndex]; //get current placeholder position data which user want to copy currentXYposition = placeholderPosition.pos.find( (pos) => pos.key === props.signKey @@ -218,9 +250,9 @@ function PlaceholderCopy(props) { handleCopyNextToWidget( currentXYposition, props.widgetType, - props.xyPostion, + props.xyPosition, getIndex, - props.setXyPostion + props.setXyPosition ); } } else { @@ -229,7 +261,7 @@ function PlaceholderCopy(props) { }; const handleUniqueId = () => { const signerId = props.signerObjId ? props.signerObjId : props.Id; - if (signerId && props.widgetType === textWidget) { + if (signerId && props.widgetType === textWidget && props.setTempSignerId) { props.setUniqueId(props?.tempSignerId); props.setTempSignerId(""); } @@ -260,7 +292,7 @@ function PlaceholderCopy(props) { ); })} - <div className="flex bg-[#9f9f9f] w-full my-[15px]"></div> + <div className="flex flex-row bg-[#9f9f9f] w-full my-[15px]"></div> <button onClick={() => { handleApplyCopy(); @@ -274,7 +306,7 @@ function PlaceholderCopy(props) { </button> <button type="button" - className="op-btn op-btn-ghost" + className="op-btn op-btn-ghost ml-2" onClick={() => handleUniqueId()} > {t("cancel")} diff --git a/apps/OpenSign/src/components/pdf/PlaceholderType.js b/apps/OpenSign/src/components/pdf/PlaceholderType.js index 96836446a..cacec7a61 100644 --- a/apps/OpenSign/src/components/pdf/PlaceholderType.js +++ b/apps/OpenSign/src/components/pdf/PlaceholderType.js @@ -19,6 +19,8 @@ const textWidgetCls = "w-full h-full md:min-w-full md:min-h-full z-[999] text-[12px] rounded-[2px] border-[1px] border-[#007bff] overflow-hidden resize-none outline-none text-base-content item-center whitespace-pre-wrap bg-white"; const selectWidgetCls = "w-full h-full absolute left-0 top-0 border-[1px] border-[#007bff] rounded-[2px] focus:outline-none text-base-content"; +const widgetCls = + "select-none-cls overflow-hidden w-full h-full text-black flex flex-col justify-center items-center"; function PlaceholderType(props) { const { t } = useTranslation(); const type = props?.pos?.type; @@ -28,7 +30,7 @@ function PlaceholderType(props) { const inputRef = useRef(null); const [textValue, setTextValue] = useState(); const [selectedCheckbox, setSelectedCheckbox] = useState([]); - const years = range(1990, getYear(new Date()) + 16, 1); + const years = range(1950, getYear(new Date()) + 16, 1); const fontSize = props.calculateFont(props.pos.options?.fontSize); const fontColor = props.pos.options?.fontColor || "black"; const months = [ @@ -45,6 +47,16 @@ function PlaceholderType(props) { "November", "December" ]; + const textWidgetStyle = { + fontSize: fontSize, + color: fontColor, + fontFamily: "Arial, sans-serif", + overflow: "hidden", + textAlign: "start", + width: "100%", + display: "flex", + height: "100%" + }; const validateExpression = (regexValidation) => { if (textValue && regexValidation) { let regexObject = regexValidation; @@ -61,7 +73,6 @@ function PlaceholderType(props) { }; const handleInputBlur = () => { - props.setDraggingEnabled(true); const validateType = props.pos?.options?.validation?.type; let regexValidation; if (validateType && validateType !== "text") { @@ -139,6 +150,11 @@ function PlaceholderType(props) { if (defaultData) { setTextValue(defaultData); } + } else if ([textInputWidget].includes(props.pos?.type)) { + const defaultData = props.pos?.options?.defaultValue; + if (defaultData) { + setTextValue(defaultData); + } } // eslint-disable-next-line react-hooks/exhaustive-deps }, [props.pos?.options?.defaultValue]); @@ -172,9 +188,9 @@ function PlaceholderType(props) { onChangeInput( jsonSender && jsonSender[0], null, - props.xyPostion, + props.xyPosition, null, - props.setXyPostion, + props.setXyPosition, props.data.Id, isDefault ); @@ -240,9 +256,9 @@ function PlaceholderType(props) { onChangeInput( checkedList ? checkedList : updateSelectedCheckbox, props.pos.key, - props.xyPostion, + props.xyPosition, props.index, - props.setXyPostion, + props.setXyPosition, props.data && props.data.Id, false, null, @@ -270,9 +286,9 @@ function PlaceholderType(props) { onChangeInput( data, props.pos.key, - props.xyPostion, + props.xyPosition, props.index, - props.setXyPostion, + props.setXyPosition, props.data && props.data.Id, false, null, @@ -283,12 +299,6 @@ function PlaceholderType(props) { //function to set onchange date const handleOnDateChange = (date) => { props.setStartDate(date); - const isDateChange = true; - const dateObj = { - date: date, - format: props.selectDate.format - }; - props.handleSaveDate(dateObj, isDateChange); }; //handle height on enter press in text area const handleEnterPress = (e) => { @@ -299,9 +309,9 @@ function PlaceholderType(props) { height, props.pos.type, props.pos.key, - props.xyPostion, + props.xyPosition, props.index, - props.setXyPostion, + props.setXyPosition, props.data && props.data?.Id ); } @@ -313,15 +323,16 @@ function PlaceholderType(props) { alt="signature" draggable="false" src={props.pos.SignUrl} - className="w-full h-full " + className="w-full h-full select-none-cls " /> ) : ( - <div className="text-[11px] w-full h-full text-black flex flex-col justify-center items-center"> + <div className={widgetCls}> {props?.handleUserName && props?.handleUserName( props?.data?.Id, props?.data?.Role, - widgetTypeTraslation + widgetTypeTraslation, + props.pos )} </div> ); @@ -331,15 +342,16 @@ function PlaceholderType(props) { alt="stamp" draggable="false" src={props.pos.SignUrl} - className="w-full h-full" + className="w-full h-full select-none-cls" /> ) : ( - <div className="text-[11px] w-full h-full text-black flex flex-col justify-center items-center"> + <div className={widgetCls}> {props?.handleUserName && props?.handleUserName( props?.data?.Id, props?.data?.Role, - widgetTypeTraslation + widgetTypeTraslation, + props.pos )} </div> ); @@ -348,12 +360,13 @@ function PlaceholderType(props) { <div style={{ zIndex: props.isSignYourself && "99" }}> {props.pos.options?.values?.map((data, ind) => { return ( - <div key={ind} className="flex items-center text-center gap-0.5"> + <div + key={ind} + className="select-none-cls flex items-center text-center gap-0.5" + > <input - style={{ - width: fontSize, - height: fontSize - }} + id={`checkbox-${props.pos.key + ind}`} + style={{ width: fontSize, height: fontSize }} className={`${ ind === 0 ? "mt-0" : "mt-[5px]" } flex justify-center op-checkbox rounded-[1px] `} @@ -391,10 +404,8 @@ function PlaceholderType(props) { /> {!props.pos.options?.isHideLabel && ( <label - style={{ - fontSize: fontSize, - color: fontColor - }} + htmlFor={`checkbox-${props.pos.key + ind}`} + style={{ fontSize: fontSize, color: fontColor }} className="text-xs mb-0 text-center" > {data} @@ -407,10 +418,11 @@ function PlaceholderType(props) { ); case textInputWidget: return props.isSignYourself || + (props.isSelfSign && props.data?.signerObjId === props.signerObjId) || (props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? ( <textarea ref={inputRef} - placeholder={validatePlaceholder || "please enter value"} + placeholder={validatePlaceholder || t("widgets-name.text")} rows={1} onKeyDown={handleEnterPress} value={textValue} @@ -420,39 +432,44 @@ function PlaceholderType(props) { onChangeInput( e.target.value, props.pos.key, - props.xyPostion, + props.xyPosition, props.index, - props.setXyPostion, + props.setXyPosition, props.data && props.data?.Id, false ); }} - className={textWidgetCls} - style={{ - fontSize: fontSize, - color: fontColor - }} + className={`${ + props.isNeedSign && + (props.pos.options?.isReadOnly || + props.data?.signerObjId !== props.signerObjId) + ? " bg-black/68 select-none " + : "" + textWidgetCls + }`} + style={{ fontSize: fontSize, color: fontColor }} + disabled={ + props.isNeedSign && + (props.pos.options?.isReadOnly || + props.data?.signerObjId !== props.signerObjId) + } cols="50" /> ) : ( - <div - style={{ - fontSize: fontSize, - color: fontColor, - overflow: "hidden" - }} - > - <span>{widgetTypeTraslation}</span> + <div style={textWidgetStyle} className="select-none-cls"> + <span>{textValue || widgetTypeTraslation}</span> </div> ); case "dropdown": return props.data?.signerObjId === props.signerObjId ? ( <select - style={{ - fontSize: fontSize, - color: fontColor - }} - className={`${selectWidgetCls} text-[12px] bg-inherit`} + style={{ fontSize: fontSize, color: fontColor }} + className={`${ + props.isNeedSign && + (props.pos.options?.isReadOnly || + props.data?.signerObjId !== props.signerObjId) + ? " disabled:bg-inherit select-none " + : "" + `${selectWidgetCls} text-[12px] bg-inherit` + }`} id="myDropdown" value={selectOption} onChange={(e) => { @@ -460,20 +477,22 @@ function PlaceholderType(props) { onChangeInput( e.target.value, props.pos.key, - props.xyPostion, + props.xyPosition, props.index, - props.setXyPostion, + props.setXyPosition, props.data && props.data?.Id, false ); }} + disabled={ + props.isNeedSign && + (props.pos.options?.isReadOnly || + props.data?.signerObjId !== props.signerObjId) + } > {/* Default/Title option */} <option - style={{ - fontSize: fontSize, - color: fontColor - }} + style={{ fontSize: fontSize, color: fontColor }} value="" disabled hidden @@ -484,10 +503,7 @@ function PlaceholderType(props) { {props.pos?.options?.values?.map((data, ind) => { return ( <option - style={{ - fontSize: fontSize, - color: fontColor - }} + style={{ fontSize: fontSize, color: fontColor }} key={ind} value={data} > @@ -497,13 +513,7 @@ function PlaceholderType(props) { })} </select> ) : ( - <div - style={{ - fontSize: fontSize, - color: fontColor - }} - className=" overflow-hidden" - > + <div style={textWidgetStyle} className="select-none-cls"> {props.pos?.options?.name ? props.pos.options.name : widgetTypeTraslation} @@ -515,24 +525,26 @@ function PlaceholderType(props) { alt="initials" draggable="false" src={props.pos.SignUrl} - className="w-full h-full" + className="w-full h-full select-none-cls" /> ) : ( - <div className="text-[11px] w-full h-full text-black flex flex-col justify-center items-center"> + <div className={widgetCls}> {props?.handleUserName && props?.handleUserName( props?.data?.Id, props?.data?.Role, - widgetTypeTraslation + widgetTypeTraslation, + props.pos )} </div> ); case "name": return props.isSignYourself || + (props.isSelfSign && props.data?.signerObjId === props.signerObjId) || (props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? ( <textarea ref={inputRef} - placeholder={"name"} + placeholder={t("widgets-name.name")} rows={1} onKeyDown={handleEnterPress} value={textValue} @@ -542,38 +554,29 @@ function PlaceholderType(props) { onChangeInput( e.target.value, props.pos.key, - props.xyPostion, + props.xyPosition, props.index, - props.setXyPostion, + props.setXyPosition, props.data && props.data?.Id, isDefault ); }} className={textWidgetCls} - style={{ - fontSize: fontSize, - color: fontColor - }} + style={{ fontSize: fontSize, color: fontColor }} cols="50" /> ) : ( - <div - style={{ - fontSize: fontSize, - color: fontColor, - fontFamily: "Arial, sans-serif", - overflow: "hidden" - }} - > + <div className="flex h-full select-none-cls" style={textWidgetStyle}> <span>{widgetTypeTraslation}</span> </div> ); case "company": return props.isSignYourself || + (props.isSelfSign && props.data?.signerObjId === props.signerObjId) || (props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? ( <textarea ref={inputRef} - placeholder="Enter text" + placeholder={t("widgets-name.company")} rows={1} onKeyDown={handleEnterPress} value={textValue} @@ -582,38 +585,29 @@ function PlaceholderType(props) { onChangeInput( e.target.value, props.pos.key, - props.xyPostion, + props.xyPosition, props.index, - props.setXyPostion, + props.setXyPosition, props.data && props.data?.Id, false ); }} className={textWidgetCls} - style={{ - fontSize: fontSize, - color: fontColor - }} + style={{ fontSize: fontSize, color: fontColor }} cols="50" /> ) : ( - <div - style={{ - fontSize: fontSize, - color: fontColor, - overflow: "hidden", - fontFamily: "Arial, sans-serif" - }} - > + <div style={textWidgetStyle} className="select-none-cls"> <span>{widgetTypeTraslation}</span> </div> ); case "job title": return props.isSignYourself || + (props.isSelfSign && props.data?.signerObjId === props.signerObjId) || (props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? ( <textarea ref={inputRef} - placeholder={"job title"} + placeholder={t("widgets-name.job title")} rows={1} onKeyDown={handleEnterPress} value={textValue} @@ -622,99 +616,83 @@ function PlaceholderType(props) { onChangeInput( e.target.value, props.pos.key, - props.xyPostion, + props.xyPosition, props.index, - props.setXyPostion, + props.setXyPosition, props.data && props.data?.Id, false ); }} className={textWidgetCls} - style={{ - fontSize: fontSize, - color: fontColor - }} + style={{ fontSize: fontSize, color: fontColor }} cols="50" /> ) : ( - <div - style={{ - fontSize: fontSize, - color: fontColor, - fontFamily: "Arial, sans-serif", - overflow: "hidden" - }} - > + <div style={textWidgetStyle} className="select-none-cls"> <span>{widgetTypeTraslation}</span> </div> ); case "date": return props.isSignYourself || + (props.isSelfSign && props.data?.signerObjId === props.signerObjId) || (props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? ( - <div> - <DatePicker - renderCustomHeader={({ date, changeYear, changeMonth }) => ( - <div className="flex justify-start ml-2 "> - <select - className="bg-transparent outline-none" - value={months[getMonth(date)]} - onChange={({ target: { value } }) => - changeMonth(months.indexOf(value)) - } - > - {months.map((option) => ( - <option key={option} value={option}> - {option} - </option> - ))} - </select> - <select - className="bg-transparent outline-none" - value={getYear(date)} - onChange={({ target: { value } }) => changeYear(value)} - > - {years.map((option) => ( - <option key={option} value={option}> - {option} - </option> - ))} - </select> - </div> - )} - disabled={ - props.isPlaceholder || - (props.isNeedSign && - props.data?.signerObjId !== props.signerObjId) - } - onBlur={handleInputBlur} - closeOnScroll={true} - className={`${selectWidgetCls} outline-[#007bff]`} - selected={ - props?.startDate - ? props?.startDate - : props.pos.options?.response && - new Date(props.pos.options.response) - } - onChange={(date) => handleOnDateChange(date)} - popperPlacement="top-end" - customInput={<ExampleCustomInput />} - dateFormat={ - props.selectDate - ? props.selectDate?.format - : props.pos?.options?.validation?.format - ? props.pos?.options?.validation?.format - : "MM/dd/yyyy" - } - /> - </div> + <DatePicker + renderCustomHeader={({ date, changeYear, changeMonth }) => ( + <div className="flex justify-start ml-2 "> + <select + className="bg-transparent outline-none" + value={months[getMonth(date)]} + onChange={({ target: { value } }) => + changeMonth(months.indexOf(value)) + } + > + {months.map((option) => ( + <option key={option} value={option}> + {option} + </option> + ))} + </select> + <select + className="bg-transparent outline-none" + value={getYear(date)} + onChange={({ target: { value } }) => changeYear(value)} + > + {years.map((option) => ( + <option key={option} value={option}> + {option} + </option> + ))} + </select> + </div> + )} + disabled={ + props.isPlaceholder || + (props.isNeedSign && props.data?.signerObjId !== props.signerObjId) + } + onBlur={handleInputBlur} + closeOnScroll={true} + className={`${selectWidgetCls} outline-[#007bff]`} + selected={ + props?.startDate + ? props?.startDate + : props.pos.options?.response && + new Date(props.pos.options.response) + } + onChange={(date) => handleOnDateChange(date)} + popperPlacement="top-end" + customInput={<ExampleCustomInput />} + dateFormat={ + props.selectDate + ? props.selectDate?.format + : props.pos?.options?.validation?.format + ? props.pos?.options?.validation?.format + : "MM/dd/yyyy" + } + /> ) : ( <div - style={{ - fontSize: fontSize, - color: fontColor, - fontFamily: "Arial, sans-serif" - }} - className="items-center overflow-hidden" + style={textWidgetStyle} + className="select-none-cls overflow-hidden" > <span> {props.selectDate @@ -731,26 +709,33 @@ function PlaceholderType(props) { alt="image" draggable="false" src={props.pos.SignUrl} - className="w-full h-full" + className="w-full h-full select-none-cls" /> ) : ( - <div className="text-[11px] w-full h-full text-black flex flex-col justify-center items-center"> + <div className={widgetCls}> {props?.handleUserName && props?.handleUserName( props?.data?.Id, props?.data?.Role, - widgetTypeTraslation + widgetTypeTraslation, + props.pos )} </div> ); case "email": return props.isSignYourself || + (props.isSelfSign && props.data?.signerObjId === props.signerObjId) || (props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? ( <textarea ref={inputRef} - placeholder={"enter email"} + placeholder={t("widgets-name.email")} rows={1} - onKeyDown={handleEnterPress} + onKeyDown={(e) => { + // Prevent new line on Enter key press + if (e.key === "Enter") { + e.preventDefault(); + } + }} value={textValue} onBlur={handleInputBlur} onChange={(e) => { @@ -758,9 +743,9 @@ function PlaceholderType(props) { onChangeInput( e.target.value, props.pos.key, - props.xyPostion, + props.xyPosition, props.index, - props.setXyPostion, + props.setXyPosition, props.data && props.data?.Id, false ); @@ -771,17 +756,10 @@ function PlaceholderType(props) { color: fontColor, fontFamily: "Arial, sans-serif" }} - cols="50" + cols="1" /> ) : ( - <div - style={{ - fontSize: fontSize, - color: fontColor, - fontFamily: "Arial, sans-serif", - overflow: "hidden" - }} - > + <div style={textWidgetStyle} className="select-none-cls"> <span>{widgetTypeTraslation}</span> </div> ); @@ -790,8 +768,12 @@ function PlaceholderType(props) { <div> {props.pos.options?.values.map((data, ind) => { return ( - <div key={ind} className="flex items-center text-center gap-0.5"> + <div + key={ind} + className="select-none-cls flex items-center text-center gap-0.5" + > <input + id={`radio-${props.pos.key + ind}`} style={{ width: fontSize, height: fontSize, @@ -813,10 +795,8 @@ function PlaceholderType(props) { /> {!props.pos.options?.isHideLabel && ( <label - style={{ - fontSize: fontSize, - color: fontColor - }} + htmlFor={`radio-${props.pos.key + ind}`} + style={{ fontSize: fontSize, color: fontColor }} className="text-xs mb-0" > {data} @@ -830,7 +810,7 @@ function PlaceholderType(props) { case textWidget: return ( <textarea - placeholder="Enter text" + placeholder={t("widgets-name.text")} rows={1} onKeyDown={handleEnterPress} value={textValue} @@ -840,9 +820,9 @@ function PlaceholderType(props) { onChangeInput( e.target.value, props.pos.key, - props.xyPostion, + props.xyPosition, props.index, - props.setXyPostion, + props.setXyPosition, props.data && props.data?.Id, false ); @@ -863,14 +843,19 @@ function PlaceholderType(props) { alt="image" draggable="false" src={props.pos.SignUrl} - className="w-full h-full" + className="w-full h-full " /> </div> ) : ( - <div className="text-[11px] w-full h-full text-black flex flex-col justify-center items-center"> + <div className={widgetCls}> {props.pos.isStamp ? <div>stamp</div> : <div>signature</div>} {props?.handleUserName && - props?.handleUserName(props?.data?.Id, props?.data?.Role)} + props?.handleUserName( + props?.data?.Id, + props?.data?.Role, + null, + props.pos + )} </div> ); } diff --git a/apps/OpenSign/src/components/pdf/PrevNext.js b/apps/OpenSign/src/components/pdf/PrevNext.js index 0154b1b3f..8c3cc166c 100644 --- a/apps/OpenSign/src/components/pdf/PrevNext.js +++ b/apps/OpenSign/src/components/pdf/PrevNext.js @@ -23,7 +23,7 @@ function PrevNext({ pageNumber, allPages, changePage }) { <i className="fa-light fa-backward" aria-hidden="true"></i> </span> </button> - <span className="text-xs text-base-content font-medium mx-2 2xl:text-[30px]"> + <span className="text-xs text-base-content font-medium mx-2 2xl:text-[20px]"> {pageNumber || (allPages ? 1 : "--")} {t("of")} {allPages || "--"} </span> <button diff --git a/apps/OpenSign/src/components/pdf/RecipientList.js b/apps/OpenSign/src/components/pdf/RecipientList.js index c2b437017..26b41c1e6 100644 --- a/apps/OpenSign/src/components/pdf/RecipientList.js +++ b/apps/OpenSign/src/components/pdf/RecipientList.js @@ -32,7 +32,7 @@ const RecipientList = (props) => { }; //handle draggable element drop and also used in mobile view on up and down key to chnage sequence of recipient's list - const handleChangeSequence = (e, ind, isUp, isDown) => { + const handleChangeSequence = (e, ind, isUp, isDown, obj) => { e.preventDefault(); let draggedItemId; let index = ind; @@ -66,8 +66,7 @@ const RecipientList = (props) => { props?.setIsSelectId(index); props?.setUniqueId(remainingItems[index]?.Id); props?.setRoleName(remainingItems[index]?.Role); - props?.setBlockColor(remainingItems[index]?.blockColor); - + props?.setBlockColor(obj.blockColor); //change order of placeholder's list using sorting method //`remainingItems` is correct order of signers after change order const changeOrderSignerList = props?.signerPos.sort((a, b) => { @@ -97,7 +96,9 @@ const RecipientList = (props) => { props.sendInOrder && !isMobile && handleDragOver(e) } onDrop={(e) => - props.sendInOrder && !isMobile && handleChangeSequence(e, ind) + props.sendInOrder && + !isMobile && + handleChangeSequence(e, ind, null, null, obj) } data-tut="recipientArea" onMouseEnter={() => setIsHover(ind)} @@ -196,7 +197,7 @@ const RecipientList = (props) => { }} /> ) : ( - <span className="text-[13px] 2xl:text-[25px]"> + <span className="text-[13px] 2xl:text-[17px]"> {obj.Role} </span> )} @@ -222,7 +223,7 @@ const RecipientList = (props) => { onClick={(e) => { if (ind !== 0) { e.stopPropagation(); - handleChangeSequence(e, ind, "up"); + handleChangeSequence(e, ind, "up", null, obj); } }} className={ind === 0 ? "text-[gray]" : "text-black"} @@ -233,7 +234,7 @@ const RecipientList = (props) => { onClick={(e) => { if (ind !== props.signersdata.length - 1) { e.stopPropagation(); - handleChangeSequence(e, ind, null, "down"); + handleChangeSequence(e, ind, null, "down", obj); } }} className={ @@ -259,7 +260,7 @@ const RecipientList = (props) => { : "text-base-content" } cursor-pointer`} > - <i className="fa-light fa-trash-can 2xl:text-[30px]"></i> + <i className="fa-light fa-trash-can 2xl:text-[22px]"></i> </div> )} <hr /> diff --git a/apps/OpenSign/src/components/pdf/RenderAllPdfPage.js b/apps/OpenSign/src/components/pdf/RenderAllPdfPage.js index 381f19be4..1c41850ee 100644 --- a/apps/OpenSign/src/components/pdf/RenderAllPdfPage.js +++ b/apps/OpenSign/src/components/pdf/RenderAllPdfPage.js @@ -2,29 +2,25 @@ import React, { useEffect, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; import { Document, Page } from "react-pdf"; import { useSelector } from "react-redux"; +import { PDFDocument } from "pdf-lib"; +import { base64ToArrayBuffer } from "../../constant/Utils"; -function RenderAllPdfPage({ - signPdfUrl, - allPages, - setAllPages, - setPageNumber, - setSignBtnPosition, - pageNumber, - signerPos, - signerObjectId, - containerWH, - pdfRotateBase64 -}) { +function RenderAllPdfPage(props) { const { t } = useTranslation(); + const pageContainer = useRef(); + const mergePdfInputRef = useRef(null); const [signPageNumber, setSignPageNumber] = useState([]); const [bookmarkColor, setBookmarkColor] = useState(""); + const isHeader = useSelector((state) => state.showHeader); + const [pageWidth, setPageWidth] = useState(""); + //set all number of pages after load pdf function onDocumentLoad({ numPages }) { - setAllPages(numPages); + props?.setAllPages(numPages); //check if signerPos array exist then save page number exist in signerPos array to show bookmark icon - if (signerPos) { - const checkUser = signerPos.filter( - (data) => data.signerObjId === signerObjectId + if (props?.signerPos) { + const checkUser = props?.signerPos.filter( + (data) => data.Id === props?.id ); setBookmarkColor(checkUser[0]?.blockColor); let pageNumberArr = []; @@ -37,9 +33,6 @@ function RenderAllPdfPage({ } } } - const pageContainer = useRef(); - const isHeader = useSelector((state) => state.showHeader); - const [pageWidth, setPageWidth] = useState(""); useEffect(() => { const updateSize = () => { @@ -52,7 +45,7 @@ function RenderAllPdfPage({ const timer = setTimeout(updateSize, 100); // match the transition duration return () => clearTimeout(timer); - }, [isHeader, pageContainer, containerWH]); + }, [isHeader, pageContainer, props?.containerWH]); //'function `addSignatureBookmark` is used to display the page where the user's signature is located. const addSignatureBookmark = (index) => { const ispageNumber = signPageNumber.includes(index + 1); @@ -67,7 +60,46 @@ function RenderAllPdfPage({ ) ); }; - const pdfDataBase64 = `data:application/pdf;base64,${pdfRotateBase64}`; + const pdfDataBase64 = `data:application/pdf;base64,${props?.pdfBase64Url}`; + + // `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]; + if (!file) { + alert("Please upload a valid PDF file."); + return; + } + if (!file.type.includes("pdf")) { + alert("Only PDF files are allowed."); + return; + } + try { + const uploadedPdfBytes = await file.arrayBuffer(); + const uploadedPdfDoc = await PDFDocument.load(uploadedPdfBytes, { + ignoreEncryption: true + }); + const basePdfDoc = await PDFDocument.load(props.pdfArrayBuffer); + + // Copy pages from the uploaded PDF to the base PDF + const uploadedPdfPages = await basePdfDoc.copyPages( + uploadedPdfDoc, + uploadedPdfDoc.getPageIndices() + ); + uploadedPdfPages.forEach((page) => basePdfDoc.addPage(page)); + // Save the updated PDF + const pdfBase64 = await basePdfDoc.saveAsBase64({ + useObjectStreams: false + }); + const pdfBuffer = base64ToArrayBuffer(pdfBase64); + props.setPdfArrayBuffer(pdfBuffer); + props.setPdfBase64Url(pdfBase64); + props.setIsUploadPdf && props.setIsUploadPdf(true); + mergePdfInputRef.current.value = ""; + } catch (error) { + mergePdfInputRef.current.value = ""; + console.error("Error merging PDF:", error); + } + }; return ( <div ref={pageContainer} className="hidden w-[20%] bg-base-100 md:block"> <div className="mx-2 pr-2 pt-2 pb-1 text-[15px] text-base-content font-semibold border-b-[1px] border-base-300"> @@ -80,24 +112,24 @@ function RenderAllPdfPage({ <Document loading={t("loading-doc")} onLoadSuccess={onDocumentLoad} - file={(pdfRotateBase64 && pdfDataBase64) || signPdfUrl} + file={pdfDataBase64} > - {Array.from(new Array(allPages), (el, index) => ( + {Array.from(new Array(props?.allPages), (el, index) => ( <div key={index} className={`${ - pageNumber - 1 === index ? "border-[red]" : "border-[#878787]" - } border-2 m-[10px] flex justify-center items-center relative`} + props?.pageNumber - 1 === index + ? "border-[red]" + : "border-[#878787]" + } border-2 m-[10px] flex justify-center items-center relative`} onClick={() => { - setPageNumber(index + 1); - if (setSignBtnPosition) { - setSignBtnPosition([]); + props?.setPageNumber(index + 1); + if (props?.setSignBtnPosition) { + props?.setSignBtnPosition([]); } }} > - {signerPos && addSignatureBookmark(index)} - - {/* <div className="relative z-[1] overflow-hidden"> */} + {props?.signerPos && addSignatureBookmark(index)} <Page key={`page_${index + 1}`} pageNumber={index + 1} @@ -106,10 +138,28 @@ function RenderAllPdfPage({ renderAnnotationLayer={false} renderTextLayer={false} /> - {/* </div> */} </div> ))} </Document> + {props?.isMergePdfBtn && ( + <button + className="mb-2 bg-base-100 px-2 py-2 ring-[0.5px] ring-base-content rounded-box flex gap-1 justify-center items-center" + onClick={() => mergePdfInputRef.current.click()} + title={t("add-pages")} + > + <input + type="file" + className="hidden" + accept="application/pdf" + ref={mergePdfInputRef} + onChange={handleFileUpload} + /> + <i className="fa-light fa-plus text-gray-500"></i> + <span className="text-xs lg:text-sm text-base-content "> + Add pages + </span> + </button> + )} </div> </div> ); diff --git a/apps/OpenSign/src/components/pdf/RenderPdf.js b/apps/OpenSign/src/components/pdf/RenderPdf.js index 29d076dda..fa35635df 100644 --- a/apps/OpenSign/src/components/pdf/RenderPdf.js +++ b/apps/OpenSign/src/components/pdf/RenderPdf.js @@ -1,137 +1,80 @@ -import React from "react"; +import React, { useState } from "react"; import RSC from "react-scrollbars-custom"; import { Document, Page } from "react-pdf"; import { defaultWidthHeight, getContainerScale, handleImageResize, - handleSignYourselfImageResize + handleSignYourselfImageResize, + isMobile } from "../../constant/Utils"; import Placeholder from "./Placeholder"; import Alert from "../../primitives/Alert"; import { useTranslation } from "react-i18next"; -function RenderPdf({ - pageNumber, - drop, - signerPos, - successEmail, - handleTabDrag, - handleStop, - isDragging, - setIsSignPad, - setIsStamp, - handleDeleteSign, - setSignKey, - pdfDetails, - xyPostion, - pageDetails, - pdfRequest, - signerObjectId, - signedSigners, - pdfLoad, - setPdfLoad, - placeholder, - setSignerPos, - setXyPostion, - index, - containerWH, - setIsResize, - handleLinkUser, - setUniqueId, - signersdata, - setIsPageCopy, - setShowDropdown, - setIsInitial, - setIsValidate, - setWidgetType, - setValidateAlert, - setIsRadio, - setCurrWidgetsDetails, - setSelectWidgetId, - selectWidgetId, - unSignedWidgetId, - setIsCheckbox, - handleNameModal, - handleTextSettingModal, - setTempSignerId, - uniqueId, - pdfOriginalWH, - scale, - setIsSelectId, - ispublicTemplate, - handleUserDetails, - pdfRotateBase64, - fontSize, - setFontSize, - fontColor, - setFontColor, - isResize -}) { +function RenderPdf(props) { const { t } = useTranslation(); - const isMobile = window.innerWidth < 767; - + const [scaledHeight, setScaledHeight] = useState(); //check isGuestSigner is present in local if yes than handle login flow header in mobile view const isGuestSigner = localStorage.getItem("isGuestSigner"); // handle signature block width and height according to screen const posWidth = (pos, signYourself) => { const containerScale = getContainerScale( - pdfOriginalWH, - pageNumber, - containerWH + props.pdfOriginalWH, + props.pageNumber, + props.containerWH ); const defaultWidth = defaultWidthHeight(pos.type).width; const posWidth = pos.Width ? pos.Width : defaultWidth; if (signYourself) { - return posWidth * scale * containerScale; + return posWidth * props.scale * containerScale; } else { if (pos.isMobile && pos.scale) { if (pos.IsResize) { - if (scale > 1) { - return posWidth * pos.scale * containerScale * scale; + if (props.scale > 1) { + return posWidth * pos.scale * containerScale * props.scale; } else { return posWidth * containerScale; } } else { - if (scale > 1) { - return posWidth * pos.scale * containerScale * scale; + if (props.scale > 1) { + return posWidth * pos.scale * containerScale * props.scale; } else { return posWidth * pos.scale * containerScale; } } } else { - return posWidth * scale * containerScale; + return posWidth * props.scale * containerScale; } } }; - const posHeight = (pos, signYourself) => { const containerScale = getContainerScale( - pdfOriginalWH, - pageNumber, - containerWH + props.pdfOriginalWH, + props.pageNumber, + props.containerWH ); const posHeight = pos.Height || defaultWidthHeight(pos.type).height; if (signYourself) { - return posHeight * scale * containerScale; + return posHeight * props.scale * containerScale; } else { if (pos.isMobile && pos.scale) { if (pos.IsResize) { - if (scale > 1) { - return posHeight * pos.scale * containerScale * scale; + if (props.scale > 1) { + return posHeight * pos.scale * containerScale * props.scale; } else { return posHeight * containerScale; } } else { - if (scale > 1) { - return posHeight * pos.scale * containerScale * scale; + if (props.scale > 1) { + return posHeight * pos.scale * containerScale * props.scale; } else { return posHeight * pos.scale * containerScale; } } } else { - return posHeight * scale * containerScale; + return posHeight * props.scale * containerScale; } } }; @@ -140,25 +83,35 @@ function RenderPdf({ const checkSignedSigners = (data) => { let checkSign = []; //condition to handle quick send flow and using normal request sign flow - checkSign = signedSigners - ? signedSigners?.filter( + checkSign = props.signedSigners + ? props.signedSigners?.filter( (sign) => sign?.Id === data?.Id || sign?.objectId === data?.signerObjId ) : []; - const handleAllUserName = (Id, Role, type) => { + const handleAllUserName = (Id, Role, type, pos) => { return ( <React.Fragment> <div className="text-black text-[8px] font-bold"> { - pdfDetails[0].Signers?.find( + props.pdfDetails[0].Signers?.find( (signer) => signer.objectId === data.signerObjId )?.Name } </div> - {type && <div className="text-[11px] font-bold">{type}</div>} + {type && ( + <div + style={{ fontSize: pos ? calculateFontsize(pos) : "11px" }} + className="font-bold" + > + {type} + </div> + )} {Role && ( - <div className="text-black text-[8px] font-medium"> + <div + style={{ fontSize: pos ? calculateFontsize(pos) : "8px" }} + className="text-black font-medium" + > {`(${Role})`} </div> )} @@ -167,49 +120,71 @@ function RenderPdf({ }; return ( checkSign.length === 0 && - data.placeHolder.map((placeData, key) => { + data?.placeHolder?.map((placeData, key) => { return ( <React.Fragment key={key}> - {placeData.pageNumber === pageNumber && + {placeData.pageNumber === props.pageNumber && placeData.pos.map((pos) => { return ( pos && ( <React.Fragment key={pos.key}> <Placeholder pos={pos} - setSignKey={setSignKey} - setIsSignPad={setIsSignPad} - setIsStamp={setIsStamp} + setSignKey={props.setSignKey} + setIsSignPad={props.setIsSignPad} + setIsStamp={props.setIsStamp} handleSignYourselfImageResize={handleImageResize} - index={pageNumber} - xyPostion={signerPos} - setXyPostion={setSignerPos} + index={props.pageNumber} + xyPosition={props.signerPos} + setXyPosition={props.setSignerPos} data={data} - setIsResize={setIsResize} - isShowBorder={false} - signerObjId={signerObjectId} + setIsResize={props.setIsResize} + isShowBorder={props.isSelfSign} + isAlllowModify={props.isAlllowModify} + signerObjId={props.signerObjectId} isShowDropdown={true} - isNeedSign={true} + isNeedSign={props.pdfRequest} + isSelfSign={true} isSignYourself={false} posWidth={posWidth} posHeight={posHeight} handleUserName={handleAllUserName} - isDragging={false} - pdfDetails={pdfDetails} - setIsInitial={setIsInitial} - setValidateAlert={setValidateAlert} - unSignedWidgetId={unSignedWidgetId} - setSelectWidgetId={setSelectWidgetId} - selectWidgetId={selectWidgetId} - setCurrWidgetsDetails={setCurrWidgetsDetails} - uniqueId={uniqueId} - scale={scale} - containerWH={containerWH} - pdfOriginalWH={pdfOriginalWH} - pageNumber={pageNumber} - ispublicTemplate={ispublicTemplate} - handleUserDetails={handleUserDetails} - isResize={isResize} + isDragging={props.isDragging} + pdfDetails={props.pdfDetails} + setIsInitial={props.setIsInitial} + setValidateAlert={props.setValidateAlert} + unSignedWidgetId={props.unSignedWidgetId} + setSelectWidgetId={props.setSelectWidgetId} + selectWidgetId={props.selectWidgetId} + setCurrWidgetsDetails={props.setCurrWidgetsDetails} + uniqueId={props.uniqueId} + scale={props.scale} + containerWH={props.containerWH} + pdfOriginalWH={props.pdfOriginalWH} + pageNumber={props.pageNumber} + ispublicTemplate={props.ispublicTemplate} + handleUserDetails={props.handleUserDetails} + isResize={props.isResize} + setIsAgreeTour={props.setIsAgreeTour} + isAgree={props.isAgree} + handleTabDrag={props.handleTabDrag} + handleStop={props.handleStop} + setWidgetType={props.setWidgetType} + setUniqueId={props.setUniqueId} + setIsSelectId={props.setIsSelectId} + handleDeleteSign={props.handleDeleteSign} + setIsPageCopy={props.setIsPageCopy} + handleTextSettingModal={props.handleTextSettingModal} + setIsCheckbox={props.setIsCheckbox} + isFreeResize={false} + isOpenSignPad={true} + assignedWidgetId={props.assignedWidgetId} + isApplyAll={true} + setFontSize={props.setFontSize} + fontSize={props.fontSize} + fontColor={props.fontColor} + setFontColor={props.setFontColor} + setRequestSignTour={props.setRequestSignTour} /> </React.Fragment> ) @@ -220,20 +195,50 @@ function RenderPdf({ }) ); }; + + const calculateFontsize = (pos) => { + const width = posWidth(pos); + const height = posHeight(pos); + + if (height === width || height < width) { + return `${height / 5}px`; + } else if (width < height) { + return `${width / 10}px`; + } + }; //function for render placeholder block over pdf document - const handleUserName = (Id, Role, type) => { + const handleUserName = (Id, Role, type, pos) => { if (Id) { - const checkSign = signersdata.find((sign) => sign.Id === Id); + const checkSign = props.signersdata.find((sign) => sign.Id === Id); if (checkSign?.Name) { return ( <> - <div className="text-black text-[8px] font-medium"> + <div + style={{ + fontSize: pos ? calculateFontsize(pos) : "8px" + }} + className="text-black font-medium" + > {checkSign?.Name} </div> - {type && <div className="text-[11px] font-bold">{type}</div>} + {type && ( + <div + style={{ + fontSize: pos ? calculateFontsize(pos) : "11px" + }} + className=" font-bold" + > + {type} + </div> + )} {Role && ( - <div className="text-black text-[8px] font-medium"> + <div + style={{ + fontSize: pos ? calculateFontsize(pos) : "8px" + }} + className="text-black text-[8px] font-medium" + > {`(${Role})`} </div> )} @@ -242,8 +247,20 @@ function RenderPdf({ } else { return ( <> - {type && <div className="text-[11px] font-bold">{type}</div>} - <div className="text-black text-[8px] font-medium">{Role}</div> + {type && ( + <div + style={{ fontSize: pos ? calculateFontsize(pos) : "11px" }} + className=" font-bold" + > + {type} + </div> + )} + <div + style={{ fontSize: pos ? calculateFontsize(pos) : "8px" }} + className="text-black font-medium" + > + {Role} + </div> </> ); } @@ -256,11 +273,18 @@ function RenderPdf({ ); } }; - const pdfDataBase64 = `data:application/pdf;base64,${pdfRotateBase64}`; - + const pdfDataBase64 = `data:application/pdf;base64,${props.pdfBase64Url}`; + //calculate render height of pdf in mobile view + const handlePageLoadSuccess = (page) => { + const containerWidth = props.divRef.current.offsetWidth; // Get container width + const viewport = page.getViewport({ scale: 1 }); + const scale = containerWidth / viewport.width; // Scale to fit container width + const scaleHeight = viewport.height * scale; + setScaledHeight(scaleHeight); + }; return ( <> - {successEmail && ( + {props.successEmail && ( <Alert type={"success"}>{t("success-email-alert")}</Alert> )} {isMobile ? ( @@ -268,12 +292,12 @@ function RenderPdf({ style={{ position: "relative", boxShadow: "rgba(17, 12, 46, 0.15) 0px 48px 100px 0px", - height: window.innerHeight - 200, + //49 is height of header + height: isGuestSigner ? window.innerHeight - 49 : scaledHeight, zIndex: 0 }} - className="h-full" - noScrollY={false} - noScrollX={scale === 1 ? true : false} + noScrollY={props.scale === 1 ? true : false} + noScrollX={props.scale === 1 ? true : false} > <div data-tut="reactourForth" @@ -281,87 +305,104 @@ function RenderPdf({ isGuestSigner ? "30px" : "" } border-[0.1px] border-[#ebe8e8] overflow-x-auto`} style={{ - width: containerWH?.width && containerWH?.width * scale + width: + props.containerWH?.width && + props.containerWH?.width * props.scale }} - ref={drop} + ref={props.drop} id="container" > - {containerWH?.width && - pdfOriginalWH.length > 0 && - (pdfRequest - ? signerPos.map((data, key) => { + {props.containerWH?.width && + props.pdfOriginalWH.length > 0 && + (props.pdfRequest || props.isSelfSign + ? props.signerPos?.map((data, key) => { return ( <React.Fragment key={key}> {checkSignedSigners(data)} </React.Fragment> ); }) - : placeholder // placeholder mobile - ? signerPos?.map((data, ind) => { + : props.placeholder // placeholder mobile + ? props.signerPos?.map((data, ind) => { return ( <React.Fragment key={ind}> {data?.placeHolder && data?.placeHolder.map((placeData, index) => { return ( <React.Fragment key={index}> - {placeData.pageNumber === pageNumber && + {placeData.pageNumber === props.pageNumber && placeData.pos.map((pos) => { return ( <React.Fragment key={pos.key}> <Placeholder pos={pos} - setIsPageCopy={setIsPageCopy} - setSignKey={setSignKey} - handleDeleteSign={handleDeleteSign} - setIsStamp={setIsStamp} - handleTabDrag={handleTabDrag} - handleStop={handleStop} + setIsPageCopy={props.setIsPageCopy} + setSignKey={props.setSignKey} + handleDeleteSign={ + props.handleDeleteSign + } + setIsStamp={props.setIsStamp} + handleTabDrag={props.handleTabDrag} + handleStop={props.handleStop} handleSignYourselfImageResize={ handleImageResize } - index={pageNumber} - xyPostion={signerPos} - setXyPostion={setSignerPos} + index={props.pageNumber} + xyPosition={props.signerPos} + setXyPosition={props.setSignerPos} data={data} - setIsResize={setIsResize} - setShowDropdown={setShowDropdown} + setIsResize={props.setIsResize} + setShowDropdown={ + props.setShowDropdown + } isShowBorder={true} isPlaceholder={true} - setUniqueId={setUniqueId} - handleLinkUser={handleLinkUser} + setUniqueId={props.setUniqueId} + handleLinkUser={ + props.handleLinkUser + } handleUserName={handleUserName} isSignYourself={false} posWidth={posWidth} posHeight={posHeight} - isDragging={isDragging} - setIsValidate={setIsValidate} - setWidgetType={setWidgetType} - setIsRadio={setIsRadio} - setIsCheckbox={setIsCheckbox} + isDragging={props.isDragging} + setIsValidate={props.setIsValidate} + setWidgetType={props.setWidgetType} + setIsRadio={props.setIsRadio} + setIsCheckbox={props.setIsCheckbox} setCurrWidgetsDetails={ - setCurrWidgetsDetails + props.setCurrWidgetsDetails } setSelectWidgetId={ - setSelectWidgetId + props.setSelectWidgetId } - selectWidgetId={selectWidgetId} - handleNameModal={handleNameModal} - setTempSignerId={setTempSignerId} - uniqueId={uniqueId} + selectWidgetId={ + props.selectWidgetId + } + handleNameModal={ + props.handleNameModal + } + setTempSignerId={ + props.setTempSignerId + } + uniqueId={props.uniqueId} handleTextSettingModal={ - handleTextSettingModal + props.handleTextSettingModal } - scale={scale} - containerWH={containerWH} - pdfOriginalWH={pdfOriginalWH} - pageNumber={pageNumber} - setIsSelectId={setIsSelectId} - fontSize={fontSize} - setFontSize={setFontSize} - fontColor={fontColor} - setFontColor={setFontColor} - isResize={isResize} - unSignedWidgetId={unSignedWidgetId} + scale={props.scale} + containerWH={props.containerWH} + pdfOriginalWH={props.pdfOriginalWH} + pageNumber={props.pageNumber} + setIsSelectId={props.setIsSelectId} + fontSize={props.fontSize} + setFontSize={props.setFontSize} + fontColor={props.fontColor} + setFontColor={props.setFontColor} + isResize={props.isResize} + unSignedWidgetId={ + props.unSignedWidgetId + } + isFreeResize={true} /> </React.Fragment> ); @@ -372,58 +413,61 @@ function RenderPdf({ </React.Fragment> ); }) - : !pdfDetails?.[0]?.IsCompleted && - xyPostion.map((data, ind) => { + : !props.pdfDetails?.[0]?.IsCompleted && + props.xyPosition?.map((data, ind) => { return ( <React.Fragment key={ind}> - {data.pageNumber === pageNumber && - data.pos.map((pos) => { + {data.pageNumber === props.pageNumber && + data.pos.map((pos, id) => { return ( pos && ( <Placeholder + key={id} pos={pos} - setIsPageCopy={setIsPageCopy} - setSignKey={setSignKey} - handleDeleteSign={handleDeleteSign} - setIsStamp={setIsStamp} - handleTabDrag={handleTabDrag} - handleStop={handleStop} + setIsPageCopy={props.setIsPageCopy} + setSignKey={props.setSignKey} + handleDeleteSign={props.handleDeleteSign} + setIsStamp={props.setIsStamp} + handleTabDrag={props.handleTabDrag} + handleStop={props.handleStop} handleSignYourselfImageResize={ handleSignYourselfImageResize } - index={index} - xyPostion={xyPostion} - setXyPostion={setXyPostion} - containerWH={containerWH} - setIsSignPad={setIsSignPad} + index={props.index} + xyPosition={props.xyPosition} + setXyPosition={props.setXyPosition} + containerWH={props.containerWH} + setIsSignPad={props.setIsSignPad} isShowBorder={true} isSignYourself={true} posWidth={posWidth} posHeight={posHeight} - pdfDetails={pdfDetails[0]} - isDragging={isDragging} - setIsInitial={setIsInitial} - setWidgetType={setWidgetType} - setSelectWidgetId={setSelectWidgetId} - selectWidgetId={selectWidgetId} + pdfDetails={props.pdfDetails[0]} + isDragging={props.isDragging} + setIsInitial={props.setIsInitial} + setWidgetType={props.setWidgetType} + setSelectWidgetId={props.setSelectWidgetId} + selectWidgetId={props.selectWidgetId} handleUserName={handleUserName} - setIsCheckbox={setIsCheckbox} - setValidateAlert={setValidateAlert} + setIsCheckbox={props.setIsCheckbox} + setValidateAlert={props.setValidateAlert} setCurrWidgetsDetails={ - setCurrWidgetsDetails + props.setCurrWidgetsDetails } handleTextSettingModal={ - handleTextSettingModal + props.handleTextSettingModal } - scale={scale} - pdfOriginalWH={pdfOriginalWH} - pageNumber={pageNumber} - fontSize={fontSize} - setFontSize={setFontSize} - fontColor={fontColor} - setFontColor={setFontColor} - isResize={isResize} - setIsResize={setIsResize} + scale={props.scale} + pdfOriginalWH={props.pdfOriginalWH} + pageNumber={props.pageNumber} + fontSize={props.fontSize} + setFontSize={props.setFontSize} + fontColor={props.fontColor} + setFontColor={props.setFontColor} + isResize={props.isResize} + setIsResize={props.setIsResize} + isFreeResize={false} + isOpenSignPad={true} /> ) ); @@ -433,26 +477,23 @@ function RenderPdf({ }))} <Document - onLoadError={() => setPdfLoad(false)} + onLoadError={() => props.setPdfLoad(false)} loading={t("loading-doc")} - onLoadSuccess={pageDetails} + onLoadSuccess={props.pageDetails} // ref={pdfRef}' onClick={() => { - if (setSelectWidgetId) { - setSelectWidgetId(""); + if (props.setSelectWidgetId) { + props.setSelectWidgetId(""); } }} - file={ - (pdfRotateBase64 && pdfDataBase64) || - pdfDetails[0]?.SignedUrl || - pdfDetails[0].URL - } + file={pdfDataBase64} > <Page - scale={scale || 1} - key={index} - pageNumber={pageNumber} - width={containerWH.width} + onLoadSuccess={handlePageLoadSuccess} + scale={props.scale || 1} + key={props.index} + pageNumber={props.pageNumber} + width={props.containerWH.width} renderAnnotationLayer={false} renderTextLayer={false} onGetAnnotationsError={(error) => { @@ -471,92 +512,109 @@ function RenderPdf({ zIndex: 0 }} noScrollY={false} - noScrollX={scale === 1 ? true : false} + noScrollX={props.scale === 1 ? true : false} > <div style={{ - width: containerWH?.width && containerWH?.width * scale + width: + props.containerWH?.width && + props.containerWH?.width * props.scale }} - ref={drop} + ref={props.drop} id="container" > - {pdfLoad && - containerWH?.width && - pdfOriginalWH.length > 0 && - (pdfRequest //pdf request sign flow - ? signerPos?.map((data, key) => { + {props.pdfLoad && + props.containerWH?.width && + props.pdfOriginalWH.length > 0 && + (props.pdfRequest || props.isSelfSign //pdf request sign flow + ? props.signerPos?.map((data, key) => { return ( <React.Fragment key={key}> {checkSignedSigners(data)} </React.Fragment> ); }) - : placeholder //placeholder and template flow - ? signerPos.map((data, ind) => { + : props.placeholder //placeholder and template flow + ? props.signerPos.map((data, ind) => { return ( <React.Fragment key={ind}> {data?.placeHolder && data?.placeHolder.map((placeData, index) => { return ( <React.Fragment key={index}> - {placeData.pageNumber === pageNumber && + {placeData.pageNumber === props.pageNumber && placeData.pos.map((pos) => { return ( <React.Fragment key={pos.key}> <Placeholder pos={pos} - setIsPageCopy={setIsPageCopy} - setSignKey={setSignKey} - handleDeleteSign={handleDeleteSign} - setIsStamp={setIsStamp} - handleTabDrag={handleTabDrag} - handleStop={handleStop} + setIsPageCopy={props.setIsPageCopy} + setSignKey={props.setSignKey} + handleDeleteSign={ + props.handleDeleteSign + } + setIsStamp={props.setIsStamp} + handleTabDrag={props.handleTabDrag} + handleStop={props.handleStop} handleSignYourselfImageResize={ handleImageResize } - index={pageNumber} - xyPostion={signerPos} - setXyPostion={setSignerPos} + index={props.pageNumber} + xyPosition={props.signerPos} + setXyPosition={props.setSignerPos} data={data} - setIsResize={setIsResize} - setShowDropdown={setShowDropdown} + setIsResize={props.setIsResize} + setShowDropdown={ + props.setShowDropdown + } isShowBorder={true} isPlaceholder={true} - setUniqueId={setUniqueId} - handleLinkUser={handleLinkUser} + setUniqueId={props.setUniqueId} + handleLinkUser={ + props.handleLinkUser + } handleUserName={handleUserName} isSignYourself={false} posWidth={posWidth} posHeight={posHeight} - isDragging={isDragging} - setIsValidate={setIsValidate} - setWidgetType={setWidgetType} - setIsRadio={setIsRadio} - setIsCheckbox={setIsCheckbox} + isDragging={props.isDragging} + setIsValidate={props.setIsValidate} + setWidgetType={props.setWidgetType} + setIsRadio={props.setIsRadio} + setIsCheckbox={props.setIsCheckbox} setCurrWidgetsDetails={ - setCurrWidgetsDetails + props.setCurrWidgetsDetails } setSelectWidgetId={ - setSelectWidgetId + props.setSelectWidgetId } - selectWidgetId={selectWidgetId} - handleNameModal={handleNameModal} - setTempSignerId={setTempSignerId} - uniqueId={uniqueId} + selectWidgetId={ + props.selectWidgetId + } + handleNameModal={ + props.handleNameModal + } + setTempSignerId={ + props.setTempSignerId + } + uniqueId={props.uniqueId} handleTextSettingModal={ - handleTextSettingModal + props.handleTextSettingModal } - scale={scale} - containerWH={containerWH} - pdfOriginalWH={pdfOriginalWH} - pageNumber={pageNumber} - setIsSelectId={setIsSelectId} - fontSize={fontSize} - setFontSize={setFontSize} - fontColor={fontColor} - setFontColor={setFontColor} - isResize={isResize} - unSignedWidgetId={unSignedWidgetId} + scale={props.scale} + containerWH={props.containerWH} + pdfOriginalWH={props.pdfOriginalWH} + pageNumber={props.pageNumber} + setIsSelectId={props.setIsSelectId} + fontSize={props.fontSize} + setFontSize={props.setFontSize} + fontColor={props.fontColor} + setFontColor={props.setFontColor} + isResize={props.isResize} + unSignedWidgetId={ + props.unSignedWidgetId + } + isFreeResize={true} /> </React.Fragment> ); @@ -567,61 +625,67 @@ function RenderPdf({ </React.Fragment> ); }) - : !pdfDetails?.[0]?.IsCompleted && - xyPostion?.map((data, ind) => { + : !props.pdfDetails?.[0]?.IsCompleted && + props.xyPosition?.map((data, ind) => { // signyourself flow return ( <React.Fragment key={ind}> - {data.pageNumber === pageNumber && + {data.pageNumber === props.pageNumber && data.pos.map((pos) => { return ( <React.Fragment key={pos.key}> <Placeholder pos={pos} - setIsPageCopy={setIsPageCopy} - setSignKey={setSignKey} - handleDeleteSign={handleDeleteSign} - setIsStamp={setIsStamp} - handleTabDrag={handleTabDrag} + setIsPageCopy={props.setIsPageCopy} + setSignKey={props.setSignKey} + handleDeleteSign={props.handleDeleteSign} + setIsStamp={props.setIsStamp} + handleTabDrag={props.handleTabDrag} handleStop={(event, dragElement) => - handleStop(event, dragElement, pos.type) + props.handleStop( + event, + dragElement, + pos.type + ) } handleSignYourselfImageResize={ handleSignYourselfImageResize } - index={index} - xyPostion={xyPostion} - setXyPostion={setXyPostion} - setIsSignPad={setIsSignPad} + index={props.index} + xyPosition={props.xyPosition} + setXyPosition={props.setXyPosition} + setIsSignPad={props.setIsSignPad} isShowBorder={true} isSignYourself={true} posWidth={posWidth} posHeight={posHeight} - pdfDetails={pdfDetails[0]} - isDragging={isDragging} - setIsInitial={setIsInitial} - setWidgetType={setWidgetType} - setSelectWidgetId={setSelectWidgetId} - selectWidgetId={selectWidgetId} + pdfDetails={props.pdfDetails[0]} + isDragging={props.isDragging} + setIsInitial={props.setIsInitial} + setWidgetType={props.setWidgetType} + setSelectWidgetId={props.setSelectWidgetId} + selectWidgetId={props.selectWidgetId} handleUserName={handleUserName} - setIsCheckbox={setIsCheckbox} - setValidateAlert={setValidateAlert} + setIsCheckbox={props.setIsCheckbox} + setValidateAlert={props.setValidateAlert} setCurrWidgetsDetails={ - setCurrWidgetsDetails + props.setCurrWidgetsDetails } handleTextSettingModal={ - handleTextSettingModal + props.handleTextSettingModal } - scale={scale} - containerWH={containerWH} - pdfOriginalWH={pdfOriginalWH} - pageNumber={pageNumber} - fontSize={fontSize} - setFontSize={setFontSize} - fontColor={fontColor} - setFontColor={setFontColor} - isResize={isResize} - setIsResize={setIsResize} + scale={props.scale} + containerWH={props.containerWH} + pdfOriginalWH={props.pdfOriginalWH} + pageNumber={props.pageNumber} + fontSize={props.fontSize} + setFontSize={props.setFontSize} + fontColor={props.fontColor} + setFontColor={props.setFontColor} + isResize={props.isResize} + setIsResize={props.setIsResize} + isFreeResize={false} + isOpenSignPad={true} /> </React.Fragment> ); @@ -632,27 +696,22 @@ function RenderPdf({ {/* this component for render pdf document is in middle of the component */} <Document - onLoadError={() => setPdfLoad(false)} + onLoadError={() => props.setPdfLoad(false)} loading={t("loading-doc")} - onLoadSuccess={pageDetails} + onLoadSuccess={props.pageDetails} onClick={() => { - if (setSelectWidgetId) { - setSelectWidgetId(""); + if (props.setSelectWidgetId) { + props.setSelectWidgetId(""); } }} - // ref={pdfRef} - file={ - (pdfRotateBase64 && pdfDataBase64) || - pdfDetails[0]?.SignedUrl || - pdfDetails[0].URL - } + file={pdfDataBase64} > <Page - key={index} - width={containerWH.width} - scale={scale || 1} + key={props.index} + width={props.containerWH.width} + scale={props.scale || 1} className={"-z-[1]"} // when user zoom-in in tablet widgets move backward that's why pass -z-[1] - pageNumber={pageNumber} + pageNumber={props.pageNumber} renderAnnotationLayer={false} renderTextLayer={false} onGetAnnotationsError={(error) => { diff --git a/apps/OpenSign/src/components/pdf/SelectLanguage.js b/apps/OpenSign/src/components/pdf/SelectLanguage.js index 7faf86c3d..473b6edc5 100644 --- a/apps/OpenSign/src/components/pdf/SelectLanguage.js +++ b/apps/OpenSign/src/components/pdf/SelectLanguage.js @@ -5,9 +5,11 @@ import { useTranslation } from "react-i18next"; function SelectLanguage(props) { const { i18n } = useTranslation(); const languages = [ - { value: "en", text: "English" }, - { value: "es", text: "Española" }, - { value: "fr", text: "Français" } + { value: "en", text: "English" }, //english + { value: "es", text: "Española" }, //spanish + { value: "fr", text: "Français" }, //french + { value: "it", text: "Italiano" }, //italian + { value: "de", text: "Deutsch" } //german ]; const defaultLanguage = i18next.language || "en"; const [lang, setLang] = useState(defaultLanguage); diff --git a/apps/OpenSign/src/components/pdf/SignPad.js b/apps/OpenSign/src/components/pdf/SignPad.js index 414805876..1076a0e9f 100644 --- a/apps/OpenSign/src/components/pdf/SignPad.js +++ b/apps/OpenSign/src/components/pdf/SignPad.js @@ -1,6 +1,15 @@ import React, { useRef, useState, useEffect } from "react"; import { useTranslation } from "react-i18next"; import SignatureCanvas from "react-signature-canvas"; +import Parse from "parse"; +import { + generateTitleFromFilename, + getBase64FromUrl, + getSecureUrl +} from "../../constant/Utils"; +import sanitizeFileName from "../../primitives/sanitizeFileName"; +import { SaveFileSize } from "../../constant/saveFileSize"; +import Loader from "../../primitives/Loader"; function SignPad(props) { const { t } = useTranslation(); @@ -10,11 +19,11 @@ function SignPad(props) { const [isDefaultSign, setIsDefaultSign] = useState(false); const [isTab, setIsTab] = useState(""); const [isSignImg, setIsSignImg] = useState(""); - const [signValue, setSignValue] = useState(""); const [textWidth, setTextWidth] = useState(0); const [textHeight, setTextHeight] = useState(0); const [signatureType, setSignatureType] = useState(""); const [isSignTypes, setIsSignTypes] = useState(true); + const [typedSignature, setTypedSignature] = useState(""); const fontOptions = [ { value: "Fasthand" }, { value: "Dancing Script" }, @@ -23,28 +32,36 @@ function SignPad(props) { // Add more font options as needed ]; const [fontSelect, setFontSelect] = useState(fontOptions[0].value); - - const senderUser = - localStorage.getItem( - `Parse/${localStorage.getItem("parseAppId")}/currentUser` - ) && - localStorage.getItem( - `Parse/${localStorage.getItem("parseAppId")}/currentUser` - ); - const jsonSender = JSON.parse(senderUser); + const [isSavedSign, setIsSavedSign] = useState(false); + const [isLoader, setIsLoader] = useState(false); + const accesstoken = localStorage.getItem("accesstoken") || ""; + const senderUser = localStorage.getItem( + `Parse/${localStorage.getItem("parseAppId")}/currentUser` + ); + const jsonSender = senderUser && JSON.parse(senderUser); const currentUserName = jsonSender && jsonSender?.name; - useEffect(() => { handleTab(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [props.signatureTypes]); - function handleTab() { const signtypes = props?.signatureTypes || []; - const index = signtypes?.findIndex((x) => x.enabled === true); - if (index !== -1) { + const defaultIndex = signtypes?.findIndex( + (x) => + x.name === "default" && + x.enabled === true && + props.defaultSign && + (props?.currWidgetsDetails?.type || props.widgetType) !== "image" && + (props?.currWidgetsDetails?.type || props.widgetType) !== "stamp" + ); + const getIndex = + defaultIndex !== -1 // Check if the default index exists + ? defaultIndex // If found, use it + : signtypes?.findIndex((x) => x.enabled === true); + + if (getIndex !== -1) { setIsSignTypes(true); - const tab = props?.signatureTypes[index].name; + const tab = props?.signatureTypes[getIndex].name; if (tab === "draw") { setIsTab("draw"); setSignatureType("draw"); @@ -54,6 +71,7 @@ function SignPad(props) { } else if (tab === "typed") { setIsTab("type"); } else if (tab === "default") { + setIsDefaultSign(true); setIsTab("mysignature"); } else { setIsTab(true); @@ -71,7 +89,6 @@ function SignPad(props) { //function for clear signature image const handleClear = () => { - props?.setCurrWidgetsDetails({}); if (isTab === "draw") { if (canvasRef.current) { canvasRef.current.clear(); @@ -88,6 +105,176 @@ function SignPad(props) { props?.setSignature(data); setIsSignImg(data); }; + function base64StringtoFile(base64String, filename) { + let arr = base64String.split(","), + // type of uploaded image + mime = arr[0].match(/:(.*?);/)[1], + // decode base64 + bstr = atob(arr[1]), + n = bstr.length, + u8arr = new Uint8Array(n); + while (n--) { + u8arr[n] = bstr.charCodeAt(n); + } + const ext = mime.split("/").pop(); + const name = `${filename}.${ext}`; + return new File([u8arr], name, { type: mime }); + } + + const uploadFile = async (file) => { + try { + const parseFile = new Parse.File(file.name, file); + const response = await parseFile.save(); + if (response?.url()) { + const fileRes = await getSecureUrl(response.url()); + if (fileRes.url) { + const tenantId = localStorage.getItem("TenantId"); + SaveFileSize(file.size, fileRes.url, tenantId); + return fileRes?.url; + } else { + alert(`${t("something-went-wrong-mssg")}`); + return false; + } + } else { + alert(`${t("something-went-wrong-mssg")}`); + return false; + } + } catch (err) { + console.log("sign upload err", err); + alert(`${err.message}`); + return false; + } + }; + + // `handlesavesign` is used to save signaute, initials, stamp as a default + const handleSaveSign = async () => { + if (isSignImg || props?.image?.src) { + setIsLoader(true); + try { + const User = Parse?.User?.current(); + const sanitizename = generateTitleFromFilename(User?.get("name")); + const replaceSpace = sanitizeFileName(sanitizename); + let file; + if (isSignImg) { + file = base64StringtoFile(isSignImg, `${replaceSpace}__sign`); + } else { + file = base64StringtoFile(props?.image?.src, `${replaceSpace}__sign`); + } + const imageUrl = await uploadFile(file); + const userId = { + __type: "Pointer", + className: "_User", + objectId: User?.id + }; + if (imageUrl) { + // below code is used to save or update default signaute, initials, stamp + try { + const signCls = new Parse.Object("contracts_Signature"); + if (props?.saveSignCheckbox?.signId) { + signCls.id = props.saveSignCheckbox.signId; + } + if ( + props.currWidgetsDetails?.type === "initials" || + props?.widgetType === "initials" + ) { + signCls.set("Initials", imageUrl); + } else if ( + props.currWidgetsDetails?.type === "signature" || + props?.widgetType === "signature" + ) { + signCls.set("ImageURL", imageUrl); + } + signCls.set("UserId", userId); + const signRes = await signCls.save(); + if (signRes) { + props.saveSignCheckbox.signId; + props.setSaveSignCheckbox((prev) => ({ + ...prev, + signId: signRes?.id + })); + const _signRes = JSON.parse(JSON.stringify(signRes)); + if ( + props.currWidgetsDetails?.type === "signature" || + props?.widgetType === "signature" + ) { + const defaultSign = await getBase64FromUrl( + _signRes?.ImageURL, + true + ); + props.setDefaultSignImg(defaultSign); + } else if ( + props.currWidgetsDetails?.type === "initials" || + props?.widgetType === "initials" + ) { + const defaultInitials = await getBase64FromUrl( + _signRes?.Initials, + true + ); + props.setMyInitial(defaultInitials); + } + alert(t("saved-successfully")); + } + return signRes; + } catch (err) { + console.log(err); + alert(`${err.message}`); + } finally { + setIsLoader(false); + } + } + } catch (err) { + console.log("Err while saving signature", err); + } + } + }; + + const handleSaveBtn = async () => { + if (accesstoken && isSavedSign) { + await handleSaveSign(); + resetToDefault(); + } else { + resetToDefault(); + } + }; + const resetToDefault = () => { + props?.setCurrWidgetsDetails({}); + if (!props?.image) { + if (isTab === "mysignature") { + setIsSignImg(""); + if (props?.isInitial) { + props?.onSaveSign(signatureType, "initials"); + } else { + props?.onSaveSign(null, "default"); + } + } else { + if (isTab === "type") { + setIsSignImg(""); + props?.onSaveSign( + null, + false, + !props?.isInitial && textWidth > 150 ? 150 : textWidth, + !props?.isInitial && textHeight > 35 ? 35 : textHeight, + typedSignature + ); + } else { + setIsSignImg(""); + canvasRef.current.clear(); + props?.onSaveSign(signatureType); + } + } + setPenColor("blue"); + } else { + setIsSignImg(""); + props?.onSaveImage(signatureType); + } + props?.setIsSignPad(false); + props?.setIsInitial && props?.setIsInitial(false); + props?.setIsImageSelect(false); + setIsDefaultSign(false); + props?.setImage(); + handleTab(); + props?.setIsStamp(false); + }; //save button component const SaveBtn = () => { return ( @@ -102,48 +289,14 @@ function SignPad(props) { </button> )} <button - onClick={() => { - props?.setCurrWidgetsDetails({}); - if (!props?.image) { - if (isTab === "mysignature") { - setIsSignImg(""); - if (props?.isInitial) { - props?.onSaveSign(signatureType, "initials"); - } else { - props?.onSaveSign(null, "default"); - } - } else { - if (isTab === "type") { - setIsSignImg(""); - props?.onSaveSign( - null, - false, - !props?.isInitial && textWidth > 150 ? 150 : textWidth, - !props?.isInitial && textHeight > 35 ? 35 : textHeight - ); - } else { - setIsSignImg(""); - canvasRef.current.clear(); - props?.onSaveSign(signatureType); - } - } - setPenColor("blue"); - } else { - setIsSignImg(""); - props?.onSaveImage(signatureType); - } - props?.setIsSignPad(false); - props?.setIsInitial(false); - props?.setIsImageSelect(false); - setIsDefaultSign(false); - props?.setImage(); - handleTab(); - setSignValue(""); - props?.setIsStamp(false); - }} + onClick={() => handleSaveBtn()} type="button" className={`${ - isSignImg || props?.image || isDefaultSign || textWidth + isSignImg || + props?.image || + isDefaultSign || + textWidth || + props.isAutoSign ? "" : "pointer-events-none" } op-btn op-btn-primary shadow-lg`} @@ -151,7 +304,8 @@ function SignPad(props) { (isTab === "draw" && isSignImg) || (isTab === "image" && props?.image) || (isTab === "mysignature" && isDefaultSign) || - (isTab === "type" && signValue) + (isTab === "type" && typedSignature) || + props.isAutoSign ? false : props?.image ? false @@ -163,9 +317,24 @@ function SignPad(props) { </div> ); }; + const autoSignAll = () => { + return ( + <label className="cursor-pointer flex items-center mb-[6px] text-center text-[11px] md:text-base"> + <input + className="mr-2 md:mr-3 op-checkbox op-checkbox-xs md:op-checkbox-sm" + type="checkbox" + value={props.isAutoSign} + onChange={(e) => { + props.setIsAutoSign(e.target.checked); + }} + /> + {t("auto-sign-mssg")} + </label> + ); + }; //useEffect for set already draw or save signature url/text url of signature text type and draw type for initial type and signature type widgets useEffect(() => { - if (props?.currWidgetsDetails && canvasRef.current) { + if (props?.currWidgetsDetails && canvasRef.current && props.isSignPad) { const isWidgetType = props?.currWidgetsDetails?.type; const signatureType = props?.currWidgetsDetails?.signatureType; const url = props?.currWidgetsDetails?.SignUrl; @@ -181,13 +350,14 @@ function SignPad(props) { ) { canvasRef.current.fromDataURL(url); } - } - const trimmedName = currentUserName && currentUserName?.trim(); - const firstCharacter = trimmedName?.charAt(0); - const userName = props?.isInitial ? firstCharacter : currentUserName; - setSignValue(userName || ""); - setFontSelect("Fasthand"); + const trimmedName = currentUserName && currentUserName?.trim(); + const firstCharacter = trimmedName?.charAt(0); + const userName = props?.isInitial ? firstCharacter : currentUserName; + const signatureValue = props?.currWidgetsDetails?.typeSignature; + setTypedSignature(signatureValue || userName || ""); + setFontSelect("Fasthand"); + } // eslint-disable-next-line react-hooks/exhaustive-deps }, [props.isSignPad]); @@ -207,19 +377,19 @@ function SignPad(props) { loadFont(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [fontSelect]); - useEffect(() => { // Load the default signature after the component mounts if (canvasRef.current) { canvasRef.current.fromDataURL(isSignImg); } if (isTab === "type") { - const trimmedName = signValue - ? signValue?.trim() + const trimmedName = typedSignature + ? typedSignature?.trim() : currentUserName?.trim(); const firstCharacter = trimmedName?.charAt(0); - const userName = props?.isInitial ? firstCharacter : signValue; - setSignValue(userName); + const userName = props?.isInitial ? firstCharacter : typedSignature; + const signatureValue = props?.currWidgetsDetails?.typeSignature; + setTypedSignature(signatureValue || userName || ""); convertToImg(fontSelect, userName); } // eslint-disable-next-line react-hooks/exhaustive-deps @@ -271,40 +441,19 @@ function SignPad(props) { const dataUrl = canvasElement.toDataURL("image/png"); props?.setSignature(dataUrl); }; - const PenColorComponent = (props) => { return ( - <div className="flex flex-row items-start"> + <div className="flex flex-row items-center m-[5px] gap-2"> {allColor.map((data, key) => { return ( <i - style={{ - margin: "5px", - color: data, - borderBottom: - key === 0 && penColor === "blue" - ? "2px solid blue" - : key === 1 && penColor === "red" - ? "2px solid red" - : key === 2 && penColor === "black" - ? "2px solid black" - : "2px solid white" - }} + key={key} onClick={() => { props?.convertToImg && - props?.convertToImg(fontSelect, signValue, data); - if (key === 0) { - setPenColor("blue"); - } else if (key === 1) { - setPenColor("red"); - } else if (key === 2) { - setPenColor("black"); - } + props?.convertToImg(fontSelect, typedSignature, data); + setPenColor(allColor[key]); }} - key={key} - className="fa-light fa-pen-nib" - width={20} - height={20} + className={`border-b-[2px] ${key === 0 && penColor === "blue" ? "border-blue-600" : key === 1 && penColor === "red" ? "border-red-500" : key === 2 && penColor === "black" ? "border-black" : "border-white"} text-[${data}] text-[16px] fa-light fa-pen-nib`} ></i> ); })} @@ -316,19 +465,35 @@ function SignPad(props) { const handleCancelBtn = () => { setPenColor("blue"); props?.setIsSignPad(false); - props?.setIsInitial(false); + props?.setIsInitial && props?.setIsInitial(false); props?.setIsImageSelect(false); setIsDefaultSign(false); props?.setImage(); handleTab(); - setSignValue(""); props?.setIsStamp(false); }; + + const savesigncheckbox = ( + <label className="cursor-pointer flex items-center mb-0 text-center text-[11px] md:text-base"> + <input + className="mr-2 md:mr-3 op-checkbox op-checkbox-xs md:op-checkbox-sm" + type="checkbox" + checked={isSavedSign} + onChange={(e) => setIsSavedSign(e.target.checked)} + /> + Save {props?.currWidgetsDetails?.type || props?.widgetType} + </label> + ); return ( <div> {props?.isSignPad && ( <div className="op-modal op-modal-open"> <div className="op-modal-box px-[13px] pt-2 pb-0"> + {isLoader && ( + <div className="absolute w-full h-full inset-0 flex justify-center items-center bg-base-content/30 z-50"> + <Loader /> + </div> + )} {isSignTypes ? ( <> <div className="flex justify-between text-base-content items-center"> @@ -344,6 +509,51 @@ function SignPad(props) { </span> ) : ( <> + {!props?.isInitial && + props?.defaultSign && + isTabEnabled("default") ? ( + <div> + <span + onClick={() => { + setIsDefaultSign(true); + props?.setIsImageSelect(true); + setIsTab("mysignature"); + setSignatureType(""); + props?.setImage(); + }} + className={`${ + isTab === "mysignature" + ? "op-link-primary" + : "no-underline" + } op-link underline-offset-8 ml-[2px]`} + > + {t("my-signature")} + </span> + </div> + ) : ( + props?.isInitial && + props?.myInitial && + isTabEnabled("default") && ( + <div> + <span + onClick={() => { + setIsDefaultSign(true); + props?.setIsImageSelect(true); + setIsTab("mysignature"); + setSignatureType(""); + props?.setImage(); + }} + className={`${ + isTab === "mysignature" + ? "op-link-primary" + : "no-underline" + } op-link underline-offset-8 ml-[2px]`} + > + {t("my-initials")} + </span> + </div> + ) + )} {isTabEnabled("draw") && ( <div> <span @@ -405,51 +615,6 @@ function SignPad(props) { </span> </div> )} - {!props?.isInitial && - props?.defaultSign && - isTabEnabled("default") ? ( - <div> - <span - onClick={() => { - setIsDefaultSign(true); - props?.setIsImageSelect(true); - setIsTab("mysignature"); - setSignatureType(""); - props?.setImage(); - }} - className={`${ - isTab === "mysignature" - ? "op-link-primary" - : "no-underline" - } op-link underline-offset-8 ml-[2px]`} - > - {t("my-signature")} - </span> - </div> - ) : ( - props?.isInitial && - props?.myInitial && - isTabEnabled("default") && ( - <div> - <span - onClick={() => { - setIsDefaultSign(true); - props?.setIsImageSelect(true); - setIsTab("mysignature"); - setSignatureType(""); - props?.setImage(); - }} - className={`${ - isTab === "mysignature" - ? "op-link-primary" - : "no-underline" - } op-link underline-offset-8 ml-[2px]`} - > - {t("my-initials")} - </span> - </div> - ) - )} </> )} </div> @@ -467,21 +632,7 @@ function SignPad(props) { <> <div className="flex justify-center"> <div - style={{ - border: "1.3px solid #007bff", - borderRadius: "2px", - display: "flex", - flexDirection: "column", - justifyContent: "center", - alignItems: "center", - marginBottom: 6, - cursor: "pointer" - }} - className={ - props?.isInitial - ? "intialSignatureCanvas" - : "signatureCanvas" - } + className={`${props?.isInitial ? "intialSignatureCanvas" : "signatureCanvas"} bg-white border-[1.3px] border-[#007bff] flex flex-col justify-center items-center mb-[6px] cursor-pointer`} > <img alt="stamp img" @@ -495,6 +646,7 @@ function SignPad(props) { /> </div> </div> + {props.setIsAutoSign && autoSignAll()} <div className="flex justify-end"> <SaveBtn /> </div> @@ -503,21 +655,7 @@ function SignPad(props) { !props?.image ? ( <div className="flex justify-center"> <div - style={{ - border: "1.3px solid #007bff", - borderRadius: "2px", - display: "flex", - flexDirection: "column", - justifyContent: "center", - alignItems: "center", - marginBottom: 6, - cursor: "pointer" - }} - className={ - props?.isInitial - ? "intialSignatureCanvas" - : "signatureCanvas" - } + className={`${props?.isInitial ? "intialSignatureCanvas" : "signatureCanvas"} bg-white border-[1.3px] border-[#007bff] flex flex-col justify-center items-center mb-[6px] cursor-pointer`} onClick={() => props?.imageRef.current.click()} > <input @@ -536,27 +674,18 @@ function SignPad(props) { <> <div className="flex justify-center"> <div - style={{ - border: "1.3px solid #007bff", - borderRadius: "2px", - marginBottom: 6, - overflow: "hidden" - }} - className={ - props?.isInitial - ? "intialSignatureCanvas" - : "signatureCanvas" - } + className={`${props?.isInitial ? "intialSignatureCanvas" : "signatureCanvas"} bg-white border-[1.3px] border-[#007bff] mb-[6px] overflow-hidden`} > <img alt="print img" ref={props?.imageRef} src={props?.image.src} draggable="false" - className=" object-contain h-full w-full" + className="object-contain h-full w-full" /> </div> </div> + {props.setIsAutoSign && autoSignAll()} <div className="flex justify-end"> <SaveBtn /> </div> @@ -576,10 +705,14 @@ function SignPad(props) { style={{ fontFamily: fontSelect, color: penColor }} type="text" className="ml-1 op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-[20px]" - placeholder="Your signature" - value={signValue} + placeholder={ + props?.isInitial + ? t("initial-type") + : t("signature-type") + } + value={typedSignature} onChange={(e) => { - setSignValue(e.target.value); + setTypedSignature(e.target.value); convertToImg(fontSelect, e.target.value); }} /> @@ -598,26 +731,28 @@ function SignPad(props) { }} onClick={() => { setFontSelect(font.value); - convertToImg(font.value, signValue); + convertToImg(font.value, typedSignature); }} > <div - style={{ - padding: "5px 10px 5px 10px", - fontSize: "20px", - color: penColor - }} + className="py-[5px] px-[10px] text-[20px]" + style={{ color: penColor }} > - {signValue ? signValue : "Your signature"} + {typedSignature + ? typedSignature + : "Your signature"} </div> </div> ); })} </div> - <div className="flex flex-row justify-between mt-[10px]"> - <PenColorComponent convertToImg={convertToImg} /> - <SaveBtn /> + <div className="flex flex-col justify-between mt-[10px]"> + {props.setIsAutoSign && autoSignAll()} + <div className="flex flex-row justify-between mt-[10px]"> + <PenColorComponent convertToImg={convertToImg} /> + <SaveBtn /> + </div> </div> </div> ) : ( @@ -627,15 +762,8 @@ function SignPad(props) { ref={canvasRef} penColor={penColor} canvasProps={{ - className: props?.isInitial - ? "intialSignatureCanvas" - : "signatureCanvas", - style: { - border: "1.6px solid #007bff", - borderRadius: "2px" - } + className: `${props?.isInitial ? "intialSignatureCanvas" : "signatureCanvas"} border-[1.3px] border-[#007bff]` }} - // backgroundColor="rgb(255, 255, 255)" onEnd={() => handleSignatureChange( canvasRef.current?.toDataURL() @@ -644,16 +772,22 @@ function SignPad(props) { dotSize={1} /> </div> - <div className="flex flex-row justify-between mt-[10px]"> - <PenColorComponent /> - <SaveBtn /> + <div className="flex flex-col justify-between mt-[10px]"> + {props.setIsAutoSign && autoSignAll()} + {accesstoken && + props?.saveSignCheckbox?.isVisible && + savesigncheckbox} + <div className="flex flex-row justify-between mt-[10px]"> + <PenColorComponent /> + <SaveBtn /> + </div> </div> </> )} </div> </> ) : ( - <div className=""> + <div> <div className="relative flex flex-row items-center justify-between"> <div className="text-base-content font-bold text-lg"> Signature diff --git a/apps/OpenSign/src/components/pdf/Signedby.js b/apps/OpenSign/src/components/pdf/Signedby.js index 0b0411d78..fe2c21032 100644 --- a/apps/OpenSign/src/components/pdf/Signedby.js +++ b/apps/OpenSign/src/components/pdf/Signedby.js @@ -1,31 +1,41 @@ import React from "react"; import "../../styles/signature.css"; import { useTranslation } from "react-i18next"; -function Signedby({ pdfDetails }) { +function Signedby(props) { const { t } = useTranslation(); - const getFirstLetter = (name) => { + const getFirstLetter = (pdfData) => { + const name = props.isSelfSign + ? (pdfData?.Signers && pdfData?.Signers[0]?.Name) || "User" + : pdfData.ExtUserPtr?.Name; const firstLetter = name.charAt(0); return firstLetter; }; - return ( <div className="hidden md:block w-full h-full bg-base-100"> <div className="mx-2 pr-2 pt-2 pb-1 text-[15px] text-base-content font-semibold border-b-[1px] border-base-300"> - {t("signed-by")} + {props.isSelfSign ? t("user") : t("signed-by")} </div> <div className="mt-[2px] bg-base-100"> <div className="bg-[#93a3db] rounded-xl mx-1 flex flex-row items-center py-[10px]"> <div className="bg-[#576081] flex w-[30px] h-[30px] rounded-full justify-center items-center mx-1"> <span className="text-[12px] text-center font-bold text-white uppercase"> - {getFirstLetter(pdfDetails.ExtUserPtr.Name)} + {getFirstLetter(props.pdfDetails)} </span> </div> <div className="flex flex-col"> <span className="text-[12px] font-bold text-[#424242] w-[100px] whitespace-nowrap overflow-hidden text-ellipsis"> - {pdfDetails.ExtUserPtr.Name} + {props.isSelfSign + ? (props.pdfDetails?.Signers && + props.pdfDetails?.Signers[0]?.Name) || + "User" + : props.pdfDetails.ExtUserPtr.Name || "User"} </span> <span className="text-[10px] font-medium text-[#424242] w-[100px] whitespace-nowrap overflow-hidden text-ellipsis"> - {pdfDetails.ExtUserPtr.Email} + {props.isSelfSign + ? (props.pdfDetails?.Signers && + props.pdfDetails?.Signers[0]?.Email) || + "" + : props.pdfDetails.ExtUserPtr.Email || ""} </span> </div> </div> diff --git a/apps/OpenSign/src/components/pdf/SignerListPlace.js b/apps/OpenSign/src/components/pdf/SignerListPlace.js index 33f90fa3e..0c3e6dab1 100644 --- a/apps/OpenSign/src/components/pdf/SignerListPlace.js +++ b/apps/OpenSign/src/components/pdf/SignerListPlace.js @@ -19,7 +19,7 @@ function SignerListPlace(props) { </sup> </a> <Tooltip id="my-tooltip" className="z-[100]"> - <div className="max-w-[450px] 2xl:max-w-[500px] 2xl:text-[20px] p-[1px]"> + <div className="max-w-[450px] 2xl:max-w-[500px] p-[1px]"> <p className="font-bold pb-[1px]">{t("role-help.p1")}</p> <p>{t("role-help.p2")} </p> <p className="font-bold">{t("role-help.p3")}</p> diff --git a/apps/OpenSign/src/components/pdf/WidgetComponent.js b/apps/OpenSign/src/components/pdf/WidgetComponent.js index e59220b68..4e6671a1c 100644 --- a/apps/OpenSign/src/components/pdf/WidgetComponent.js +++ b/apps/OpenSign/src/components/pdf/WidgetComponent.js @@ -5,107 +5,74 @@ import { useDrag } from "react-dnd"; import WidgetList from "./WidgetList"; import { color, + isMobile, radioButtonWidget, textInputWidget, textWidget, widgets } from "../../constant/Utils"; import { useTranslation } from "react-i18next"; -function WidgetComponent({ - dragSignature, - signRef, - handleDivClick, - handleMouseLeave, - dragStamp, - isSignYourself, - addPositionOfSignature, - signersdata, - isSelectListId, - setIsSelectId, - isSigners, - dataTut, - isMailSend, - handleAddSigner, - setUniqueId, - setRoleName, - handleDeleteUser, - signerPos, - handleRoleChange, - handleOnBlur, - title, - setSignersData, - sendInOrder, - isTemplateFlow, - setBlockColor, - setIsAddSigner, - uniqueId -}) { +function WidgetComponent(props) { const { t } = useTranslation(); + const signRef = useRef(null); + const userInformation = localStorage.getItem("UserInformation"); const [isSignersModal, setIsSignersModal] = useState(false); + const [, signature] = useDrag({ + type: "BOX", + item: { type: "BOX", id: 1, text: "signature" } + }); + const [, stamp] = useDrag({ + type: "BOX", + item: { type: "BOX", id: 2, text: "stamp" } + }); const [, dropdown] = useDrag({ type: "BOX", - item: { type: "BOX", id: 5, text: "dropdown" }, - collect: (monitor) => ({ - isDragDropdown: !!monitor.isDragging() - }) + item: { type: "BOX", id: 5, text: "dropdown" } }); const [, checkbox] = useDrag({ type: "BOX", - item: { type: "BOX", id: 6, text: "checkbox" }, - collect: (monitor) => ({ isDragCheck: !!monitor.isDragging() }) + item: { type: "BOX", id: 6, text: "checkbox" } }); const [, textInput] = useDrag({ type: "BOX", - item: { type: "BOX", id: 7, text: textInputWidget }, - collect: (monitor) => ({ isDragTextInput: !!monitor.isDragging() }) + item: { type: "BOX", id: 7, text: textInputWidget } }); const [, initials] = useDrag({ type: "BOX", - item: { type: "BOX", id: 8, text: "initials" }, - collect: (monitor) => ({ isDragInitial: !!monitor.isDragging() }) + item: { type: "BOX", id: 8, text: "initials" } }); const [, name] = useDrag({ type: "BOX", - item: { type: "BOX", id: 9, text: "name" }, - collect: (monitor) => ({ isDragName: !!monitor.isDragging() }) + item: { type: "BOX", id: 9, text: "name" } }); const [, company] = useDrag({ type: "BOX", - item: { type: "BOX", id: 10, text: "company" }, - collect: (monitor) => ({ isDragCompany: !!monitor.isDragging() }) + item: { type: "BOX", id: 10, text: "company" } }); const [, jobTitle] = useDrag({ type: "BOX", - item: { type: "BOX", id: 11, text: "job title" }, - collect: (monitor) => ({ isDragJobtitle: !!monitor.isDragging() }) + item: { type: "BOX", id: 11, text: "job title" } }); const [, date] = useDrag({ type: "BOX", - item: { type: "BOX", id: 12, text: "date" }, - collect: (monitor) => ({ isDragDate: !!monitor.isDragging() }) + item: { type: "BOX", id: 12, text: "date" } }); const [, image] = useDrag({ type: "BOX", - item: { type: "BOX", id: 13, text: "image" }, - collect: (monitor) => ({ isDragImage: !!monitor.isDragging() }) + item: { type: "BOX", id: 13, text: "image" } }); const [, email] = useDrag({ type: "BOX", - item: { type: "BOX", id: 14, text: "email" }, - collect: (monitor) => ({ isDragEmail: !!monitor.isDragging() }) + item: { type: "BOX", id: 14, text: "email" } }); const [, radioButton] = useDrag({ type: "BOX", - item: { type: "BOX", id: 15, text: radioButtonWidget }, - collect: (monitor) => ({ isDragRadiotton: !!monitor.isDragging() }) + item: { type: "BOX", id: 15, text: radioButtonWidget } }); const [, text] = useDrag({ type: "BOX", - item: { type: "BOX", id: 16, text: textWidget }, - collect: (monitor) => ({ isDragText: !!monitor.isDragging() }) + item: { type: "BOX", id: 16, text: textWidget } }); - const isMobile = window.innerWidth < 767; - const scrollContainerRef = useRef(null); const [widget, setWidget] = useState([]); const handleModal = () => { setIsSignersModal(!isSignersModal); @@ -113,8 +80,8 @@ function WidgetComponent({ useEffect(() => { const widgetRef = [ - dragSignature, - dragStamp, + signature, + stamp, initials, name, jobTitle, @@ -137,37 +104,67 @@ function WidgetComponent({ // eslint-disable-next-line }, []); + const modifiedWidgets = widget.filter( + (data) => + ![ + "dropdown", + radioButtonWidget, + textInputWidget, + "date", + "image", + "checkbox" + ].includes(data.type) + ); + const unlogedInUserWidgets = widget.filter( + (data) => + ![ + "dropdown", + radioButtonWidget, + textInputWidget, + "date", + "image", + "checkbox", + "name", + "email", + "job title", + "company" + ].includes(data.type) + ); const filterWidgets = widget.filter( (data) => - data.type !== "dropdown" && - data.type !== radioButtonWidget && - data.type !== textInputWidget + !["dropdown", radioButtonWidget, textInputWidget].includes(data.type) ); const textWidgetData = widget.filter((data) => data.type !== textWidget); - const updateWidgets = isSignYourself + const updateWidgets = props.isSignYourself ? filterWidgets - : isTemplateFlow + : props.isTemplateFlow ? textWidgetData - : widget; + : props.isAlllowModify + ? userInformation + ? modifiedWidgets + : unlogedInUserWidgets + : widget; const handleSelectRecipient = () => { if ( - signersdata[isSelectListId]?.Email || - signersdata[isSelectListId]?.Role + props.signersdata[props.isSelectListId]?.Email || + props.signersdata[props.isSelectListId]?.Role ) { const userData = - signersdata[isSelectListId]?.Name || signersdata[isSelectListId]?.Role; + props.signersdata[props.isSelectListId]?.Name || + props.signersdata[props.isSelectListId]?.Role; const name = userData?.length > 20 ? `${userData.slice(0, 20)}...` : userData; return name; } }; + return ( <> {isMobile ? ( - !isMailSend && ( + !props.isMailSend && ( <div id="navbar" className="fixed z-[99] bottom-0 right-0 w-full"> - {isSigners && ( + {props.isSigners && ( <div className="w-full mb-[5px] flex justify-center items-center gap-1"> <div className="w-full ml-[5px]" onClick={() => handleModal()}> <select @@ -175,8 +172,8 @@ function WidgetComponent({ className="w-full op-select op-select-bordered pointer-events-none" value={handleSelectRecipient()} style={{ - backgroundColor: isSelectListId - ? color[isSelectListId % color.length] + backgroundColor: props.blockColor + ? props.blockColor : color[0] }} > @@ -187,19 +184,19 @@ function WidgetComponent({ </div> <div className="w-[18%]"> - {handleAddSigner ? ( + {props.handleAddSigner ? ( <button data-tut="reactourAddbtn" - onClick={() => handleAddSigner()} + onClick={() => props.handleAddSigner()} className="op-btn op-btn-accent" > <i className="fa-light fa-plus "></i> </button> ) : ( - setIsAddSigner && ( + props.setIsAddSigner && ( <button data-tut="addRecipient" - onClick={() => setIsAddSigner(true)} + onClick={() => props.setIsAddSigner(true)} className="op-btn op-btn-accent" > <i className="fa-light fa-plus"></i> @@ -212,18 +209,16 @@ function WidgetComponent({ <div data-tut="addWidgets" - ref={scrollContainerRef} className="bg-base-100 border-[2px] border-t-primary" > <div className="flex whitespace-nowrap overflow-x-scroll pt-[10px] pb-[5px] pr-[5px]"> <WidgetList updateWidgets={updateWidgets} - handleDivClick={handleDivClick} - handleMouseLeave={handleMouseLeave} + handleDivClick={props.handleDivClick} + handleMouseLeave={props.handleMouseLeave} signRef={signRef} marginLeft={5} - addPositionOfSignature={addPositionOfSignature} - isMobile={isMobile} + addPositionOfSignature={props.addPositionOfSignature} /> </div> </div> @@ -231,23 +226,20 @@ function WidgetComponent({ ) ) : ( <div - data-tut={dataTut} + data-tut={props.dataTut} className={`${ - isMailSend ? "bg-opacity-50 pointer-events-none" : "" + props.isMailSend ? "bg-opacity-50 pointer-events-none" : "" } hidden md:block h-full bg-base-100`} > <div className="mx-2 pr-2 pt-2 pb-1 text-[15px] text-base-content font-semibold border-b-[1px] border-base-300"> <span>{t("fields")}</span> </div> - <div - className="p-[15px] flex flex-col pt-4 2xl:m-5" - data-tut="addWidgets" - > + <div className="p-[15px] flex flex-col pt-4" data-tut="addWidgets"> <WidgetList updateWidgets={updateWidgets} - handleDivClick={handleDivClick} - handleMouseLeave={handleMouseLeave} + handleDivClick={props.handleDivClick} + handleMouseLeave={props.handleMouseLeave} signRef={signRef} /> </div> @@ -255,32 +247,33 @@ function WidgetComponent({ )} {isSignersModal && ( <ModalUi - title={title ? title : t("recipients")} + title={props.title ? props.title : t("recipients")} isOpen={isSignersModal} handleClose={handleModal} > - {signersdata.length > 0 ? ( + {props.signersdata.length > 0 ? ( <div className="max-h-[600px] overflow-auto pb-1"> <RecipientList - signerPos={signerPos} - signersdata={signersdata} - isSelectListId={isSelectListId} - setIsSelectId={setIsSelectId} - setUniqueId={setUniqueId} - setRoleName={setRoleName} - handleDeleteUser={handleDeleteUser} - handleRoleChange={handleRoleChange} - handleOnBlur={handleOnBlur} + signerPos={props.signerPos} + signersdata={props.signersdata} + isSelectListId={props.isSelectListId} + setIsSelectId={props.setIsSelectId} + setUniqueId={props.setUniqueId} + setRoleName={props.setRoleName} + handleDeleteUser={props.handleDeleteUser} + handleRoleChange={props.handleRoleChange} + handleOnBlur={props.handleOnBlur} handleModal={handleModal} - sendInOrder={sendInOrder} - setSignersData={setSignersData} - setBlockColor={setBlockColor} - uniqueId={uniqueId} + sendInOrder={props.sendInOrder} + setSignersData={props.setSignersData} + setBlockColor={props.setBlockColor} + uniqueId={props.uniqueId} + setSignerPos={props.setSignerPos} /> </div> ) : ( <div className=" p-[20px] text-[15px] font-medium text-center"> - {t("please-add")} {title ? title : t("recipients")} + {t("please-add")} {props.title ? props.title : t("recipients")} </div> )} </ModalUi> diff --git a/apps/OpenSign/src/components/pdf/WidgetList.js b/apps/OpenSign/src/components/pdf/WidgetList.js index 2189a0e7d..f502eed2d 100644 --- a/apps/OpenSign/src/components/pdf/WidgetList.js +++ b/apps/OpenSign/src/components/pdf/WidgetList.js @@ -1,32 +1,23 @@ import React from "react"; -import { getWidgetType } from "../../constant/Utils"; +import { getWidgetType, isMobile } from "../../constant/Utils"; import { useTranslation } from "react-i18next"; function WidgetList(props) { const { t } = useTranslation(); - return props.updateWidgets.map((item, ind) => { return ( - <div className="2xl:p-3 mb-[5px]" key={ind}> + <div className="2xl:p-1 mb-[5px]" key={ind}> <div + data-tut="isSignatureWidget" className="select-none mx-[2px] md:mx-0 cursor-all-scroll" onClick={() => { props.addPositionOfSignature && props.addPositionOfSignature("onclick", item); }} - ref={(element) => { - if (!props.isMobile) { - item.ref(element); - if (element) { - if (props?.signRef) { - props.signRef.current = element; - } - } - } - }} - onMouseMove={props?.handleDivClick} - onMouseDown={() => props?.handleMouseLeave()} - onTouchStart={props?.handleDivClick} + ref={(element) => !isMobile && item.ref(element)} + onMouseMove={(e) => !isMobile && props?.handleDivClick(e)} + onMouseDown={() => !isMobile && props?.handleMouseLeave()} + onTouchStart={(e) => !isMobile && props?.handleDivClick(e)} > {item.ref && getWidgetType(item, t(`widgets-name.${item.type}`))} </div> diff --git a/apps/OpenSign/src/components/pdf/WidgetNameModal.js b/apps/OpenSign/src/components/pdf/WidgetNameModal.js index f20acf7a4..96bdf0dda 100644 --- a/apps/OpenSign/src/components/pdf/WidgetNameModal.js +++ b/apps/OpenSign/src/components/pdf/WidgetNameModal.js @@ -7,9 +7,6 @@ import { textInputWidget, textWidget } from "../../constant/Utils"; -import Upgrade from "../../primitives/Upgrade"; -import { isEnableSubscription } from "../../constant/const"; -import Tooltip from "../../primitives/Tooltip"; import { fontColorArr, fontsizeArr } from "../../constant/Utils"; import { useTranslation } from "react-i18next"; @@ -21,11 +18,11 @@ const WidgetNameModal = (props) => { defaultValue: "", status: "required", hint: "", - textvalidate: "" + textvalidate: "", + isReadOnly: false }); const [isValid, setIsValid] = useState(true); const statusArr = ["Required", "Optional"]; - const inputOpt = ["text", "email", "number"]; const [signatureType, setSignatureType] = useState([]); useEffect(() => { @@ -38,7 +35,8 @@ const WidgetNameModal = (props) => { textvalidate: props.defaultdata?.options?.validation?.type === "regex" ? props.defaultdata?.options?.validation?.pattern - : props.defaultdata?.options?.validation?.type || "" + : props.defaultdata?.options?.validation?.type || "", + isReadOnly: props.defaultdata?.options?.isReadOnly || false }); } else { setFormdata({ @@ -73,6 +71,7 @@ const WidgetNameModal = (props) => { props.handleData(formdata); } setFormdata({ + isReadOnly: false, name: "", defaultValue: "", status: "required", @@ -114,35 +113,24 @@ const WidgetNameModal = (props) => { } } - function handleBlurRegex() { - if (!formdata.textvalidate) { - setFormdata({ ...formdata, textvalidate: "" }); - } else { - if (formdata.defaultValue) { - const regexObject = RegexParser( - handleValidation(formdata.textvalidate) - ); - const isValidate = regexObject?.test(formdata.defaultValue); - if (isValidate === false) { - setFormdata({ ...formdata, defaultValue: "" }); - } - } - } - } const handleCheckboxChange = (index) => { - // Create a copy of the signatureType array - const updatedSignatureType = [...signatureType]; - // Toggle the enabled value for the clicked item - updatedSignatureType[index].enabled = !updatedSignatureType[index].enabled; // Update the state with the modified array - setSignatureType(updatedSignatureType); + setSignatureType((prev) => + prev.map((item, i) => + i === index ? { ...item, enabled: !item.enabled } : item + ) + ); }; return ( <ModalUi isOpen={props.isOpen} handleClose={props.handleClose && props.handleClose} - title={t("widget-info")} + title={ + ["signature", "initials"].includes(props.defaultdata?.type) + ? t("signature-setting") + : t("widget-info") + } > <form onSubmit={handleSubmit} @@ -173,69 +161,6 @@ const WidgetNameModal = (props) => { )} {props.defaultdata?.type === textInputWidget && ( <> - {isEnableSubscription && ( - <div className="mb-[0.75rem]"> - <div className="flex items-center gap-1"> - <label - htmlFor="textvalidate" - className={`${ - !props.isSubscribe && isEnableSubscription - ? "bg-opacity-50 pointer-events-none" - : "" - } text-[13px]`} - > - {t("validation")} - </label> - <Tooltip - url={"https://www.w3schools.com/jsref/jsref_obj_regexp.asp"} - /> - {!props.isSubscribe && isEnableSubscription && <Upgrade />} - </div> - <div - className={`${ - !props.isSubscribe && isEnableSubscription - ? "bg-opacity-50 pointer-events-none" - : "" - } flex flex-row gap-[10px] mb-[0.5rem]`} - > - <div className="w-full relative group"> - <input - className="z-20 relative op-input op-input-bordered rounded-r-none op-input-sm focus:outline-none group-hover:border-base-content w-[87%] md:w-[92%] text-xs" - name="textvalidate" - placeholder="Enter custom regular expression" - value={formdata.textvalidate} - onChange={(e) => handleChange(e)} - // onBlur={() => handleBlurRegex()} - /> - <select - className="validationlist op-input op-input-bordered op-input-sm focus:outline-none group-hover:border-base-content w-full text-xs" - name="textvalidate" - value={formdata.textvalidate} - onChange={(e) => handleChange(e)} - onBlur={() => handleBlurRegex()} - > - <option - disabled={formdata?.textvalidate} - className="text-[13px]" - > - Select... - </option> - {inputOpt.map((data, ind) => { - return ( - <option - className="text-[13px]" - key={ind} - value={data} - > - {data} - </option> - ); - })} - </select> - </div> - </div> - </div> - )} <div className="mb-[0.75rem]"> <label htmlFor="name" className="text-[13px]"> {t("default-value")} @@ -268,7 +193,9 @@ const WidgetNameModal = (props) => { </div> </> )} - {!["signature", "initials"].includes(props.defaultdata?.type) && ( + {!["signature", "initials", textWidget].includes( + props.defaultdata?.type + ) && ( <div className="mb-[0.75rem]"> <div className="flex flex-row gap-[10px] mb-[0.5rem]"> {statusArr.map((data, ind) => { @@ -295,6 +222,26 @@ const WidgetNameModal = (props) => { ); })} </div> + {[textInputWidget].includes(props.defaultdata?.type) && ( + <div className="flex items-center"> + <input + id="isReadOnly" + name="isReadOnly" + type="checkbox" + checked={formdata.isReadOnly} + className="op-checkbox op-checkbox-xs" + onChange={() => + setFormdata((prev) => ({ + ...formdata, + isReadOnly: !prev.isReadOnly + })) + } + /> + <label className="ml-1 mb-0" htmlFor="isreadonly"> + {t("read-only")} + </label> + </div> + )} </div> )} {["signature", "initials"].includes(props.defaultdata?.type) && ( diff --git a/apps/OpenSign/src/components/shared/fields/DropboxChoose.js b/apps/OpenSign/src/components/shared/fields/DropboxChoose.js deleted file mode 100644 index 5c8cf80d5..000000000 --- a/apps/OpenSign/src/components/shared/fields/DropboxChoose.js +++ /dev/null @@ -1,60 +0,0 @@ -import React, { useCallback, useMemo } from "react"; -import { useDropScript } from "../../../hook/useScript"; - -const DROPBOX_APP_KEY = process.env.REACT_APP_DROPBOX_API_KEY; // App key -const DROPBOX_SDK_URL = "https://www.dropbox.com/static/api/2/dropins.js"; -const DROPBOX_SCRIPT_ID = "dropboxjs"; - -export default function DropboxChooser({ children, onSuccess, onCancel }) { - useDropScript(DROPBOX_SDK_URL, { - attrs: { id: DROPBOX_SCRIPT_ID, "data-app-key": DROPBOX_APP_KEY } - }); - - const options = useMemo( - () => ({ - // Required. Called when a user selects an item in the Chooser. - success: (files) => { - // console.log("success", files); - onSuccess && onSuccess(files); - }, - // Optional. Called when the user closes the dialog without selecting a file - // and does not include any parameters. - cancel: () => { - console.log("cancel"); - onCancel && onCancel(); - }, - - // Optional. "preview" (default) is a preview link to the document for sharing, - // "direct" is an expiring link to download the contents of the file. For more - linkType: "direct", // or "preview" - multiselect: false, // 是否支持多选 - extensions: [".pdf"], - - // Optional. A value of false (default) limits selection to files, - // while true allows the user to select both folders and files. - // You cannot specify `linkType: "direct"` when using `folderselect: true`. - folderselect: false // or true - }), - [onSuccess, onCancel] - ); - - const handleChoose = useCallback( - (e) => { - e.preventDefault(); - if (window.Dropbox) { - window.Dropbox.choose(options); - } - }, - [options] - ); - - return ( - <div onClick={handleChoose}> - {children || ( - <button className="cursor-pointer op-input op-input-bordered focus:outline-none hover:border-base-content max-h-[35px] max-w-[45px] flex justify-center items-center"> - <i className="fa-brands fa-dropbox"></i> - </button> - )} - </div> - ); -} diff --git a/apps/OpenSign/src/components/shared/fields/SelectSigners.js b/apps/OpenSign/src/components/shared/fields/SelectSigners.js index 50b65ea6f..b7733a4d7 100644 --- a/apps/OpenSign/src/components/shared/fields/SelectSigners.js +++ b/apps/OpenSign/src/components/shared/fields/SelectSigners.js @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import AsyncSelect from "react-select/async"; import { useTranslation } from "react-i18next"; import axios from "axios"; @@ -9,12 +9,42 @@ const SelectSigners = (props) => { const [selected, setSelected] = useState(); const [userData, setUserData] = useState({}); const [isError, setIsError] = useState(false); + + useEffect(() => { + //condition to check already assign signer exist if yes then show signer's email on dropdown input box + if (userList.length > 0 && props.isExistSigner) { + const alreadyAssign = userList.find( + (item) => item.objectId === props.isExistSigner.signerObjId + ); + if (alreadyAssign) { + setSelected({ + label: `${alreadyAssign.Name}<${alreadyAssign.Email}>`, + value: alreadyAssign.objectId + }); + } + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [userList]); // `handleOptions` is used to set just save from quick form to selected option in dropdown const handleOptions = (item) => { - setSelected(item); - const userData = userList.find((x) => x.objectId === item.value); - if (userData) { - setUserData(userData); + //checking if user select no signer option from dropdown + if (item) { + //checking selected signer is already assign to the document or not + const alreadyAssign = props.signersData.some( + (item2) => item2.objectId === item.value + ); + if (alreadyAssign) { + alert(t("already-exist-signer")); + setSelected(""); + } else { + setSelected(item); + const userData = userList.find((x) => x.objectId === item.value); + if (userData) { + setUserData(userData); + } + } + } else { + setSelected(item); } }; const handleAdd = () => { @@ -28,39 +58,44 @@ const SelectSigners = (props) => { setTimeout(() => setIsError(false), 1000); } }; - + //function to use remove signer from assigned widgets in create template flow + const handleRemove = () => { + props.handleUnlinkSigner(); + if (props.closePopup) { + props.closePopup(); + } + }; const loadOptions = async (inputValue) => { try { const baseURL = localStorage.getItem("baseUrl"); const url = `${baseURL}functions/getsigners`; - const token = props.jwttoken - ? { jwttoken: props.jwttoken } - : { "X-Parse-Session-Token": localStorage.getItem("accesstoken") }; + const token = + { "X-Parse-Session-Token": localStorage.getItem("accesstoken") }; const headers = { "Content-Type": "application/json", "X-Parse-Application-Id": localStorage.getItem("parseAppId"), ...token }; - const searchEmail = inputValue ? inputValue : ""; - const axiosRes = await axios.post(url, { searchEmail }, { headers }); + const search = inputValue; + const axiosRes = await axios.post(url, { search }, { headers }); const contactRes = axiosRes?.data?.result || []; if (contactRes) { const res = JSON.parse(JSON.stringify(contactRes)); //compareArrays is a function where compare between two array (total signersList and dcument signers list) //and filter signers from total signer's list which already present in document's signers list - const compareArrays = (res, signerObj) => { - return res.filter( - (item1) => - !signerObj.find((item2) => item2.objectId === item1.objectId) - ); - }; + // const compareArrays = (res, signerObj) => { + // return res.filter( + // (item1) => + // !signerObj.find((item2) => item2.objectId === item1.objectId) + // ); + // }; //get update signer's List if signersdata is present - const updateSignersList = - props?.signersData && compareArrays(res, props?.signersData); - const result = updateSignersList ? updateSignersList : res; + // const updateSignersList = + // props?.signersData && compareArrays(res, props?.signersData); + const result = res; setUserList(result); return await result.map((item) => ({ - label: item.Email, + label: `${item.Name}<${item.Email}>`, value: item.objectId })); } @@ -75,31 +110,45 @@ const SelectSigners = (props) => { <label className="text-[14px] font-bold"> {t("choose-from-contacts")} </label> - <AsyncSelect - cacheOptions - defaultOptions - value={selected} - loadingMessage={() => t("loading")} - noOptionsMessage={() => t("contact-not-found")} - loadOptions={loadOptions} - onChange={handleOptions} - unstyled - onFocus={() => loadOptions()} - classNames={{ - control: () => - "op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full h-full text-[11px]", - valueContainer: () => - "flex flex-row gap-x-[2px] gap-y-[2px] md:gap-y-0 w-full my-[2px]", - multiValue: () => "op-badge op-badge-primary h-full text-[11px]", - multiValueLabel: () => "mb-[2px]", - menu: () => - "mt-1 shadow-md rounded-lg bg-base-200 text-base-content", - menuList: () => "shadow-md rounded-lg overflow-hidden", - option: () => - "bg-base-200 text-base-content rounded-lg m-1 hover:bg-base-300 p-2", - noOptionsMessage: () => "p-2 bg-base-200 rounded-lg m-1 p-2" - }} - /> + <div className="flex gap-2 "> + <div className="flex-1"> + <AsyncSelect + cacheOptions + defaultOptions + value={selected} + loadingMessage={() => t("loading")} + noOptionsMessage={() => t("contact-not-found")} + loadOptions={loadOptions} + onChange={handleOptions} + unstyled + onFocus={() => loadOptions()} + classNames={{ + control: () => + "op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full h-full text-[11px]", + valueContainer: () => + "flex flex-row gap-x-[2px] gap-y-[2px] md:gap-y-0 w-full my-[2px]", + multiValue: () => + "op-badge op-badge-primary h-full text-[11px]", + multiValueLabel: () => "mb-[2px]", + menu: () => + "mt-1 shadow-md rounded-lg bg-base-200 text-base-content absolute z-9999", + menuList: () => "shadow-md rounded-lg ", + option: () => + "bg-base-200 text-base-content rounded-lg m-1 hover:bg-base-300 p-2 ", + noOptionsMessage: () => "p-2 bg-base-200 rounded-lg m-1 p-2" + }} + menuPortalTarget={document.getElementById("selectSignerModal")} + /> + </div> + {!props.isContact && ( + <button + onClick={() => props.setIsContact(true)} + className="op-btn op-btn-accent op-btn-outline op-btn-sm " + > + <i className="fa-light fa-plus"></i> + </button> + )} + </div> </div> <p className={`${ @@ -108,10 +157,18 @@ const SelectSigners = (props) => { > {t("select-signer")} </p> - <div> + <div className="flex gap-2"> <button className="op-btn op-btn-primary" onClick={() => handleAdd()}> {t("submit")} </button> + {props.isExistSigner && props.handleUnlinkSigner && ( + <button + className="op-btn op-btn-accent op-btn-outline" + onClick={() => handleRemove()} + > + {t("no-signer")} + </button> + )} </div> </div> </div> diff --git a/apps/OpenSign/src/components/shared/fields/SignersInput.js b/apps/OpenSign/src/components/shared/fields/SignersInput.js index 0bfed21f1..73dc9c79f 100644 --- a/apps/OpenSign/src/components/shared/fields/SignersInput.js +++ b/apps/OpenSign/src/components/shared/fields/SignersInput.js @@ -37,9 +37,32 @@ const SignersInput = (props) => { const [state, setState] = useState(undefined); const [selected, setSelected] = useState([]); const [isModal, setIsModel] = useState(false); - const onChange = (selectedOptions) => setSelected(selectedOptions); const [modalIsOpen, setModalIsOpen] = useState(false); + useEffect(() => { + // to provide initial data for selected list items in Bcc for edit template + if (props?.initialData && props?.initialData?.length > 0) { + const trimEmail = props?.initialData.map((item) => ({ + value: item?.objectId, + label: item?.Name, + email: item?.Email + })); + setSelected(trimEmail); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + const onChange = (selectedOptions) => { + if (selectedOptions && selectedOptions?.length > 0) { + const trimEmail = selectedOptions.map((item) => ({ + ...item, + label: item?.label?.split("<")?.shift() + })); + setSelected(trimEmail); + } else { + setSelected(selectedOptions); + } + }; + const onSortEnd = ({ oldIndex, newIndex }) => { const newValue = arrayMove(selected, oldIndex, newIndex); setSelected(newValue); @@ -55,7 +78,11 @@ const SignersInput = (props) => { if (selected && selected.length) { let newData = []; selected.forEach((x) => { - newData.push(x.value); + if (props?.isCaptureAllData) { + newData.push(x); + } else { + newData.push(x.value); + } }); if (props.onChange) { props.onChange(newData); @@ -85,17 +112,8 @@ const SignersInput = (props) => { }; const loadOptions = async (inputValue) => { try { - const currentUser = Parse.User.current(); - const contactbook = new Parse.Query("contracts_Contactbook"); - contactbook.equalTo( - "CreatedBy", - Parse.User.createWithoutData(currentUser.id) - ); - if (inputValue.length > 1) { - contactbook.matches("Name", new RegExp(inputValue, "i")); - } - contactbook.notEqualTo("IsDeleted", true); - const contactRes = await contactbook.find(); + const params = { search: inputValue }; + const contactRes = await Parse.Cloud.run("getsigners", params); if (contactRes) { const res = JSON.parse(JSON.stringify(contactRes)); //compareArrays is a function where compare between two array (total signersList and dcument signers list) @@ -114,8 +132,9 @@ const SignersInput = (props) => { const result = updateSignersList ? updateSignersList : res; setState(result); return await result.map((item) => ({ - label: item.Name, + label: item.Name + "<" + item.Email + ">", value: item.objectId, + email: item.Email, isChecked: true })); } @@ -126,14 +145,19 @@ const SignersInput = (props) => { return ( <div className="text-xs mt-2 "> <label className="block relative"> - {t("signers")} + {props.label ? props.label : t("signers")} {props.required && <span className="text-red-500 text-[13px]">*</span>} - <span className="absolute ml-1 text-xs z-30"> - <Tooltip id={"signer-tooltip"} message={t("signers-help")} /> + <span + className={`z-[${props?.helptextZindex ? props.helptextZindex : 30}] absolute ml-1 text-xs`} + > + <Tooltip + id={`${props.label ? props.label : "signers"}-tooltip`} + message={props.helpText ? props.helpText : t("signers-help")} + /> </span> </label> <div className="flex gap-x-[5px]"> - <div className="w-full"> + <div className="w-full z-40"> <AsyncSelect onSortEnd={onSortEnd} distance={4} @@ -176,7 +200,7 @@ const SignersInput = (props) => { </div> <AddSignerModal isOpen={modalIsOpen}> <h3 className="text-base-content font-bold text-lg pt-[15px] px-[20px]"> - {t("add-signer")} + {t("add-contact")} </h3> <button onClick={handleModalCloseClick} diff --git a/apps/OpenSign/src/components/shared/fields/SuggestionInput.js b/apps/OpenSign/src/components/shared/fields/SuggestionInput.js index 797515aec..b616f425d 100644 --- a/apps/OpenSign/src/components/shared/fields/SuggestionInput.js +++ b/apps/OpenSign/src/components/shared/fields/SuggestionInput.js @@ -25,7 +25,9 @@ const SuggestionInput = (props) => { if (timer) clearTimeout(timer); timer = setTimeout(() => { (async () => { - const res = await findContact(inputValue, props.jwttoken); + const res = await findContact( + inputValue, + ); if (res?.length > 0) { setSuggestions(res); setShowSuggestions(true); @@ -74,7 +76,7 @@ const SuggestionInput = (props) => { {showSuggestions && ( <ul ref={ref} - className="absolute z-50 left-0 top-[2.55rem] w-full max-h-[100px] overflow-auto bg-base-200 border border-gray-300 rounded shadow-md" + className="absolute z-50 left-0 top-[2.55rem] w-full max-h-[100px] overflow-y-auto bg-base-200 border border-gray-300 rounded shadow-md" > {suggestions.map((suggestion, index) => ( <li @@ -82,7 +84,7 @@ const SuggestionInput = (props) => { className="py-2 px-2 w-full text-sm cursor-pointer hover:bg-base-300" onClick={() => handleSuggestionClick(suggestion)} > - {suggestion.Email} + {suggestion.Name} {"<" + suggestion.Email + ">"} </li> ))} </ul> diff --git a/apps/OpenSign/src/components/shared/fields/TimezoneSelector.js b/apps/OpenSign/src/components/shared/fields/TimezoneSelector.js new file mode 100644 index 000000000..4aaf74219 --- /dev/null +++ b/apps/OpenSign/src/components/shared/fields/TimezoneSelector.js @@ -0,0 +1,72 @@ +import { t } from "i18next"; +import React, { useState } from "react"; +import TimezoneSelect from "react-timezone-select"; + +const TimezoneSelector = (props) => { + const [selectedTimezone, setSelectedTimezone] = useState(props?.timezone); + // Intl.DateTimeFormat().resolvedOptions().timeZone // Default to the user's local timezone + + const onChangeTimezone = (timezone) => { + setSelectedTimezone(timezone); + props.setTimezone && props.setTimezone(timezone?.value); + }; + + // Format date and time for the selected timezone + const formatDate = (date, timezone) => { + return timezone + ? new Intl.DateTimeFormat("en-US", { + weekday: "short", + year: "numeric", + month: "short", + day: "numeric", + hour: "2-digit", + minute: "2-digit", + second: "2-digit", + timeZone: timezone, + hour12: false + }).format(date) + : new Date(date).toUTCString(); + }; + + return ( + <> + <div className="max-w-[400px] pr-[20px]"> + <h1 className="text-[14px] mb-[0.7rem] font-medium"> + {t("select-timezone")} + </h1> + <TimezoneSelect + value={selectedTimezone} + onChange={(timezone) => onChangeTimezone(timezone)} + unstyled + classNames={{ + control: () => + "op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full h-full text-[11px]", + valueContainer: () => + "flex flex-row gap-x-[2px] gap-y-[2px] md:gap-y-0 w-full my-[2px]", + multiValue: () => "op-badge op-badge-primary h-full text-[11px]", + multiValueLabel: () => "mb-[2px]", + menu: () => + "mt-1 shadow-md rounded-lg bg-base-200 text-base-content", + menuList: () => "shadow-md rounded-lg overflow-hidden", + option: () => + "bg-base-200 text-base-content rounded-lg m-1 hover:bg-base-300 p-2", + noOptionsMessage: () => "p-2 bg-base-200 rounded-lg m-1 p-2" + }} + /> + </div> + <div className="mt-[20px] text-[13px]"> + <p> + {t("current-time")}:{" "} + <strong> + {formatDate( + new Date(), + selectedTimezone?.value || selectedTimezone + )} + </strong>{" "} + </p> + </div> + </> + ); +}; + +export default TimezoneSelector; diff --git a/apps/OpenSign/src/components/sidebar/Menu.js b/apps/OpenSign/src/components/sidebar/Menu.js index c8cf57e8d..db0dc731b 100644 --- a/apps/OpenSign/src/components/sidebar/Menu.js +++ b/apps/OpenSign/src/components/sidebar/Menu.js @@ -1,6 +1,6 @@ import React from "react"; import { useTranslation } from "react-i18next"; -import { NavLink } from "react-router-dom"; +import { NavLink } from "react-router"; const Menu = ({ item, isOpen, closeSidebar }) => { const { t } = useTranslation(); diff --git a/apps/OpenSign/src/components/sidebar/Sidebar.js b/apps/OpenSign/src/components/sidebar/Sidebar.js index 84c6404ac..2bc2831ef 100644 --- a/apps/OpenSign/src/components/sidebar/Sidebar.js +++ b/apps/OpenSign/src/components/sidebar/Sidebar.js @@ -3,9 +3,8 @@ import Menu from "./Menu"; import Submenu from "./SubMenu"; import SocialMedia from "./SocialMedia"; import dp from "../../assets/images/dp.png"; -import sidebarList from "../../json/menuJson"; -import { useNavigate } from "react-router-dom"; -import { isEnableSubscription } from "../../constant/const"; +import sidebarList, { subSetting } from "../../json/menuJson"; +import { useNavigate } from "react-router"; const Sidebar = ({ isOpen, closeSidebar }) => { const navigate = useNavigate(); @@ -41,47 +40,14 @@ const Sidebar = ({ isOpen, closeSidebar }) => { if (item.title === "Settings") { // Make a shallow copy of the item const newItem = { ...item }; - if (isEnableSubscription) { - newItem.children = [ - ...newItem.children, - { - icon: "fa-light fa-building-memo", - title: "Teams", - target: "_self", - pageType: "", - description: "", - objectId: "teams" - }, - { - icon: "fa-light fa-users fa-fw", - title: "Users", - target: "_self", - pageType: "", - description: "", - objectId: "users" - } - ]; - } else { const arr = newItem.children.slice(0, 1); - newItem.children = [ - ...arr, - { - icon: "fa-light fa-users fa-fw", - title: "Users", - target: "_self", - pageType: "", - description: "", - objectId: "users" - } - ]; - } + newItem.children = [...arr, ...subSetting]; return newItem; } return item; }); setmenuList(newSidebarList); } else { - if (!isEnableSubscription) { const newSidebarList = sidebarList.map((item) => { if (item.title === "Settings") { // Make a shallow copy of the item @@ -93,9 +59,6 @@ const Sidebar = ({ isOpen, closeSidebar }) => { return item; }); setmenuList(newSidebarList); - } else { - setmenuList(sidebarList); - } } } } catch (e) { @@ -112,6 +75,7 @@ const Sidebar = ({ isOpen, closeSidebar }) => { setSubmenuOpen({}); }; const handleProfile = () => { + closeSidebar(); navigate("/profile"); }; return ( diff --git a/apps/OpenSign/src/components/sidebar/SocialMedia.js b/apps/OpenSign/src/components/sidebar/SocialMedia.js index a1d0aeb01..02655436f 100644 --- a/apps/OpenSign/src/components/sidebar/SocialMedia.js +++ b/apps/OpenSign/src/components/sidebar/SocialMedia.js @@ -1,6 +1,6 @@ import React from "react"; import { useTranslation } from "react-i18next"; -import { NavLink } from "react-router-dom"; +import { NavLink } from "react-router"; const SocialMedia = () => { const { t } = useTranslation(); diff --git a/apps/OpenSign/src/components/sidebar/SubMenu.js b/apps/OpenSign/src/components/sidebar/SubMenu.js index 2ad5e3dbe..f186cc7f0 100644 --- a/apps/OpenSign/src/components/sidebar/SubMenu.js +++ b/apps/OpenSign/src/components/sidebar/SubMenu.js @@ -1,6 +1,6 @@ import React from "react"; import { useTranslation } from "react-i18next"; -import { NavLink } from "react-router-dom"; +import { NavLink } from "react-router"; const Submenu = ({ item, closeSidebar, toggleSubmenu, submenuOpen }) => { const { t } = useTranslation(); diff --git a/apps/OpenSign/src/constant/Utils.js b/apps/OpenSign/src/constant/Utils.js index 808d6c633..29956fe7a 100644 --- a/apps/OpenSign/src/constant/Utils.js +++ b/apps/OpenSign/src/constant/Utils.js @@ -6,12 +6,13 @@ import Parse from "parse"; import { appInfo } from "./appinfo"; import { saveAs } from "file-saver"; import printModule from "print-js"; -import { validplan } from "../json/plansArr"; import fontkit from "@pdf-lib/fontkit"; export const fontsizeArr = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28]; export const fontColorArr = ["red", "black", "blue", "yellow"]; export const isMobile = window.innerWidth < 767; +export const isTab = 767 < window.innerWidth < 1023; +export const isHighResolution = window.innerWidth > 1023; export const isTabAndMobile = window.innerWidth < 1023; export const textInputWidget = "text input"; export const textWidget = "text"; @@ -30,124 +31,25 @@ export const openInNewTab = (url, target) => { } }; -export async function fetchSubscription( - extUserId, - contactObjId, - isGuestSign = false, - isPublic = false, - jwtToken -) { - try { - const Extand_Class = localStorage.getItem("Extand_Class"); - const extClass = Extand_Class && JSON.parse(Extand_Class); - // console.log("extClass ", extClass); - let extUser; - if (extClass && extClass.length > 0 && !isPublic) { - extUser = extClass[0].objectId; - } else { - extUser = extUserId; - } - const baseURL = localStorage.getItem("baseUrl"); - const url = `${baseURL}functions/getsubscriptions`; - const token = jwtToken - ? { jwttoken: jwtToken } - : { sessionToken: localStorage.getItem("accesstoken") }; - const headers = { - "Content-Type": "application/json", - "X-Parse-Application-Id": localStorage.getItem("parseAppId"), - ...token - }; - const params = isGuestSign - ? { contactId: contactObjId } - : { extUserId: extUser, ispublic: isPublic }; - const tenatRes = await axios.post(url, params, { headers: headers }); - let plan, status, billingDate, adminId; - if (isGuestSign) { - plan = tenatRes.data?.result?.result?.plan; - status = tenatRes.data?.result?.result?.isSubscribed; - } else { - plan = tenatRes.data?.result?.result?.PlanCode; - billingDate = tenatRes.data?.result?.result?.Next_billing_date?.iso; - const allowedUsers = tenatRes.data?.result?.result?.AllowedUsers || 0; - adminId = tenatRes?.data?.result?.result?.ExtUserPtr?.objectId; - localStorage.setItem("allowedUsers", allowedUsers); - } - return { plan, billingDate, status, adminId }; - } catch (err) { - console.log("Err in fetch subscription", err); - return { plan: "", billingDate: "", status: "", adminId: "" }; - } -} - -export async function fetchSubscriptionInfo() { - try { - const Extand_Class = localStorage.getItem("Extand_Class"); - const extClass = Extand_Class && JSON.parse(Extand_Class); - // console.log("extClass ", extClass); - if (extClass && extClass.length > 0) { - const extUser = extClass[0].objectId; - const baseURL = localStorage.getItem("baseUrl"); - const url = `${baseURL}functions/getsubscriptions`; - const headers = { - "Content-Type": "application/json", - "X-Parse-Application-Id": localStorage.getItem("parseAppId"), - sessionToken: localStorage.getItem("accesstoken") - }; - const params = { extUserId: extUser }; - const tenatRes = await axios.post(url, params, { headers: headers }); - - const price = - tenatRes.data?.result?.result?.SubscriptionDetails?.data?.subscription - ?.plan?.price; - const totalPrice = - tenatRes.data?.result?.result?.SubscriptionDetails?.data?.subscription - ?.amount; - const planId = - tenatRes.data?.result?.result?.SubscriptionDetails?.data?.subscription - ?.subscription_id; - const plan_code = tenatRes.data?.result?.result?.PlanCode; - const totalAllowedUser = tenatRes.data?.result?.result?.AllowedUsers || 0; - const adminId = - tenatRes?.data?.result?.result?.ExtUserPtr?.objectId || ""; - - return { - status: "success", - price: price, - totalPrice: totalPrice, - planId: planId, - plan_code: plan_code, - totalAllowedUser: totalAllowedUser, - adminId: adminId - }; - } - } catch (err) { - console.log("Err in fetch subscription", err); - return { status: "error", error: err }; - } -} -//function to get subcripition details from subscription class -export async function checkIsSubscribed(jwttoken) { - try { - const res = await fetchSubscription("", "", false, false, jwttoken); - if (res.plan === "freeplan") { - return { plan: res.plan, isValid: false, adminId: res?.adminId }; - } else if (res.billingDate) { - const plan = validplan[res.plan] || false; - if (plan && new Date(res.billingDate) > new Date()) { - return { plan: res.plan, isValid: true, adminId: res?.adminId }; - } else if (new Date(res.billingDate) > new Date()) { - return { plan: res.plan, isValid: true, adminId: res?.adminId }; +// `getSecureUrl` is used to return local secure url if local files +export const getSecureUrl = async (url) => { + const fileUrl = new URL(url)?.pathname?.includes("files"); + if (fileUrl) { + try { + const fileRes = await Parse.Cloud.run("fileupload", { url: url }); + if (fileRes.url) { + return { url: fileRes.url }; } else { - return { plan: res.plan, isValid: false, adminId: res?.adminId }; + return { url: "" }; } - } else { - return { plan: res.plan, isValid: false, adminId: res?.adminId }; + } catch (err) { + console.log("err while fileupload ", err); + return { url: "" }; } - } catch (err) { - console.log("Err in fetch subscription", err); - return { plan: "no-plan", isValid: false, adminId: "" }; + } else { + return { url: url }; } -} +}; export const color = [ "#93a3db", @@ -189,7 +91,7 @@ export const toDataUrl = (file) => { }; //function for getting document details for getDrive cloud function -export const getDrive = async (documentId, skip = 0, limit = 100) => { +export const getDrive = async (documentId, skip = 0, limit = 50) => { const data = { docId: documentId && documentId, limit: limit, @@ -230,14 +132,14 @@ export const pdfNewWidthFun = (divRef) => { }; //`contractUsers` function is used to get contract_User details -export const contractUsers = async (jwttoken) => { +export const contractUsers = async ( +) => { try { const url = `${localStorage.getItem("baseUrl")}functions/getUserDetails`; const parseAppId = localStorage.getItem("parseAppId"); const accesstoken = localStorage.getItem("accesstoken"); - const token = jwttoken - ? { jwttoken: jwttoken } - : { "X-Parse-Session-Token": accesstoken }; + const token = + { "X-Parse-Session-Token": accesstoken }; const headers = { headers: { "Content-Type": "application/json", @@ -310,76 +212,24 @@ export const handleImageResize = ( } }; export const widgets = [ - { - type: "signature", - icon: "fa-light fa-pen-nib", - iconSize: "20px" - }, - { - type: "stamp", - icon: "fa-light fa-stamp", - iconSize: "19px" - }, - { - type: "initials", - icon: "fa-light fa-signature", - iconSize: "15px" - }, - { - type: "name", - icon: "fa-light fa-user", - iconSize: "21px" - }, - { - type: "job title", - icon: "fa-light fa-address-card", - iconSize: "17px" - }, - { - type: "company", - icon: "fa-light fa-building", - iconSize: "25px" - }, - { - type: "date", - icon: "fa-light fa-calendar-days", - iconSize: "20px" - }, - { - type: textWidget, - icon: "fa-light fa-text-width", - iconSize: "20px" - }, - { - type: textInputWidget, - icon: "fa-light fa-font", - iconSize: "21px" - }, - { - type: "checkbox", - icon: "fa-light fa-square-check", - iconSize: "22px" - }, + { type: "signature", icon: "fa-light fa-pen-nib", iconSize: "20px" }, + { type: "stamp", icon: "fa-light fa-stamp", iconSize: "19px" }, + { type: "initials", icon: "fa-light fa-signature", iconSize: "15px" }, + { type: "name", icon: "fa-light fa-user", iconSize: "21px" }, + { type: "job title", icon: "fa-light fa-address-card", iconSize: "17px" }, + { type: "company", icon: "fa-light fa-building", iconSize: "25px" }, + { type: "date", icon: "fa-light fa-calendar-days", iconSize: "20px" }, + { type: textWidget, icon: "fa-light fa-text-width", iconSize: "20px" }, + { type: textInputWidget, icon: "fa-light fa-font", iconSize: "21px" }, + { type: "checkbox", icon: "fa-light fa-square-check", iconSize: "22px" }, { type: "dropdown", icon: "fa-light fa-circle-chevron-down", iconSize: "19px" }, - { - type: radioButtonWidget, - icon: "fa-light fa-circle-dot", - iconSize: "20px" - }, - { - type: "image", - icon: "fa-light fa-image", - iconSize: "20px" - }, - { - type: "email", - icon: "fa-light fa-envelope", - iconSize: "20px" - } + { type: radioButtonWidget, icon: "fa-light fa-circle-dot", iconSize: "20px" }, + { type: "image", icon: "fa-light fa-image", iconSize: "20px" }, + { type: "email", icon: "fa-light fa-envelope", iconSize: "20px" } ]; export const getDate = () => { @@ -404,7 +254,7 @@ export const addWidgetOptions = (type) => { options: { isReadOnly: false, isHideLabel: false } }; case textInputWidget: - return { ...defaultOpt }; + return { ...defaultOpt, isReadOnly: false }; case "initials": return defaultOpt; case "name": @@ -438,6 +288,55 @@ export const addWidgetOptions = (type) => { return {}; } }; + +export const addWidgetSelfsignOptions = (type, getWidgetValue) => { + switch (type) { + case "signature": + return { name: "signature" }; + case "stamp": + return { name: "stamp" }; + case "checkbox": + return { name: "checkbox" }; + case textWidget: + return { name: "text" }; + case "initials": + return { name: "initials" }; + case "name": + return { + name: "name", + defaultValue: getWidgetValue(type), + validation: { type: "text", pattern: "" } + }; + case "company": + return { + name: "company", + defaultValue: getWidgetValue(type), + validation: { type: "text", pattern: "" } + }; + case "job title": + return { + name: "job title", + defaultValue: getWidgetValue(type), + validation: { type: "text", pattern: "" } + }; + case "date": + return { + name: "date", + response: getDate(), + validation: { format: "MM/dd/yyyy", type: "date-format" } + }; + case "image": + return { name: "image" }; + case "email": + return { + name: "email", + defaultValue: getWidgetValue(type), + validation: { type: "email", pattern: "" } + }; + default: + return {}; + } +}; export const getWidgetType = (item, widgetName) => { return ( <div className="op-btn w-fit md:w-[100%] op-btn-primary op-btn-outline op-btn-sm focus:outline-none outline outline-[1.5px] ml-[6px] md:ml-0 p-0 overflow-hidden"> @@ -557,13 +456,13 @@ export const convertPNGtoJPEG = (base64Data) => { export const handleSignYourselfImageResize = ( ref, key, - xyPostion, - setXyPostion, + xyPosition, + setXyPosition, index, containerScale, scale ) => { - const getXYdata = xyPostion[index].pos; + const getXYdata = xyPosition[index].pos; const getPosData = getXYdata; const addSign = getPosData.map((url) => { if (url.key === key) { @@ -577,13 +476,13 @@ export const handleSignYourselfImageResize = ( return url; }); - const newUpdateUrl = xyPostion.map((obj, ind) => { + const newUpdateUrl = xyPosition.map((obj, ind) => { if (ind === index) { return { ...obj, pos: addSign }; } return obj; }); - setXyPostion(newUpdateUrl); + setXyPosition(newUpdateUrl); }; //function for call cloud function signPdf and generate digital signature @@ -592,8 +491,6 @@ export const signPdfFun = async ( documentId, signerObjectId, objectId, - isSubscribed, - activeMailAdapter, widgets ) => { let isCustomCompletionMail = false; @@ -605,8 +502,7 @@ export const signPdfFun = async ( } else { if ( tenantDetails?.CompletionBody && - tenantDetails?.CompletionSubject && - isSubscribed + tenantDetails?.CompletionSubject ) { isCustomCompletionMail = true; } @@ -643,7 +539,6 @@ export const signPdfFun = async ( const suffixbase64 = imagebase64 && imagebase64.split(",").pop(); const params = { - mailProvider: activeMailAdapter, pdfFile: base64Url, docId: documentId, userId: signerObjectId, @@ -708,6 +603,10 @@ export const createDocument = async ( const NotifyOnSignatures = Doc?.NotifyOnSignatures ? { NotifyOnSignatures: Doc?.NotifyOnSignatures } : {}; + const Bcc = Doc?.Bcc?.length > 0 ? { Bcc: Doc?.Bcc } : {}; + const RedirectUrl = Doc?.RedirectUrl + ? { RedirectUrl: Doc?.RedirectUrl } + : {}; const data = { Name: Doc.Name, URL: pdfUrl, @@ -732,9 +631,11 @@ export const createDocument = async ( RemindOnceInEvery: parseInt(Doc?.RemindOnceInEvery || 5), IsEnableOTP: Doc?.IsEnableOTP || false, IsTourEnabled: Doc?.IsTourEnabled || false, - FileAdapterId: Doc?.FileAdapterId || "", + AllowModifications: Doc?.AllowModifications || false, ...SignatureType, - ...NotifyOnSignatures + ...NotifyOnSignatures, + ...Bcc, + ...RedirectUrl }; try { @@ -817,9 +718,9 @@ export const addZIndex = (signerPos, key, setZIndex) => { export const onChangeInput = ( value, signKey, - xyPostion, + xyPosition, index, - setXyPostion, + setXyPosition, userId, initial, dateFormat, @@ -828,16 +729,16 @@ export const onChangeInput = ( fontSize, fontColor ) => { - const isSigners = xyPostion.some((data) => data.signerPtr); + const isSigners = xyPosition.some((data) => data.signerPtr); let filterSignerPos; if (isSigners) { if (userId) { - filterSignerPos = xyPostion.filter((data) => data.Id === userId); + filterSignerPos = xyPosition.filter((data) => data.Id === userId); } const getPlaceHolder = filterSignerPos[0]?.placeHolder; if (initial) { - const xyData = addInitialData(xyPostion, setXyPostion, value, userId); - setXyPostion(xyData); + const xyData = addInitialData(xyPosition, setXyPosition, value, userId); + setXyPosition(xyData); } else { const getPageNumer = getPlaceHolder.filter( (data) => data.pageNumber === index @@ -889,18 +790,18 @@ export const onChangeInput = ( return obj; }); - const newUpdateSigner = xyPostion.map((obj) => { + const newUpdateSigner = xyPosition.map((obj) => { if (obj.Id === userId) { return { ...obj, placeHolder: newUpdateSignPos }; } return obj; }); - setXyPostion(newUpdateSigner); + setXyPosition(newUpdateSigner); } } } else { - let getXYdata = xyPostion[index].pos; + let getXYdata = xyPosition[index].pos; const updatePosition = getXYdata.map((positionData) => { if (positionData.key === signKey) { if (dateFormat) { @@ -930,13 +831,13 @@ export const onChangeInput = ( return positionData; }); - const updatePlaceholder = xyPostion.map((obj, ind) => { + const updatePlaceholder = xyPosition.map((obj, ind) => { if (ind === index) { return { ...obj, pos: updatePosition }; } return obj; }); - setXyPostion(updatePlaceholder); + setXyPosition(updatePlaceholder); } }; @@ -945,16 +846,16 @@ export const onChangeHeightOfTextArea = ( height, widgetType, signKey, - xyPostion, + xyPosition, index, - setXyPostion, + setXyPosition, userId ) => { - const isSigners = xyPostion.some((data) => data.signerPtr); + const isSigners = xyPosition.some((data) => data.signerPtr); let filterSignerPos; if (isSigners) { if (userId) { - filterSignerPos = xyPostion.filter((data) => data.Id === userId); + filterSignerPos = xyPosition.filter((data) => data.Id === userId); } const getPlaceHolder = filterSignerPos[0]?.placeHolder; @@ -982,17 +883,17 @@ export const onChangeHeightOfTextArea = ( return obj; }); - const newUpdateSigner = xyPostion.map((obj) => { + const newUpdateSigner = xyPosition.map((obj) => { if (obj.Id === userId) { return { ...obj, placeHolder: newUpdateSignPos }; } return obj; }); - setXyPostion(newUpdateSigner); + setXyPosition(newUpdateSigner); } } else { - let getXYdata = xyPostion[index].pos; + let getXYdata = xyPosition[index].pos; const updatePosition = getXYdata.map((position) => { if (position.key === signKey) { @@ -1006,13 +907,13 @@ export const onChangeHeightOfTextArea = ( return position; }); - const updatePlaceholder = xyPostion.map((obj, ind) => { + const updatePlaceholder = xyPosition.map((obj, ind) => { if (ind === index) { return { ...obj, pos: updatePosition }; } return obj; }); - setXyPostion(updatePlaceholder); + setXyPosition(updatePlaceholder); } }; //calculate width and height @@ -1032,7 +933,7 @@ export const calculateInitialWidthHeight = (widgetData) => { getHeight: height }; }; -export const addInitialData = (signerPos, setXyPostion, value, userId) => { +export const addInitialData = (signerPos, setXyPosition, value, userId) => { function widgetDataValue(type) { switch (type) { case "name": @@ -1055,7 +956,7 @@ export const addInitialData = (signerPos, setXyPostion, value, userId) => { ...item, placeHolder: addInitialData( item.placeHolder, - setXyPostion, + setXyPosition, value, userId ) @@ -1069,7 +970,7 @@ export const addInitialData = (signerPos, setXyPostion, value, userId) => { // If there is no nested array, add the new field return { ...item, - pos: addInitialData(item.pos, setXyPostion, value, userId) + pos: addInitialData(item.pos, setXyPosition, value, userId) // Adjust this line to add the desired field }; } else { @@ -1132,25 +1033,32 @@ export const embedDocId = async (pdfDoc, documentId, allPages) => { //function for save button to save signature or image url export function onSaveSign( type, - xyPostion, + xyPosition, index, signKey, signatureImg, - imgWH, + defaultImgWH, isDefaultSign, - isTypeText + isTypeText, + typedSignature, + isAutoSign, + widgetsType, + isApplyAll ) { - let getIMGWH; - let getXYdata = xyPostion[index].pos; + let getIMGWH, posWidth, posHeight; + let getXYdata = xyPosition[index].pos; const updateXYData = getXYdata.map((position) => { if (position.key === signKey) { if (isDefaultSign === "initials") { let imgWH = { width: position.Width, height: position.Height }; getIMGWH = calculateImgAspectRatio(imgWH, position); } else if (isDefaultSign === "default") { - getIMGWH = calculateImgAspectRatio(imgWH, position); + getIMGWH = calculateImgAspectRatio(defaultImgWH, position); } else if (isTypeText) { - getIMGWH = { newWidth: imgWH.width, newHeight: imgWH.height }; + getIMGWH = { + newWidth: defaultImgWH.width, + newHeight: defaultImgWH.height + }; } else { const defaultWidth = defaultWidthHeight(position?.type).width; const defaultHeight = defaultWidthHeight(position?.type).height; @@ -1163,31 +1071,125 @@ export function onSaveSign( position ); } - - const posWidth = getIMGWH ? getIMGWH.newWidth : 150; - const posHeight = getIMGWH ? getIMGWH.newHeight : 60; - + posWidth = getIMGWH ? getIMGWH.newWidth : 150; + posHeight = getIMGWH ? getIMGWH.newHeight : 60; return { ...position, Width: posWidth, Height: posHeight, SignUrl: signatureImg, - signatureType: type && type, - options: { ...position.options, response: signatureImg } + ...(type && { signatureType: type }), + options: { ...position.options, response: signatureImg }, + ...(typedSignature && { typeSignature: typedSignature }) }; } return position; }); - const updateXYposition = xyPostion.map((obj, ind) => { + const updateXYposition = xyPosition.map((obj, ind) => { if (ind === index) { return { ...obj, pos: updateXYData }; } return obj; }); - return updateXYposition; + //condition when user click on apply(signature,image,typed signature or defaullt signature) all widgets on signature pad for same widgets + if (isAutoSign) { + const updatedArray = updateXYposition.map((page) => ({ + ...page, + pos: page.pos.map( + (item) => + item.type === widgetsType + ? { + ...item, + Width: posWidth, + Height: posHeight, + SignUrl: signatureImg, + ...(type && { signatureType: type }), + options: { ...item.options, response: signatureImg }, + ...(typedSignature && { typeSignature: typedSignature }) + } + : item // Otherwise, keep it unchanged + ) + })); + return updatedArray; + } //condition when user edit signature/initial then updated signature apply all existing drawn signatures + else if (isApplyAll) { + // console.log("signatureImg",signatureImg) + const updatedArray = updateXYposition.map((page) => ({ + ...page, + pos: page.pos.map( + (item) => + item.SignUrl && item.type === widgetsType + ? { + ...item, + Width: posWidth, + Height: posHeight, + SignUrl: signatureImg, + ...(type && { signatureType: type }), + options: { ...item.options, response: signatureImg }, + ...(typedSignature && { typeSignature: typedSignature }) + } + : item // Otherwise, keep it unchanged + ) + })); + return updatedArray; + } else { + return updateXYposition; + } } +//function to use After setting the signature URL for the first signature widget, clicking on subsequent +//signature widgets should automatically apply and display the signature. apply for initial,signature and stamp widget +export const handleCopySignUrl = ( + currentPos, + existSignPosition, + setXyPosition, + xyPosition, + pageNumber, + signerObjectId +) => { + //get current signer details + const currentSigner = xyPosition.filter( + (data) => data.signerObjId === signerObjectId + ); + //get current signer placeholder details + const placeholderPosition = currentSigner[0].placeHolder; + //get current pagenumber position + const getcurrentPagePosition = placeholderPosition.find( + (data) => data.pageNumber === pageNumber + ); + let getXYdata = getcurrentPagePosition.pos; + const updatePos = getXYdata.map((x) => { + //update widgets sign url details + if (x.key === currentPos.key) { + return { + ...x, + Width: existSignPosition.Width, + Height: existSignPosition.Height, + SignUrl: existSignPosition.SignUrl, + signatureType: existSignPosition.signatureType, + options: { ...x.options, response: existSignPosition.SignUrl }, + ...(existSignPosition.typedSignature && { + typeSignature: existSignPosition.typedSignature + }) + }; + } + return x; + }); + const updateXYposition = placeholderPosition.map((obj) => { + if (obj.pageNumber === pageNumber) { + return { ...obj, pos: updatePos }; + } + return obj; + }); + const newUpdateSigner = xyPosition.map((obj) => { + if (obj.signerObjId === signerObjectId) { + return { ...obj, placeHolder: updateXYposition }; + } + return obj; + }); + setXyPosition(newUpdateSigner); +}; export const calculateImgAspectRatio = (imgWH, pos) => { let newWidth, newHeight; @@ -1200,11 +1202,20 @@ export const calculateImgAspectRatio = (imgWH, pos) => { }; //function for upload stamp or image -export function onSaveImage(xyPostion, index, signKey, imgWH, image) { +export function onSaveImage( + xyPosition, + index, + signKey, + imgWH, + image, + isAutoSign, + widgetsType, + isApplyAll +) { let getIMGWH; //get current page position - const getXYData = xyPostion[index].pos; + const getXYData = xyPosition[index].pos; const updateXYData = getXYData.map((position) => { if (position.key === signKey) { getIMGWH = calculateImgAspectRatio(imgWH, position); @@ -1224,31 +1235,74 @@ export function onSaveImage(xyPostion, index, signKey, imgWH, image) { return position; }); - const updateXYposition = xyPostion.map((obj, ind) => { + const updateXYposition = xyPosition.map((obj, ind) => { if (ind === index) { return { ...obj, pos: updateXYData }; } return obj; }); - return updateXYposition; + //condition when user click on apply(stamp) all widgets on signature pad for same widgets + if (isAutoSign) { + const updatedArray = updateXYposition.map((page) => ({ + ...page, + pos: page.pos.map( + (item) => + item.type === widgetsType + ? { + ...item, + Width: getIMGWH.newWidth, + Height: getIMGWH.newHeight, + SignUrl: image.src, + ImageType: image.imgType, + options: { + ...item.options, + response: image.src + } + } + : item // Otherwise, keep it unchanged + ) + })); + return updatedArray; + } //condition when user edit stamp then updated signature apply all existing drawn signatures + else if (isApplyAll) { + const updatedArray = updateXYposition.map((page) => ({ + ...page, + pos: page.pos.map( + (item) => + item.SignUrl && item.type === widgetsType && item.type !== "image" + ? { + ...item, + Width: getIMGWH.newWidth, + Height: getIMGWH.newHeight, + SignUrl: image.src, + ImageType: image.imgType, + options: { + ...item.options, + response: image.src + } + } + : item // Otherwise, keep it unchanged + ) + })); + return updatedArray; + } else { + return updateXYposition; + } } //function for select image and upload image -export const onImageSelect = (event, setImgWH, setImage) => { - const imageType = event.target.files[0].type; +export const onImageSelect = (setImgWH, setImage, file) => { const reader = new FileReader(); - reader.readAsDataURL(event.target.files[0]); + reader.readAsDataURL(file); reader.onloadend = function (e) { let width, height; const image = new Image(); - image.src = e.target.result; image.onload = function () { width = image.width; height = image.height; const aspectRatio = 460 / 184; const imgR = width / height; - if (imgR > aspectRatio) { width = 460; height = 460 / imgR; @@ -1258,12 +1312,56 @@ export const onImageSelect = (event, setImgWH, setImage) => { } setImgWH({ width: width, height: height }); }; - image.src = reader.result; - - setImage({ src: image.src, imgType: imageType }); + setImage({ src: image.src, imgType: file.type }); }; }; +export const compressedFileSize = (file, setImgWH, setImage) => { + // Create a new FileReader instance to read the uploaded file + const reader = new FileReader(); + + // Event listener triggered when the file is read successfully + reader.onload = (e) => { + // Create a new Image instance to manipulate the image data + const img = new Image(); + + // Set the image source to the file's data URL (base64 string) + img.src = e.target.result; + + // Event listener triggered when the image is fully loaded + img.onload = () => { + // Create a canvas element to resize and compress the image + const canvas = document.createElement("canvas"); + const ctx = canvas.getContext("2d"); // Get the drawing context of the canvas + + // Set the canvas dimensions, ensuring they don't exceed 1920x1920 + canvas.width = Math.min(img.width, 1920); // Limit width to 1920px + canvas.height = Math.min(img.height, 1920); // Limit height to 1920px + + // Draw the image onto the canvas with the specified dimensions + ctx.drawImage(img, 0, 0, canvas.width, canvas.height); + // Get the original file type (default to "image/png" if not recognized) + const fileType = file.type || "image/png"; + // Compress the image and convert it into a Blob + canvas.toBlob( + (blob) => { + // Create a new File object from the compressed Blob + const compressedFile = new File([blob], file.name, { + type: fileType, // Set the file type to JPEG + lastModified: Date.now() // Update the last modified timestamp + }); + // Pass the compressed file to a custom function for further processing + onImageSelect(setImgWH, setImage, compressedFile); + }, + fileType, // Output format for the compressed image + 0.3 // Compression quality (30%) + ); + }; + }; + + // Read the file as a data URL (base64 string) to be processed + reader.readAsDataURL(file); +}; //convert https url to base64 export const fetchImageBase64 = async (imageUrl) => { try { @@ -1763,11 +1861,12 @@ export const contactBook = async (objectId) => { }; //function for getting document details from contract_Documents class -export const contractDocument = async (documentId, JwtToken) => { +export const contractDocument = async ( + documentId, +) => { const data = { docId: documentId }; - const token = JwtToken - ? { jwtToken: JwtToken } - : { sessionToken: localStorage.getItem("accesstoken") }; + const token = + { sessionToken: localStorage.getItem("accesstoken") }; const documentDeatils = await axios .post(`${localStorage.getItem("baseUrl")}functions/getDocument`, data, { headers: { @@ -1797,7 +1896,7 @@ export const contractDocument = async (documentId, JwtToken) => { }; //function for add default signature or image for all requested location -export const addDefaultSignatureImg = (xyPostion, defaultSignImg) => { +export const addDefaultSignatureImg = (xyPosition, defaultSignImg, type) => { let imgWH = { width: "", height: "" }; const img = new Image(); img.src = defaultSignImg; @@ -1809,16 +1908,16 @@ export const addDefaultSignatureImg = (xyPostion, defaultSignImg) => { } let xyDefaultPos = []; - for (let i = 0; i < xyPostion.length; i++) { + for (let i = 0; i < xyPosition.length; i++) { let getIMGWH; - const getXYdata = xyPostion[i].pos; - const getPageNo = xyPostion[i].pageNumber; + const getXYdata = xyPosition[i].pos; + const getPageNo = xyPosition[i].pageNumber; const getPosData = getXYdata; const addSign = getPosData.map((position) => { getIMGWH = calculateImgAspectRatio(imgWH, position); if (position.type) { - if (position?.type === "signature") { + if (position?.type === type) { return { ...position, SignUrl: defaultSignImg, @@ -1880,9 +1979,9 @@ export const getYear = (date) => { export const handleCopyNextToWidget = ( position, widgetType, - xyPostion, + xyPosition, index, - setXyPostion, + setXyPosition, userId ) => { let filterSignerPos; @@ -1901,7 +2000,7 @@ export const handleCopyNextToWidget = ( }; //if condition to create widget in request-sign flow if (userId) { - filterSignerPos = xyPostion.filter((data) => data.Id === userId); + filterSignerPos = xyPosition.filter((data) => data.Id === userId); const getPlaceHolder = filterSignerPos && filterSignerPos[0]?.placeHolder; const getPageNumer = getPlaceHolder?.filter( (data) => data.pageNumber === index @@ -1916,26 +2015,26 @@ export const handleCopyNextToWidget = ( return obj; }); - const newUpdateSigner = xyPostion.map((obj) => { + const newUpdateSigner = xyPosition.map((obj) => { if (obj.Id === userId) { return { ...obj, placeHolder: newUpdateSignPos }; } return obj; }); - setXyPostion(newUpdateSigner); + setXyPosition(newUpdateSigner); } } else { - let getXYdata = xyPostion[index]?.pos || []; + let getXYdata = xyPosition[index]?.pos || []; getXYdata.push(newposition); - const updatePlaceholder = xyPostion.map((obj, ind) => { + const updatePlaceholder = xyPosition.map((obj, ind) => { if (ind === index) { return { ...obj, pos: getXYdata }; } return obj; }); - setXyPostion(updatePlaceholder); + setXyPosition(updatePlaceholder); } }; @@ -1951,9 +2050,6 @@ export const getFileName = (fileUrl) => { //fetch tenant app logo from `partners_Tenant` class by domain name export const getAppLogo = async () => { - if (window.location.host === "app.opensignlabs.com") { - return { logo: appInfo.applogo, user: "exist" }; - } else { const domain = window.location.host; try { const tenant = await Parse.Cloud.run("getlogobydomain", { @@ -1970,18 +2066,19 @@ export const getAppLogo = async () => { return { logo: appInfo.applogo, user: "exist" }; } } - } }; - -export const getTenantDetails = async (objectId, jwttoken, contactId) => { +export const getTenantDetails = async ( + objectId, + contactId +) => { try { const url = `${localStorage.getItem("baseUrl")}functions/gettenant`; const parseAppId = localStorage.getItem("parseAppId"); const accesstoken = localStorage.getItem("accesstoken"); - const token = jwttoken - ? { jwttoken: jwttoken } - : { "X-Parse-Session-Token": accesstoken }; - const data = jwttoken ? {} : { userId: objectId, contactId: contactId }; + const token = + { "X-Parse-Session-Token": accesstoken }; + const data = + { userId: objectId, contactId: contactId }; const res = await axios.post(url, data, { headers: { "Content-Type": "application/json", @@ -1989,9 +2086,11 @@ export const getTenantDetails = async (objectId, jwttoken, contactId) => { ...token } }); - if (res) { + if (res.data.result) { const updateRes = JSON.parse(JSON.stringify(res.data.result)); return updateRes; + } else { + return ""; } } catch (err) { console.log("err in gettenant", err); @@ -2082,7 +2181,6 @@ export const fetchUrl = async (url, pdfName) => { export const getSignedUrl = async ( pdfUrl, docId, - fileAdapterId, templateId ) => { //use only axios here due to public template sign @@ -2091,7 +2189,6 @@ export const getSignedUrl = async ( { url: pdfUrl, docId: docId || "", - fileAdapterId: fileAdapterId, templateId: templateId || "" }, { @@ -2105,23 +2202,58 @@ export const getSignedUrl = async ( const url = axiosRes.data.result; return url; }; +//download base64 type pdf +export const fetchBase64 = async (pdfBase64, pdfName) => { + // Create a Blob from the Base64 string + const byteCharacters = atob(pdfBase64); + const byteNumbers = new Array(byteCharacters.length) + .fill(0) + .map((_, i) => byteCharacters.charCodeAt(i)); + const byteArray = new Uint8Array(byteNumbers); + const blob = new Blob([byteArray], { type: "application/pdf" }); + + // Create a link element + const link = document.createElement("a"); + link.href = URL.createObjectURL(blob); + link.download = pdfName; + + // Programmatically click the link to trigger the download + document.body.appendChild(link); + link.click(); + + // Clean up + document.body.removeChild(link); + URL.revokeObjectURL(link.href); +}; //handle download signed pdf -export const handleDownloadPdf = async (pdfDetails, setIsDownloading) => { - const pdfName = pdfDetails[0] && pdfDetails[0]?.Name; - const pdfUrl = pdfDetails?.[0]?.SignedUrl || pdfDetails?.[0]?.URL; - setIsDownloading && setIsDownloading("pdf"); - const docId = pdfDetails?.[0]?.objectId || ""; - const fileAdapterId = pdfDetails?.[0]?.FileAdapterId - ? pdfDetails?.[0]?.FileAdapterId - : ""; - try { - const url = await getSignedUrl(pdfUrl, docId, fileAdapterId); - await fetchUrl(url, pdfName); +export const handleDownloadPdf = async ( + pdfDetails, + setIsDownloading, + pdfBase64 +) => { + const pdfName = + pdfDetails?.[0]?.Name?.length > 100 + ? pdfDetails?.[0]?.Name?.slice(0, 100) + : pdfDetails?.[0]?.Name || "Document"; + if (pdfBase64) { + await fetchBase64(pdfBase64, pdfName); setIsDownloading && setIsDownloading(""); - } catch (err) { - console.log("err in getsignedurl", err); - setIsDownloading(""); - alert("something went wrong, please try again later."); + } else { + const pdfUrl = pdfDetails?.[0]?.SignedUrl || pdfDetails?.[0]?.URL; + setIsDownloading && setIsDownloading("pdf"); + const docId = pdfDetails?.[0]?.objectId || ""; + try { + const url = await getSignedUrl( + pdfUrl, + docId, + ); + await fetchUrl(url, pdfName); + setIsDownloading && setIsDownloading(""); + } catch (err) { + console.log("err in getsignedurl", err); + setIsDownloading(""); + alert("something went wrong, please try again later."); + } } }; @@ -2130,25 +2262,22 @@ export const sanitizeFileName = (pdfName) => { return pdfName.replace(/ /g, "_"); }; //function for print digital sign pdf -export const handleToPrint = async ( - event, - pdfUrl, - setIsDownloading, - pdfDetails -) => { +export const handleToPrint = async (event, setIsDownloading, pdfDetails) => { event.preventDefault(); setIsDownloading("pdf"); + const pdfUrl = pdfDetails?.[0]?.SignedUrl || pdfDetails?.[0]?.URL; const docId = pdfDetails?.[0]?.objectId || ""; - const FileAdapterId = pdfDetails?.[0]?.FileAdapterId - ? pdfDetails?.[0]?.FileAdapterId - : ""; + try { // const url = await Parse.Cloud.run("getsignedurl", { url: pdfUrl }); //`localStorage.getItem("baseUrl")` is also use in public-profile flow for public-sign //if we give this `appInfo.baseUrl` as a base url then in public-profile it will create base url of it's window.location.origin ex- opensign.me which is not base url const axiosRes = await axios.post( `${localStorage.getItem("baseUrl")}/functions/getsignedurl`, - { url: pdfUrl, docId: docId, fileAdapterId: FileAdapterId }, + { + url: pdfUrl, + docId: docId, + }, { headers: { "content-type": "Application/json", @@ -2206,9 +2335,7 @@ export const handleDownloadCertificate = async ( } else { setIsDownloading("certificate"); try { - const data = { - docId: pdfDetails[0]?.objectId - }; + const data = { docId: pdfDetails[0]?.objectId }; const docDetails = await axios.post( `${localStorage.getItem("baseUrl")}functions/getDocument`, data, @@ -2230,33 +2357,66 @@ export const handleDownloadCertificate = async ( return certificateUrl; } else { saveAs(certificateUrl, `Certificate_signed_by_OpenSign™.pdf`); + setIsDownloading(""); } - - setIsDownloading(""); } else { - setIsDownloading("certificate"); + const generateRes = await axios.post( + `${localStorage.getItem("baseUrl")}functions/generatecertificate`, + data, + { + headers: { + "Content-Type": "application/json", + "X-Parse-Application-Id": localStorage.getItem("parseAppId") + } + } + ); + if (generateRes?.data?.result?.CertificateUrl) { + try { + const certificateUrl = generateRes.data.result.CertificateUrl; + const fetchCertificate = await fetch(certificateUrl); + if (isZip) { + setIsDownloading(""); + return certificateUrl; + } else { + // Convert the response into a Blob + const certificateBlob = await fetchCertificate.blob(); + setIsDownloading(""); + saveAs(certificateBlob, `Certificate_signed_by_OpenSign™.pdf`); + } + } catch (err) { + console.log("err in download in certificate", err); + setIsDownloading("certificate_err"); + } + } else { + setIsDownloading("certificate_err"); + } } } } catch (err) { + setIsDownloading("certificate_err"); console.log("err in download in certificate", err); alert("something went wrong, please try again later."); } } }; -export async function findContact(value, jwttoken) { +// Function to escape special characters in the search string +export function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // Escape special characters +} +export async function findContact( + value, +) { try { const baseURL = localStorage.getItem("baseUrl"); const url = `${baseURL}functions/getsigners`; - const token = jwttoken - ? { jwttoken: jwttoken } - : { "X-Parse-Session-Token": localStorage.getItem("accesstoken") }; + const token = + { "X-Parse-Session-Token": localStorage.getItem("accesstoken") }; const headers = { "Content-Type": "application/json", "X-Parse-Application-Id": localStorage.getItem("parseAppId"), ...token }; - const searchEmail = value; - const axiosRes = await axios.post(url, { searchEmail }, { headers }); + const axiosRes = await axios.post(url, { search: value }, { headers }); const contactRes = axiosRes?.data?.result || []; if (contactRes) { const res = JSON.parse(JSON.stringify(contactRes)); @@ -2411,37 +2571,25 @@ export const getDefaultSignature = async (objectId) => { return { status: "success", res: { + id: result?.id, defaultSignature: defaultSignature, defaultInitial: defaultInitial } }; } } catch (err) { - console.log("Error: error in fetch data in contracts_Signature", err); - return { - status: "error" - }; + console.log( + "Error: error in fetch data in contracts_Signature", + err?.message || err + ); + return { status: "error" }; } }; //function to rotate pdf page -export async function rotatePdfPage( - url, - rotateDegree, - pageNumber, - pdfRotateBase64 -) { - let file; - - //condition to handle pdf base64 in arrayBuffer format - if (pdfRotateBase64) { - file = base64ToArrayBuffer(pdfRotateBase64); - } else { - //condition to handle pdf url in arrayBuffer format - file = await convertPdfArrayBuffer(url); - } +export async function rotatePdfPage(rotateDegree, pageNumber, pdfArrayBuffer) { // Load the existing PDF - const pdfDoc = await PDFDocument.load(file); + const pdfDoc = await PDFDocument.load(pdfArrayBuffer); // Get the page according to page number const page = pdfDoc.getPage(pageNumber); //get current page rotation angle @@ -2460,7 +2608,7 @@ export async function rotatePdfPage( //`base64` is used to show pdf return { arrayBuffer: arrayBuffer, base64: pdfbase64 }; } -function base64ToArrayBuffer(base64) { +export function base64ToArrayBuffer(base64) { // Decode the base64 string to a binary string const binaryString = atob(base64); // Create a new ArrayBuffer with the same length as the binary string @@ -2474,13 +2622,23 @@ function base64ToArrayBuffer(base64) { return bytes.buffer; } -export const convertBase64ToFile = async (pdfName, pdfBase64) => { +export const convertBase64ToFile = async ( + pdfName, + pdfBase64, +) => { const fileName = sanitizeFileName(pdfName) + ".pdf"; - const pdfFile = new Parse.File(fileName, { base64: pdfBase64 }); - // Save the Parse File if needed - const pdfData = await pdfFile.save(); - const pdfUrl = pdfData.url(); - return pdfUrl; + try { + const pdfFile = new Parse.File(fileName, { base64: pdfBase64 }); + // Save the Parse File if needed + const pdfData = await pdfFile.save(); + const pdfUrl = pdfData.url(); + const fileRes = await getSecureUrl(pdfUrl); + if (fileRes?.url) { + return fileRes.url; + } + } catch (e) { + console.log("error in convertbase64tofile", e); + } }; export const onClickZoomIn = (scale, zoomPercent, setScale, setZoomPercent) => { setScale(scale + 0.1 * scale); @@ -2509,19 +2667,63 @@ export const handleRemoveWidgets = ( pageNumber, setIsRotate ) => { - const updatedSignerPos = signerPos.map((placeholderObj) => { - return { - ...placeholderObj, - placeHolder: placeholderObj?.placeHolder?.filter( - (data) => data?.pageNumber !== pageNumber - ) - }; - }); - setSignerPos(updatedSignerPos); - setIsRotate({ - status: false, - degree: 0 - }); + const isSigners = signerPos.some((data) => data.signerPtr); + //placeholder,template,draftTemplate flow + if (isSigners) { + const updatedSignerPos = signerPos.map((placeholderObj) => { + return { + ...placeholderObj, + placeHolder: placeholderObj?.placeHolder?.filter( + (data) => data?.pageNumber !== pageNumber + ) + }; + }); + + if (setIsRotate) { + setSignerPos(updatedSignerPos); + setIsRotate({ status: false, degree: 0 }); + } else { + //after deleting pdf page we need to update page number of widgets + //For example, consider a PDF with 3 pages where widgets are placed on the 2nd page. + //If we delete the 1st page, the total number of pages will be reduced to 2. In this case, + // the widgets need to be updated to reflect the new page numbering and should now appear on the 1st page. + const updatePageNumber = updatedSignerPos?.map((placeholderObj) => { + return { + ...placeholderObj, + placeHolder: placeholderObj?.placeHolder?.map((data) => { + if (data.pageNumber > pageNumber) { + return { ...data, pageNumber: data.pageNumber - 1 }; + } else { + return data; + } + }) + }; + }); + setSignerPos(updatePageNumber); + } + } else { + //signyourself flow + const updatedSignerPos = signerPos?.filter( + (data) => data?.pageNumber !== pageNumber + ); + if (setIsRotate) { + setSignerPos(updatedSignerPos); + setIsRotate({ status: false, degree: 0 }); + } else { + //after deleting pdf page we need to update page number of widgets + //For example, consider a PDF with 3 pages where widgets are placed on the 2nd page. + //If we delete the 1st page, the total number of pages will be reduced to 2. In this case, + // the widgets need to be updated to reflect the new page numbering and should now appear on the 1st page. + const updatePageNumber = updatedSignerPos?.map((data) => { + if (data.pageNumber > pageNumber) { + return { ...data, pageNumber: data.pageNumber - 1 }; + } else { + return data; + } + }); + setSignerPos(updatePageNumber); + } + } }; //function to show warning when user rotate page and there are some already widgets on that page export const handleRotateWarning = (signerPos, pageNumber) => { @@ -2610,3 +2812,126 @@ export const formatDate = (date) => { const format = formattedDate.replaceAll(/ /g, "-"); return format; }; + +export const deletePdfPage = async (pdfArrayBuffer, pageNumber) => { + try { + // Load the existing PDF + const pdfDoc = await PDFDocument.load(pdfArrayBuffer); + // Get the total number of pages + const totalPages = pdfDoc.getPageCount(); + // Ensure the page index is valid + if (totalPages > 1) { + //Remove the specified page + pdfDoc.removePage(pageNumber - 1); + // Save the modified PDF + const modifiedPdfBytes = await pdfDoc.saveAsBase64({ + useObjectStreams: false + }); + const arrayBuffer = base64ToArrayBuffer(modifiedPdfBytes); + return { + arrayBuffer: arrayBuffer, + base64: modifiedPdfBytes, + remainingPages: totalPages - 1 + }; + } else { + return { totalPages: 1 }; + } + } catch (err) { + console.log("Err while deleting page", err); + } +}; + +// `generatePdfName` is used to generate file name +export function generatePdfName(length) { + const characters = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + let result = ""; + const charactersLength = characters.length; + + for (let i = 0; i < length; i++) { + result += characters.charAt(Math.floor(Math.random() * charactersLength)); + } + return result; +} + +// Format date and time for the selected timezone +export const formatTimeInTimezone = (date, timezone) => { + return timezone + ? new Intl.DateTimeFormat("en-US", { + weekday: "short", + year: "numeric", + month: "short", + day: "numeric", + hour: "2-digit", + minute: "2-digit", + second: "2-digit", + timeZone: timezone, + timeZoneName: "short", + hour12: false + }).format(date) + : new Date(date).toUTCString(); +}; + +// `usertimezone` is used to get timezone of current user +export const usertimezone = Intl.DateTimeFormat().resolvedOptions().timeZone; +export const handleHeighlightWidget = ( + getCurrentSignerPos, + key, + pageNumber +) => { + const placeholder = getCurrentSignerPos.placeHolder; + // Find the highest zIndex value + const highestZIndex = placeholder + .flatMap((item) => item.pos.map((position) => position.zIndex)) + .reduce((max, zIndex) => (zIndex > max ? zIndex : max), -Infinity); //-Infinity represents the smallest possible number + // Update the zIndex of the current signer + const updateZindex = placeholder.map((data) => { + if (data.pageNumber === pageNumber) { + return { + ...data, + pos: data.pos.map((position) => { + if (position.key === key) { + return { + ...position, + zIndex: highestZIndex + 1 + }; + } + return position; + }) + }; + } + return data; + }); + return updateZindex; +}; +/** + * FlattenPdf is used to remove existing widgets if present any and flatten pdf. + * @param {string | Uint8Array | ArrayBuffer} pdfFile - pdf file. + * @returns {Promise<Uint8Array>} flatPdf - pdf file in unit8arry + */ +export const flattenPdf = async (pdfFile) => { + const pdfDoc = await PDFDocument.load(pdfFile); + // Get the form + const form = pdfDoc.getForm(); + // fetch form fields + const fields = form.getFields(); + // remove form all existing fields and their widgets + if (fields && fields?.length > 0) { + try { + for (const field of fields) { + while (field.acroField.getWidgets().length) { + field.acroField.removeWidget(0); + } + form.removeField(field); + } + } catch (err) { + console.log("err while removing field from pdf", err); + } + } + // Updates the field appearances to ensure visual changes are reflected. + form.updateFieldAppearances(); + // Flattens the form, converting all form fields into non-editable, static content + form.flatten(); + const flatPdf = await pdfDoc.save({ useObjectStreams: false }); + return flatPdf; +}; diff --git a/apps/OpenSign/src/constant/appinfo.js b/apps/OpenSign/src/constant/appinfo.js index 64dbd87b2..8541bd2b7 100644 --- a/apps/OpenSign/src/constant/appinfo.js +++ b/apps/OpenSign/src/constant/appinfo.js @@ -1,17 +1,11 @@ import logo from "../assets/images/logo.png"; -import { isEnableSubscription } from "./const"; export function serverUrl_fn() { let baseUrl; - if (isEnableSubscription) { - baseUrl = process.env.REACT_APP_SERVERURL - ? process.env.REACT_APP_SERVERURL - : window.location.origin + "/api/app"; - } else { baseUrl = process.env.REACT_APP_SERVERURL ? process.env.REACT_APP_SERVERURL : window.location.origin + "/app"; - } + return baseUrl; } export const appInfo = { diff --git a/apps/OpenSign/src/constant/const.js b/apps/OpenSign/src/constant/const.js index 8b91c2589..30ed76297 100644 --- a/apps/OpenSign/src/constant/const.js +++ b/apps/OpenSign/src/constant/const.js @@ -4,12 +4,3 @@ 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 isEnableSubscription = - process.env.REACT_APP_ENABLE_SUBSCRIPTION && - process.env.REACT_APP_ENABLE_SUBSCRIPTION?.toLowerCase() === "true" - ? true - : false; -export const isStaging = - window.location.origin === "https://staging-app.opensignlabs.com"; -export const isPublicStaging = - window.location.origin === "https://staging.opensign.me"; diff --git a/apps/OpenSign/src/hook/useScript.js b/apps/OpenSign/src/hook/useScript.js index 354ad1fe1..b94a35155 100644 --- a/apps/OpenSign/src/hook/useScript.js +++ b/apps/OpenSign/src/hook/useScript.js @@ -16,19 +16,3 @@ export const useScript = (url, onload) => { }, [url, onload]); }; -/**`useScript` hook is generated scripte for google sign in button */ -export const useDropScript = (url, onload) => { - useEffect(() => { - const script = document.createElement("script"); - //add url parameter to the script src, for load and it will remove after load in return - script.src = url; - script.async = true; - script.defer = true; - script.id = "dropboxjs"; - script.setAttribute("data-app-key", "8k0thg9r1t7asqg"); - document.head.appendChild(script); - return () => { - document.head.removeChild(script); - }; - }, [url, onload]); -}; diff --git a/apps/OpenSign/src/i18n.js b/apps/OpenSign/src/i18n.js index bad8f1ed1..212960251 100644 --- a/apps/OpenSign/src/i18n.js +++ b/apps/OpenSign/src/i18n.js @@ -25,7 +25,7 @@ i18n interpolation: { escapeValue: false // Not needed for react as it escapes by default }, - whitelist: ["en", "es", "fr"] // List of allowed languages + whitelist: ["en", "es", "fr", "it", "de"] // List of allowed languages }); export default i18n; diff --git a/apps/OpenSign/src/index.css b/apps/OpenSign/src/index.css index 3aa22814d..be62c615f 100644 --- a/apps/OpenSign/src/index.css +++ b/apps/OpenSign/src/index.css @@ -19,8 +19,9 @@ body { } @media screen and (max-width: 766px) { - .bBofGr { - width: 14px !important; + .reactour__close { + width: 17px !important; + padding-left: 3px !important; } } diff --git a/apps/OpenSign/src/json/FormJson.js b/apps/OpenSign/src/json/FormJson.js index 8e0b4f6a1..955185e28 100644 --- a/apps/OpenSign/src/json/FormJson.js +++ b/apps/OpenSign/src/json/FormJson.js @@ -14,13 +14,15 @@ export const formJson = { msgVar: "Document", redirectRoute: "placeHolderSign", Cls: documentCls, - signers: true + signers: true, + bcc: true }, //json form for template template: { title: "New Template", redirectRoute: "template", msgVar: "Template", - Cls: templateCls + Cls: templateCls, + bcc: true } }; diff --git a/apps/OpenSign/src/json/ReportJson.js b/apps/OpenSign/src/json/ReportJson.js index 025ed065d..f27819bd0 100644 --- a/apps/OpenSign/src/json/ReportJson.js +++ b/apps/OpenSign/src/json/ReportJson.js @@ -1,4 +1,3 @@ -import { isEnableSubscription } from "../constant/const"; export default function reportJson(id) { // console.log("json ", json); @@ -8,31 +7,6 @@ export default function reportJson(id) { const contactbook = ["Name", "Email", "Phone"]; const dashboardReportHead = ["Title", "File", "Owner", "Signers"]; const templateReport = ["Title", "File", "Owner", "Signers"]; - const templateSubAction = isEnableSubscription - ? [ - { - btnId: "2435", - btnLabel: "Embed", - hoverLabel: "Embed", - btnIcon: "fa-light fa-code", - action: "Embed" - }, - { - btnId: "2436", - btnLabel: "Copy TemplateId", - hoverLabel: "Copy TemplateId", - btnIcon: "fa-light fa-copy", - action: "CopyTemplateId" - }, - { - btnId: "2437", - btnLabel: "Copy Public URL", - hoverLabel: "Copy Public URL", - btnIcon: "fa-light fa-copy", - action: "CopyPublicURL" - } - ] - : []; switch (id) { // draft documents report case "ByHuevtCFY": @@ -117,6 +91,14 @@ export default function reportJson(id) { redirectUrl: "", action: "resend" }, + { + btnId: "1633", + btnLabel: "Rename", + hoverLabel: "Rename", + btnIcon: "fa-light fa-pen-to-square", + redirectUrl: "", + action: "rename" + }, { btnId: "1688", btnLabel: "Revoke", @@ -158,6 +140,7 @@ export default function reportJson(id) { hoverLabel: "Delete", btnColor: "op-btn-secondary", btnIcon: "fa-light fa-trash", + restrictBtn: true, redirectUrl: "", action: "delete" } @@ -274,6 +257,14 @@ export default function reportJson(id) { redirectUrl: "", action: "resend" }, + { + btnId: "1633", + btnLabel: "Rename", + hoverLabel: "Rename", + btnIcon: "fa-light fa-pen-to-square", + redirectUrl: "", + action: "rename" + }, { btnId: "6788", btnLabel: "Revoke", @@ -336,11 +327,18 @@ export default function reportJson(id) { ] }; // contactbook report - case "5KhaPr482K": + case "contacts": return { reportName: "Contactbook", heading: contactbook, actions: [ + { + btnId: "2674", + hoverLabel: "Edit", + btnColor: "op-btn-primary", + btnIcon: "fa-light fa-pen", + action: "edit" + }, { btnId: "2204", hoverLabel: "Delete", @@ -349,6 +347,7 @@ export default function reportJson(id) { action: "delete" } ], + import: true, form: "ContactBook", helpMsg: "This is a list of contacts/signers added by you. These will appear as suggestions when you try to add signers to a new document." @@ -393,7 +392,14 @@ export default function reportJson(id) { redirectUrl: "template", action: "redirect" }, - ...templateSubAction, + { + btnId: "1633", + btnLabel: "Rename", + hoverLabel: "Rename", + btnIcon: "fa-light fa-pen-to-square", + redirectUrl: "", + action: "rename" + }, { btnId: "1834", btnLabel: "Delete", diff --git a/apps/OpenSign/src/json/menuJson.js b/apps/OpenSign/src/json/menuJson.js index 6c70006f7..91acb7324 100644 --- a/apps/OpenSign/src/json/menuJson.js +++ b/apps/OpenSign/src/json/menuJson.js @@ -1,3 +1,22 @@ +export const subSetting = [ + { + icon: "fa-light fa-sliders", + title: "Preferences", + target: "_self", + pageType: "", + description: "", + objectId: "preferences" + }, + { + icon: "fa-light fa-users fa-fw", + title: "Users", + target: "_self", + pageType: "", + description: "", + objectId: "users" + } +]; + const sidebarList = [ { icon: "fa-light fa-tachometer-alt", @@ -46,7 +65,7 @@ const sidebarList = [ pageType: "report", description: "", objectId: "6TeaPr321t" - } + }, ] }, { @@ -59,7 +78,7 @@ const sidebarList = [ }, { icon: "fa-light fa-address-card", - title: "Reports", + title: "Documents", target: "_self", pageType: null, description: "", @@ -112,17 +131,17 @@ const sidebarList = [ pageType: "report", description: "", objectId: "zNqBHXHsYH" - }, - { - icon: "fa-light fa-address-book", - title: "Contactbook", - target: "_self", - pageType: "report", - description: "", - objectId: "5KhaPr482K" } ] }, + { + icon: "fa-light fa-address-book", + title: "Contactbook", + target: "_self", + pageType: "report", + description: "", + objectId: "contacts" + }, { icon: "fa-light fa-cog", title: "Settings", @@ -154,14 +173,6 @@ const sidebarList = [ pageType: "", description: "", objectId: "webhook" - }, - { - icon: "fa-light fa-sliders", - title: "Preferences", - target: "_self", - pageType: "", - description: "", - objectId: "preferences" } ] } diff --git a/apps/OpenSign/src/json/plansArr.js b/apps/OpenSign/src/json/plansArr.js deleted file mode 100644 index 337338fb2..000000000 --- a/apps/OpenSign/src/json/plansArr.js +++ /dev/null @@ -1,255 +0,0 @@ -import { isStaging } from "../constant/const"; - -const plans = [ - { - planName: "OPENSIGN™ FREE", - code: { monthly: "freeplan", yearly: "freeplan" }, - img: "free.png", - currency: "", - monthlyPrice: "Free", - yearlyPrice: "Free", - subtitle: "Free Unlimited E-signatures, Forever.", - btn: { text: "Subscribe", color: "op-btn-primary" }, - url: "", - target: "_blank", - benefits: [ - "Unlimited digital signatures", - "Sign documents yourself", - "Request signatures from others", - "Unlimited templates", - "14 field types", - "Automatic e-signatures", - "Completion certificates", - "Send in order", - "Organize docs in OpenSign™ Drive", - "Document templates", - "Import from Dropbox", - "Contact book", - "Document expiry support", - "Decline document support", - "Email notifications", - "Public profiles", - "And much more" - ], - yearlyBenefits: [ - "Unlimited digital signatures", - "Sign documents yourself", - "Request signatures from others", - "Unlimited templates", - "14 field types", - "Automatic e-signatures", - "Completion certificates", - "Send in order", - "Organize docs in OpenSign™ Drive", - "Document templates", - "Import from Dropbox", - "Contact book", - "Document expiry support", - "Decline document support", - "Email notifications", - "Public profiles", - "And much more" - ] - }, - { - planName: "OPENSIGN™ PROFESSIONAL", - code: isStaging - ? { monthly: "pro-weekly", yearly: "pro-yearly" } - : { monthly: "professional-monthly", yearly: "professional-yearly" }, - img: "professional.png", - currency: "$", - monthlyPrice: "29.99", - yearlyPrice: `9.99<sup style="font-size: 17px;">/month</sup>`, - subtitle: "Exclusive Access to advanced features.", - btn: { text: "Subscribe", color: "op-btn-primary" }, - url: isStaging - ? "https://billing.zohosecure.in/subscribe/9627f62a09df1c8ce500f2f4dc8328dd84ecda20eeae13878ce581d60240f206/pro-weekly" - : "https://billing.opensignlabs.com/subscribe/ef798486e6a0a11ea65f2bae8f2af901d1a09dfa8085585cdd4ec4d7f32137f3/professional-monthly", - yearlyUrl: isStaging - ? "https://billing.zohosecure.in/subscribe/9627f62a09df1c8ce500f2f4dc8328ddc184411129224f1f29ed84f6cef3b862/pro-yearly" - : "https://billing.opensignlabs.com/subscribe/ef798486e6a0a11ea65f2bae8f2af901d8ad1135190dff951330360e47585a71/professional-yearly", - target: "_self", - benefits: [ - "Everything in OpenSign™ free", - "Field validations", - "Regular expression validations", - "Organize docs in OpenSign™ Drive", - "Webhooks", - "Zapier integration", - "API Access", - "upto 100 API signatures", - "Custom email templates", - "Connect your own Gmail or SMTP account for sending emails", - "Auto reminders", - "Bulk send (upto 100 docs)", - "Premium Public profile usernames", - "Enforce email-based verification to confirm signer identity", - "Embedded signing" - ], - yearlyBenefits: [ - "Everything in OpenSign™ free", - "Field validations", - "Regular expression validations", - "Organize docs in OpenSign™ Drive", - "Webhooks", - "Zapier integration", - "API Access", - "upto 240 API signatures", - "Custom email templates", - "Connect your own Gmail or SMTP account for sending emails", - "Auto reminders", - "Bulk send (upto 240 docs)", - "Premium Public profile usernames", - "Enforce email-based verification to confirm signer identity", - "Embedded signing" - ] - }, - { - planName: "OPENSIGN™ TEAMS", - code: { monthly: "teams-monthly", yearly: "teams-yearly" }, - img: "teams.png", - currency: "$", - monthlyPrice: `39.99<sup style="font-size: 17px;">/user</sup>`, - yearlyPrice: `19.99<sup style="font-size: 17px;">/user/month</sup>`, - subtitle: "Exclusive Access to advanced features.", - btn: { text: "Subscribe", color: "op-btn-accent" }, - url: isStaging - ? "https://billing.zohosecure.in/subscribe/ed8097273a82b6bf39892c11a3bb3c381eb2705736014cfbdbde1ccf1c7a189d/teams-monthly" - : "https://billing.opensignlabs.com/subscribe/ef798486e6a0a11ea65f2bae8f2af901237d0702bfaa959406306635d80f138c/teams-monthly", - yearlyUrl: isStaging - ? "https://billing.zohosecure.in/subscribe/ed8097273a82b6bf39892c11a3bb3c381eb2705736014cfbdbde1ccf1c7a189d/teams-yearly" - : "https://billing.opensignlabs.com/subscribe/ef798486e6a0a11ea65f2bae8f2af9011a864994bbeeec71fcf106188630199d/teams-yearly", - target: "_self", - benefits: [ - "Everything in OpenSign™ professional", - "upto 100 API signatures", - "Teams and Organizations", - "Share Templates with teams", - "Share Templates with individuals", - "BYOC - Store your documents in your own cloud storage", - "DocumentId removal from signed docs", - "Bulk send (upto 100 docs)", - "Request Payments (coming soon)", - "Mobile app (coming soon)" - ], - yearlyBenefits: [ - "Everything in OpenSign™ professional", - "upto 500 API signatures", - "Teams and Organizations", - "Share Templates with teams", - "Share Templates with individuals", - "BYOC - Store your documents in your own cloud storage", - "DocumentId removal from signed docs", - "Bulk send (upto 500 docs)", - "Request Payments (coming soon)", - "Mobile app (coming soon)" - ] - }, - { - planName: "OPENSIGN™ ENTERPRISE", - img: "enterprise.png", - currency: "", - monthlyPrice: `<p style="font-size: 22px;">Request Price</p>`, - yearlyPrice: `<p style="font-size: 22px;">Request Price</p>`, - subtitle: "Scalable Features with priority support.", - btn: { text: "Contact us", color: "op-btn-primary" }, - url: "https://www.opensignlabs.com/contact-us", - target: "_blank", - benefits: [ - "All features", - "Custom domain", - "Custom branding", - "Uptime SLA", - "SSO support", - "Priority support" - ], - yearlyBenefits: [ - "All features", - "Custom domain", - "Custom branding", - "Uptime SLA", - "SSO support", - "Priority support" - ] - } -]; - -export const validplan = { - "team-weekly": true, - "team-yearly": true, - "teams-monthly": true, - "teams-yearly": true, - "enterprise-monthly": true, - "enterprise-yearly": true -}; -export const paidUrl = (plan) => { - const teamperiod = { - "team-weekly": "monthly", - "team-yearly": "yearly", - "teams-monthly": "monthly", - "teams-yearly": "yearly" - }; - const period = teamperiod[plan] || ""; - if (period) { - const extUser = - localStorage.getItem("Extand_Class") && - JSON.parse(localStorage.getItem("Extand_Class"))?.[0]; - const user = { - name: extUser?.Name, - email: extUser?.Email, - company: extUser?.Company, - phone: extUser?.Phone - }; - // console.log("userDetails ", userDetails); - const fullname = user && user.name ? user.name.split(" ") : ""; - const firstname = fullname?.[0] - ? "first_name=" + encodeURIComponent(fullname?.[0]) - : ""; - const lastname = fullname?.[1] - ? "&last_name=" + encodeURIComponent(fullname?.[1]) - : ""; - const name = firstname ? firstname + lastname : ""; - const email = - user && user.email ? "&email=" + encodeURIComponent(user.email) : ""; - const company = - user && user.company - ? "&company_name=" + encodeURIComponent(user.company) - : ""; - const phone = - user && user.phone ? "&mobile=" + encodeURIComponent(user.phone) : ""; - const allowedUsers = - localStorage.getItem("allowedUsers") && - localStorage.getItem("allowedUsers") > 0 - ? localStorage.getItem("allowedUsers") - 1 - : ""; - const quantity = allowedUsers - ? `addon_code%5B0%5D=extra-teams-users-${period}&addon_quantity%5B0%5D=${allowedUsers}&` - : ""; - - const details = - "?shipping_country_code=US&billing_country_code=US&billing_state_code=CA&" + - quantity + - name + - email + - company + - phone; - - if (user) { - localStorage.setItem("userDetails", JSON.stringify(user)); - } - const url = { - monthly: isStaging - ? "https://billing.zohosecure.in/subscribe/ed8097273a82b6bf39892c11a3bb3c381eb2705736014cfbdbde1ccf1c7a189d/teams-monthly" - : "https://billing.opensignlabs.com/subscribe/ef798486e6a0a11ea65f2bae8f2af901237d0702bfaa959406306635d80f138c/teams-monthly", - yearly: isStaging - ? "https://billing.zohosecure.in/subscribe/ed8097273a82b6bf39892c11a3bb3c381eb2705736014cfbdbde1ccf1c7a189d/teams-yearly" - : "https://billing.opensignlabs.com/subscribe/ef798486e6a0a11ea65f2bae8f2af9011a864994bbeeec71fcf106188630199d/teams-yearly" - }; - - const planurl = url[period] + details; - return planurl; - } else { - return "/subscription"; - } -}; -export default plans; diff --git a/apps/OpenSign/src/layout/HomeLayout.js b/apps/OpenSign/src/layout/HomeLayout.js index 625bac547..ecdac1c34 100644 --- a/apps/OpenSign/src/layout/HomeLayout.js +++ b/apps/OpenSign/src/layout/HomeLayout.js @@ -8,10 +8,8 @@ import axios from "axios"; import { useDispatch, useSelector } from "react-redux"; import Parse from "parse"; import ModalUi from "../primitives/ModalUi"; -import { useNavigate, useLocation, Outlet } from "react-router-dom"; -import { isEnableSubscription } from "../constant/const"; +import { useNavigate, useLocation, Outlet } from "react-router"; import { useCookies } from "react-cookie"; -import { fetchSubscription } from "../constant/Utils"; import Loader from "../primitives/Loader"; import { showHeader } from "../redux/reducers/showHeader"; import { useTranslation } from "react-i18next"; @@ -26,7 +24,6 @@ const HomeLayout = () => { const arr = useSelector((state) => state.TourSteps); const [isUserValid, setIsUserValid] = useState(true); const [isLoader, setIsLoader] = useState(true); - // reactour state const [isCloseBtn, setIsCloseBtn] = useState(true); const [isTour, setIsTour] = useState(false); const [tourStatusArr, setTourStatusArr] = useState([]); @@ -38,6 +35,7 @@ const HomeLayout = () => { useEffect(() => { const language = localStorage.getItem("i18nextLng"); i18n.changeLanguage(language); + localStorage.setItem("isGuestSigner", ""); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); @@ -54,7 +52,8 @@ const HomeLayout = () => { }); if (user) { localStorage.setItem("profileImg", user.get("ProfilePic") || ""); - checkIsSubscribed(); + setIsUserValid(true); + setIsLoader(false); } else { setIsUserValid(false); } @@ -95,30 +94,6 @@ const HomeLayout = () => { domain: updateDomain }); }; - const handleNavigation = () => { - navigate("/subscription"); - }; - async function checkIsSubscribed() { - if (isEnableSubscription) { - const res = await fetchSubscription(); - if (res.plan === "freeplan") { - setIsUserValid(true); - setIsLoader(false); - } else if (res.billingDate) { - if (new Date(res.billingDate) > new Date()) { - setIsUserValid(true); - setIsLoader(false); - } else { - handleNavigation(res.plan); - } - } else { - handleNavigation(res.plan); - } - } else { - setIsUserValid(true); - setIsLoader(false); - } - } const showSidebar = () => { setIsOpen((value) => !value); dispatch(showHeader(!isOpen)); diff --git a/apps/OpenSign/src/pages/AddAdmin.js b/apps/OpenSign/src/pages/AddAdmin.js index 6dc83ac1c..17cdb1ac1 100644 --- a/apps/OpenSign/src/pages/AddAdmin.js +++ b/apps/OpenSign/src/pages/AddAdmin.js @@ -1,11 +1,12 @@ import React, { useEffect, useState } from "react"; import Parse from "parse"; import { appInfo } from "../constant/appinfo"; -import { NavLink, useNavigate } from "react-router-dom"; +import { NavLink, useNavigate } from "react-router"; import { getAppLogo, openInNewTab, - saveLanguageInLocal + saveLanguageInLocal, + usertimezone } from "../constant/Utils"; import { useDispatch } from "react-redux"; import { showTenant } from "../redux/reducers/ShowTenant"; @@ -116,7 +117,8 @@ const AddAdmin = () => { name: name, email: email, phone: phone, - role: "contracts_Admin" + role: "contracts_Admin", + timezone: usertimezone } }; try { diff --git a/apps/OpenSign/src/pages/ChangePassword.js b/apps/OpenSign/src/pages/ChangePassword.js index d903c504b..bf693a986 100644 --- a/apps/OpenSign/src/pages/ChangePassword.js +++ b/apps/OpenSign/src/pages/ChangePassword.js @@ -1,6 +1,6 @@ import React, { useState } from "react"; import Parse from "parse"; -import { Navigate } from "react-router-dom"; +import { Navigate } from "react-router"; import Title from "../components/Title"; import { useTranslation } from "react-i18next"; diff --git a/apps/OpenSign/src/pages/Dashboard.js b/apps/OpenSign/src/pages/Dashboard.js index 79947bd64..d135c3c0e 100644 --- a/apps/OpenSign/src/pages/Dashboard.js +++ b/apps/OpenSign/src/pages/Dashboard.js @@ -1,6 +1,6 @@ import React, { useState, useEffect } from "react"; import GetDashboard from "../components/dashboard/GetDashboard"; -import { useNavigate, useParams } from "react-router-dom"; +import { useNavigate, useParams } from "react-router"; import Title from "../components/Title"; import { useDispatch } from "react-redux"; import { saveTourSteps } from "../redux/reducers/TourStepsReducer"; diff --git a/apps/OpenSign/src/pages/DebugPdf.js b/apps/OpenSign/src/pages/DebugPdf.js index dba54fdfe..52b52a830 100644 --- a/apps/OpenSign/src/pages/DebugPdf.js +++ b/apps/OpenSign/src/pages/DebugPdf.js @@ -225,7 +225,7 @@ const DebugPdf = () => { <div className="flex flex-row justify-between"> {/* this component used to render all pdf pages in left side */} <RenderAllPdfPage - signPdfUrl={pdf} + pdfBase64Url={pdfDetails.base64} allPages={allPages} setAllPages={setAllPages} setPageNumber={setPageNumber} diff --git a/apps/OpenSign/src/pages/DocSuccessPage.js b/apps/OpenSign/src/pages/DocSuccessPage.js new file mode 100644 index 000000000..2ca550e0b --- /dev/null +++ b/apps/OpenSign/src/pages/DocSuccessPage.js @@ -0,0 +1,138 @@ +import React, { useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { + getBase64FromUrl, + handleDownloadCertificate, + handleDownloadPdf, + handleToPrint +} from "../constant/Utils"; +import ModalUi from "../primitives/ModalUi"; +import Loader from "../primitives/Loader"; +import DownloadPdfZip from "../primitives/DownloadPdfZip"; + +const DocSuccessPage = () => { + 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(); + + useEffect(() => { + initialsetup(); + }, []); + const initialsetup = async () => { + const search = window.location.search.split("?")[1]; + if (search) { + const urlParams = new URLSearchParams(search); + const docId = urlParams.get("docid"); + const docUrl = urlParams.get("docurl"); + const certificate = urlParams.get("certificate"); + const completed = urlParams?.get("completed") || false; + const details = { + objectId: docId, + SignedUrl: docUrl, + CertificateUrl: certificate, + IsCompleted: completed + }; + setPdfDetails([details]); + const base64Pdf = await getBase64FromUrl(docUrl); + if (base64Pdf) { + setPdfBase64Url(base64Pdf); + } + } + }; + const handleDownload = () => { + if (pdfDetails?.[0]?.IsCompleted) { + setIsDownloadModal(true); + } else { + handleDownloadPdf(pdfDetails, setIsDownloading, pdfBase64Url); + } + }; + return ( + <div className="flex h-screen justify-center items-center text-sm md:text-base"> + {sent ? ( + <div>{t("doc-sent")}</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> + {isDownloading === "pdf" && ( + <div className="fixed z-[1000] inset-0 flex justify-center items-center bg-black bg-opacity-30"> + <Loader /> + </div> + )} + <ModalUi + isOpen={ + isDownloading === "certificate" || + isDownloading === "certificate_err" + } + title={ + isDownloading === "certificate" || + isDownloading === "certificate_err" + ? t("generating-certificate") + : t("pdf-download") + } + handleClose={() => setIsDownloading("")} + > + <div className="p-3 md:p-5 text-[13px] md:text-base text-center text-base-content"> + {isDownloading === "certificate" ? ( + <p>{t("generate-certificate-alert")}</p> + ) : ( + <p>{t("generate-certificate-err")}</p> + )} + </div> + </ModalUi> + <DownloadPdfZip + setIsDownloadModal={setIsDownloadModal} + isDownloadModal={isDownloadModal} + pdfDetails={pdfDetails} + isDocId={true} + pdfBase64={pdfBase64Url} + /> + </div> + ) : ( + <></> + )} + </div> + ); +}; + +export default DocSuccessPage; diff --git a/apps/OpenSign/src/pages/ForgetPassword.js b/apps/OpenSign/src/pages/ForgetPassword.js index 89f38d908..6e957dbfe 100644 --- a/apps/OpenSign/src/pages/ForgetPassword.js +++ b/apps/OpenSign/src/pages/ForgetPassword.js @@ -1,14 +1,15 @@ import React, { useEffect, useState } from "react"; import Title from "../components/Title"; -import { useNavigate } from "react-router-dom"; +import { useNavigate } from "react-router"; import login_img from "../assets/images/login_img.svg"; import Parse from "parse"; import Alert from "../primitives/Alert"; import { appInfo } from "../constant/appinfo"; import { useDispatch } from "react-redux"; import { fetchAppInfo } from "../redux/reducers/infoReducer"; -import { emailRegex, isEnableSubscription } from "../constant/const"; -import { getAppLogo } from "../constant/Utils"; +import { + emailRegex, +} from "../constant/const"; import { useTranslation } from "react-i18next"; function ForgotPassword() { @@ -70,16 +71,7 @@ function ForgotPassword() { } catch (err) { console.log("err while logging out ", err); } - if (isEnableSubscription) { - const app = await getAppLogo(); - if (app?.logo) { - setImage(app?.logo); - } else { - setImage(appInfo?.applogo || undefined); - } - } else { setImage(appInfo?.applogo || undefined); - } }; return ( <div> diff --git a/apps/OpenSign/src/pages/Form.js b/apps/OpenSign/src/pages/Form.js index 4f474ff44..f8bb4454d 100644 --- a/apps/OpenSign/src/pages/Form.js +++ b/apps/OpenSign/src/pages/Form.js @@ -1,8 +1,7 @@ import React, { useEffect, useRef, useState } from "react"; -import { useNavigate, useParams } from "react-router-dom"; +import { useNavigate, useParams } from "react-router"; import { formJson } from "../json/FormJson"; import Parse from "parse"; -import DropboxChooser from "../components/shared/fields/DropboxChoose"; import Alert from "../primitives/Alert"; import SelectFolder from "../components/shared/fields/SelectFolder"; import SignersInput from "../components/shared/fields/SignersInput"; @@ -10,33 +9,20 @@ import Title from "../components/Title"; import PageNotFound from "./PageNotFound"; import { SaveFileSize } from "../constant/saveFileSize"; import { - checkIsSubscribed, + flattenPdf, + generatePdfName, generateTitleFromFilename, getFileName, + getSecureUrl, toDataUrl } from "../constant/Utils"; import { PDFDocument } from "pdf-lib"; import axios from "axios"; -import { isEnableSubscription } from "../constant/const"; import ModalUi from "../primitives/ModalUi"; import { Tooltip } from "react-tooltip"; -import Upgrade from "../primitives/Upgrade"; import Loader from "../primitives/Loader"; import { useTranslation } from "react-i18next"; -// `generatePdfName` is used to generate file name -function generatePdfName(length) { - const characters = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - let result = ""; - const charactersLength = characters.length; - - for (let i = 0; i < length; i++) { - result += characters.charAt(Math.floor(Math.random() * charactersLength)); - } - return result; -} - // `Form` render all type of Form on this basis of their provided in path function Form() { const { id } = useParams(); @@ -69,7 +55,10 @@ const Forms = (props) => { autoreminder: false, IsEnableOTP: "false", IsTourEnabled: "false", - NotifyOnSignatures: "" + NotifyOnSignatures: "", + Bcc: [], + RedirectUrl: "", + AllowModifications: false }); const [fileupload, setFileUpload] = useState(""); const [fileload, setfileload] = useState(false); @@ -80,8 +69,9 @@ const Forms = (props) => { const [isPassword, setIsPassword] = useState(false); const [isDecrypting, setIsDecrypting] = useState(false); const [isCorrectPass, setIsCorrectPass] = useState(true); - const [isSubscribe, setIsSubscribe] = useState(false); const [isAdvanceOpt, setIsAdvanceOpt] = useState(false); + const [bcc, setBcc] = useState([]); + const handleStrInput = (e) => { setIsCorrectPass(true); setFormData({ ...formData, [e.target.name]: e.target.value }); @@ -96,25 +86,11 @@ const Forms = (props) => { }, [props.title]); useEffect(() => { - fetchSubscription(); + initializeValues(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - const fetchSubscription = async () => { - if (isEnableSubscription) { - const subscribe = await checkIsSubscribed(); - setIsSubscribe(subscribe.isValid); - if (subscribe.isValid && extUserData.NotifyOnSignatures !== undefined) { - setFormData((obj) => ({ - ...obj, - NotifyOnSignatures: extUserData.NotifyOnSignatures - })); - } else if (subscribe.isValid) { - setFormData((obj) => ({ ...obj, NotifyOnSignatures: true })); - } - } else { - setIsSubscribe(true); + const initializeValues = async () => { setFormData((obj) => ({ ...obj, NotifyOnSignatures: true })); - } }; function getFileAsArrayBuffer(file) { @@ -125,6 +101,15 @@ const Forms = (props) => { reader.readAsArrayBuffer(file); }); } + + // `removeFile` is used to reset progress, percentage and remove file if exists + const removeFile = (e) => { + setfileload(false); + setpercentage(0); + if (e) { + e.target.value = ""; + } + }; const handleFileInput = async (e) => { setpercentage(0); try { @@ -135,117 +120,141 @@ const Forms = (props) => { if (mb > maxFileSize) { alert(`${t("file-alert-1")} ${maxFileSize} MB`); setFileUpload(""); - e.target.value = ""; + removeFile(e); return; } else { if (files?.[0]?.type === "application/pdf") { - try { - const res = await getFileAsArrayBuffer(files[0]); - await PDFDocument.load(res); - handleFileUpload(files[0]); - } catch (err) { - if (err?.message?.includes("is encrypted")) { + const size = files?.[0]?.size; + const name = generatePdfName(16); + const pdfName = `${name?.split(".")[0]}.pdf`; + setfileload(true); + try { + const res = await getFileAsArrayBuffer(files[0]); + const flatPdf = await flattenPdf(res); + const parseFile = new Parse.File( + pdfName, + [...flatPdf], + "application/pdf" + ); + try { - await Parse.Cloud.run("encryptedpdf", { - email: Parse.User.current().getEmail() + const response = await parseFile.save({ + progress: (progressValue, loaded, total, { type }) => { + if (type === "upload" && progressValue !== null) { + const percentCompleted = Math.round( + (loaded * 100) / total + ); + setpercentage(percentCompleted); + } + } }); - } catch (err) { - console.log("err in sending posthog encryptedpdf", err); - } - try { - setIsDecrypting(true); - const size = files?.[0].size; - const name = generatePdfName(16); - const url = "https://ai.nxglabs.in/decryptpdf"; // - let formData = new FormData(); - formData.append("file", files[0]); - formData.append("password", ""); - const config = { - headers: { "content-type": "multipart/form-data" }, - responseType: "blob" - }; - const response = await axios.post(url, formData, config); - const pdfBlob = new Blob([response.data], { - type: "application/pdf" - }); - const pdfFile = new File([pdfBlob], name, { - type: "application/pdf" - }); - setIsDecrypting(false); - setfileload(true); - const fileAdapterId = - extUserData?.TenantId?.ActiveFileAdapter || ""; - if (fileAdapterId) { - const base64 = await toDataUrl(pdfFile); - const fileBase64 = base64.split(",").pop(); - const ext = files?.[0]?.name?.split(".").pop(); - const fileRes = await saveToCustomFile( - fileBase64, - `${name}.${ext}`, - fileAdapterId - ); + // The response object will contain information about the uploaded file + // You can access the URL of the uploaded file using response.url() + if (response.url()) { + const fileRes = await getSecureUrl(response.url()); if (fileRes.url) { setFileUpload(fileRes.url); setfileload(false); - setpercentage(0); + const tenantId = localStorage.getItem("TenantId"); const title = generateTitleFromFilename(files?.[0]?.name); setFormData((obj) => ({ ...obj, Name: title })); - const tenantId = localStorage.getItem("TenantId"); SaveFileSize(size, fileRes.url, tenantId); return fileRes.url; } else { - setfileload(false); - setpercentage(0); - setFileUpload(""); + removeFile(e); + } + } else { + removeFile(e); + } + } catch (error) { + removeFile(e); + console.error("Error uploading file:", error); + } + } catch (err) { + if (err?.message?.includes("is encrypted")) { + try { + await Parse.Cloud.run("encryptedpdf", { + email: Parse.User.current().getEmail() + }); + } catch (err) { + console.log("err in sending posthog encryptedpdf", err); + } + try { + setIsDecrypting(true); + const size = files?.[0].size; + const name = generatePdfName(16); + const url = "https://ai.nxglabs.in/decryptpdf"; // + let formData = new FormData(); + formData.append("file", files[0]); + formData.append("password", ""); + const config = { + headers: { "content-type": "multipart/form-data" }, + responseType: "blob" + }; + const response = await axios.post(url, formData, config); + const pdfBlob = new Blob([response.data], { + type: "application/pdf" + }); + const pdfFile = new File([pdfBlob], name, { + type: "application/pdf" + }); + setIsDecrypting(false); + setfileload(true); + const res = await getFileAsArrayBuffer(pdfFile); + const flatPdf = await flattenPdf(res); + // Upload the file to Parse Server + const parseFile = new Parse.File( + name, + [...flatPdf], + "application/pdf" + ); + + await parseFile.save({ + progress: (progressValue, loaded, total, { type }) => { + if (type === "upload" && progressValue !== null) { + const percentCompleted = Math.round( + (loaded * 100) / total + ); + setpercentage(percentCompleted); + } + } + }); + + // Retrieve the URL of the uploaded file + if (parseFile.url()) { + const fileRes = await getSecureUrl(parseFile.url()); + if (fileRes.url) { + setFileUpload(fileRes.url); + removeFile(); + const title = generateTitleFromFilename( + files?.[0]?.name + ); + setFormData((obj) => ({ ...obj, Name: title })); + const tenantId = localStorage.getItem("TenantId"); + SaveFileSize(size, fileRes.url, tenantId); + return fileRes.url; + } else { + removeFile(e); + } + } else { + removeFile(e); + } + } catch (err) { + removeFile(); + if (err?.response?.status === 401) { + setIsPassword(true); + } else { + console.log("Error uploading file: ", err?.response); + setIsDecrypting(false); e.target.value = ""; } - } else { - // Upload the file to Parse Server - const parseFile = new Parse.File( - name, - pdfFile, - "application/pdf" - ); - - await parseFile.save({ - progress: (progressValue, loaded, total, { type }) => { - if (type === "upload" && progressValue !== null) { - const percentCompleted = Math.round( - (loaded * 100) / total - ); - setpercentage(percentCompleted); - } - } - }); - - // Retrieve the URL of the uploaded file - if (parseFile.url()) { - setFileUpload(parseFile.url()); - setfileload(false); - const title = generateTitleFromFilename(files?.[0]?.name); - setFormData((obj) => ({ ...obj, Name: title })); - const tenantId = localStorage.getItem("TenantId"); - SaveFileSize(size, parseFile.url(), tenantId); - return parseFile.url(); - } - } - } catch (err) { - setfileload(false); - setpercentage(0); - if (err?.response?.status === 401) { - setIsPassword(true); - } else { - console.log("Error uploading file: ", err?.response); - setIsDecrypting(false); - e.target.value = ""; } + } else { + console.log("err ", err); + setFileUpload(""); + removeFile(e); } - } else { - console.log("err ", err); - setFileUpload(""); - e.target.value = ""; } - } } else { const isImage = files?.[0]?.type.includes("image/"); if (isImage) { @@ -270,35 +279,6 @@ const Forms = (props) => { }); const size = files?.[0]?.size; const name = generatePdfName(16); - const fileAdapterId = - extUserData?.TenantId?.ActiveFileAdapter || ""; - if (fileAdapterId) { - const base64 = await pdfDoc.saveAsBase64({ - useObjectStreams: false - }); - setfileload(true); - const fileBase64 = base64.split(",").pop(); - const ext = files?.[0]?.name?.split(".").pop(); - const fileRes = await saveToCustomFile( - fileBase64, - `${name}.${ext}`, - fileAdapterId - ); - if (fileRes.url) { - setFileUpload(fileRes.url); - setfileload(false); - setpercentage(0); - const title = generateTitleFromFilename(files?.[0]?.name); - setFormData((obj) => ({ ...obj, Name: title })); - const tenantId = localStorage.getItem("TenantId"); - SaveFileSize(size, fileRes.url, tenantId); - return fileRes.url; - } else { - setfileload(false); - setpercentage(0); - e.target.value = ""; - } - } else { const getFile = await pdfDoc.save({ useObjectStreams: false }); @@ -323,53 +303,26 @@ const Forms = (props) => { }); // The response object will contain information about the uploaded file // You can access the URL of the uploaded file using response.url() - setFileUpload(response.url()); - setfileload(false); if (response.url()) { - const tenantId = localStorage.getItem("TenantId"); - const title = generateTitleFromFilename(files?.[0]?.name); - setFormData((obj) => ({ ...obj, Name: title })); - SaveFileSize(size, response.url(), tenantId); - return response.url(); + const fileRes = await getSecureUrl(response.url()); + if (fileRes.url) { + setFileUpload(fileRes.url); + setfileload(false); + const tenantId = localStorage.getItem("TenantId"); + const title = generateTitleFromFilename(files?.[0]?.name); + setFormData((obj) => ({ ...obj, Name: title })); + SaveFileSize(size, fileRes.url, tenantId); + return fileRes.url; + } else { + removeFile(e); + } + } else { + removeFile(e); } } catch (error) { - e.target.value = ""; - setfileload(false); - setpercentage(0); + removeFile(e); console.error("Error uploading file:", error); } - } - } else { - if (isEnableSubscription) { - try { - setfileload(true); - const url = "https://ai.nxglabs.in/docxtopdf"; - let formData = new FormData(); - formData.append("file", files[0]); - const config = { - headers: { - "content-type": "multipart/form-data", - sessiontoken: Parse.User.current().getSessionToken() - }, - signal: abortController.signal - }; - const res = await axios.post(url, formData, config); - if (res.data) { - setFileUpload(res.data.url); - setfileload(false); - const title = generateTitleFromFilename(files?.[0]?.name); - setFormData((obj) => ({ ...obj, Name: title })); - } - } catch (err) { - e.target.value = ""; - setfileload(false); - setpercentage(0); - console.log("err in libreconverter ", err); - alert( - "We are currently experiencing some issues with processing DOCX files. Please upload the PDF version or contact us on support@opensignlabs.com" - ); - } - } } } } @@ -382,158 +335,23 @@ const Forms = (props) => { return false; } }; - - const saveToCustomFile = async (base64, filename, fileAdapterId) => { + // `isValidURL` is used to check valid webhook url + function isValidURL(value) { try { - const savetos3 = await Parse.Cloud.run("savetofileadapter", { - fileBase64: base64, - fileName: filename, - id: fileAdapterId - }); - return { url: savetos3.url }; - } catch (err) { - console.log("err in save to customfile", err); - alert(err?.message); - if (inputFileRef.current) { - inputFileRef.current.value = ""; // Set file input value to empty string - } - return { url: "" }; + const url = new URL(value); + return url.protocol === "https:" || url.protocol === "http:"; + } catch (error) { + return false; } - }; - - const handleFileUpload = async (file) => { - setfileload(true); - const size = file.size; - const name = generatePdfName(16); - const pdfFile = file; - const fileAdapterId = extUserData?.TenantId?.ActiveFileAdapter || ""; - if (fileAdapterId) { - const base64 = await toDataUrl(file); - const fileBase64 = base64.split(",").pop(); - const ext = file?.name?.split(".").pop(); - const fileRes = await saveToCustomFile( - fileBase64, - `${name}.${ext}`, - fileAdapterId - ); - if (fileRes.url) { - setFileUpload(fileRes?.url); - const tenantId = localStorage.getItem("TenantId"); - const title = generateTitleFromFilename(file.name); - setFormData((obj) => ({ ...obj, Name: title })); - SaveFileSize(size, fileRes.url, tenantId); - } - setfileload(false); - setpercentage(0); - } else { - const parseFile = new Parse.File(name, pdfFile); - try { - const response = await parseFile.save({ - progress: (progressValue, loaded, total, { type }) => { - if (type === "upload" && progressValue !== null) { - const percentCompleted = Math.round((loaded * 100) / total); - setpercentage(percentCompleted); - } - } - }); - - // The response object will contain information about the uploaded file - // You can access the URL of the uploaded file using response.url() - setFileUpload(response.url()); - setfileload(false); - if (response.url()) { - const tenantId = localStorage.getItem("TenantId"); - const title = generateTitleFromFilename(file.name); - setFormData((obj) => ({ ...obj, Name: title })); - SaveFileSize(size, response.url(), tenantId); - return response.url(); - } - } catch (error) { - setfileload(false); - setpercentage(0); - console.error("Error uploading file:", error); - } - } - }; - async function uriToBase64(uri) { - const response = await fetch(uri); - const blob = await response.blob(); - return new Promise((resolve, reject) => { - const reader = new FileReader(); - reader.onloadend = () => resolve(reader.result); - reader.onerror = reject; - reader.readAsDataURL(blob); // Convert to Base64 - }); } - const dropboxSuccess = async (files) => { - setfileload(true); - const file = files[0]; - const size = file.bytes; - const url = file.link; - const mb = Math.round(file.bytes / Math.pow(1024, 2)); - - if (mb > maxFileSize) { - setTimeout(() => { - alert(`${t("file-alert-1")}${maxFileSize} MB`); - }, 500); - return; - } else { - const name = generatePdfName(16); - const fileAdapterId = extUserData?.TenantId?.ActiveFileAdapter || ""; - if (fileAdapterId) { - const base64 = await uriToBase64(url); - const fileBase64 = base64.split(",").pop(); - const ext = file?.name?.split(".").pop(); - const fileRes = await saveToCustomFile( - fileBase64, - `${name}.${ext}`, - fileAdapterId - ); - if (fileRes.url) { - setFileUpload(fileRes.url); - setfileload(false); - setpercentage(0); - const title = generateTitleFromFilename(files?.[0]?.name); - setFormData((obj) => ({ ...obj, Name: title })); - const tenantId = localStorage.getItem("TenantId"); - SaveFileSize(size, fileRes.url, tenantId); - return fileRes.url; - } else { - setfileload(false); - setpercentage(0); - } - } else { - const parseFile = new Parse.File(name, { uri: url }); - try { - const response = await parseFile.save({ - progress: (progressValue, loaded, total, { type }) => { - if (type === "upload" && progressValue !== null) { - const percentCompleted = Math.round((loaded * 100) / total); - setpercentage(percentCompleted); - } - } - }); - setFileUpload(response.url()); - setfileload(false); - if (response.url()) { - const tenantId = localStorage.getItem("TenantId"); - const title = generateTitleFromFilename(file.name); - setFormData((obj) => ({ ...obj, Name: title })); - SaveFileSize(size, response.url(), tenantId); - return response.url(); - } - } catch (error) { - setfileload(false); - setpercentage(0); - console.error("Error uploading file:", error); - } - } - } - }; const handleSubmit = async (e) => { e.preventDefault(); e.stopPropagation(); if (fileupload) { + if (formData.RedirectUrl && !isValidURL(formData?.RedirectUrl)) { + alert(t("invalid-redirect-url")); + return; + } setIsSubmit(true); try { const currentUser = Parse.User.current(); @@ -546,6 +364,13 @@ const Forms = (props) => { "TimeToCompleteDays", parseInt(formData?.TimeToCompleteDays) ); + if ( + extUserData?.TenantId?.RequestBody && + extUserData?.TenantId?.RequestSubject + ) { + object.set("RequestBody", extUserData?.TenantId?.RequestBody); + object.set("RequestSubject", extUserData?.TenantId?.RequestSubject); + } } if (props.title !== "Sign Yourself") { const isChecked = formData.SendinOrder === "false" ? false : true; @@ -555,18 +380,13 @@ const Forms = (props) => { object.set("AutomaticReminders", formData.autoreminder); object.set("RemindOnceInEvery", parseInt(formData.remindOnceInEvery)); object.set("IsTourEnabled", isTourEnabled); - if (isEnableSubscription) { - const IsEnableOTP = - formData?.IsEnableOTP === "false" ? false : true; - object.set("IsEnableOTP", IsEnableOTP); - if (isSubscribe && formData.NotifyOnSignatures !== undefined) { - object.set("NotifyOnSignatures", formData.NotifyOnSignatures); - } - } else { + object.set("AllowModifications", false); object.set("IsEnableOTP", false); if (formData.NotifyOnSignatures !== undefined) { object.set("NotifyOnSignatures", formData.NotifyOnSignatures); } + if (formData?.RedirectUrl) { + object.set("RedirectUrl", formData.RedirectUrl); } } object.set("URL", fileupload); @@ -581,6 +401,14 @@ const Forms = (props) => { if (signers && signers.length > 0) { object.set("Signers", signers); } + if (bcc && bcc.length > 0) { + const Bcc = bcc.map((x) => ({ + __type: "Pointer", + className: "contracts_Contactbook", + objectId: x.objectId + })); + object.set("Bcc", Bcc); + } const ExtCls = JSON.parse(localStorage.getItem("Extand_Class")); object.set("ExtUserPtr", { __type: "Pointer", @@ -593,7 +421,12 @@ const Forms = (props) => { const res = await object.save(); if (res) { setSigners([]); + setBcc([]); setFolder({ ObjectId: "", Name: "" }); + const notifySign = + extUserData?.NotifyOnSignatures + ? extUserData?.NotifyOnSignatures + : true; setFormData({ Name: "", Description: "", @@ -605,10 +438,13 @@ const Forms = (props) => { SendinOrder: "true", password: "", file: "", + NotifyOnSignatures: notifySign, remindOnceInEvery: 5, autoreminder: false, IsEnableOTP: "false", - IsTourEnabled: "true" + IsTourEnabled: "true", + RedirectUrl: "", + AllowModifications: false }); setFileUpload(""); setpercentage(0); @@ -645,10 +481,26 @@ const Forms = (props) => { } }; + const handleBcc = (data) => { + if (data && data.length > 0) { + const trimEmail = data.map((item) => ({ + objectId: item?.value, + Name: item?.label, + Email: item?.email + })); + setBcc(trimEmail); + } + }; + const handleReset = () => { setIsReset(true); setSigners([]); + setBcc([]); setFolder({ ObjectId: "", Name: "" }); + const notifySign = + extUserData?.NotifyOnSignatures + ? extUserData?.NotifyOnSignatures + : true; let obj = { Name: "", Description: "", @@ -663,11 +515,14 @@ const Forms = (props) => { remindOnceInEvery: 5, autoreminder: false, IsEnableOTP: "false", - IsTourEnabled: "true" + IsTourEnabled: "true", + NotifyOnSignatures: notifySign, + RedirectUrl: "", + AllowModifications: false }; setFormData(obj); + removeFile(); setFileUpload(""); - setpercentage(0); setTimeout(() => setIsReset(false), 50); }; const handleCancel = () => { @@ -699,33 +554,9 @@ const Forms = (props) => { type: "application/pdf" }); setIsDecrypting(false); - const fileAdapterId = extUserData?.TenantId?.ActiveFileAdapter || ""; - // Upload the file to Parse Server - if (fileAdapterId) { - const base64 = await toDataUrl(pdfFile); - const fileBase64 = base64.split(",").pop(); - const ext = formData?.file?.name?.split(".").pop(); - const fileRes = await saveToCustomFile( - fileBase64, - `${name}.${ext}`, - fileAdapterId - ); - if (fileRes.url) { - setFormData((prev) => ({ ...prev, password: "" })); - setFileUpload(fileRes?.url); - setfileload(false); - setpercentage(0); - const title = generateTitleFromFilename(formData?.file?.name); - setFormData((obj) => ({ ...obj, Name: title })); - const tenantId = localStorage.getItem("TenantId"); - SaveFileSize(size, fileRes.url, tenantId); - return fileRes.url; - } else { - setfileload(false); - setpercentage(0); - } - } else { - const parseFile = new Parse.File(name, pdfFile, "application/pdf"); + const res = await getFileAsArrayBuffer(pdfFile); + const flatPdf = await flattenPdf(res); + const parseFile = new Parse.File(name, [...flatPdf], "application/pdf"); await parseFile.save({ progress: (progressValue, loaded, total, { type }) => { if (type === "upload" && progressValue !== null) { @@ -736,28 +567,33 @@ const Forms = (props) => { }); // Retrieve the URL of the uploaded file if (parseFile.url()) { - setFormData((prev) => ({ ...prev, password: "" })); - setFileUpload(parseFile.url()); - setfileload(false); - setpercentage(0); - const title = generateTitleFromFilename(formData?.file?.name); - setFormData((obj) => ({ ...obj, Name: title })); - const tenantId = localStorage.getItem("TenantId"); - SaveFileSize(size, parseFile.url(), tenantId); - return parseFile.url(); + const fileRes = await getSecureUrl(parseFile.url()); + if (fileRes.url) { + setFileUpload(fileRes.url); + removeFile(); + const title = generateTitleFromFilename(formData?.file?.name); + setFormData((obj) => ({ ...obj, password: "", Name: title })); + const tenantId = localStorage.getItem("TenantId"); + SaveFileSize(size, fileRes.url, tenantId); + return fileRes.url; + } else { + removeFile(); + setFormData((prev) => ({ ...prev, password: "" })); + setIsDecrypting(false); + if (inputFileRef.current) { + inputFileRef.current.value = ""; // Set file input value to empty string + } + } } else { - setfileload(false); - setpercentage(0); + removeFile(); setFormData((prev) => ({ ...prev, password: "" })); setIsDecrypting(false); if (inputFileRef.current) { inputFileRef.current.value = ""; // Set file input value to empty string } } - } } catch (err) { - setfileload(false); - setpercentage(0); + removeFile(); if (err?.response?.status === 401) { setIsPassword(true); setIsCorrectPass(false); @@ -780,9 +616,6 @@ const Forms = (props) => { inputFileRef.current.value = ""; // Set file input value to empty string } }; - const handleAutoReminder = () => { - setFormData((prev) => ({ ...prev, autoreminder: !formData.autoreminder })); - }; // `handleNotifySignChange` is trigger when user change radio of notify on signatures const handleNotifySignChange = (value) => { @@ -840,9 +673,26 @@ const Forms = (props) => { </form> </ModalUi> <form onSubmit={handleSubmit}> - <h1 className="text-[20px] font-semibold mb-4"> - {t(`form-name.${props?.title}`)} - </h1> + <div className="mb-[11px]"> + <h1 className="text-[20px] font-semibold"> + {t(`form-name.${props?.title}`)} + </h1> + {props.title === "Sign Yourself" && ( + <div className="text-gray-500 text-xs mt-1"> + {t("signyour-self-description")} + </div> + )} + {props.title === "Request Signatures" && ( + <div className="text-gray-500 text-xs mt-1"> + {t("requestsign-description")} + </div> + )} + {props.title === "New Template" && ( + <div className="text-gray-500 text-xs mt-1"> + {t("template-form-description")} + </div> + )} + </div> {fileload && ( <div className="flex items-center gap-x-2"> <div className="h-2 rounded-full w-[200px] md:w-[400px] bg-gray-200"> @@ -863,8 +713,8 @@ const Forms = (props) => { )} <div className="text-xs"> <label className="block"> - {`${t("report-heading.File")} (${t("file-type")}${ - isEnableSubscription ? ", docx)" : ")" + {`${`${t("report-heading.File")} (${t("file-type")}`}${ + ")" }`} <span className="text-red-500 text-[13px]">*</span> </label> @@ -881,9 +731,6 @@ const Forms = (props) => { <i className="fa-light fa-xmark"></i> </div> </div> - {process.env.REACT_APP_DROPBOX_API_KEY && ( - <DropboxChooser onSuccess={dropboxSuccess} /> - )} </div> ) : ( <div className="flex gap-1 justify-center items-center"> @@ -893,9 +740,7 @@ const Forms = (props) => { onChange={(e) => handleFileInput(e)} ref={inputFileRef} accept={ - isEnableSubscription - ? "application/pdf,application/vnd.openxmlformats-officedocument.wordprocessingml.document,image/png,image/jpeg" - : "application/pdf,image/png,image/jpeg" + "application/pdf,image/png,image/jpeg" } onInvalid={(e) => e.target.setCustomValidity(t("input-required")) @@ -903,9 +748,6 @@ const Forms = (props) => { onInput={(e) => e.target.setCustomValidity("")} required /> - {process.env.REACT_APP_DROPBOX_API_KEY && ( - <DropboxChooser onSuccess={dropboxSuccess} /> - )} </div> )} </div> @@ -941,8 +783,10 @@ const Forms = (props) => { )} {props.signers && ( <SignersInput + label={t("signers")} onChange={handleSigners} isReset={isReset} + helptextZindex={50} required /> )} @@ -1047,33 +891,6 @@ const Forms = (props) => { )} {isAdvanceOpt && ( <> - {isEnableSubscription && - props.title === "New Template" && ( - <div className="text-xs mt-[15px]"> - <span - className={isSubscribe ? "" : " text-gray-300"} - > - {t("auto-reminder")}{" "} - {!isSubscribe && isEnableSubscription && ( - <Upgrade /> - )} - </span> - <label - className={`${ - isSubscribe - ? "cursor-pointer " - : "pointer-events-none opacity-50" - } relative block items-center mb-0 mt-1.5`} - > - <input - type="checkbox" - className="op-toggle transition-all checked:[--tglbg:#3368ff] checked:bg-white" - checked={formData.autoreminder} - onChange={handleAutoReminder} - /> - </label> - </div> - )} {props.title === "New Template" && formData?.autoreminder === true && ( <div className="text-xs mt-2"> @@ -1173,8 +990,7 @@ const Forms = (props) => { </div> </> )} - - <div className="overflow-y-auto z-[500] transition-all"> + <div className="overflow-y-auto z-[40] transition-all"> {props.title === "Request Signatures" && ( <div className="text-xs mt-2"> <label className="block"> @@ -1198,6 +1014,17 @@ const Forms = (props) => { </div> )} </div> + {props.bcc && ( + <SignersInput + label={t("Bcc")} + initialData={bcc} + onChange={handleBcc} + isReset={isReset} + helptextZindex={50} + helpText={t("bcc-help")} + isCaptureAllData + /> + )} </> )} </div> @@ -1205,9 +1032,6 @@ const Forms = (props) => { <div style={{ height: - props.title === "New Template" && isEnableSubscription - ? "220px" - : !isEnableSubscription && props.title === "New Template" ? "100px" : "280px" @@ -1217,28 +1041,6 @@ const Forms = (props) => { )} {isAdvanceOpt && ( <div className="card bg-base-100 rounded-box p-3 flex-grow "> - {isEnableSubscription && props.title !== "New Template" && ( - <div className="text-xs mt-[10px]"> - <span className={isSubscribe ? "" : " text-gray-300"}> - {t("auto-reminder")}{" "} - {!isSubscribe && isEnableSubscription && <Upgrade />} - </span> - <label - className={`${ - isSubscribe - ? "cursor-pointer" - : "pointer-events-none opacity-50" - } relative block items-center mb-0 mt-1.5`} - > - <input - type="checkbox" - className="op-toggle transition-all checked:[--tglbg:#3368ff] checked:bg-white" - checked={formData.autoreminder} - onChange={handleAutoReminder} - /> - </label> - </div> - )} {formData?.autoreminder === true && props.title !== "New Template" && ( <div className="text-xs mt-2"> @@ -1261,85 +1063,6 @@ const Forms = (props) => { </div> )} <span className="font-[400] mt-2">{t("form-title-2")}</span> - {isEnableSubscription && ( - <div className="text-xs mt-3"> - <label className="block"> - <span className={isSubscribe ? "" : " text-gray-300"}> - {t("isenable-otp")}{" "} - <a - data-tooltip-id="isenableotp-tooltip" - className="ml-1" - > - <sup> - <i className="fa-light fa-question rounded-full border-[#33bbff] text-[#33bbff] text-[13px] border-[1px] py-[1.5px] px-[4px]"></i> - </sup> - </a> - {!isSubscribe && isEnableSubscription && ( - <Upgrade /> - )} - </span> - <Tooltip id="isenableotp-tooltip" className="z-[999]"> - <div className="max-w-[200px] md:max-w-[450px]"> - <p className="font-bold">{t("isenable-otp")}</p> - <p>{t("isenable-otp-help.p1")}</p> - <p className="p-[5px]"> - <ol className="list-disc"> - <li> - <span className="font-bold"> - {t("yes")}:{" "} - </span> - <span>{t("isenable-otp-help.p2")}</span> - </li> - <li> - <span className="font-bold"> - {t("no")}:{" "} - </span> - <span>{t("isenable-otp-help.p3")}</span> - </li> - </ol> - </p> - <p>{t("isenable-otp-help.p4")}</p> - </div> - </Tooltip> - </label> - <div className="flex flex-col md:flex-row md:gap-4"> - <div - className={`${ - isSubscribe - ? "" - : "pointer-events-none opacity-50" - } flex items-center gap-2 ml-2 mb-1 `} - > - <input - type="radio" - value={"true"} - className="op-radio op-radio-xs" - name="IsEnableOTP" - checked={formData.IsEnableOTP === "true"} - onChange={handleStrInput} - /> - <div className="text-center">{t("yes")}</div> - </div> - <div - className={`${ - isSubscribe - ? "" - : "pointer-events-none opacity-50" - } flex items-center gap-2 ml-2 mb-1 `} - > - <input - type="radio" - value={"false"} - name="IsEnableOTP" - className="op-radio op-radio-xs" - checked={formData.IsEnableOTP === "false"} - onChange={handleStrInput} - /> - <div className="text-center">{t("no")}</div> - </div> - </div> - </div> - )} <div className="text-xs mt-3"> <label className="block"> <span> @@ -1401,9 +1124,9 @@ const Forms = (props) => { </div> <div className="text-xs mt-3"> <label - className={`${ - isSubscribe ? "" : "text-gray-300" - } block`} + className={ + "block" + } > {t("notify-on-signatures")} <a data-tooltip-id="nos-tooltip" className="ml-1"> @@ -1411,7 +1134,6 @@ const Forms = (props) => { <i className="fa-light fa-question rounded-full border-[#33bbff] text-[#33bbff] text-[13px] border-[1px] py-[1.5px] px-[4px]"></i> </sup> </a> - {!isSubscribe && isEnableSubscription && <Upgrade />} <Tooltip id="nos-tooltip" className="z-[999]"> <div className="max-w-[200px] md:max-w-[450px] text-[11px]"> <p className="font-bold"> @@ -1424,9 +1146,9 @@ const Forms = (props) => { </label> <div className="flex flex-col md:flex-row md:gap-4"> <div - className={`${ - isSubscribe ? "" : "pointer-events-none opacity-50" - } flex items-center gap-2 ml-2 mb-1`} + className={ + "flex items-center gap-2 ml-2 mb-1" + } > <input className="mr-[2px] op-radio op-radio-xs" @@ -1437,9 +1159,9 @@ const Forms = (props) => { <div className="text-center">{t("yes")}</div> </div> <div - className={`${ - isSubscribe ? "" : "pointer-events-none opacity-50" - } flex items-center gap-2 ml-2 mb-1`} + className={ + "flex items-center gap-2 ml-2 mb-1" + } > <input className="mr-[2px] op-radio op-radio-xs" @@ -1451,6 +1173,19 @@ const Forms = (props) => { </div> </div> </div> + <div className="text-xs mt-2"> + <label className="block">{t("redirect-url")}</label> + <input + name="RedirectUrl" + className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" + value={formData.RedirectUrl} + onChange={(e) => handleStrInput(e)} + onInvalid={(e) => + e.target.setCustomValidity(t("input-required")) + } + onInput={(e) => e.target.setCustomValidity("")} + /> + </div> </div> )} </div> @@ -1473,14 +1208,13 @@ const Forms = (props) => { </span> ) )} - <div className="flex items-center mt-3 gap-2"> <button className={`${ - isSubmit ? "cursor-progress" : "" + isSubmit || !fileupload ? "cursor-progress" : "" } op-btn op-btn-primary`} type="submit" - disabled={isSubmit} + disabled={isSubmit || !fileupload} > {t("next")} </button> diff --git a/apps/OpenSign/src/pages/GenerateToken.js b/apps/OpenSign/src/pages/GenerateToken.js deleted file mode 100644 index 0e8d48b82..000000000 --- a/apps/OpenSign/src/pages/GenerateToken.js +++ /dev/null @@ -1,473 +0,0 @@ -import React, { useEffect, useState } from "react"; -import Title from "../components/Title"; -import axios from "axios"; -import Alert from "../primitives/Alert"; -import ModalUi from "../primitives/ModalUi"; -import { isEnableSubscription } from "../constant/const"; -import { checkIsSubscribed, copytoData, openInNewTab } from "../constant/Utils"; -import Tooltip from "../primitives/Tooltip"; -import Loader from "../primitives/Loader"; -import SubscribeCard from "../primitives/SubscribeCard"; -import Tour from "reactour"; -import { useTranslation } from "react-i18next"; -import Parse from "parse"; - -function GenerateToken() { - const origin = window.location.origin; - const { t } = useTranslation(); - const parseBaseUrl = localStorage.getItem("baseUrl"); - const parseAppId = localStorage.getItem("parseAppId"); - const [apiToken, SetApiToken] = useState(""); - const [isLoader, setIsLoader] = useState(true); - const [isModal, setIsModal] = useState({ - generateapi: false, - buyapis: false, - unauthorized: false - }); - const [isSubscribe, setIsSubscribe] = useState({ - plan: "", - isValid: false, - adminId: "", - adminEmail: "" - }); - const [isAlert, setIsAlert] = useState({ type: "success", msg: "" }); - const [isTour, setIsTour] = useState(false); - const [amount, setAmount] = useState({ - quantity: 500, - priceperapi: 0.15, - allowedcredits: 0, - addoncredits: 0, - totalcredits: 0, - price: (75.0).toFixed(2) - }); - const [isFormLoader, setIsFormLoader] = useState(false); - const [apitestToken, setApiTestToken] = useState(""); - const quantityList = [500, 1000, 5000, 50000]; - useEffect(() => { - fetchToken(); - // eslint-disable-next-line - }, []); - const tourSteps = [ - { - selector: '[data-tut="apisubscribe"]', - content: t("tour-mssg.generate-token") - } - ]; - const fetchToken = async () => { - try { - if (isEnableSubscription) { - const subscribe = await checkIsSubscribed(); - setIsSubscribe(subscribe); - } - const url = parseBaseUrl + "functions/getapitoken"; - const headers = { - "Content-Type": "application/json", - "X-Parse-Application-Id": parseAppId, - sessiontoken: localStorage.getItem("accesstoken") - }; - const res = await axios.post(url, {}, { headers: headers }); - if (res) { - const resCredits = await Parse.Cloud.run("allowedcredits"); - const allowedcredits = resCredits?.allowedcredits || 0; - const addoncredits = resCredits?.addoncredits || 0; - const totalcredits = allowedcredits + addoncredits; - setAmount((obj) => ({ - ...obj, - allowedcredits: allowedcredits, - addoncredits: addoncredits, - totalcredits: totalcredits - })); - SetApiToken(res?.data?.result?.result); - } - try { - const body = { email: Parse?.User?.current()?.getEmail() || "" }; - const testurl = "https://sandbox.opensignlabs.com/api/gettesttoken"; - const testRes = await axios.post(testurl, body); - setApiTestToken(testRes.data?.token); - } catch (err) { - console.log("err in fetch test token", err); - } - } catch (err) { - SetApiToken(); - console.log("Err", err); - } finally { - setIsLoader(false); - } - }; - const handleSubmit = async (e) => { - e.preventDefault(); - if (isSubscribe?.plan === "freeplan" && isEnableSubscription) { - setIsTour(true); - } else { - setIsLoader(true); - setIsModal((obj) => ({ ...obj, generateapi: false })); - try { - const url = parseBaseUrl + "functions/generateapitoken"; - const headers = { - "Content-Type": "application/json", - "X-Parse-Application-Id": parseAppId, - sessiontoken: localStorage.getItem("accesstoken") - }; - const res = await axios.post(url, {}, { headers: headers }); - if (res) { - SetApiToken(res.data.result.token); - setIsAlert({ type: "success", msg: t("token-generated") }); - } else { - console.error("Error while generating Token"); - setIsAlert({ type: "danger", msg: t("something-went-wrong-mssg") }); - } - } catch (error) { - setIsAlert({ type: "danger", msg: t("something-went-wrong-mssg") }); - console.log("while generating Token", error); - } finally { - setIsLoader(false); - setTimeout(() => { - setIsAlert({ type: "success", msg: "" }); - }, 1500); - } - } - }; - - const copytoclipboard = (text) => { - copytoData(text); - setIsAlert({ type: "success", msg: t("copied") }); - setTimeout(() => setIsAlert({ type: "success", msg: "" }), 1500); // Reset copied state after 1.5 seconds - }; - const handleModal = () => { - if (isSubscribe?.plan === "freeplan" && isEnableSubscription) { - setIsTour(true); - } else { - setIsModal((obj) => ({ ...obj, generateapi: !obj.generateapi })); - } - }; - - const handleBuyAPIsModal = () => { - if (isSubscribe?.plan === "freeplan" && isEnableSubscription) { - setIsTour(true); - } else { - const extUser = - localStorage.getItem("Extand_Class") && - JSON.parse(localStorage.getItem("Extand_Class"))?.[0]; - if (isSubscribe?.adminId && extUser?.objectId === isSubscribe?.adminId) { - setIsModal((obj) => ({ ...obj, buyapis: !obj.buyapis })); - } else { - setIsSubscribe((obj) => ({ - ...obj, - adminEmail: extUser?.TenantId?.EmailAddress - })); - setIsModal((obj) => ({ ...obj, unauthorized: !obj.unauthorized })); - } - } - }; - const handleCloseModal = () => { - setIsModal({ generateapi: false, buyapis: false, unauthorized: false }); - }; - const handlePricePerAPIs = (e) => { - const quantity = e.target?.value; - const price = - quantity > 0 - ? (Math.round(quantity * amount.priceperapi * 100) / 100).toFixed(2) - : (Math.round(500 * amount.priceperapi * 100) / 100).toFixed(2); - setAmount((prev) => ({ ...prev, quantity: quantity, price: price })); - }; - const handleAddOnApiSubmit = async (e) => { - e.preventDefault(); - e.stopPropagation(); - setIsFormLoader(true); - try { - const resAddon = await Parse.Cloud.run("buycredits", { - credits: amount.quantity - }); - if (resAddon) { - const _resAddon = JSON.parse(JSON.stringify(resAddon)); - if (_resAddon.status === "success") { - setAmount((obj) => ({ - ...obj, - quantity: 500, - priceperapi: 0.15, - price: (75.0).toFixed(2), - totalcredits: obj?.totalcredits + _resAddon.addon, - addoncredits: obj?.addoncredits + _resAddon.addon - })); - } - } - setIsModal((obj) => ({ ...obj, buyapis: false })); - } catch (err) { - console.log("Err in buy addon", err); - setIsAlert({ type: "danger", msg: t("something-went-wrong-mssg") }); - } finally { - setTimeout(() => setIsAlert({ type: "success", msg: "" }), 2000); - setIsFormLoader(false); - } - }; - - const handleGenerateTestToken = async (e) => { - e.preventDefault(); - setIsLoader(true); - // setIsModal((obj) => ({ ...obj, generateapi: false })); - try { - const url = "https://sandbox.opensignlabs.com/api/generatetesttoken"; - const headers = { - "Content-Type": "application/json", - token: apitestToken || "1" - }; - const extUser = JSON.parse(localStorage.getItem("Extand_Class"))?.[0]; - const body = { - name: extUser?.Name, - email: extUser?.Email, - phone: extUser?.Phone, - company: extUser?.Company, - jobTitle: extUser?.JobTitle - }; - const res = await axios.post(url, body, { headers: headers }); - if (res) { - setApiTestToken(res.data?.token); - setIsAlert({ type: "success", msg: t("token-generated") }); - } else { - console.error("Error while generating Token"); - setIsAlert({ type: "danger", msg: t("something-went-wrong-mssg") }); - } - } catch (error) { - setIsAlert({ type: "danger", msg: t("something-went-wrong-mssg") }); - console.log("while generating Token", error); - } finally { - setIsLoader(false); - setTimeout(() => setIsAlert({ type: "success", msg: "" }), 1500); - } - }; - return ( - <React.Fragment> - <Title title={"API Token"} /> - {isAlert.msg && <Alert type={isAlert.type}>{isAlert.msg}</Alert>} - {isLoader ? ( - <div className="flex justify-center items-center h-screen"> - <Loader /> - </div> - ) : ( - <> - <div className="bg-base-100 text-base-content flex flex-col justify-center shadow-md rounded-box mb-3"> - <h1 className={"ml-4 mt-3 mb-2 font-semibold"}> - OpenSign™ {t("API")}{" "} - <Tooltip - url="https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1" - isSubscribe={true} - /> - </h1> - <ul className="w-full flex flex-col p-2 text-sm"> - <li className="flex flex-col md:flex-row justify-between items-center border-t-[1px] border-gray-300 break-all py-2"> - <div className="w-full md:w-[70%] flex-col md:flex-row text-xs md:text-[15px] flex items-center gap-x-5"> - <span className="ml-1"> - <span className="font-medium">API Test Token : </span> - <span className="text-xs"> - <Tooltip message={t("help-test-token")} /> - </span> - </span> - <span id="token" className="md:text-end py-2 md:py-0"> - <span - className="cursor-pointer" - onClick={() => copytoclipboard(apitestToken)} - > - {apitestToken ? apitestToken : "_____"} - </span> - <button - className="op-btn op-btn-accent op-btn-outline op-btn-sm ml-2 cursor-pointer" - onClick={() => copytoclipboard(apitestToken)} - > - <i className="fa-light fa-copy"></i> - </button> - </span> - </div> - <button - onClick={handleGenerateTestToken} - className="op-btn op-btn-primary w-[210px] md:w-auto" - > - {apitestToken - ? t("regenerate-test-token") - : t("generate-test-token")} - </button> - </li> - <li className="flex flex-col md:flex-row justify-between items-center border-y-[1px] border-gray-300 break-all py-2"> - <div className="w-full md:w-[70%] flex-col md:flex-row text-xs md:text-[15px] flex items-center gap-x-5"> - <span className="ml-1"> - <span className="font-medium">{t("api-token")} : </span> - <span className="text-xs"> - <Tooltip message={t("help-api-token", { origin })} /> - </span> - </span> - <span - id="token" - className={`${ - isSubscribe?.plan === "freeplan" - ? "bg-white/20 pointer-events-none select-none" - : "" - } md:text-end py-2 md:py-0`} - > - <span - className="cursor-pointer" - onClick={() => copytoclipboard(apiToken)} - > - {isSubscribe?.plan !== "freeplan" && apiToken - ? apiToken - : "_____"} - </span> - <button - className="op-btn op-btn-accent op-btn-outline op-btn-sm ml-2 cursor-pointer" - onClick={() => copytoclipboard(apiToken)} - > - <i className="fa-light fa-copy"></i> - </button> - </span> - </div> - <button - onClick={apiToken ? handleModal : handleSubmit} - className="op-btn op-btn-primary w-[210px] md:w-auto" - > - {apiToken ? t("regenerate-token") : t("generate-token")} - </button> - </li> - <div className="text-xs md:text-[15px] my-3 w-full md:w-[70%] flex-col md:flex-row flex items-center gap-x-5"> - <span className="font-medium"> - {t("remaining-credits")}{" "} - <span className="text-xs"> - <Tooltip - message={t("remaining-credits-help", { - allowedcredits: amount?.allowedcredits || 0, - addoncredits: amount?.addoncredits || 0 - })} - /> - </span> - </span> - <span className="md:text-end py-2 md:py-0"> - {amount.totalcredits} - </span> - </div> - <hr /> - </ul> - <div className="flex flex-col md:flex-row items-center justify-center gap-0 md:gap-1"> - <button - type="button" - onClick={() => - openInNewTab( - "https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1" - ) - } - className="op-btn op-btn-secondary mt-2 md:mb-3 px-8 w-[210px] md:w-auto" - > - {t("view-docs")} - </button> - <button - type="button" - onClick={() => handleBuyAPIsModal()} - className="op-btn op-btn-accent mt-2 mb-3 px-8 w-[210px] md:w-auto" - > - {t("buy-credits")} - </button> - </div> - <ModalUi - isOpen={isModal.generateapi} - title={apiToken ? t("regenerate-token") : t("generate-token")} - handleClose={handleModal} - > - <div className="m-[20px]"> - <div className="text-lg font-normal text-base-content"> - {t("generate-token-alert")} - </div> - <hr className="bg-[#ccc] mt-4" /> - <div className="flex items-center mt-3 gap-2 text-white"> - <button - onClick={handleSubmit} - className="op-btn op-btn-primary ml-[2px]" - > - {t("yes")} - </button> - <button - onClick={handleModal} - className="op-btn op-btn-secondary" - > - {t("no")} - </button> - </div> - </div> - </ModalUi> - {/* buy APIs */} - <ModalUi - isOpen={isModal.buyapis} - title={"Buy Credits"} - handleClose={handleCloseModal} - > - {isFormLoader && ( - <div className="absolute w-full h-full inset-0 flex justify-center items-center bg-base-content/30 z-50"> - <Loader /> - </div> - )} - <form onSubmit={handleAddOnApiSubmit} className="p-3"> - <div className="mb-3 flex justify-between"> - <label - htmlFor="quantity" - className="block text-xs text-gray-700 font-semibold" - > - {t("quantity-of-credits")} - <span className="text-[red] text-[13px]"> *</span> - </label> - <select - value={amount.quantity} - onChange={(e) => handlePricePerAPIs(e)} - name="quantity" - className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-1/4 text-xs" - required - > - {quantityList.length > 0 && - quantityList.map((x) => ( - <option key={x} value={x}> - {x} - </option> - ))} - </select> - </div> - <div className="mb-3 flex justify-between"> - <label className="block text-xs text-gray-700 font-semibold"> - {t("Price")} (1 * {amount.priceperapi}) - </label> - <div className="w-1/4 flex justify-center items-center text-sm"> - USD {amount.price} - </div> - </div> - <hr className="text-base-content mb-3" /> - <button className="op-btn op-btn-primary w-full mt-2"> - {t("Proceed")} - </button> - </form> - </ModalUi> - <ModalUi - isOpen={isModal.unauthorized} - title={"Unauthorized"} - handleClose={handleCloseModal} - > - <div className="m-8 flex justify-center text-center items-center font-medium break-all"> - {t("unauthorized-modal", { - adminEmail: isSubscribe?.adminEmail - })} - </div> - </ModalUi> - </div> - {isEnableSubscription && isSubscribe?.plan === "freeplan" && ( - <div data-tut="apisubscribe"> - <SubscribeCard /> - </div> - )} - </> - )} - <Tour - onRequestClose={() => setIsTour(false)} - steps={tourSteps} - isOpen={isTour} - closeWithMask={false} - disableKeyboardNavigation={["esc"]} - scrollOffset={-100} - rounded={5} - /> - </React.Fragment> - ); -} - -export default GenerateToken; diff --git a/apps/OpenSign/src/pages/GuestLogin.js b/apps/OpenSign/src/pages/GuestLogin.js index f7eaa8bea..06060d76f 100644 --- a/apps/OpenSign/src/pages/GuestLogin.js +++ b/apps/OpenSign/src/pages/GuestLogin.js @@ -1,18 +1,19 @@ import React, { useState, useEffect } from "react"; -import { useNavigate, useParams } from "react-router-dom"; +import { useNavigate, useParams } from "react-router"; import axios from "axios"; -import { emailRegex, isEnableSubscription } from "../constant/const"; +import { + emailRegex, +} from "../constant/const"; import { contractUsers, - getAppLogo, saveLanguageInLocal } from "../constant/Utils"; import logo from "../assets/images/logo.png"; import { appInfo } from "../constant/appinfo"; import Parse from "parse"; -import Loader from "../primitives/Loader"; import { useTranslation } from "react-i18next"; import SelectLanguage from "../components/pdf/SelectLanguage"; +import LoaderWithMsg from "../primitives/LoaderWithMsg"; function GuestLogin() { const { t, i18n } = useTranslation(); @@ -22,7 +23,10 @@ function GuestLogin() { const [OTP, setOTP] = useState(""); const [EnterOTP, setEnterOtp] = useState(false); const [loading, setLoading] = useState(false); - const [isLoading, setIsLoading] = useState(true); + const [isLoading, setIsLoading] = useState({ + isLoad: true, + message: t("loading-mssg") + }); const [appLogo, setAppLogo] = useState(""); const [documentId, setDocumentId] = useState(id); const [contactId, setContactId] = useState(contactBookId); @@ -43,6 +47,7 @@ function GuestLogin() { } return true; } else { + setIsLoading({ isLoad: false }); return false; } } catch (err) { @@ -57,18 +62,11 @@ function GuestLogin() { //function generate serverUrl and parseAppId from url and save it in local storage const handleServerUrl = async () => { - if (isEnableSubscription) { - const app = await getAppLogo(); - if (app?.logo) { - setAppLogo(app?.logo); - } else { - setAppLogo(logo); - } - } else { setAppLogo(logo); - } localStorage.clear(); + //save isGuestSigner true in local to handle login flow header in mobile view + localStorage.setItem("isGuestSigner", true); saveLanguageInLocal(i18n); const parseId = appInfo.appId; const newServer = `${appInfo.baseUrl}/`; @@ -95,6 +93,7 @@ function GuestLogin() { setContactId(linkContactRes?.contactId); await navigateToDoc(checkSplit[0], linkContactRes?.contactId); } catch (err) { + setIsLoading({ isLoad: false }); console.log("Err in link ext contact", err); } } else { @@ -102,8 +101,6 @@ function GuestLogin() { await navigateToDoc(checkSplit[0], checkSplit[2]); } } - - setIsLoading(false); }; //send email OTP function @@ -154,23 +151,21 @@ function GuestLogin() { let _user = user.data.result; await Parse.User.become(_user.sessionToken); const parseId = localStorage.getItem("parseAppId"); + if (_user) { + localStorage.setItem("accesstoken", _user?.sessionToken); + localStorage.setItem("UserInformation", JSON.stringify(_user)); + localStorage.setItem( + `Parse/${parseId}/currentUser`, + JSON.stringify(_user) + ); + } const contractUserDetails = await contractUsers(); - localStorage.setItem("UserInformation", JSON.stringify(_user)); - localStorage.setItem( - `Parse/${parseId}/currentUser`, - JSON.stringify(_user) - ); if (contractUserDetails && contractUserDetails.length > 0) { localStorage.setItem( "Extand_Class", JSON.stringify(contractUserDetails) ); } - - localStorage.setItem("username", _user.name); - localStorage.setItem("accesstoken", _user.sessionToken); - //save isGuestSigner true in local to handle login flow header in mobile view - localStorage.setItem("isGuestSigner", true); setLoading(false); if (sendmail === "false") { navigate( @@ -219,14 +214,11 @@ function GuestLogin() { setContact((prev) => ({ ...prev, [e.target.name]: e.target.value })); }; return ( - <div className="p-14"> - <div> - {isLoading ? ( - <div className="flex flex-col justify-center items-center h-[100vh]"> - <Loader /> - <span className="text-[13px] text-[gray]">{isLoading.message}</span> - </div> - ) : ( + <div> + {isLoading.isLoad ? ( + <LoaderWithMsg isLoading={isLoading} /> + ) : ( + <div className="p-14 h"> <div className="m-1 md:m-2 p-[30px] text-base-content bg-base-100 op-card shadow-md"> <div className="md:w-[250px] md:h-[66px] inline-block overflow-hidden mt-2 mb-11"> {appLogo && ( @@ -371,9 +363,9 @@ function GuestLogin() { </div> )} </div> - )} - </div> - <SelectLanguage /> + <SelectLanguage /> + </div> + )} </div> ); } diff --git a/apps/OpenSign/src/pages/Login.js b/apps/OpenSign/src/pages/Login.js index 7d38a1846..69f4cdead 100644 --- a/apps/OpenSign/src/pages/Login.js +++ b/apps/OpenSign/src/pages/Login.js @@ -3,22 +3,21 @@ import Parse from "parse"; import { useDispatch } from "react-redux"; import axios from "axios"; import Title from "../components/Title"; -import GoogleSignInBtn from "../components/LoginGoogle"; -// import LoginFacebook from "../components/LoginFacebook"; -import { NavLink, useNavigate, useLocation } from "react-router-dom"; +import { NavLink, useNavigate, useLocation } from "react-router"; import login_img from "../assets/images/login_img.svg"; import { useWindowSize } from "../hook/useWindowSize"; import ModalUi from "../primitives/ModalUi"; -import { emailRegex, isEnableSubscription } from "../constant/const"; +import { + emailRegex, +} from "../constant/const"; import Alert from "../primitives/Alert"; import { appInfo } from "../constant/appinfo"; import { fetchAppInfo } from "../redux/reducers/infoReducer"; import { showTenant } from "../redux/reducers/ShowTenant"; import { - fetchSubscription, getAppLogo, - openInNewTab, - saveLanguageInLocal + saveLanguageInLocal, + usertimezone } from "../constant/Utils"; import Loader from "../primitives/Loader"; import { useTranslation } from "react-i18next"; @@ -42,7 +41,7 @@ function Login() { baseUrl: localStorage.getItem("baseUrl"), parseAppId: localStorage.getItem("parseAppId"), loading: false, - thirdpartyLoader: false + thirdpartyLoader: false, }); const [userDetails, setUserDetails] = useState({ Company: "", @@ -50,9 +49,7 @@ function Login() { }); const [isModal, setIsModal] = useState(false); const [image, setImage] = useState(); - const [isLoginSSO, setIsLoginSSO] = useState(false); const [errMsg, setErrMsg] = useState(); - useEffect(() => { checkUserExt(); // eslint-disable-next-line @@ -62,7 +59,9 @@ function Login() { const app = await getAppLogo(); if (app?.error === "invalid_json") { setErrMsg(t("server-down")); - } else if (!isEnableSubscription && app?.user === "not_exist") { + } else if ( + app?.user === "not_exist" + ) { navigate("/addadmin"); } if (app?.logo) { @@ -83,9 +82,7 @@ function Login() { } setState({ ...state, [name]: value }); }; - const handlePaidRoute = () => { - navigate("/subscription"); - }; + const handleSubmit = async (event) => { localStorage.removeItem("accesstoken"); event.preventDefault(); @@ -154,42 +151,9 @@ function Login() { localStorage.setItem("PageLanding", menu.pageId); localStorage.setItem("defaultmenuid", menu.menuId); localStorage.setItem("pageType", menu.pageType); - if (isEnableSubscription) { - const LocalUserDetails = { - name: results[0].get("Name"), - email: results[0].get("Email"), - phone: results[0]?.get("Phone") || "", - company: results[0].get("Company") - }; - localStorage.setItem( - "userDetails", - JSON.stringify(LocalUserDetails) - ); - const res = await fetchSubscription(); - const plan = res.plan; - const billingDate = res.billingDate; - if (plan === "freeplan") { - setState({ ...state, loading: false }); - navigate(redirectUrl); - } else if (billingDate) { - if (new Date(billingDate) > new Date()) { - localStorage.removeItem("userDetails"); - // Redirect to the appropriate URL after successful login setState({ ...state, loading: false }); - setState({ ...state, loading: false }); - navigate(redirectUrl); - } else { - setState({ ...state, loading: false }); - handlePaidRoute(plan); - } - } else { - setState({ ...state, loading: false }); - handlePaidRoute(plan); - } - } else { setState({ ...state, loading: false }); // Redirect to the appropriate URL after successful login navigate(redirectUrl); - } } else { setState({ ...state, loading: false }); setIsModal(true); @@ -205,10 +169,6 @@ function Login() { logOutUser(); } } else { - if (isEnableSubscription) { - setState({ ...state, loading: false }); - setIsModal(true); - } else { setState({ ...state, loading: false }); setState({ ...state, @@ -217,12 +177,9 @@ function Login() { alertMsg: "User not found." }); logOutUser(); - } } }) .catch((error) => { - // const payload = { sessionToken: user.getSessionToken() }; - // handleSubmitbtn(payload); setState({ ...state, loading: false, @@ -248,7 +205,7 @@ function Login() { ...state, loading: false, alertType: "danger", - alertMsg: "Invalid username or password!" + alertMsg: "Invalid username/password or region" }); console.error("Error while logging in user", error); } finally { @@ -264,18 +221,6 @@ function Login() { const setThirdpartyLoader = (value) => { setState({ ...state, thirdpartyLoader: value }); }; - const handleFreePlan = async (id) => { - try { - const params = { userId: id }; - const res = await Parse.Cloud.run("freesubscription", params); - if (res.status === "error") { - alert(res.result); - } - } catch (err) { - console.log("err in free subscribe", err.message); - alert(t("something-went-wrong-mssg")); - } - }; const thirdpartyLoginfn = async (sessionToken) => { const baseUrl = localStorage.getItem("baseUrl"); const parseAppId = localStorage.getItem("parseAppId"); @@ -285,11 +230,6 @@ function Login() { "X-Parse-Application-Id": parseAppId } }); - const param = new URLSearchParams(location.search); - const isFreeplan = param?.get("subscription") === "freeplan"; - if (isFreeplan) { - await handleFreePlan(res.data.objectId); - } await Parse.User.become(sessionToken).then(() => { window.localStorage.setItem("accesstoken", sessionToken); }); @@ -340,33 +280,7 @@ function Login() { localStorage.setItem("PageLanding", menu.pageId); localStorage.setItem("defaultmenuid", menu.menuId); localStorage.setItem("pageType", menu.pageType); - if (isEnableSubscription) { - const res = await fetchSubscription(); - const plan = res.plan; - const billingDate = res.billingDate; - if (plan === "freeplan") { - navigate(redirectUrl); - } else if (billingDate) { - if (new Date(billingDate) > new Date()) { - localStorage.removeItem("userDetails"); - navigate(redirectUrl); - } else { - if (isFreeplan) { - navigate(redirectUrl); - } else { - handlePaidRoute(plan); - } - } - } else { - if (isFreeplan) { - navigate(redirectUrl); - } else { - handlePaidRoute(plan); - } - } - } else { navigate(redirectUrl); - } } else { setState({ ...state, @@ -464,34 +378,8 @@ function Login() { localStorage.setItem("PageLanding", menu.pageId); localStorage.setItem("defaultmenuid", menu.menuId); localStorage.setItem("pageType", menu.pageType); - if (isEnableSubscription) { - const userInfo = { - name: results[0].get("Name"), - email: results[0].get("Email"), - phone: results[0]?.get("Phone") || "", - company: results[0]?.get("Company") - }; - localStorage.setItem("userDetails", JSON.stringify(userInfo)); - const res = await fetchSubscription(); - const billingDate = res.billingDate; - const plan = res.plan; - if (plan === "freeplan") { - navigate(redirectUrl); - } else if (billingDate) { - if (new Date(billingDate) > new Date()) { - localStorage.removeItem("userDetails"); - // Redirect to the appropriate URL after successful login - navigate(redirectUrl); - } else { - handlePaidRoute(plan); - } - } else { - handlePaidRoute(plan); - } - } else { // Redirect to the appropriate URL after successful login navigate(redirectUrl); - } } else { setState({ ...state, loading: false }); logOutUser(); @@ -550,7 +438,8 @@ function Login() { phone: userInformation?.phone || "", role: "contracts_User", company: userDetails.Company, - jobTitle: userDetails.Destination + jobTitle: userDetails.Destination, + timezone: usertimezone } }; const userSignUp = await Parse.Cloud.run("usersignup", params); @@ -610,25 +499,6 @@ function Login() { localStorage.setItem("parseAppId", appid); }; - // `handleSignInWithSSO` is trigger when user click sign in with sso and open sso authorize endpoint - const handleSignInWithSSO = () => { - if (isLoginSSO === false) { - if (state?.email) { - setIsLoginSSO(true); - const encodedEmail = encodeURIComponent(state.email); - const clientUrl = window.location.origin; - const domain = state.email.split("@")?.pop(); - const ssoApiUrl = - process.env.SSO_API_URL || "https://sso.opensignlabs.com/api"; - openInNewTab( - `${ssoApiUrl}/oauth/authorize?response_type=code&provider=saml&tenant=${domain}&product=OpenSign&redirect_uri=${clientUrl}/sso&state=${encodedEmail}`, - "_self" - ); - } else { - alert(t("provide-email")); - } - } - }; return errMsg ? ( <div className="h-screen flex justify-center text-center items-center p-4 text-gray-500 text-base"> @@ -650,7 +520,7 @@ function Login() { <div aria-labelledby="loginHeading" role="region" - className="md:p-10 lg:p-16" + className="pb-1 md:pb-4 pt-10 md:px-10 lg:px-16" > <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"> @@ -689,8 +559,6 @@ function Login() { onInput={(e) => e.target.setCustomValidity("")} /> <hr className="my-1 border-none" /> - {!isLoginSSO && ( - <> <label className="block text-xs" htmlFor="password"> {t("password")} </label> @@ -724,8 +592,7 @@ function Login() { )} </span> </div> - </> - )} + <div className="relative mt-1"> <NavLink to="/forgetpassword" @@ -744,53 +611,8 @@ function Login() { > {state.loading ? t("loading") : t("login")} </button> - {isEnableSubscription && ( - <button - type="button" - className="op-btn op-btn-accent" - disabled={state.loading} - onClick={() => - navigate( - location.search - ? "/signup" + location.search - : "/signup" - ) - } - > - {t("create-account")} - </button> - )} </div> </form> - {(appInfo.googleClietId || isEnableSubscription) && ( - <div className="op-divider my-4 text-sm">{t("or")}</div> - )} - <div className="flex flex-col justify-center items-center gap-y-3"> - {/* {appInfo?.fbAppId && ( - <LoginFacebook - FBCred={appInfo.fbAppId} - thirdpartyLoginfn={thirdpartyLoginfn} - thirdpartyLoader={state.thirdpartyLoader} - setThirdpartyLoader={setThirdpartyLoader} - /> - )} */} - {appInfo?.googleClietId && ( - <GoogleSignInBtn - GoogleCred={appInfo.googleClietId} - thirdpartyLoginfn={thirdpartyLoginfn} - thirdpartyLoader={state.thirdpartyLoader} - setThirdpartyLoader={setThirdpartyLoader} - /> - )} - {isEnableSubscription && ( - <div - className="cursor-pointer border-[1px] border-gray-300 rounded px-[40px] py-2 font-semibold text-sm hover:border-[#d2e3fc] hover:bg-[#ecf3feb7]" - onClick={() => handleSignInWithSSO()} - > - {t("sign-SSO")} - </div> - )} - </div> </div> {width >= 768 && ( <div className="place-self-center"> diff --git a/apps/OpenSign/src/pages/Managesign.js b/apps/OpenSign/src/pages/Managesign.js index 28de605ef..e5ba2fcd3 100644 --- a/apps/OpenSign/src/pages/Managesign.js +++ b/apps/OpenSign/src/pages/Managesign.js @@ -2,7 +2,11 @@ import React, { useState, useRef, useEffect } from "react"; import SignatureCanvas from "react-signature-canvas"; import "../styles/managesign.css"; import "../styles/signature.css"; -import { generateTitleFromFilename, toDataUrl } from "../constant/Utils"; +import { + generateTitleFromFilename, + getSecureUrl, + toDataUrl +} from "../constant/Utils"; import Parse from "parse"; import { SaveFileSize } from "../constant/saveFileSize"; import Alert from "../primitives/Alert"; @@ -198,9 +202,20 @@ const ManageSign = () => { const parseFile = new Parse.File(file.name, file); const response = await parseFile.save(); if (response?.url()) { - const tenantId = localStorage.getItem("TenantId"); - SaveFileSize(file.size, response.url(), tenantId); - return response?.url(); + const fileRes = await getSecureUrl(response?.url()); + if (fileRes?.url) { + const tenantId = localStorage.getItem("TenantId"); + SaveFileSize(file.size, fileRes?.url, tenantId); + return fileRes?.url; + } else { + alert(t("something-went-wrong-mssg")); + setIsLoader(false); + return false; + } + } else { + alert(t("something-went-wrong-mssg")); + setIsLoader(false); + return false; } } catch (err) { console.log("sign upload err", err); @@ -323,7 +338,8 @@ const ManageSign = () => { canvasProps={{ width: "456px", height: "180px", - className: "signatureCanvas rounded-box" + className: + "signatureCanvas border-[2px] border-[#888] rounded-box" }} // backgroundColor="rgb(255, 255, 255)" onEnd={() => @@ -335,35 +351,13 @@ const ManageSign = () => { <div className="penContainerDefault flex flex-row justify-between"> <div> {!image && ( - <div className="flex flex-row"> + <div className="flex flex-row gap-1.5 m-[5px]"> {allColor.map((data, key) => { return ( <i - style={{ - margin: "5px", - color: data, - borderBottom: - key === 0 && penColor === "blue" - ? "2px solid blue" - : key === 1 && penColor === "red" - ? "2px solid red" - : key === 2 && penColor === "black" - ? "2px solid black" - : "2px solid white" - }} - onClick={() => { - if (key === 0) { - setPenColor("blue"); - } else if (key === 1) { - setPenColor("red"); - } else if (key === 2) { - setPenColor("black"); - } - }} key={key} - className="fa-light fa-pen-nib" - width={20} - height={20} + onClick={() => setPenColor(allColor[key])} + className={`border-b-[2px] ${key === 0 && penColor === "blue" ? "border-blue-600" : key === 1 && penColor === "red" ? "border-red-500" : key === 2 && penColor === "black" ? "border-black" : "border-white"} text-[${data}] text-[16px] fa-light fa-pen-nib`} ></i> ); })} @@ -432,35 +426,13 @@ const ManageSign = () => { <div className="flex flex-row justify-between w-[183px]"> <div> {!isInitials && ( - <div className="flex flex-row"> + <div className="flex flex-row gap-1.5 m-[5px]"> {allColor.map((data, key) => { return ( <i - style={{ - margin: "5px", - color: data, - borderBottom: - key === 0 && initialPen === "blue" - ? "2px solid blue" - : key === 1 && initialPen === "red" - ? "2px solid red" - : key === 2 && initialPen === "black" - ? "2px solid black" - : "2px solid white" - }} - className="fa-light fa-pen-nib" - onClick={() => { - if (key === 0) { - setInitialPen("blue"); - } else if (key === 1) { - setInitialPen("red"); - } else if (key === 2) { - setInitialPen("black"); - } - }} key={key} - width={20} - height={20} + onClick={() => setInitialPen(allColor[key])} + className={`border-b-[2px] ${key === 0 && initialPen === "blue" ? "border-blue-600" : key === 1 && initialPen === "red" ? "border-red-500" : key === 2 && initialPen === "black" ? "border-black" : "border-white"} text-[${data}] text-[16px] fa-light fa-pen-nib`} ></i> ); })} diff --git a/apps/OpenSign/src/pages/Opensigndrive.js b/apps/OpenSign/src/pages/Opensigndrive.js index 1d99116a6..f467a0bd1 100644 --- a/apps/OpenSign/src/pages/Opensigndrive.js +++ b/apps/OpenSign/src/pages/Opensigndrive.js @@ -1,8 +1,10 @@ import React, { useEffect, useState, useRef } from "react"; import "../styles/opensigndrive.css"; -import { iconColor } from "../constant/const"; +import { + iconColor, +} from "../constant/const"; import { getDrive } from "../constant/Utils"; -import { useNavigate } from "react-router-dom"; +import { useNavigate } from "react-router"; import Title from "../components/Title"; import Parse from "parse"; import ModalUi from "../primitives/ModalUi"; @@ -11,10 +13,11 @@ import Tour from "reactour"; import axios from "axios"; import Loader from "../primitives/Loader"; import { useTranslation } from "react-i18next"; - const DriveBody = React.lazy( () => import("../components/opensigndrive/DriveBody") ); +const dropdowncss = + "absolute right-0 py-2 text-[1rem] text-left bg-white border-[1px] border-gray-300 min-w-1 hover:bg-gray-300 rounded-[0.25rem] z-[800]"; const AppLoader = () => { return ( <div className="h-[100vh] flex justify-center items-center"> @@ -45,9 +48,9 @@ function Opensigndrive() { const [handleError, setHandleError] = useState(""); const [folderName, setFolderName] = useState([]); const [isAlert, setIsAlert] = useState({ isShow: false, alertMessage: "" }); - const [isNewFol, setIsNewFol] = useState(false); + const [isOptions, setIsOptions] = useState(false); const [skip, setSkip] = useState(0); - const limit = 100; + const limit = 50; const [loading, setLoading] = useState(false); const sortOrder = ["Ascending", "Descending"]; const sortingValue = ["Name", "Date"]; @@ -223,8 +226,7 @@ function Opensigndrive() { //disableLoading is used disable initial loader const disableLoading = true; // If the fetched data length is less than the limit, it means there's no more data to fetch - - if (!loading && pdfData.length % 100 === 0) { + if (!loading && pdfData.length % 50 === 0) { getPdfDocumentList(disableLoading); } } @@ -420,8 +422,8 @@ function Opensigndrive() { const closeMenuOnOutsideClick = (e) => { if (isShowSort && !e.target.closest("#menu-container")) { setIsShowSort(!isShowSort); - } else if (isNewFol && !e.target.closest("#folder-menu")) { - setIsNewFol(!isNewFol); + } else if (isOptions && !e.target.closest("#folder-menu")) { + setIsOptions(!isOptions); } }; @@ -432,7 +434,7 @@ function Opensigndrive() { document.removeEventListener("click", closeMenuOnOutsideClick); }; // eslint-disable-next-line - }, [isShowSort, isNewFol]); + }, [isShowSort, isOptions]); const handleFolderTab = (folderData) => { return folderData.map((data, id) => { @@ -601,7 +603,7 @@ function Opensigndrive() { </div> ) : ( <> - <div className="flex flex-row justify-between items-center px-[25px] pt-[20px]"> + <div className="flex flex-row justify-between items-center px-[15px] md:px-[25px] pt-[20px]"> {tourData && ( <Tour onRequestClose={closeTour} @@ -623,10 +625,8 @@ function Opensigndrive() { <div className="flex flex-row items-center"> <div id="folder-menu" - className={ - isNewFol ? "dropdown show dropDownStyle" : "dropdown" - } - onClick={() => setIsNewFol(!isNewFol)} + className={`${isOptions ? "dropdown show dropDownStyle" : "dropdown"} hidden md:block`} + onClick={() => setIsOptions(!isOptions)} > <div className="sort" data-tut="reactourSecond"> <i @@ -636,9 +636,10 @@ function Opensigndrive() { ></i> </div> <div - className={isNewFol ? "dropdown-menu show" : "dropdown-menu"} + className={`${isOptions ? "block" : "hidden"} ${dropdowncss}`} + // className={isOptions ? "dropdown-menu show" : "dropdown-menu"} aria-labelledby="dropdownMenuButton" - aria-expanded={isNewFol ? "true" : "false"} + aria-expanded={isOptions ? "true" : "false"} > <div className="flex flex-col"> <span @@ -719,7 +720,6 @@ function Opensigndrive() { </span> ); })} - <hr className="hrStyle" /> {sortOrder.map((order, ind) => { return ( @@ -748,30 +748,66 @@ function Opensigndrive() { })} </div> </div> - - <div> - {isList ? ( - <div className="sort" onClick={() => setIsList(!isList)}> - <i - onClick={() => setIsList(!isList)} - className="fa-light fa-th-large" - style={{ fontSize: "24px", color: `${iconColor}` }} - aria-hidden="true" - ></i> + <div + data-tut="reactourForth" + className="sort" + onClick={() => setIsList(!isList)} + > + <i + className={ + isList ? "fa-light fa-th-large" : "fa-light fa-list" + } + style={{ fontSize: "24px", color: `${iconColor}` }} + aria-hidden="true" + ></i> + </div> + <div + id="folder-menu" + className={`${isOptions ? "dropdown show dropDownStyle" : "dropdown"} md:hidden`} + onClick={() => setIsOptions(!isOptions)} + > + <div + className="p-[19px] my-2 flex items-center justify-center cursor-pointer hover:bg-[var(--mauve-3)] rounded-[2px] shadow-[0_2px_4px_rgba(168,204,206,0.1)]" + data-tut="reactourSecond" + > + <i + className="fa-light fa-ellipsis-vertical fa-lg" + aria-hidden="true" + style={{ color: `${iconColor}` }} + ></i> + </div> + <div + className={`${isOptions ? "block" : "hidden"} ${dropdowncss}`} + aria-labelledby="dropdownMenuButton" + aria-expanded={isOptions ? "true" : "false"} + > + <div className="flex flex-col"> + <span + className="dropdown-item text-[10px] md:text-[13px]" + onClick={() => setIsFolder(true)} + > + <i + className="fa-light fa-plus mr-[5px]" + aria-hidden="true" + ></i> + {t("create-folder")} + </span> + <span + className="dropdown-item text-[10px] md:text-[13px]" + onClick={() => navigate("/form/sHAnZphf69")} + > + <i className="fa-light fa-pen-nib mr-[5px]"></i> + {t("form-name.Sign Yourself")} + </span> + <span + className="dropdown-item text-[10px] md:text-[13px]" + onClick={() => navigate("/form/8mZzFxbG1z")} + > + <i className="fa-light fa-file-signature mr-[5px]"></i> + {t("form-name.Request Signatures")} + </span> </div> - ) : ( - <div - data-tut="reactourForth" - className="sort" - onClick={() => setIsList(!isList)} - > - <i - className="fa-light fa-list" - aria-hidden="true" - style={{ fontSize: "23px", color: `${iconColor}` }} - ></i> - </div> - )} + </div> </div> </div> </div> diff --git a/apps/OpenSign/src/pages/PdfRequestFiles.js b/apps/OpenSign/src/pages/PdfRequestFiles.js index 98828177b..6b432c93c 100644 --- a/apps/OpenSign/src/pages/PdfRequestFiles.js +++ b/apps/OpenSign/src/pages/PdfRequestFiles.js @@ -1,15 +1,12 @@ import React, { useState, useRef, useEffect } from "react"; import { - emailRegex, - isEnableSubscription, - isStaging, themeColor } from "../constant/const"; import { PDFDocument } from "pdf-lib"; import "../styles/signature.css"; import Parse from "parse"; import axios from "axios"; -import { DndProvider } from "react-dnd"; +import { DndProvider, useDrop } from "react-dnd"; import { HTML5Backend } from "react-dnd-html5-backend"; import SignPad from "../components/pdf/SignPad"; import RenderAllPdfPage from "../components/pdf/RenderAllPdfPage"; @@ -22,16 +19,13 @@ import { embedDocId, pdfNewWidthFun, signPdfFun, - onImageSelect, onSaveSign, onSaveImage, addDefaultSignatureImg, radioButtonWidget, replaceMailVaribles, - fetchSubscription, convertPdfArrayBuffer, contractUsers, - handleSendOTP, contactBook, handleToPrint, handleDownloadCertificate, @@ -41,7 +35,15 @@ import { fetchUrl, signatureTypes, handleSignatureType, - getTenantDetails + getTenantDetails, + getBase64FromUrl, + openInNewTab, + getContainerScale, + randomId, + defaultWidthHeight, + addWidgetOptions, + textWidget, + compressedFileSize } from "../constant/Utils"; import Header from "../components/pdf/PdfHeader"; import RenderPdf from "../components/pdf/RenderPdf"; @@ -49,7 +51,6 @@ import Title from "../components/Title"; import DefaultSignature from "../components/pdf/DefaultSignature"; import { useSelector } from "react-redux"; import SignerListComponent from "../components/pdf/SignerListComponent"; -import VerifyEmail from "../components/pdf/VerifyEmail"; import PdfZoom from "../components/pdf/PdfZoom"; import { useTranslation } from "react-i18next"; import ModalUi from "../primitives/ModalUi"; @@ -60,8 +61,13 @@ import DownloadPdfZip from "../primitives/DownloadPdfZip"; import Loader from "../primitives/Loader"; import PdfDeclineModal from "../primitives/PdfDeclineModal"; import { serverUrl_fn } from "../constant/appinfo"; +import AgreementSign from "../components/pdf/AgreementSign"; +import WidgetComponent from "../components/pdf/WidgetComponent"; +import PlaceholderCopy from "../components/pdf/PlaceholderCopy"; +import TextFontSetting from "../components/pdf/TextFontSetting"; -function PdfRequestFiles(props) { +function PdfRequestFiles( +) { const { t } = useTranslation(); const [pdfDetails, setPdfDetails] = useState([]); const [signedSigners, setSignedSigners] = useState([]); @@ -80,7 +86,6 @@ function PdfRequestFiles(props) { const imageRef = useRef(null); const [handleError, setHandleError] = useState(); const [selectWidgetId, setSelectWidgetId] = useState(""); - const [otpLoader, setOtpLoader] = useState(false); const [isCelebration, setIsCelebration] = useState(false); const [requestSignTour, setRequestSignTour] = useState(true); const [tourStatus, setTourStatus] = useState([]); @@ -108,7 +113,6 @@ function PdfRequestFiles(props) { isShow: false, alertMessage: "" }); - const [isSubscribed, setIsSubscribed] = useState(false); const [isCompleted, setIsCompleted] = useState({ isCertificate: false, isModal: false @@ -125,35 +129,52 @@ function PdfRequestFiles(props) { const [minRequiredCount, setminRequiredCount] = useState(); const [sendInOrder, setSendInOrder] = useState(false); const [currWidgetsDetails, setCurrWidgetsDetails] = useState({}); - const [isSubscriptionExpired, setIsSubscriptionExpired] = useState(false); const [extUserId, setExtUserId] = useState(""); - const [isEmailVerified, setIsEmailVerified] = useState(true); - const [isVerifyModal, setIsVerifyModal] = useState(false); - const [otp, setOtp] = useState(""); const [contractName, setContractName] = useState(""); const [zoomPercent, setZoomPercent] = useState(0); const [scale, setScale] = useState(1); const [uniqueId, setUniqueId] = useState(""); - const [isPublicTemplate, setIsPublicTemplate] = useState(false); - const [contact, setContact] = useState({ name: "", phone: "", email: "" }); - const [isOtp, setIsOtp] = useState(false); - const [loading, setLoading] = useState(false); - const [publicRes, setPublicRes] = useState({}); const [documentId, setDocumentId] = useState(""); - const [isPublicContact, setIsPublicContact] = useState(false); - const [plancode, setPlanCode] = useState(""); const isHeader = useSelector((state) => state.showHeader); const divRef = useRef(null); const [isDownloadModal, setIsDownloadModal] = useState(false); const [signatureType, setSignatureType] = useState([]); + const [pdfBase64Url, setPdfBase64Url] = useState(""); + const [isAgree, setIsAgree] = useState(false); + const [isAgreeTour, setIsAgreeTour] = useState(false); + const [redirectTimeLeft, setRedirectTimeLeft] = useState(5); + const [isredirectCanceled, setIsredirectCanceled] = useState(true); + const [isDragging, setIsDragging] = useState(false); + const [dragKey, setDragKey] = useState(); + const [isAutoSign, setIsAutoSign] = useState(false); + const [signBtnPosition, setSignBtnPosition] = useState([]); + const [xySignature, setXYSignature] = useState({}); + const [zIndex, setZIndex] = useState(1); + const [fontSize, setFontSize] = useState(); + const [fontColor, setFontColor] = useState(); + const [widgetType, setWidgetType] = useState(""); + const [isTextSetting, setIsTextSetting] = useState(false); + const [isPageCopy, setIsPageCopy] = useState(false); + const [assignedWidgetId, setAssignedWidgetId] = useState([]); + const [saveSignCheckbox, setSaveSignCheckbox] = useState({ + isVisible: false, + signId: "" + }); + const [showSignPagenumber, setShowSignPagenumber] = useState([]); + const [, drop] = useDrop({ + accept: "BOX", + drop: (item, monitor) => addPositionOfSignature(item, monitor), + collect: (monitor) => ({ isOver: !!monitor.isOver() }) + }); const isMobile = window.innerWidth < 767; - let isGuestSignFlow = false; let sendmail; let getDocId = ""; let contactBookId = ""; - const route = !props.templateId && window.location.pathname; - const getQuery = !props.templateId && window.location?.search?.split("?"); //['','sendmail=false'] + const route = + window.location.pathname; + const getQuery = + window.location?.search?.split("?"); //['','sendmail=false'] if (getQuery) { sendmail = getQuery?.[1]?.split("=")[1]; //false } @@ -174,11 +195,11 @@ function PdfRequestFiles(props) { if (getDocumentId) { setDocumentId(getDocumentId); getDocumentDetails(getDocumentId); - } else if (props.templateId) { - getTemplateDetails(); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [props.templateId, getDocumentId]); + }, [ + getDocumentId + ]); useEffect(() => { const updateSize = () => { if (divRef.current) { @@ -196,194 +217,20 @@ function PdfRequestFiles(props) { return () => clearTimeout(timer); // eslint-disable-next-line react-hooks/exhaustive-deps }, [divRef.current, isHeader]); - //function to use resend otp for email verification - const handleResend = async (e) => { - e.preventDefault(); - setOtpLoader(true); - const localuser = localStorage.getItem( - `Parse/${localStorage.getItem("parseAppId")}/currentUser` - ); - const currentUser = JSON.parse(localuser); - await handleSendOTP(currentUser?.email); - setOtpLoader(false); - alert(t("otp-sent-alert")); - }; - //`handleVerifyEmail` function is used to verify email with otp - const handleVerifyEmail = async (e) => { - e.preventDefault(); - setOtpLoader(true); - const localuser = localStorage.getItem( - `Parse/${localStorage.getItem("parseAppId")}/currentUser` - ); - const currentUser = JSON.parse(localuser); - try { - const resEmail = await Parse.Cloud.run("verifyemail", { - otp: otp, - email: currentUser?.email - }); - if (resEmail?.message === "Email is verified.") { - setIsEmailVerified(true); - alert(t("Email-verified-alert-1")); - } else if (resEmail?.message === "Email is already verified.") { - setIsEmailVerified(true); - alert(t("Email-verified-alert-2")); + const redirectUrl = pdfDetails?.[0]?.RedirectUrl || ""; + useEffect(() => { + if (isredirectCanceled) return; // Stop the redirect timer if canceled + if (redirectUrl) { + if (redirectTimeLeft === 0) { + openInNewTab(redirectUrl, "_self"); // Replace with your target URL } - setOtp(""); - setIsVerifyModal(false); - //handleRecipientSign(); - } catch (error) { - alert(error.message); - } finally { - setOtpLoader(false); + const timer = setTimeout(() => { + setRedirectTimeLeft((prev) => prev - 1); // Decrement the timer + }, 1000); + return () => clearTimeout(timer); // Cleanup the timer } - }; - //`handleVerifyBtn` function is used to send otp on user mail - const handleVerifyBtn = async () => { - setIsVerifyModal(true); - const localuser = localStorage.getItem( - `Parse/${localStorage.getItem("parseAppId")}/currentUser` - ); - const currentUser = JSON.parse(localuser); - await handleSendOTP(currentUser?.email); - }; + }, [redirectTimeLeft, isredirectCanceled, redirectUrl]); - const handleNavigation = () => { - window.location.href = "/subscription"; - }; - async function checkIsSubscribed(extUserId, contactId) { - const isGuestSign = isGuestSignFlow || false; - const isPublic = props.templateId ? true : false; - const res = await fetchSubscription( - extUserId, - contactId, - isGuestSign, - isPublic - ); - const plan = res.plan; - const billingDate = res?.billingDate; - const status = res?.status; - setPlanCode(plan); - if (plan === "freeplan") { - return true; - } else if (billingDate) { - if (new Date(billingDate) > new Date()) { - setIsSubscribed(true); - return true; - } else { - if (isGuestSign) { - setIsSubscriptionExpired(true); - } else { - handleNavigation(plan); - } - } - } else if (isGuestSign) { - if (status) { - setIsSubscribed(true); - return true; - } else { - setIsSubscriptionExpired(true); - } - } else { - if (isGuestSign) { - setIsSubscriptionExpired(true); - } else { - handleNavigation(res.plan); - } - } - } - //function for get document details for perticular signer with signer'object id - //whenever change anything in this function check react/angular packages also in plan js - const getTemplateDetails = async () => { - try { - const params = { templateId: props.templateId, ispublic: true }; - 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 documentData = templateDeatils?.data?.result - ? [templateDeatils?.data?.result] - : []; - if (documentData && documentData[0]?.error) { - props?.setTemplateStatus && - props?.setTemplateStatus({ status: "Invalid" }); - throw new Error("error: Invalid TemplateId"); - } else if (documentData && documentData.length > 0) { - if (documentData[0]?.IsPublic) { - //handle condition when someone use plan js then setTemplateStatus is not supporting - props?.setTemplateStatus && - props?.setTemplateStatus({ status: "Success" }); - const url = - documentData[0] && - (documentData[0]?.SignedUrl || documentData[0]?.URL); - if (url) { - //convert document url in array buffer format to use embed widgets in pdf using pdf-lib - const arrayBuffer = await convertPdfArrayBuffer(url); - if (arrayBuffer === "Error") { - setHandleError(t("something-went-wrong-mssg")); - } - } else { - setHandleError(t("something-went-wrong-mssg")); - } - setIsPublicTemplate(true); - const getPublicRole = documentData[0]?.PublicRole[0]; - const getUniqueIdDetails = documentData[0]?.Placeholders.find( - (x) => x.Role === getPublicRole - ); - if (getUniqueIdDetails) { - setUniqueId(getUniqueIdDetails.Id); - } - setSignerPos(documentData[0]?.Placeholders); - let placeholdersOrSigners = []; - // const placeholder = documentData[0]?.Placeholders; - for (const placeholder of documentData[0].Placeholders) { - //`emailExist` variable to handle condition for quick send flow and show unsigned signers list - const signerIdExist = placeholder?.signerObjId; - if (signerIdExist) { - const getSignerData = documentData[0].Signers.find( - (data) => data.objectId === placeholder?.signerObjId - ); - placeholdersOrSigners.push(getSignerData); - } else { - placeholdersOrSigners.push(placeholder); - } - } - setUnSignedSigners(placeholdersOrSigners); - setPdfDetails(documentData); - setIsLoading({ isLoad: false }); - } else { - props?.setTemplateStatus && - props?.setTemplateStatus({ status: "Private" }); - setIsLoading({ isLoad: false }); - setHandleError(t("something-went-wrong-mssg")); - console.error("error: TemplateId is not public"); - return; - } - } else { - props?.setTemplateStatus && - props?.setTemplateStatus({ status: "Invalid" }); - setIsLoading(false); - setHandleError(t("something-went-wrong-mssg")); - console.error("error: Invalid TemplateId"); - return; - } - } catch (err) { - setIsLoading(false); - if (err?.response?.data?.code === 101) { - setHandleError(t("error-template")); - } else { - setHandleError(t("something-went-wrong-mssg")); - } - console.error("error: Invalid TemplateId"); - return; - } - }; const fetchTenantDetails = async (contactId) => { const user = JSON.parse( localStorage.getItem( @@ -393,7 +240,6 @@ function PdfRequestFiles(props) { try { const tenantDetails = await getTenantDetails( user?.objectId, // userId - "", // jwttoken contactId // contactId ); if (tenantDetails && tenantDetails === "user does not exist!") { @@ -412,7 +258,11 @@ function PdfRequestFiles(props) { }; //function for get document details for perticular signer with signer'object id - const getDocumentDetails = async (docId, isNextUser) => { + const getDocumentDetails = async ( + docId, + isNextUser, + isSuccessPage = false + ) => { try { const senderUser = localStorage.getItem( `Parse/${localStorage.getItem("parseAppId")}/currentUser` @@ -443,10 +293,9 @@ function PdfRequestFiles(props) { documentData[0] && (documentData[0]?.SignedUrl || documentData[0]?.URL); if (url) { - //convert document url in array buffer format to use embed widgets in pdf using pdf-lib - const arrayBuffer = await convertPdfArrayBuffer(url); - if (arrayBuffer === "Error") { - setHandleError(t("something-went-wrong-mssg")); + const base64Pdf = await getBase64FromUrl(url); + if (base64Pdf) { + setPdfBase64Url(base64Pdf); } } else { setHandleError(t("something-went-wrong-mssg")); @@ -469,12 +318,6 @@ function PdfRequestFiles(props) { currUserId = getCurrentSigner?.objectId ? getCurrentSigner.objectId : contactBookId || signerObjectId || ""; //signerObjectId is contactBookId refer from public template flow - if (isEnableSubscription) { - await checkIsSubscribed( - documentData[0]?.ExtUserPtr?.objectId, - currUserId - ); - } if (currUserId) { setSignerObjectId(currUserId); } @@ -485,11 +328,13 @@ function PdfRequestFiles(props) { } if (isCompleted) { setIsSigned(true); - const data = { isCertificate: true, isModal: true }; setAlreadySign(true); - setIsCompleted(data); setIsCelebration(true); setTimeout(() => setIsCelebration(false), 5000); + if (!isSuccessPage) { + const data = { isCertificate: true, isModal: true }; + setIsCompleted(data); + } } else if (declined) { const currentDecline = { currnt: "another", isDeclined: true }; setIsDecline(currentDecline); @@ -503,16 +348,26 @@ function PdfRequestFiles(props) { else if (isNextUser) { setIsCelebration(true); setTimeout(() => setIsCelebration(false), 5000); - setIsCompleted({ - isModal: true, - message: t("document-signed-alert-1") - }); + if (!isSuccessPage) { + setIsCompleted({ + isModal: true, + message: t("document-signed-alert-1") + }); + } } else { if (currUserId) { const checkCurrentUser = documentData[0].Placeholders.find( (data) => data?.signerObjId === currUserId ); if (checkCurrentUser) { + const widgetId = []; + for (let placeholder of checkCurrentUser.placeHolder) { + for (let item of placeholder.pos) { + widgetId.push(item.key); + } + } + setAssignedWidgetId(widgetId); + setUniqueId(checkCurrentUser.Id); setCurrentSigner(true); } } @@ -531,51 +386,6 @@ function PdfRequestFiles(props) { } else { const obj = documentData?.[0]; setSendInOrder(obj?.SendinOrder || false); - if ( - obj && - obj?.Signers?.length > 0 && - obj?.Placeholders?.length > 0 - ) { - const params = { - event: "viewed", - contactId: currUserId, - body: { - objectId: documentData?.[0].objectId, - file: documentData?.[0]?.SignedUrl || documentData?.[0]?.URL, - name: documentData?.[0].Name, - note: documentData?.[0].Note || "", - description: documentData?.[0].Description || "", - signers: documentData?.[0].Signers?.map((x) => ({ - name: x?.Name, - email: x?.Email, - phone: x?.Phone - })), - viewedBy: - documentData?.[0].Signers?.find( - (x) => x.objectId === currUserId - )?.Email || jsonSender?.email, - viewedAt: new Date(), - createdAt: documentData?.[0].createdAt - } - }; - - try { - await axios.post( - `${localStorage.getItem("baseUrl")}functions/callwebhook`, - params, - { - headers: { - "Content-Type": "application/json", - "X-Parse-Application-Id": - localStorage.getItem("parseAppId"), - sessiontoken: localStorage.getItem("accesstoken") - } - } - ); - } catch (err) { - console.log("Err ", err); - } - } } let signers = []; @@ -647,9 +457,7 @@ function PdfRequestFiles(props) { try { const resContact = await axios.post( `${localStorage.getItem("baseUrl")}functions/getcontact`, - { - contactId: currUserId - }, + { contactId: currUserId }, { headers: { "Content-Type": "application/json", @@ -692,6 +500,22 @@ function PdfRequestFiles(props) { } else { setRequestSignTour(false); } + setSaveSignCheckbox((prev) => ({ ...prev, isVisible: true })); + //function to get default signatur of current user from `contracts_Signature` class + const defaultSignRes = await getDefaultSignature( + jsonSender?.objectId + ); + if (defaultSignRes?.status === "success") { + setSaveSignCheckbox((prev) => ({ + ...prev, + isVisible: true, + signId: defaultSignRes?.res?.id + })); + const sign = defaultSignRes?.res?.defaultSignature || ""; + const initials = defaultSignRes?.res?.defaultInitial || ""; + setDefaultSignImg(sign); + setMyInitial(initials); + } } else if (res?.length === 0) { const res = await contactBook(currUserId); if (res === "Error: Something went wrong!") { @@ -717,6 +541,8 @@ function PdfRequestFiles(props) { } } setIsUiLoading(false); + setIsLoading({ isLoad: false }); + return updatedPdfDetails; } else if ( documentData === "Error: Something went wrong!" || (documentData.result && documentData.result.error) @@ -726,15 +552,8 @@ function PdfRequestFiles(props) { console.log("err in getDocument cloud function "); } else { setHandleError(t("no-data")); - setIsUiLoading({ isLoad: false }); - } - //function to get default signatur eof current user from `contracts_Signature` class - const defaultSignRes = await getDefaultSignature(jsonSender?.objectId); - if (defaultSignRes?.status === "success") { - const sign = defaultSignRes?.res?.defaultSignature || ""; - const initials = defaultSignRes?.res?.defaultInitial || ""; - setDefaultSignImg(sign); - setMyInitial(initials); + setIsUiLoading(false); + setIsLoading({ isLoad: false }); } setIsLoading({ isLoad: false }); } catch (err) { @@ -766,7 +585,6 @@ function PdfRequestFiles(props) { } } isEmailVerified = currentUser?.emailVerified; - setIsEmailVerified(isEmailVerified); } catch (err) { console.log("err in get email verification ", err); setHandleError(t("something-went-wrong-mssg")); @@ -973,16 +791,12 @@ function PdfRequestFiles(props) { //get ExistUserPtr object id of user class to get tenantDetails if (!pdfBytes?.error) { const objectId = pdfDetails?.[0]?.ExtUserPtr?.UserId?.objectId; - let activeMailAdapter = - pdfDetails?.[0]?.ExtUserPtr?.active_mail_adapter; //function for call to embed signature in pdf and get digital signature pdf const resSign = await signPdfFun( pdfBytes, documentId, signerObjectId, objectId, - isSubscribed, - activeMailAdapter, widgets ); if (resSign && resSign.status === "success") { @@ -990,7 +804,14 @@ function PdfRequestFiles(props) { setIsSigned(true); setSignedSigners([]); setUnSignedSigners([]); - getDocumentDetails(documentId, true); + const isSuccessRoute = pdfDetails?.[0]?.RedirectUrl + ? false + : window.location?.pathname?.includes("load"); + const updateDoc = await getDocumentDetails( + documentId, + true, + isSuccessRoute + ); const index = pdfDetails?.[0]?.Signers.findIndex( (x) => x.objectId === signerObjectId ); @@ -1018,9 +839,7 @@ function PdfRequestFiles(props) { try { const imgPng = "https://qikinnovation.ams3.digitaloceanspaces.com/logo.png"; - let url = `${localStorage.getItem( - "baseUrl" - )}functions/sendmailv3`; + let url = `${localStorage.getItem("baseUrl")}functions/sendmailv3`; const headers = { "Content-Type": "application/json", "X-Parse-Application-Id": @@ -1040,12 +859,8 @@ function PdfRequestFiles(props) { `${pdfDetails?.[0].objectId}/${user.Email}` ); } - const hostPublicUrl = isStaging - ? "https://staging-app.opensignlabs.com" - : "https://app.opensignlabs.com"; - let signPdf = props?.templateId - ? `${hostPublicUrl}/login/${encodeBase64}` - : `${hostUrl}/login/${encodeBase64}`; + let signPdf = + `${hostUrl}/login/${encodeBase64}`; const openSignUrl = "https://www.opensignlabs.com/contact-us"; const orgName = pdfDetails[0]?.ExtUserPtr.Company @@ -1053,7 +868,10 @@ function PdfRequestFiles(props) { : ""; const themeBGcolor = themeColor; let replaceVar; - if (requestBody && requestSubject && isSubscribed) { + if ( + requestBody && + requestSubject + ) { const replacedRequestBody = requestBody.replace( /"/g, "'" @@ -1065,12 +883,14 @@ function PdfRequestFiles(props) { const variables = { document_title: pdfDetails?.[0].Name, - sender_name: senderName, - sender_mail: senderEmail, + sender_name: + senderName, + sender_mail: + senderEmail, sender_phone: senderPhone, - receiver_name: user.Name, + receiver_name: user?.Name || "", receiver_email: user.Email, - receiver_phone: user.Phone, + receiver_phone: user?.Phone || "", expiry_date: localExpireDate, company_name: orgName, signing_url: `<a href=${signPdf} target=_blank>Sign here</a>` @@ -1083,15 +903,17 @@ function PdfRequestFiles(props) { } let params = { - mailProvider: activeMailAdapter, + replyto: + senderEmail || + "", extUserId: extUserId, recipient: user.Email, - subject: requestSubject + subject: replaceVar?.subject ? replaceVar?.subject : `${pdfDetails?.[0].ExtUserPtr.Name} has requested you to sign "${pdfDetails?.[0].Name}"`, - from: senderEmail, - plan: plancode, - html: requestBody + from: + senderEmail, + html: replaceVar?.body ? replaceVar?.body : "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /> </head> <body> <div style='background-color: #f5f5f5; padding: 20px'=> <div style=' box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background: white;padding-bottom: 20px;'> <div style='padding:10px 10px 0 10px'><img src=" + imgPng + @@ -1121,6 +943,19 @@ function PdfRequestFiles(props) { } } } + if (!isSuccessRoute) { + setIsredirectCanceled(false); + } else { + const url = + updateDoc?.[0]?.SignedUrl || updateDoc?.[0]?.URL; + const fileAdapter = + ""; + const isCompleted = updateDoc?.[0]?.IsCompleted + ? `&completed=true` + : ""; + const params = `docid=${updateDoc[0].objectId}&docurl=${encodeURIComponent(url)}${isCompleted}${fileAdapter}`; + window.location.href = `/success?${params}`; + } } else { setIsUiLoading(false); setIsAlert({ @@ -1171,6 +1006,126 @@ function PdfRequestFiles(props) { } } + //function for save x and y position and show signature tab on that position + const handleTabDrag = (key) => { + setDragKey(key); + setIsDragging(true); + }; + //function for set and update x and y postion after drag and drop signature tab + const handleStop = (event, dragElement, signerId, key) => { + if (!isResize && isDragging) { + let updateSignPos = [...signerPos]; + const signerObjId = signerId ? signerId : uniqueId; + const keyValue = key ? key : dragKey; + const containerScale = getContainerScale( + pdfOriginalWH, + pageNumber, + containerWH + ); + if (keyValue >= 0) { + let filterSignerPos = []; + if (signerObjId) { + //get current signerObjId placeholder details + filterSignerPos = updateSignPos.filter( + (data) => data.Id === signerObjId + ); + } + + if (filterSignerPos.length > 0) { + const getPlaceHolder = filterSignerPos[0].placeHolder; + //get position of current pagenumber + const getPageNumer = getPlaceHolder.filter( + (data) => data.pageNumber === pageNumber + ); + if (getPageNumer.length > 0) { + const getXYdata = getPageNumer[0].pos; + const addSignPos = getXYdata.map((url) => { + //add new position after drag widgets + if (url.key === keyValue) { + return { + ...url, + xPosition: dragElement.x / (containerScale * scale), + yPosition: dragElement.y / (containerScale * scale) + }; + } + return url; + }); + //update new position of current page number + const newUpdateSignPos = getPlaceHolder.map((obj) => { + if (obj.pageNumber === pageNumber) { + return { ...obj, pos: addSignPos }; + } + return obj; + }); + //update new placeholder of current signer + const newUpdateSigner = updateSignPos.map((obj) => { + if (signerObjId) { + if (obj.Id === signerObjId) { + return { ...obj, placeHolder: newUpdateSignPos }; + } + } + return obj; + }); + setSignerPos(newUpdateSigner); + } + } + } + } + setTimeout(() => setIsDragging(false), 200); + }; + + const handleTextSettingModal = (value) => { + setIsTextSetting(value); + }; + const handleSaveFontSize = () => { + const filterSignerPos = signerPos.filter((data) => data.Id === uniqueId); + if (filterSignerPos) { + const placehoder = filterSignerPos[0].placeHolder; + const getPageNumer = placehoder.filter( + (data) => data.pageNumber === pageNumber + ); + if (getPageNumer.length > 0) { + const getXYdata = getPageNumer[0].pos; + const getPosData = getXYdata; + const updateSignPos = getPosData.map((position) => { + if (position.key === signKey) { + return { + ...position, + options: { + ...position.options, + fontSize: + fontSize || currWidgetsDetails?.options?.fontSize || 12, + fontColor: + fontColor || currWidgetsDetails?.options?.fontColor || "black" + } + }; + } + return position; + }); + + //update new position of current page number + const newUpdateSignPos = placehoder.map((obj) => { + if (obj.pageNumber === pageNumber) { + return { ...obj, pos: updateSignPos }; + } + return obj; + }); + //update new placeholder of current signer + const newUpdateSigner = signerPos.map((obj) => { + if (obj.Id === uniqueId) { + return { ...obj, placeHolder: newUpdateSignPos }; + } + + return obj; + }); + setSignerPos(newUpdateSigner); + + setFontSize(); + setFontColor(); + handleTextSettingModal(false); + } + } + }; //function for update TourStatus const closeTour = async () => { setWidgetsTour(false); @@ -1207,11 +1162,13 @@ function PdfRequestFiles(props) { //function for image upload or update const onImageChange = (event) => { if (event.target.files && event.target.files[0]) { - onImageSelect(event, setImgWH, setImage); + const file = event.target.files[0]; + compressedFileSize(file, setImgWH, setImage); } }; //function for upload stamp image const saveImage = () => { + const widgetsType = currWidgetsDetails?.type; //get current signers placeholder position data const currentSigner = signerPos.filter( (data) => data.signerObjId === signerObjectId @@ -1222,13 +1179,18 @@ function PdfRequestFiles(props) { }); //get current signer placeholder position data const placeholderPosition = currentSigner[0].placeHolder; + //`isApplyAll` is used when user edit stamp then updated signature apply all existing drawn signatures + const isApplyAll = true; //function of save image and get updated position with image url const getUpdatePosition = onSaveImage( placeholderPosition, getIndex, signKey, imgWH, - image + image, + isAutoSign, + widgetsType, + isApplyAll ); //replace updated placeholder position with old data @@ -1247,9 +1209,11 @@ function PdfRequestFiles(props) { newState.splice(indexofSigner, 1, ...currentSigner); // Modify the copy return newState; // Update the state with the modified copy }); + setIsAutoSign(false); }; //function for save button to save signature or image url - const saveSign = (type, isDefaultSign, width, height) => { + const saveSign = (type, isDefaultSign, width, height, typedSignature) => { + const widgetsType = currWidgetsDetails?.type; const isTypeText = width && height ? true : false; const signatureImg = isDefaultSign ? isDefaultSign === "initials" @@ -1280,6 +1244,8 @@ function PdfRequestFiles(props) { } //get current signer placeholder position data const placeholderPosition = currentSigner[0].placeHolder; + //`isApplyAll` is used when user edit signature/initial then updated signature apply all existing drawn signatures + const isApplyAll = true; //function of save signature image and get updated position with signature image url const getUpdatePosition = onSaveSign( type, @@ -1289,9 +1255,12 @@ function PdfRequestFiles(props) { signatureImg, imgWH, isDefaultSign, - isTypeText + isTypeText, + typedSignature, + isAutoSign, + widgetsType, + isApplyAll ); - const updateSignerData = currentSigner.map((obj) => { if (obj.signerObjId === signerObjectId) { return { ...obj, placeHolder: getUpdatePosition }; @@ -1307,6 +1276,8 @@ function PdfRequestFiles(props) { newState.splice(index, 1, ...updateSignerData); return newState; }); + + setIsAutoSign(false); }; //function for set decline true on press decline button const declineDoc = async (reason) => { @@ -1316,9 +1287,6 @@ function PdfRequestFiles(props) { const jsonSender = JSON.parse(senderUser); setIsDecline({ isDeclined: false }); setIsUiLoading(true); - const email = - pdfDetails?.[0].Signers?.find((x) => x.objectId === signerObjectId) - ?.Email || jsonSender?.email; const userId = pdfDetails?.[0].Signers?.find((x) => x.objectId === signerObjectId) ?.UserId?.objectId || jsonSender?.objectId; @@ -1341,41 +1309,6 @@ function PdfRequestFiles(props) { const currentDecline = { currnt: "YouDeclined", isDeclined: true }; setIsDecline(currentDecline); setIsUiLoading(false); - const params = { - event: "declined", - body: { - objectId: pdfDetails?.[0].objectId, - file: pdfDetails?.[0]?.SignedUrl || pdfDetails?.[0]?.URL, - name: pdfDetails?.[0].Name, - note: pdfDetails?.[0].Note || "", - description: pdfDetails?.[0].Description || "", - signers: pdfDetails?.[0].Signers?.map((x) => ({ - name: x?.Name, - email: x?.Email, - phone: x?.Phone - })), - declinedBy: email, - declinedReason: reason, - declinedAt: new Date(), - createdAt: pdfDetails?.[0].createdAt - } - }; - - try { - await axios.post( - `${localStorage.getItem("baseUrl")}functions/callwebhook`, - params, - { - headers: { - "Content-Type": "application/json", - "X-Parse-Application-Id": localStorage.getItem("parseAppId"), - sessiontoken: localStorage.getItem("accesstoken") - } - } - ); - } catch (err) { - console.log("Err ", err); - } } }) .catch((err) => { @@ -1390,14 +1323,17 @@ function PdfRequestFiles(props) { }; //function to add default signature for all requested placeholder of sign const addDefaultSignature = () => { + const type = defaultSignAlert?.type; //get current signers placeholder position data const currentSignerPosition = signerPos.filter( (data) => data.signerObjId === signerObjectId ); + const defaultSign = type === "signature" ? defaultSignImg : myInitial; //function for save default signature url for all placeholder position const updatePlace = addDefaultSignatureImg( currentSignerPosition[0].placeHolder, - defaultSignImg + defaultSign, + type ); const updatesignerPos = signerPos.map((x) => @@ -1466,8 +1402,27 @@ function PdfRequestFiles(props) { } } }; + const formatArrayToString = (arr) => { + if (arr.length === 0) return ""; // Handle empty array + if (arr.length === 1) return `${arr[0]}`; // Handle single-element array + + const lastElement = arr.pop(); // Remove and store the last element + return `${arr.join(", ")} ${t("and")} ${lastElement}`; // Format the string + }; const requestSignTourFunction = () => { + const pagenumbers = formatArrayToString(showSignPagenumber); const tourConfig = [ + { + selector: '[data-tut="IsSigned"]', + content: () => ( + <TourContentWithBtn + message={t("tour-mssg.pdf-request-file-6", { pagenumbers })} + isChecked={handleDontShow} + /> + ), + position: "top", + style: { fontSize: "13px" } + }, { selector: '[data-tut="reactourFirst"]', content: () => ( @@ -1513,13 +1468,13 @@ function PdfRequestFiles(props) { position: "top", style: { fontSize: "13px" } }; - //checking if signed by user component exist then add signed step + //checking if signed by user component exist then add signed by tour step const signedBy = signedSigners.length > 0 ? [...tourConfig.slice(0, 0), signedByStep, ...tourConfig.slice(0)] : tourConfig; - //checking if default signature component exist then add defaultSign step + //checking if default signature component exist then add defaultSign tour step const defaultSignStep = { selector: '[data-tut="reactourThird"]', content: () => ( @@ -1531,20 +1486,47 @@ function PdfRequestFiles(props) { position: "top", style: { fontSize: "13px" } }; - //index is handle is signed by exist then 2 else 1 to add tour step - const index = signedSigners.length > 0 ? 2 : 1; - const defaultSignTour = defaultSignImg + //checking if AllowModifications is true then add allow widgets panel tour step + const allModifyWidgets = { + selector: '[data-tut="reactourFourth"]', + content: () => ( + <TourContentWithBtn + message={t("tour-mssg.allowModify-widgets")} + isChecked={handleDontShow} + /> + ), + position: "top", + style: { fontSize: "13px" } + }; + + //handle signed by panel index if signed by exist then 2 else 1 to add tour step + const index = signedSigners.length > 0 ? 3 : 2; + let defaultSignTour = defaultSignImg ? [...signedBy.slice(0, index), defaultSignStep, ...signedBy.slice(index)] : signedBy; - - if (isMobile) { - tourConfig.shift(); + //handle index when AllowModifications is true and defaultSignImg & signedSigners both exist or only + //signedSigners or defaultSignImg exist then adjust index + const modifyIndex = + signedSigners > 0 && defaultSignImg + ? 4 + : signedSigners > 0 || defaultSignImg + ? 3 + : 2; + if (pdfDetails[0]?.AllowModifications) { + defaultSignTour = [ + ...defaultSignTour.slice(0, modifyIndex), + allModifyWidgets, + ...defaultSignTour.slice(modifyIndex) + ]; + } + let mobileTour; + if (isMobile) { + mobileTour = tourConfig.filter((_, ind) => ind !== 1); } - return ( <Tour onRequestClose={closeRequestSignTour} - steps={isMobile ? tourConfig : defaultSignTour} + steps={isMobile ? mobileTour : defaultSignTour} isOpen={true} closeWithMask={false} rounded={5} @@ -1552,178 +1534,6 @@ function PdfRequestFiles(props) { ); }; - const handleUserDetails = () => { - setIsPublicContact(true); - }; - - //`handlePublicUser` function to use create user from public role and create document from public template - const handlePublicUser = async (e) => { - e.preventDefault(); - if (!emailRegex.test(contact.email)) { - alert("Please enter a valid email address."); - } else { - setLoading(true); - try { - const params = { - ...contact, - templateid: pdfDetails[0]?.objectId, - role: pdfDetails[0]?.PublicRole[0] - }; - const userRes = await axios.post( - `${localStorage.getItem( - "baseUrl" - )}/functions/publicuserlinkcontacttodoc`, - params, - { - headers: { - "Content-Type": "application/json", - "X-Parse-Application-Id": localStorage.getItem("parseAppId") - } - } - ); - - if (userRes?.data?.result) { - setPublicRes(userRes.data.result); - const isEnableOTP = pdfDetails?.[0]?.IsEnableOTP || false; - if (isEnableOTP) { - await SendOtp(); - } else { - setIsPublicContact(false); - setIsPublicTemplate(false); - setDocumentId(userRes.data?.result?.docId); - const contactId = userRes.data.result?.contactId; - setSignerObjectId(contactId); - } - } else { - console.log("error in public-sign to create user details"); - setIsAlert({ - title: "Error", - isShow: true, - alertMessage: t("something-went-wrong-mssg") - }); - } - } catch (e) { - console.log("e", e); - if ( - e?.response?.data?.error === "Insufficient Credit" || - e?.response?.data?.error === "Plan expired" - ) { - handleCloseOtp(); - setIsAlert({ - title: t("insufficient-credits"), - isShow: true, - alertMessage: t("insufficient-credits-mssg") - }); - } else { - handleCloseOtp(); - setIsAlert({ - title: "Error", - isShow: true, - alertMessage: t("something-went-wrong-mssg") - }); - } - } - } - }; - - const handleInputChange = (e) => { - let { name, value } = e.target; - if (name === "email") { - value = value?.toLowerCase()?.replace(/\s/g, ""); - } - setContact({ ...contact, [name]: value }); - }; - - const SendOtp = async () => { - try { - const params = { email: contact.email, docId: publicRes?.docId }; - const Otp = await axios.post( - `${localStorage.getItem("baseUrl")}/functions/SendOTPMailV1`, - params, - { - headers: { - "Content-Type": "application/json", - "X-Parse-Application-Id": localStorage.getItem("parseAppId") - } - } - ); - - if (Otp) { - setIsOtp(true); - setLoading(false); - } - } catch (error) { - console.log("error in verify otp in public-sign", error); - setIsAlert({ - title: "Error", - isShow: true, - alertMessage: t("something-went-wrong-mssg") - }); - } - }; - - //verify OTP send on via email - const VerifyOTP = async (e) => { - e.preventDefault(); - setLoading(true); - const serverUrl = - localStorage.getItem("baseUrl") && localStorage.getItem("baseUrl"); - const parseId = - localStorage.getItem("parseAppId") && localStorage.getItem("parseAppId"); - if (otp) { - // setLoading(true); - try { - let url = `${serverUrl}/functions/AuthLoginAsMail/`; - const headers = { - "Content-Type": "application/json", - "X-Parse-Application-Id": parseId - }; - let body = { email: contact.email, otp: otp }; - let user = await axios.post(url, body, { headers: headers }); - if (user.data.result === "Invalid Otp") { - alert(t("invalid-otp")); - setLoading(false); - } else if (user.data.result === "user not found!") { - alert(t("user-not-found")); - setLoading(false); - } else { - let _user = user.data.result; - const parseId = localStorage.getItem("parseAppId"); - await Parse.User.become(_user.sessionToken); - const contractUserDetails = await contractUsers(); - localStorage.setItem("UserInformation", JSON.stringify(_user)); - localStorage.setItem( - `Parse/${parseId}/currentUser`, - JSON.stringify(_user) - ); - if (contractUserDetails && contractUserDetails.length > 0) { - localStorage.setItem( - "Extand_Class", - JSON.stringify(contractUserDetails) - ); - } - localStorage.setItem("username", _user.name); - localStorage.setItem("accesstoken", _user.sessionToken); - setLoading(false); - setIsPublicContact(false); - setIsPublicTemplate(false); - setIsLoading({ isLoad: false }); - setDocumentId(publicRes?.docId); - } - } catch (error) { - console.log("err ", error); - } - } else { - alert(t("enter-otp-alert")); - } - }; - const handleCloseOtp = () => { - setIsPublicContact(false); - setLoading(false); - setIsOtp(false); - setOtp(); - setContact({ name: "", email: "", phone: "" }); - }; const clickOnZoomIn = () => { onClickZoomIn(scale, zoomPercent, setScale, setZoomPercent); @@ -1733,7 +1543,10 @@ function PdfRequestFiles(props) { }; const handleDownloadBtn = async () => { const url = pdfDetails?.[0]?.SignedUrl || pdfDetails?.[0]?.URL; - const name = pdfDetails?.[0]?.Name; + const name = + pdfDetails?.[0]?.Name?.length > 100 + ? pdfDetails?.[0]?.Name?.slice(0, 100) + : pdfDetails?.[0]?.Name || "Document"; await fetchUrl(url, name); }; const handleDeclineMssg = () => { @@ -1789,29 +1602,295 @@ function PdfRequestFiles(props) { alert(t("expiry-date-error")); } }; + const AgreementTour = [ + { + selector: '[data-tut="IsAgree"]', + content: () => <p className="p-0">{t("agrrement-alert")}</p>, + position: "top", + style: { fontSize: "13px" } + } + ]; + const handleCloseAgreeTour = () => { + setIsAgreeTour(false); + }; + // `handleRedirectCancel` is used to cancel redirecting to redirectUrl + const handleRedirectCancel = () => { + setIsredirectCanceled(true); + }; + //function for capture position on hover or touch widgets + const handleDivClick = (e) => { + const isTouchEvent = e.type.startsWith("touch"); + const divRect = e.currentTarget.getBoundingClientRect(); + let mouseX, mouseY; + if (isTouchEvent) { + const touch = e.touches[0]; // Get the first touch point + mouseX = touch.clientX - divRect.left; + mouseY = touch.clientY - divRect.top; + setSignBtnPosition([{ xPos: mouseX, yPos: mouseY }]); + } else { + mouseX = e.clientX - divRect.left; + mouseY = e.clientY - divRect.top; + setXYSignature({ xPos: mouseX, yPos: mouseY }); + } + }; + //function for capture position of x and y on hover signature button last position + const handleMouseLeave = () => { + setSignBtnPosition([xySignature]); + }; + //function for setting position after drop signature button over pdf + const addPositionOfSignature = (item, monitor) => { + getSignerPos(item, monitor); + }; + const getSignerPos = (item, monitor) => { + const posZIndex = zIndex + 1; + setZIndex(posZIndex); + const key = randomId(); + const containerScale = getContainerScale( + pdfOriginalWH, + pageNumber, + containerWH + ); + let dropData = []; + let placeHolder; + const dragTypeValue = item?.text ? item.text : monitor.type; + const widgetWidth = + defaultWidthHeight(dragTypeValue).width * containerScale; + const widgetHeight = + defaultWidthHeight(dragTypeValue).height * containerScale; + //adding and updating drop position in array when user drop signature button in div + if (item === "onclick") { + const divHeight = divRef.current.getBoundingClientRect().height; + // `getBoundingClientRect()` is used to get accurate measurement height of the div + const dropObj = { + //onclick put placeholder center on pdf + xPosition: widgetWidth / 4 + containerWH.width / 2, + yPosition: widgetHeight + divHeight / 2, + isStamp: + (dragTypeValue === "stamp" || dragTypeValue === "image") && true, + key: key, + scale: containerScale, + zIndex: posZIndex, + type: dragTypeValue, + options: addWidgetOptions(dragTypeValue), + Width: widgetWidth / (containerScale * scale), + Height: widgetHeight / (containerScale * scale) + }; + dropData.push(dropObj); + placeHolder = { pageNumber: pageNumber, pos: dropData }; + } else { + const offset = monitor.getClientOffset(); + //This method returns the offset of the current pointer (mouse) position relative to the client viewport. + const containerRect = document + .getElementById("container") + .getBoundingClientRect(); + //`containerRect.left`, The distance from the left of the viewport to the left side of the element. + //`containerRect.top` The distance from the top of the viewport to the top of the element. + const x = offset.x - containerRect.left; + const y = offset.y - containerRect.top; + const getXPosition = signBtnPosition[0] ? x - signBtnPosition[0].xPos : x; + const getYPosition = signBtnPosition[0] ? y - signBtnPosition[0].yPos : y; + const dropObj = { + xPosition: getXPosition / (containerScale * scale), + yPosition: getYPosition / (containerScale * scale), + isStamp: + (dragTypeValue === "stamp" || dragTypeValue === "image") && true, + key: key, + scale: containerScale, + zIndex: posZIndex, + type: dragTypeValue, + options: addWidgetOptions(dragTypeValue), + Width: widgetWidth / (containerScale * scale), + Height: widgetHeight / (containerScale * scale) + }; + dropData.push(dropObj); + placeHolder = { pageNumber: pageNumber, pos: dropData }; + } + setSelectWidgetId(key); + if (uniqueId) { + let filterSignerPos, currentPagePosition; + filterSignerPos = signerPos.find((data) => data.Id === uniqueId); + const getPlaceHolder = filterSignerPos?.placeHolder; + if (getPlaceHolder) { + //checking exist placeholder on same page + currentPagePosition = getPlaceHolder.find( + (data) => data.pageNumber === pageNumber + ); + } + //checking current page has already some placeholders then update that placeholder and add upcoming placehoder position + if (getPlaceHolder && currentPagePosition) { + const updatePlace = getPlaceHolder.filter( + (data) => data.pageNumber !== pageNumber + ); + const getPos = currentPagePosition?.pos; + const newSignPos = getPos.concat(dropData); + let xyPos = { pageNumber: pageNumber, pos: newSignPos }; + updatePlace.push(xyPos); + const updatesignerPos = signerPos.map((x) => + x.Id === uniqueId ? { ...x, placeHolder: updatePlace } : x + ); + setSignerPos(updatesignerPos); + } else { + //else condition to add placeholder widgets on multiple page first time + const updatesignerPos = signerPos.map((x) => + x.Id === uniqueId && x?.placeHolder + ? { ...x, placeHolder: [...x.placeHolder, placeHolder] } + : x.Id === uniqueId + ? { ...x, placeHolder: [placeHolder] } + : x + ); + setSignerPos(updatesignerPos); + } + + // if (dragTypeValue === "dropdown") { + // setShowDropdown(true); + // } else if (dragTypeValue === "checkbox") { + // setIsCheckbox(true); + // } else + if ( + [textWidget, "name", "company", "job title", "email"].includes( + dragTypeValue + ) + ) { + setFontSize(12); + setFontColor("black"); + } + setWidgetType(dragTypeValue); + setSignKey(key); + setCurrWidgetsDetails({}); + } + }; + + //function for delete signature block + const handleDeleteSign = (key, Id) => { + const updateData = []; + const filterSignerPos = signerPos.filter((data) => data.Id === Id); + if (filterSignerPos.length > 0) { + const getPlaceHolder = filterSignerPos[0].placeHolder; + const getPageNumer = getPlaceHolder.filter( + (data) => data.pageNumber === pageNumber + ); + if (getPageNumer.length > 0) { + const getXYdata = getPageNumer[0].pos.filter( + (data) => data.key !== key + ); + //condition to check on same has multiple widgets so do not delete all widgets + if (getXYdata.length > 0) { + updateData.push(getXYdata); + const newUpdatePos = getPlaceHolder.map((obj) => { + if (obj.pageNumber === pageNumber) { + return { ...obj, pos: updateData[0] }; + } + return obj; + }); + + const newUpdateSigner = signerPos.map((obj) => { + if (obj.Id === Id) { + return { ...obj, placeHolder: newUpdatePos }; + } + return obj; + }); + setSignerPos(newUpdateSigner); + } else { + const getRemainPage = filterSignerPos[0].placeHolder.filter( + (data) => data.pageNumber !== pageNumber + ); + //condition to check placeholder length is greater than 1 do not need to remove whole placeholder + //array only resove particular widgets + if (getRemainPage && getRemainPage.length > 0) { + const newUpdatePos = filterSignerPos.map((obj) => { + if (obj.Id === Id) { + return { ...obj, placeHolder: getRemainPage }; + } + return obj; + }); + let signerupdate = []; + signerupdate = signerPos.filter((data) => data.Id !== Id); + signerupdate.push(newUpdatePos[0]); + setSignerPos(signerupdate); + } else { + const updatedData = signerPos.map((item) => { + if (item.Id === Id) { + // Create a copy of the item object and delete the placeHolder field + const updatedItem = { ...item }; + delete updatedItem.placeHolder; + return updatedItem; + } + return item; + }); + setSignerPos(updatedData); + } + } + } + } + }; + //function to get first widget and page number to assign currect signer and tour message + const showFirstWidget = () => { + if (!requestSignTour) { + const getCurrentUserPlaceholder = signerPos.find( + (x) => x.Id === uniqueId + ); + const placeholder = getCurrentUserPlaceholder.placeHolder; + //checking minimum pagnumber of existing widgets and throw tour message on that page + const getPosition = placeholder.reduce( + (min, obj) => (obj.pageNumber < min.pageNumber ? obj : min), + placeholder[0] + ); + const getWidgetId = getPosition.pos[0].key; + setUnSignedWidgetId(getWidgetId); + setPageNumber(getPosition.pageNumber); + let pagenumber = []; + for (let item of getCurrentUserPlaceholder.placeHolder) { + pagenumber.push(item.pageNumber); + } + // Sort the pagenumber in ascending order + const sortedPagenumber = [...pagenumber].sort((a, b) => a - b); + setShowSignPagenumber(sortedPagenumber); + } + }; return ( <DndProvider backend={HTML5Backend}> - <Title title={props.templateId ? "Public Sign" : "Request Sign"} /> - {isSubscriptionExpired ? ( - <ModalUi - title={t("subscription-expired")} - isOpen={isSubscriptionExpired} - showClose={false} - > - <div className="flex flex-col justify-center items-center py-4 md:py-5 gap-5"> - <p className="text-sm md:text-lg font-normal"> - {t("owner-subscription-expired")} - </p> - </div> - </ModalUi> - ) : ( - <> + <Title + title={ + "Request Sign" + } + /> {isLoading.isLoad ? ( <LoaderWithMsg isLoading={isLoading} /> ) : handleError ? ( <HandleError handleError={handleError} /> ) : ( <div> + {!isAgree && + currentSigner && + !isExpired && + !alreadySign && + !isCompleted?.isCertificate && + !isDecline?.isDeclined && ( + <AgreementSign + setIsAgree={setIsAgree} + setIsAgreeTour={setIsAgreeTour} + showFirstWidget={showFirstWidget} + /> + )} + <Tour + showNumber={false} + showNavigation={false} + showNavigationNumber={false} + onRequestClose={handleCloseAgreeTour} + steps={AgreementTour} + isOpen={isAgreeTour} + rounded={5} + closeWithMask={false} + /> + + {isUiLoading && ( + <div className="absolute h-[100vh] w-full flex flex-col justify-center items-center z-[999] bg-[#e6f2f2] bg-opacity-80"> + <Loader /> + <span className="text-[13px] text-base-content"> + {t("loading-mssg")} + </span> + </div> + )} {isUiLoading && ( <div className="absolute h-[100vh] w-full flex flex-col justify-center items-center z-[999] bg-[#e6f2f2] bg-opacity-80"> <Loader /> @@ -1839,11 +1918,13 @@ function PdfRequestFiles(props) { : "auto" }} className={`${ - (props.templateId || isGuestSignFlow) && - "mx-2 border-[0.5px] border-gray-300" - } relative op-card overflow-hidden flex flex-col md:flex-row justify-between bg-base-300`} + isGuestSignFlow + ? "border-[0.5px] border-gray-300" + : "op-card" + } relative overflow-hidden flex flex-col md:flex-row justify-between bg-base-300`} > {!requestSignTour && + isAgree && signerObjectId && requestSignTourFunction()} <Tour @@ -1882,138 +1963,6 @@ function PdfRequestFiles(props) { handleDownloadBtn={handleDownloadBtn} handleExpiry={handleExpiry} /> - {!isEmailVerified && ( - <VerifyEmail - isVerifyModal={isVerifyModal} - setIsVerifyModal={setIsVerifyModal} - handleVerifyEmail={handleVerifyEmail} - setOtp={setOtp} - otp={otp} - otpLoader={otpLoader} - handleVerifyBtn={handleVerifyBtn} - handleResend={handleResend} - /> - )} - <ModalUi - isOpen={isPublicContact} - title={isOtp ? t("verify-email-1") : t("contact-details")} - handleClose={() => handleCloseOtp()} - > - <div className="h-full p-[20px]"> - {isOtp ? ( - <form onSubmit={VerifyOTP}> - <div className="mb-[0.75rem]"> - <label className="block text-xs font-semibold mb-2"> - {t("get-otp-alert")} - <span className="text-[13px] text-[red]"> *</span> - </label> - <input - type="number" - name="otp" - placeholder={t("otp-placeholder")} - onInvalid={(e) => - e.target.setCustomValidity(t("input-required")) - } - onInput={(e) => e.target.setCustomValidity("")} - required - value={otp} - onChange={(e) => setOtp(e.target.value)} - disabled={loading} - className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" - /> - </div> - <div className="mt-6 flex justify-start gap-2"> - <button - className="op-btn op-btn-primary" - disabled={loading} - > - {loading ? t("loading") : t("verify")} - </button> - <button - className="op-btn op-btn-ghost" - onClick={() => handleCloseOtp()} - > - {t("cancel")} - </button> - </div> - </form> - ) : ( - <form - className="text-base-content p-2 mx-auto" - onSubmit={handlePublicUser} - > - <div className="mb-[0.75rem]"> - <label className="block text-xs font-semibold mb-[5px]"> - {t("name")} - <span className="text-[13px] text-[red]"> *</span> - </label> - <input - type="text" - id="name" - name="name" - value={contact.name} - onChange={handleInputChange} - onInvalid={(e) => - e.target.setCustomValidity(t("input-required")) - } - onInput={(e) => e.target.setCustomValidity("")} - required - disabled={loading} - className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" - /> - </div> - <div className="mb-[0.75rem]"> - <label className="block text-xs font-semibold mb-[5px]"> - {t("email")} - <span className="text-[13px] text-[red]"> *</span> - </label> - <input - type="email" - name="email" - value={contact.email} - onChange={handleInputChange} - onInvalid={(e) => - e.target.setCustomValidity(t("input-required")) - } - onInput={(e) => e.target.setCustomValidity("")} - required - disabled={loading} - className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" - /> - </div> - <div className="mb-[0.75rem]"> - <label className="block text-xs font-semibold mb-[5px]"> - {t("phone")} - </label> - <input - value={contact.phone} - onChange={handleInputChange} - type="text" - name="phone" - placeholder={t("phone-optional")} - disabled={loading} - className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" - /> - </div> - - <div className="mt-6 flex justify-start gap-2"> - <button - className="op-btn op-btn-primary" - disabled={loading} - > - {loading ? t("loading") : t("submit")} - </button> - <button - className="op-btn op-btn-ghost" - onClick={() => handleCloseOtp()} - > - {t("close")} - </button> - </div> - </form> - )} - </div> - </ModalUi> <ModalUi isOpen={defaultSignAlert.isShow} title={t("auto-sign-all")} @@ -2062,23 +2011,36 @@ function PdfRequestFiles(props) { {/* this component used to render all pdf pages in left side */} <RenderAllPdfPage signerPos={signerPos} - signerObjectId={signerObjectId} - signPdfUrl={ - pdfDetails[0] && - (pdfDetails[0]?.SignedUrl || pdfDetails[0]?.URL) - } + id={uniqueId} allPages={allPages} setAllPages={setAllPages} setPageNumber={setPageNumber} pageNumber={pageNumber} containerWH={containerWH} + pdfBase64Url={pdfBase64Url} + signedUrl={pdfDetails?.[0]?.SignedUrl || ""} /> {/* pdf render view */} <div className=" w-full md:w-[57%] flex mr-4"> <PdfZoom clickOnZoomIn={clickOnZoomIn} clickOnZoomOut={clickOnZoomOut} - isDisableRotate={true} + isDisableEditTools={true} + allPages={allPages} + setAllPages={setAllPages} + setPageNumber={setPageNumber} + /> + <PlaceholderCopy + isPageCopy={isPageCopy} + setIsPageCopy={setIsPageCopy} + xyPosition={signerPos} + setXyPosition={setSignerPos} + allPages={allPages} + pageNumber={pageNumber} + signKey={signKey} + Id={uniqueId} + widgetType={widgetType} + setUniqueId={setUniqueId} /> <div className=" w-full md:w-[95%] "> {/* this modal is used show this document is already sign */} @@ -2095,71 +2057,96 @@ function PdfRequestFiles(props) { > <div className="h-full p-[20px] text-base-content"> {isCompleted?.message ? ( - <p>{isCompleted?.message}</p> + <> + <p>{isCompleted?.message}</p> + {!isredirectCanceled && redirectUrl && ( + <div className="flex flex-row gap-1 items-center justify-center mb-3 mt-2"> + <p> + Redirecting you in {redirectTimeLeft} sec... + </p> + <button + onClick={handleRedirectCancel} + className="underline cursor-pointer op-text-primary focus:outline-none ml-2" + > + Cancel + </button> + </div> + )} + </> ) : ( <div className="px-[15px]"> <span>{t("document-signed-alert-4")}</span> </div> )} {!isCompleted?.message && ( - <div className="flex mt-4 gap-1 px-[15px]"> - <button - onClick={(e) => - handleToPrint( - e, - pdfUrl, - 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> - <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={() => { - setIsCompleted((prev) => ({ - ...prev, - isModal: false - })); - setIsDownloadModal(true); - }} - > - <i - className="fa-light fa-download" - aria-hidden="true" - ></i> - <span className="hidden lg:block"> - {t("download")} - </span> - </button> + <div className="flex flex-col mt-3 gap-1 px-[10px] justify-center items-center"> + {!isredirectCanceled && redirectUrl && ( + <div className="flex flex-row gap-1 items-center justify-center mb-3"> + <p> + Redirecting you in {redirectTimeLeft} sec... + </p> + <button + onClick={handleRedirectCancel} + className="underline cursor-pointer op-text-primary focus:outline-none ml-2" + > + Cancel + </button> + </div> + )} + <div className={`${!redirectUrl ? "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> + <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={() => { + setIsCompleted((prev) => ({ + ...prev, + isModal: false + })); + setIsDownloadModal(true); + }} + > + <i + className="fa-light fa-download" + aria-hidden="true" + ></i> + <span className="hidden lg:block"> + {t("download")} + </span> + </button> + </div> </div> )} </div> @@ -2170,22 +2157,31 @@ function PdfRequestFiles(props) { </div> )} <ModalUi - isOpen={isDownloading === "certificate"} + isOpen={ + isDownloading === "certificate" || + isDownloading === "certificate_err" + } title={ - isDownloading === "certificate" + isDownloading === "certificate" || + isDownloading === "certificate_err" ? t("generating-certificate") : t("pdf-download") } handleClose={() => setIsDownloading("")} > <div className="p-3 md:p-5 text-[13px] md:text-base text-center text-base-content"> - {isDownloading === "certificate"}{" "} - <p>{t("generate-certificate-alert")}</p> + {isDownloading === "certificate" ? ( + <p>{t("generate-certificate-alert")}</p> + ) : ( + <p>{t("generate-certificate-err")}</p> + )} </div> </ModalUi> {/* this component is used for signature pad modal */} - {documentId && ( + {documentId && isSignPad && ( <SignPad + saveSignCheckbox={saveSignCheckbox} + setSaveSignCheckbox={setSaveSignCheckbox} signatureTypes={signatureType} isSignPad={isSignPad} isStamp={isStamp} @@ -2201,16 +2197,22 @@ function PdfRequestFiles(props) { onSaveSign={saveSign} defaultSign={defaultSignImg} myInitial={myInitial} + setDefaultSignImg={setDefaultSignImg} + setMyInitial={setMyInitial} isInitial={isInitial} setIsInitial={setIsInitial} setIsStamp={setIsStamp} currWidgetsDetails={currWidgetsDetails} setCurrWidgetsDetails={setCurrWidgetsDetails} + setIsAutoSign={setIsAutoSign} + isAutoSign={isAutoSign} /> )} {/* pdf header which contain funish back button */} <Header - isPdfRequestFiles={isPublicTemplate ? false : true} + isPdfRequestFiles={ + true + } pageNumber={pageNumber} allPages={allPages} changePage={changePage} @@ -2219,26 +2221,31 @@ function PdfRequestFiles(props) { isSigned={isSigned} isCompleted={isCompleted.isCertificate} embedWidgetsData={ - isPublicTemplate ? handleUserDetails : embedWidgetsData + embedWidgetsData } isShowHeader={true} setIsDecline={setIsDecline} decline={true} currentSigner={currentSigner} - pdfUrl={pdfUrl} alreadySign={alreadySign} containerWH={containerWH} - isPublicTemplate={isPublicTemplate} clickOnZoomIn={clickOnZoomIn} clickOnZoomOut={clickOnZoomOut} - isDisableRotate={true} - templateId={props.templateId} + isDisablePdfEditTools={true} setIsDownloadModal={setIsDownloadModal} + pdfBase64={pdfBase64Url} + isGuestSignFlow={isGuestSignFlow} /> - <div ref={divRef} data-tut="pdfArea" className="h-[95%]"> + <div + ref={divRef} + data-tut="pdfArea" + className="h-full md:h-[95%]" + > {containerWH && ( <RenderPdf + setIsPageCopy={setIsPageCopy} + drop={drop} pageNumber={pageNumber} pdfOriginalWH={pdfOriginalWH} pdfNewWidth={pdfNewWidth} @@ -2270,78 +2277,111 @@ function PdfRequestFiles(props) { setScale={setScale} scale={scale} uniqueId={uniqueId} - ispublicTemplate={isPublicTemplate} - handleUserDetails={handleUserDetails} + pdfBase64Url={pdfBase64Url} + setIsAgreeTour={setIsAgreeTour} + isAgree={isAgree} + handleTabDrag={handleTabDrag} + handleStop={handleStop} + isDragging={isDragging} + isAlllowModify={pdfDetails[0]?.AllowModifications} + setUniqueId={setUniqueId} + handleDeleteSign={handleDeleteSign} + handleTextSettingModal={handleTextSettingModal} + setWidgetType={setWidgetType} + assignedWidgetId={assignedWidgetId} + setRequestSignTour={setRequestSignTour} /> )} </div> </div> </div> - <div className="w-full md:w-[23%] bg-base-100 overflow-y-auto hide-scrollbar hidden md:inline-block"> + <div className="w-full md:w-[23%] bg-base-100 overflow-y-auto hide-scrollbar "> <div className={`max-h-screen`}> - {signedSigners.length > 0 && ( - <> - <div - data-tut="reactourSecond" - className="mx-2 pr-2 pt-2 pb-1 text-[15px] text-base-content font-semibold border-b-[1px] border-base-300" - > - <span>{t("signed-by")}</span> - </div> - <div className="mt-[2px]"> - {signedSigners.map((obj, ind) => { - return ( - <div key={ind}> - <SignerListComponent - ind={ind} - obj={obj} - isMenu={isHeader} - signerPos={signerPos} - /> - </div> - ); - })} - </div> - </> - )} + <div className="w-full hidden md:inline-block"> + {signedSigners.length > 0 && ( + <> + <div + data-tut="reactourSecond" + className="mx-2 pr-2 pt-2 pb-1 text-[15px] text-base-content font-semibold border-b-[1px] border-base-300" + > + <span>{t("signed-by")}</span> + </div> + <div className="mt-[2px]"> + {signedSigners.map((obj, ind) => { + return ( + <div key={ind}> + <SignerListComponent + ind={ind} + obj={obj} + isMenu={isHeader} + signerPos={signerPos} + /> + </div> + ); + })} + </div> + </> + )} - {unsignedSigners.length > 0 && ( - <> - <div - data-tut="reactourFirst" - className="mx-2 pr-2 pt-2 pb-1 text-[15px] text-base-content font-semibold border-b-[1px] border-base-300" - > - <span>{t("yet-to-sign")}</span> + {unsignedSigners.length > 0 && ( + <> + <div + data-tut="reactourFirst" + className="mx-2 pr-2 pt-2 pb-1 text-[15px] text-base-content font-semibold border-b-[1px] border-base-300" + > + <span>{t("yet-to-sign")}</span> + </div> + <div className="mt-[5px]"> + {unsignedSigners.map((obj, ind) => { + return ( + <div key={ind}> + <SignerListComponent + ind={ind} + obj={obj} + isMenu={isHeader} + signerPos={signerPos} + /> + </div> + ); + })} + </div> + </> + )} + {(defaultSignImg || myInitial) && + !alreadySign && + currentSigner && ( + <DefaultSignature + defaultSignImg={defaultSignImg} + myInitial={myInitial} + userObjectId={signerObjectId} + setIsLoading={setIsLoading} + xyPosition={signerPos} + uniqueId={uniqueId} + setDefaultSignAlert={setDefaultSignAlert} + isDefault={ + signatureType?.find((x) => x.name === "default") + ?.enabled || false + } + isAgree={isAgree} + setIsAgreeTour={setIsAgreeTour} + /> + )} + </div> + {pdfDetails[0]?.AllowModifications && + currentSigner && + !alreadySign && ( + <div data-tut="reactourFourth"> + <WidgetComponent + pdfUrl={pdfUrl} + handleDivClick={handleDivClick} + handleMouseLeave={handleMouseLeave} + xyPosition={signerPos} + addPositionOfSignature={addPositionOfSignature} + isAlllowModify={true} + /> </div> - <div className="mt-[5px]"> - {unsignedSigners.map((obj, ind) => { - return ( - <div key={ind}> - <SignerListComponent - ind={ind} - obj={obj} - isMenu={isHeader} - signerPos={signerPos} - /> - </div> - ); - })} - </div> - </> - )} - {defaultSignImg && !alreadySign && currentSigner && ( - <DefaultSignature - defaultSignImg={defaultSignImg} - userObjectId={signerObjectId} - setIsLoading={setIsLoading} - xyPostion={signerPos} - setDefaultSignAlert={setDefaultSignAlert} - isDefault={ - signatureType?.find((x) => x.name === "default") - ?.enabled || false - } - /> - )} + )} </div> </div> </div> @@ -2369,6 +2409,7 @@ function PdfRequestFiles(props) { isDownloadModal={isDownloadModal} pdfDetails={pdfDetails} isDocId={true} + pdfBase64={pdfBase64Url} /> <ModalUi isOpen={isAlert.isShow} @@ -2386,8 +2427,16 @@ function PdfRequestFiles(props) { </button> </div> </ModalUi> - </> - )} + <TextFontSetting + isTextSetting={isTextSetting} + setIsTextSetting={setIsTextSetting} + fontSize={fontSize} + setFontSize={setFontSize} + fontColor={fontColor} + setFontColor={setFontColor} + handleSaveFontSize={handleSaveFontSize} + currWidgetsDetails={currWidgetsDetails} + /> </DndProvider> ); } diff --git a/apps/OpenSign/src/pages/Pgsignup.js b/apps/OpenSign/src/pages/Pgsignup.js deleted file mode 100644 index 1ba337614..000000000 --- a/apps/OpenSign/src/pages/Pgsignup.js +++ /dev/null @@ -1,384 +0,0 @@ -import React, { useState, useEffect } from "react"; -import Parse from "parse"; -import axios from "axios"; -import { useDispatch } from "react-redux"; -import Title from "../components/Title"; -import { useNavigate, useLocation } from "react-router-dom"; -import { appInfo } from "../constant/appinfo"; -import { showTenant } from "../redux/reducers/ShowTenant"; -import { fetchAppInfo } from "../redux/reducers/infoReducer"; -import Loader from "../primitives/Loader"; -import { useTranslation } from "react-i18next"; - -const PgSignUp = () => { - const { t } = useTranslation(); - const navigate = useNavigate(); - const location = useLocation(); - const dispatch = useDispatch(); - const [parseBaseUrl] = useState(localStorage.getItem("baseUrl")); - const [parseAppId] = useState(localStorage.getItem("parseAppId")); - const [formData, setFormData] = useState({ - password: "", - confirmPassword: "" - }); - const [validationMessage, setValidationMessage] = useState(""); - const [isLoader, setIsLoader] = useState(true); - const [lengthValid, setLengthValid] = useState(false); - const [caseDigitValid, setCaseDigitValid] = useState(false); - const [specialCharValid, setSpecialCharValid] = useState(false); - - // below useEffect is used to fetch App data and save to redux state - useEffect(() => { - dispatch(fetchAppInfo()); - handleSignedUpUser(); - // eslint-disable-next-line - }, []); - - //`handleSignedUpUser` is called first time and it only work for user who comes from login with google, facebook or normal sign up flow - const handleSignedUpUser = async () => { - const userDetails = JSON.parse(localStorage.getItem("userDetails")); - - if (userDetails && userDetails.email) { - try { - const url = window.location.href; - let paramString = url.split("?")[1]; - let queryString = new URLSearchParams(paramString); - let obj = { ...formData }; - for (let pair of queryString.entries()) { - obj = { ...obj, [pair[0]]: pair[1] }; - } - const zohoRes = await axios.post( - parseBaseUrl + "functions/zohodetails", - { - hostedpagesId: obj.hostedpage_id - }, - { - headers: { - "Content-Type": "application/json", - "X-Parse-Application-Id": parseAppId - } - } - ); - const userSettings = JSON.parse(localStorage.getItem("userSettings")); - const params = { subscription: zohoRes.data.result.subscription }; - const baseurl = `${parseBaseUrl}functions/savesubscription`; - try { - const res = await axios.post(baseurl, params, { - headers: { - "Content-Type": "application/json", - "X-Parse-Application-Id": parseAppId, - sessiontoken: localStorage.getItem("accesstoken") - } - }); - if (res) { - localStorage.removeItem("userDetails"); - try { - const extUser = await Parse.Cloud.run("getUserDetails"); - const userRole = extUser?.get("UserRole"); - const _currentRole = userRole; - const _role = _currentRole.replace("contracts_", ""); - localStorage.setItem("_user_role", _role); - const extInfo_stringify = JSON.stringify([extUser]); - localStorage.setItem("Extand_Class", extInfo_stringify); - } catch (err) { - console.log("Err in fetching extuser", err); - } - navigate( - "/" + userSettings[0].pageType + "/" + userSettings[0].pageId - ); - setIsLoader(false); - } - } catch (err) { - console.log("err ", err.message); - setIsLoader(false); - } - } catch (err) { - console.log("err ", err); - setIsLoader(false); - } - } else { - setIsLoader(false); - } - }; - - // "handleSubmit" is used to save user details signup him/her who come from plan-pricing page - const handleSubmit = (e) => { - e.preventDefault(); - if (lengthValid && caseDigitValid && specialCharValid) { - setIsLoader(true); - if (formData.password === formData.confirmPassword) { - const url = window.location.href; - let paramString = url.split("?")[1]; - let queryString = new URLSearchParams(paramString); - let obj = { ...formData }; - for (let pair of queryString.entries()) { - obj = { ...obj, [pair[0]]: pair[1] }; - } - saveUser(obj); - // console.log("obj ", obj);} - } - } - }; - const saveUser = async (obj) => { - try { - const zohoRes = await axios.post( - parseBaseUrl + "functions/zohodetails", - { - hostedpagesId: obj.hostedpage_id - }, - { - headers: { - "Content-Type": "application/json", - "X-Parse-Application-Id": parseAppId - } - } - ); - - const user = new Parse.User(); - user.set("username", zohoRes.data.result.email); - user.set("password", obj.password); - user.set("email", zohoRes.data.result.email); - if (zohoRes?.data?.result?.phone) { - user.set("phone", zohoRes.data.result.phone); - } - user.set("name", zohoRes.data.result.name); - - const res = await user.signUp(); - // console.log("res ", res); - - if (res) { - const params = { - userDetails: { - jobTitle: zohoRes.data.result.jobTitle, - company: zohoRes.data.result.company, - name: zohoRes.data.result.name, - email: zohoRes.data.result.email, - phone: zohoRes?.data?.result?.phone || "", - role: obj.role - }, - subscription: zohoRes.data.result.subscription - }; - const usersignup = await Parse.Cloud.run("usersignup", params); - // console.log("usersignup ", usersignup); - if (usersignup && usersignup.sessionToken) { - handleNavigation(usersignup.sessionToken); - } - } - // setIsLoader(false); - } catch (error) { - console.log("err ", error); - if (error.message === "Account already exists for this username.") { - alert(t("account-already-exists")); - navigate("/", { replace: true }); - } else { - setIsLoader(false); - alert(t("something-went-wrong-mssg")); - } - } - }; - - const handlePassowordChange = (e) => { - const newPassword = e.target.value; - setFormData({ ...formData, [e.target.name]: e.target.value }); - validatePasswords(newPassword, formData.confirmPassword); - - // Check conditions separately - setLengthValid(newPassword.length >= 8); - setCaseDigitValid( - /[a-z]/.test(newPassword) && - /[A-Z]/.test(newPassword) && - /\d/.test(newPassword) - ); - setSpecialCharValid(/[!@#$%^&*()\-_=+{};:,<.>]/.test(newPassword)); - }; - const handleConFirmPassowordChange = (e) => { - const newConfirmPassword = e.target.value; - setFormData({ ...formData, [e.target.name]: e.target.value }); - validatePasswords(formData.password, newConfirmPassword); - }; - const validatePasswords = (newPassword, newConfirmPassword) => { - if (newPassword === newConfirmPassword) { - setValidationMessage("Passwords match!"); - } else { - setValidationMessage("Passwords not match!"); - } - }; - - const handleNavigation = async (sessionToken) => { - const baseUrl = localStorage.getItem("baseUrl"); - const parseAppId = localStorage.getItem("parseAppId"); - const res = await axios.get(baseUrl + "users/me", { - headers: { - "X-Parse-Session-Token": sessionToken, - "X-Parse-Application-Id": parseAppId - } - }); - await Parse.User.become(sessionToken).then(() => { - window.localStorage.setItem("accesstoken", sessionToken); - }); - // console.log("me res ", res); - if (res.data) { - let _user = res.data; - localStorage.setItem("UserInformation", JSON.stringify(_user)); - localStorage.setItem("accesstoken", _user.sessionToken); - localStorage.setItem("scriptId", true); - if (_user.ProfilePic) { - localStorage.setItem("profileImg", _user.ProfilePic); - } else { - localStorage.setItem("profileImg", ""); - } - // Check extended class user role and tenentId - try { - const userSettings = appInfo.settings; - const extUser = await Parse.Cloud.run("getUserDetails"); - if (extUser) { - const IsDisabled = extUser?.get("IsDisabled") || false; - if (!IsDisabled) { - const userRole = extUser?.get("UserRole"); - const menu = - userRole && userSettings.find((menu) => menu.role === userRole); - if (menu) { - const _currentRole = userRole; - const _role = _currentRole.replace("contracts_", ""); - localStorage.setItem("_user_role", _role); - const extInfo_stringify = JSON.stringify([extUser]); - localStorage.setItem("Extand_Class", extInfo_stringify); - const extInfo = JSON.parse(JSON.stringify(extUser)); - localStorage.setItem("userEmail", extInfo?.Email); - localStorage.setItem("username", extInfo?.Name); - if (extInfo?.TenantId) { - const tenant = { - Id: extInfo?.TenantId?.objectId || "", - Name: extInfo?.TenantId?.TenantName || "" - }; - localStorage.setItem("TenantId", tenant?.Id); - dispatch(showTenant(tenant?.Name)); - localStorage.setItem("TenantName", tenant?.Name); - } - localStorage.setItem("PageLanding", menu.pageId); - localStorage.setItem("defaultmenuid", menu.menuId); - localStorage.setItem("pageType", menu.pageType); - setIsLoader(false); - alert(t("registered-user-successfully")); - const redirectUrl = - location?.state?.from || `/${menu.pageType}/${menu.pageId}`; - // Redirect to the appropriate URL after successful login - navigate(redirectUrl); - } - } else { - setIsLoader(false); - } - } - } catch (error) { - setIsLoader(false); - console.log("Err in fetch extuser", error); - } - } - }; - return ( - <div className="w-full h-screen"> - <Title title={"Pgsignup page"} /> - {isLoader ? ( - <div className="flex justify-center items-center h-[100vh]"> - <Loader /> - </div> - ) : ( - <div className="py-10 lg:p-16 flex justify-center"> - <form - id="signup" - className="w-[90%] md:w-[55%] bg-base-100 text-base-content op-card shadow-md" - onSubmit={handleSubmit} - > - <div className="p-[16px]"> - <h1 className="text-2xl md:text-3xl font-bold"> - {t("choose-password")} - </h1> - <hr className="border-[1px] border-[#cecece] mb-[5px]" /> - <label htmlFor="password"> - <b className="text-[13px]">{t("password")}</b> - </label> - <input - type="password" - placeholder={t("enter-password")} - name="password" - className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" - value={formData.password} - onChange={handlePassowordChange} - onInvalid={(e) => - e.target.setCustomValidity(t("input-required")) - } - onInput={(e) => e.target.setCustomValidity("")} - required - /> - <label htmlFor="confirmPassword"> - <b className="text-[13px]">{t("confirm-password")}</b> - </label> - <input - type="password" - placeholder={t("confirm-password")} - name="confirmPassword" - className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" - style={{ - border: validationMessage - ? validationMessage === "Passwords match!" - ? "1px solid green" - : "1px solid red" - : "" - }} - value={formData.confirmPassword} - onChange={handleConFirmPassowordChange} - onInvalid={(e) => - e.target.setCustomValidity(t("input-required")) - } - onInput={(e) => e.target.setCustomValidity("")} - required - /> - <div - className={`${ - validationMessage === "Passwords match!" - ? "text-[green]" - : "text-[red]" - } ml-[13px] text-[11px]`} - > - {validationMessage} - </div> - {formData.password.length > 0 && ( - <div className="mt-1 text-[11px]"> - <p - className={`${ - lengthValid ? "text-green-600" : "text-red-600" - }`} - > - {lengthValid ? "✓" : "✗"} {t("password-length")} - </p> - <p - className={`${ - caseDigitValid ? "text-green-600" : "text-red-600" - }`} - > - {caseDigitValid ? "✓" : "✗"} {t("password-case")} - </p> - <p - className={`${ - specialCharValid ? "text-green-600" : "text-red-600" - }`} - > - {specialCharValid ? "✓" : "✗"} {t("password-special-char")} - </p> - </div> - )} - <button - type="submit" - className="op-btn op-btn-primary w-full mt-[8px]" - > - {t("submit")} - </button> - </div> - </form> - </div> - )} - </div> - ); -}; - -export default PgSignUp; diff --git a/apps/OpenSign/src/pages/PlaceHolderSign.js b/apps/OpenSign/src/pages/PlaceHolderSign.js index 3018953cb..c31d3c2bb 100644 --- a/apps/OpenSign/src/pages/PlaceHolderSign.js +++ b/apps/OpenSign/src/pages/PlaceHolderSign.js @@ -3,18 +3,21 @@ import axios from "axios"; import Parse from "parse"; import "../styles/signature.css"; import { PDFDocument } from "pdf-lib"; -import { isEnableSubscription, themeColor } from "../constant/const"; +import { + themeColor +} from "../constant/const"; import { DndProvider } from "react-dnd"; import { HTML5Backend } from "react-dnd-html5-backend"; -import { useDrag, useDrop } from "react-dnd"; +import { useDrop } from "react-dnd"; import RenderAllPdfPage from "../components/pdf/RenderAllPdfPage"; import WidgetComponent from "../components/pdf/WidgetComponent"; import Tour from "reactour"; -import { useLocation, useParams } from "react-router-dom"; +import { useLocation, useParams } from "react-router"; import SignerListPlace from "../components/pdf/SignerListPlace"; import Header from "../components/pdf/PdfHeader"; import { RWebShare } from "react-web-share"; import { + replaceMailVaribles, pdfNewWidthFun, contractDocument, contractUsers, @@ -28,9 +31,7 @@ import { radioButtonWidget, color, getTenantDetails, - replaceMailVaribles, copytoData, - fetchSubscription, convertPdfArrayBuffer, getContainerScale, convertBase64ToFile, @@ -41,16 +42,16 @@ import { handleRotateWarning, signatureTypes, handleSignatureType, - formatDate + getBase64FromUrl, + generatePdfName } from "../constant/Utils"; import RenderPdf from "../components/pdf/RenderPdf"; -import { useNavigate } from "react-router-dom"; +import { useNavigate } from "react-router"; import PlaceholderCopy from "../components/pdf/PlaceholderCopy"; import Title from "../components/Title"; import DropdownWidgetOption from "../components/pdf/DropdownWidgetOption"; import WidgetNameModal from "../components/pdf/WidgetNameModal"; import { SaveFileSize } from "../constant/saveFileSize"; -import { EmailBody } from "../components/pdf/EmailBody"; import { useSelector } from "react-redux"; import PdfZoom from "../components/pdf/PdfZoom"; import { useTranslation } from "react-i18next"; @@ -61,16 +62,25 @@ import TourContentWithBtn from "../primitives/TourContentWithBtn"; import HandleError from "../primitives/HandleError"; import LoaderWithMsg from "../primitives/LoaderWithMsg"; import LinkUserModal from "../primitives/LinkUserModal"; -import QuotaCard from "../primitives/QuotaCard"; +import { EmailBody } from "../components/pdf/EmailBody"; import LottieWithLoader from "../primitives/DotLottieReact"; import Alert from "../primitives/Alert"; -import Upgrade from "../primitives/Upgrade"; +import AsyncSelect from "react-select/async"; +import AddContact from "../primitives/AddContact"; function PlaceHolderSign() { const { t } = useTranslation(); const editorRef = useRef(); - const navigate = useNavigate(); const { state } = useLocation(); + const navigate = useNavigate(); + const [defaultBody, setDefaultBody] = useState(""); + const [defaultSubject, setDefaultSubject] = useState(""); + const [requestSubject, setRequestSubject] = useState(""); + const [requestBody, setRequestBody] = useState(""); + const [tenantMailTemplate, setTenantMailTemplate] = useState({ + body: "", + subject: "" + }); const [pdfDetails, setPdfDetails] = useState([]); const [isMailSend, setIsMailSend] = useState(false); const [allPages, setAllPages] = useState(null); @@ -102,8 +112,6 @@ function PlaceHolderSign() { const [pdfOriginalWH, setPdfOriginalWH] = useState([]); const [containerWH, setContainerWH] = useState(); const { docId } = useParams(); - const signRef = useRef(null); - const dragRef = useRef(null); const divRef = useRef(null); const [isShowEmail, setIsShowEmail] = useState(false); const [selectedEmail, setSelectedEmail] = useState(false); @@ -112,8 +120,6 @@ function PlaceHolderSign() { const [signKey, setSignKey] = useState(); const [tempSignerId, setTempSignerId] = useState(""); const [blockColor, setBlockColor] = useState(""); - const [defaultBody, setDefaultBody] = useState(""); - const [defaultSubject, setDefaultSubject] = useState(""); const [isTextSetting, setIsTextSetting] = useState(false); const [pdfLoad, setPdfLoad] = useState(false); const [isPageCopy, setIsPageCopy] = useState(false); @@ -134,13 +140,9 @@ function PlaceHolderSign() { const [widgetName, setWidgetName] = useState(false); const [mailStatus, setMailStatus] = useState(""); const [isCurrUser, setIsCurrUser] = useState(false); - const [isSubscribe, setIsSubscribe] = useState(false); - const [requestSubject, setRequestSubject] = useState(""); - const [requestBody, setRequestBody] = useState(""); const [pdfArrayBuffer, setPdfArrayBuffer] = useState(""); const isHeader = useSelector((state) => state.showHeader); - const [activeMailAdapter, setActiveMailAdapter] = useState(""); - const [isRotate, setIsRotate] = useState({ + const [showRotateAlert, setShowRotateAlert] = useState({ status: false, degree: 0 }); @@ -152,27 +154,23 @@ function PlaceHolderSign() { const [isCustomize, setIsCustomize] = useState(false); const [zoomPercent, setZoomPercent] = useState(0); const [scale, setScale] = useState(1); - const [pdfRotateBase64, setPdfRotatese64] = useState(""); - const [planCode, setPlanCode] = useState(""); + const [pdfBase64Url, setPdfBase64Url] = useState(""); const [unSignedWidgetId, setUnSignedWidgetId] = useState(""); const [signatureType, setSignatureType] = useState(signatureTypes); - const [emailResetDate, setEmailResetDate] = useState(""); + const [isUploadPdf, setIsUploadPdf] = useState(false); + //'signersName' variable used to show all signer's name that do not have a signature widget assigned + const [signersName, setSignersName] = useState(""); + const [forms, setForms] = useState([]); + const [userList, setUserList] = useState([]); + const [isAttchSignerModal, setIsAttchSignerModal] = useState(false); + const [isNewContact, setIsNewContact] = useState({ status: false, id: "" }); const isMobile = window.innerWidth < 767; const [, drop] = useDrop({ accept: "BOX", drop: (item, monitor) => addPositionOfSignature(item, monitor), collect: (monitor) => ({ isOver: !!monitor.isOver() }) }); - const [{ isDragSign }, dragSignature] = useDrag({ - type: "BOX", - item: { type: "BOX", id: 1, text: "signature" }, - collect: (monitor) => ({ isDragSign: !!monitor.isDragging() }) - }); - const [{ isDragStamp }, dragStamp] = useDrag({ - type: "BOX", - item: { type: "BOX", id: 2, text: "stamp" }, - collect: (monitor) => ({ isDragStamp: !!monitor.isDragging() }) - }); + const documentId = docId; useEffect(() => { if (documentId) { @@ -207,6 +205,10 @@ function PlaceHolderSign() { if (tenantDetails?.RequestBody) { setRequestBody(tenantDetails?.RequestBody); setRequestSubject(tenantDetails?.RequestSubject); + setTenantMailTemplate({ + body: tenantDetails?.RequestBody, + subject: tenantDetails?.RequestSubject + }); } return filterSignTypes; } @@ -236,51 +238,51 @@ function PlaceHolderSign() { return () => clearTimeout(timer); // eslint-disable-next-line react-hooks/exhaustive-deps }, [divRef.current, isHeader]); - const handleNavigation = () => { - navigate("/subscription"); - }; - async function checkIsSubscribed() { - const res = await fetchSubscription(); - const plan = res.plan; - const billingDate = res.billingDate; - setPlanCode(plan); - if (plan === "freeplan") { - return true; - } else if (billingDate) { - if (new Date(billingDate) > new Date()) { - setIsSubscribe(true); - return true; - } else { - handleNavigation(plan); - } - } else { - handleNavigation(plan); - } - } //function for get document details const getDocumentDetails = async () => { const tenantSignTypes = await fetchTenantDetails(); //getting document details const documentData = await contractDocument(documentId); if (documentData && documentData.length > 0) { + if (documentData[0]?.Placeholders?.length > 0) { + const signerNotExist = documentData[0]?.Placeholders.some( + (data) => !data.signerObjId + ); + //condition to check any role does not attach signer + if (signerNotExist) { + let users = []; + documentData[0]?.Placeholders?.forEach((element) => { + let label = ""; + const signerData = documentData[0]?.Signers.find( + (x) => element.signerObjId && element.signerObjId === x.objectId + ); + if (signerData) { + label = `${signerData.Name}<${signerData.Email}>`; + } + users = [ + ...users, + { + value: element.Id, + label: label || "", + role: element.Role + } + ]; + }); + setIsAttchSignerModal(true); + setForms(users); + } + } const url = documentData[0] && documentData[0]?.URL; //convert document url in array buffer format to use embed widgets in pdf using pdf-lib const arrayBuffer = await convertPdfArrayBuffer(url); + const base64Pdf = await getBase64FromUrl(url); if (arrayBuffer === "Error") { setHandleError(t("something-went-wrong-mssg")); } else { setPdfArrayBuffer(arrayBuffer); - } - if (documentData[0]?.ExtUserPtr?.LastEmailCountReset?.iso) { - const resetDate = formatDate( - documentData[0]?.ExtUserPtr?.LastEmailCountReset?.iso - ); - setEmailResetDate(resetDate); + setPdfBase64Url(base64Pdf); } setExtUserId(documentData[0]?.ExtUserPtr?.objectId); - if (isEnableSubscription) { - checkIsSubscribed(documentData[0]?.ExtUserPtr?.Email); - } const alreadyPlaceholder = documentData[0]?.SignedUrl; // Check if document is sent for signing if (alreadyPlaceholder) { @@ -334,6 +336,12 @@ function PlaceHolderSign() { const updatedPdfDetails = [...documentData]; updatedPdfDetails[0].SignatureType = updatedSignatureType; setPdfDetails(updatedPdfDetails); + if (documentData?.[0]?.RequestBody && documentData?.[0]?.RequestSubject) { + setTenantMailTemplate({ + body: documentData?.[0]?.RequestBody, + subject: documentData?.[0]?.RequestSubject + }); + } //condition when placeholder have empty array with role details and signers array have signers data //and both array length are same //this case happen using placeholder form in auto save funtionality to save draft type document without adding any placehlder @@ -456,7 +464,6 @@ function PlaceHolderSign() { setHandleError(t("something-went-wrong-mssg")); setIsLoading({ isLoad: false }); } else if (res.length && res[0]?.objectId) { - setActiveMailAdapter(res[0]?.active_mail_adapter); setSignerUserId(res[0].objectId); const tourstatus = res[0].TourStatus && res[0].TourStatus; const alreadyPlaceholder = documentData[0]?.SignedUrl; @@ -851,26 +858,32 @@ function PlaceHolderSign() { isSignYourSelfFlow, scale ); - const pdfUrl = await convertBase64ToFile(pdfDetails[0].Name, pdfBase64); + const pdfName = generatePdfName(16); + const pdfUrl = await convertBase64ToFile( + pdfName, + pdfBase64, + "", + ); const tenantId = localStorage.getItem("TenantId"); const buffer = atob(pdfBase64); SaveFileSize(buffer.length, pdfUrl, tenantId); return pdfUrl; - } catch (e) { - console.log("error to convertBase64ToFile in placeholder flow", e); + } catch (err) { + console.log("error to convertBase64ToFile in placeholder flow", err); + alert(err?.message); } - } else if (pdfRotateBase64) { + } else if (pdfBase64Url) { try { + const pdfName = generatePdfName(16); const pdfUrl = await convertBase64ToFile( - pdfDetails[0].Name, - pdfRotateBase64 + pdfName, + pdfBase64Url, + "", ); - const tenantId = localStorage.getItem("TenantId"); - const buffer = atob(pdfRotateBase64); - SaveFileSize(buffer.length, pdfUrl, tenantId); return pdfUrl; - } catch (e) { - console.log("error to convertBase64ToFile in placeholder flow", e); + } catch (err) { + console.log("error to convertBase64ToFile in placeholder flow", err); + alert(err?.message); } } else { return pdfDetails[0].URL; @@ -879,6 +892,8 @@ function PlaceHolderSign() { const alertSendEmail = async () => { const filterPrefill = signerPos?.filter((data) => data.Role !== "prefill"); const getPrefill = signerPos?.find((data) => data.Role === "prefill"); + //unassigned signature widgets signer's list + let unassignedWidget = []; let isLabel = false; let unfilledTextWidgetId = ""; //checking all signers placeholder exist or not @@ -900,56 +915,60 @@ function PlaceHolderSign() { }); } } - let isSignatureExist = true; // variable is used to check a signature widget exit or not then execute other code - if (isPlaceholderExist) { - //for loop is used to check signature widget exist or not - for (let item of filterPrefill) { - let signatureExist = false; // Reset for each iteration + + //for loop is used to check signature widget exist or not + //if signature widget does not exist then show tour messages on signature widgets + //and show list of signers who need to add signature widget + for (let item of filterPrefill) { + let signatureExist = false; // Reset for each iteration + //condition if placeholder filed exist then check which signer do not have signature widget + if (item.placeHolder) { for (let x of item.placeHolder) { if (!signatureExist) { - const typeExist = x.pos.some((data) => data?.type); - if (typeExist) { - signatureExist = x.pos.some((data) => data?.type === "signature"); - } else { - signatureExist = x.pos.some((data) => !data.isStamp); - } + signatureExist = x.pos.some((data) => data?.type === "signature"); } } if (!signatureExist) { - isSignatureExist = false; - setIsSendAlert({ mssg: "sure", alert: true }); + unassignedWidget.push(item); } + } else { + //condition if placeholder filed does not exist then it means there are no any signature widget for any signer + unassignedWidget.push(item); } } + //checking if there are any signer list which do not have signture widget then show signers name on tour messages + if (unassignedWidget.length > 0) { + const getSigner = unassignedWidget.map((x) => { + return signersdata.find((y) => y.Id === x.Id).Name; + }); + const signersName = getSigner.join(", "); + setSignersName(signersName); + setIsSendAlert({ mssg: "sure", alert: true }); + } + if (getPrefill && isLabel) { setIsSendAlert({ mssg: textWidget, alert: true }); setUnSignedWidgetId(unfilledTextWidgetId); - } else if (isSignatureExist) { - if (isPlaceholderExist) { - const IsSignerNotExist = filterPrefill?.filter((x) => !x.signerObjId); - if (IsSignerNotExist && IsSignerNotExist?.length > 0) { - setSignerExistModal(true); - setSelectWidgetId( - IsSignerNotExist[0]?.placeHolder?.[0]?.pos?.[0]?.key - ); - } else { - saveDocumentDetails(); - } + } else if (isPlaceholderExist && unassignedWidget.length === 0) { + const IsSignerNotExist = filterPrefill?.filter((x) => !x.signerObjId); + if (IsSignerNotExist && IsSignerNotExist?.length > 0) { + setSignerExistModal(true); + setSelectWidgetId(IsSignerNotExist[0]?.placeHolder?.[0]?.pos?.[0]?.key); } else { - setIsSendAlert({ mssg: "sure", alert: true }); + saveDocumentDetails(); } } }; useEffect(() => { const timer = setTimeout(() => { - if (signerPos?.length > 0 && !pdfDetails?.[0]?.IsCompleted) { + if (!pdfDetails?.[0]?.IsCompleted) { autosavedetails(); } }, 2000); return () => clearTimeout(timer); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [signerPos, signersdata, signatureType]); + }, [signerPos, signersdata, signatureType, pdfBase64Url]); // `autosavedetails` is used to save doc details after every 2 sec when changes are happern in placeholder like drag-drop widgets, remove signers const autosavedetails = async () => { @@ -963,13 +982,30 @@ function PlaceHolderSign() { } return acc; }, []); + let pdfUrl; + if (isUploadPdf) { + const pdfName = generatePdfName(16); + pdfUrl = await convertBase64ToFile( + pdfName, + pdfBase64Url, + "", + ); + } try { const docCls = new Parse.Object("contracts_Document"); docCls.id = documentId; - docCls.set("Placeholders", signerPos); + if (signerPos?.length > 0) { + docCls.set("Placeholders", signerPos); + } docCls.set("Signers", signers); docCls.set("SignatureType", signatureType); - await docCls.save(); + if (pdfUrl) { + docCls.set("URL", pdfUrl); + } + const res = await docCls.save(); + if (res) { + pdfDetails[0] = { ...pdfDetails[0], URL: pdfUrl }; + } } catch (e) { console.log("error", e); alert(t("something-went-wrong-mssg")); @@ -983,69 +1019,76 @@ function PlaceHolderSign() { signerMail.splice(1); } const pdfUrl = await embedPrefilllData(); - const signers = signersdata?.map((x) => { - return { - __type: "Pointer", - className: "contracts_Contactbook", - objectId: x.objectId - }; - }); - const addExtraDays = pdfDetails[0]?.TimeToCompleteDays - ? pdfDetails[0].TimeToCompleteDays - : 15; - const currentUser = signersdata.find((x) => x.Email === currentId); - setCurrentId(currentUser?.objectId); - if (pdfDetails?.[0]?.SendinOrder && pdfDetails?.[0]?.SendinOrder === true) { - const currentUserMail = Parse.User.current()?.getEmail(); - const isCurrentUser = signerMail?.[0]?.Email === currentUserMail; - setIsCurrUser(isCurrentUser); - } else { - setIsCurrUser(currentUser?.objectId ? true : false); - } - let updateExpiryDate, data; - updateExpiryDate = new Date(); - updateExpiryDate.setDate(updateExpiryDate.getDate() + addExtraDays); - //filter label widgets after add label widgets data on pdf - const filterPrefill = signerPos.filter((data) => data.Role !== "prefill"); - try { - data = { - Placeholders: filterPrefill, - SignedUrl: pdfUrl, - Signers: signers, - SentToOthers: true, - SignatureType: pdfDetails?.[0]?.SignatureType - }; - if (updateExpiryDate) { - data["ExpiryDate"] = { iso: updateExpiryDate, __type: "Date" }; + if (pdfUrl) { + const signers = signersdata?.map((x) => { + return { + __type: "Pointer", + className: "contracts_Contactbook", + objectId: x.objectId + }; + }); + const addExtraDays = pdfDetails[0]?.TimeToCompleteDays + ? pdfDetails[0].TimeToCompleteDays + : 15; + const currentUser = signersdata.find((x) => x.Email === currentId); + setCurrentId(currentUser?.objectId); + if ( + pdfDetails?.[0]?.SendinOrder && + pdfDetails?.[0]?.SendinOrder === true + ) { + const currentUserMail = Parse.User.current()?.getEmail(); + const isCurrentUser = signerMail?.[0]?.Email === currentUserMail; + setIsCurrUser(isCurrentUser); + } else { + setIsCurrUser(currentUser?.objectId ? true : false); } - await axios - .put( - `${localStorage.getItem( - "baseUrl" - )}classes/contracts_Document/${documentId}`, - data, - { - headers: { - "Content-Type": "application/json", - "X-Parse-Application-Id": localStorage.getItem("parseAppId"), - "X-Parse-Session-Token": localStorage.getItem("accesstoken") + let updateExpiryDate, data; + updateExpiryDate = new Date(); + updateExpiryDate.setDate(updateExpiryDate.getDate() + addExtraDays); + //filter label widgets after add label widgets data on pdf + const filterPrefill = signerPos.filter((data) => data.Role !== "prefill"); + try { + data = { + Placeholders: filterPrefill, + SignedUrl: pdfUrl, + Signers: signers, + SentToOthers: true, + SignatureType: pdfDetails?.[0]?.SignatureType + }; + if (updateExpiryDate) { + data["ExpiryDate"] = { iso: updateExpiryDate, __type: "Date" }; + } + await axios + .put( + `${localStorage.getItem( + "baseUrl" + )}classes/contracts_Document/${documentId}`, + data, + { + headers: { + "Content-Type": "application/json", + "X-Parse-Application-Id": localStorage.getItem("parseAppId"), + "X-Parse-Session-Token": localStorage.getItem("accesstoken") + } } - } - ) - .then(() => { - setIsMailSend(true); - setIsLoading({ isLoad: false }); - setIsUiLoading(false); - setSignerPos([]); - setIsSendAlert({ mssg: "confirm", alert: true }); - }) - .catch((err) => { - console.log("axois err ", err); - alert(t("something-went-wrong-mssg")); - }); - } catch (e) { - console.log("error", e); - alert(t("something-went-wrong-mssg")); + ) + .then(() => { + setIsMailSend(true); + setIsLoading({ isLoad: false }); + setIsUiLoading(false); + setSignerPos([]); + setIsSendAlert({ mssg: "confirm", alert: true }); + }) + .catch((err) => { + console.log("axois err ", err); + alert(t("something-went-wrong-mssg")); + }); + } catch (e) { + console.log("error", e); + alert(t("something-went-wrong-mssg")); + } + } else { + setIsUiLoading(false); } }; @@ -1142,7 +1185,12 @@ function PlaceHolderSign() { const senderName = `${pdfDetails?.[0].ExtUserPtr.Name}`; const documentName = `${pdfDetails?.[0].Name}`; let replaceVar; - if (requestBody && requestSubject && isCustomize && isSubscribe) { + + if ( + requestBody && + requestSubject && + isCustomize + ) { const replacedRequestBody = requestBody.replace(/"/g, "'"); htmlReqBody = "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body>" + @@ -1151,10 +1199,12 @@ function PlaceHolderSign() { const variables = { document_title: documentName, - sender_name: senderName, - sender_mail: senderEmail, + sender_name: + senderName, + sender_mail: + senderEmail, sender_phone: senderPhone || "", - receiver_name: signerMail[i].Name, + receiver_name: signerMail[i]?.Name || "", receiver_email: signerMail[i].Email, receiver_phone: signerMail[i]?.Phone || "", expiry_date: localExpireDate, @@ -1166,40 +1216,67 @@ function PlaceHolderSign() { htmlReqBody, variables ); + } else if ( + tenantMailTemplate?.body && + tenantMailTemplate?.subject + ) { + const mailBody = tenantMailTemplate?.body; + const mailSubject = tenantMailTemplate?.subject; + const replacedRequestBody = mailBody.replace(/"/g, "'"); + const htmlReqBody = + "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body>" + + replacedRequestBody + + "</body> </html>"; + const variables = { + document_title: documentName, + sender_name: + senderName, + sender_mail: + senderEmail, + sender_phone: senderPhone || "", + receiver_name: signerMail[i]?.Name || "", + receiver_email: signerMail[i].Email, + receiver_phone: signerMail[i]?.Phone || "", + expiry_date: localExpireDate, + company_name: orgName, + signing_url: `<a href=${signPdf} target=_blank>Sign here</a>` + }; + replaceVar = replaceMailVaribles(mailSubject, htmlReqBody, variables); } - let params = { - mailProvider: activeMailAdapter, extUserId: extUserId, recipient: signerMail[i].Email, - subject: isCustomize + subject: replaceVar?.subject ? replaceVar?.subject : `${senderName} has requested you to sign "${documentName}"`, - from: senderEmail, - plan: planCode, - html: isCustomize + replyto: + senderEmail || + "", + from: + senderEmail, + html: replaceVar?.body ? replaceVar?.body - : "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /> </head> <body> <div style='background-color: #f5f5f5; padding: 20px'=> <div style=' box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background: white;padding-bottom: 20px;'> <div style='padding:10px 10px 0 10px'><img src=" + + : "<html><head><meta http-equiv='Content-Type' content='text/html;charset=UTF-8' /></head><body><div style='background-color:#f5f5f5; padding:20px;'><div style='box-shadow:rgba(0, 0, 0, 0.1) 0px 4px 12px;background:white;padding-bottom:20px;'><div style='padding:10px 10px 0 10px'><img src=" + imgPng + - " height='50' style='padding: 20px,width:170px,height:40px' /></div> <div style=' padding: 2px;font-family: system-ui;background-color:" + + " height='50' style='padding:20px,width:170px,height:40px' /></div><div style='padding:2px;font-family:system-ui;background-color:" + themeBGcolor + - ";'><p style='font-size: 20px;font-weight: 400;color: white;padding-left: 20px;' > Digital Signature Request</p></div><div><p style='padding: 20px;font-family: system-ui;font-size: 14px; margin-bottom: 10px;'> " + + ";'><p style='font-size:20px;font-weight:400;color:white;padding-left:20px;' > Digital Signature Request</p></div><div><p style='padding:20px;font-family:system-ui;font-size:14px;margin-bottom:10px;'> " + pdfDetails?.[0].ExtUserPtr.Name + " has requested you to review and sign <strong> " + pdfDetails?.[0].Name + - "</strong>.</p><div style='padding: 5px 0px 5px 25px;display: flex;flex-direction: row;justify-content: space-around;'><table> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Sender</td> <td> </td> <td style='color:#626363;font-weight:bold'>" + + "</strong>.</p><div style='padding: 5px 0px 5px 25px;display:flex;flex-direction:row;justify-content:space-around;'><table><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Sender</td><td></td><td style='color:#626363;font-weight:bold;'>" + senderEmail + - "</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'> " + + "</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Organization</td><td></td><td style='color:#626363;font-weight:bold'> " + orgName + - "</td></tr> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>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'>Expire on</td><td></td><td style='color:#626363;font-weight:bold'>" + localExpireDate + - "</td></tr><tr> <td></td> <td> </td></tr></table> </div> <div style='margin-left:70px'><a target=_blank href=" + + "</td></tr><tr><td></td><td></td></tr></table></div> <div style='margin-left:70px'><a target=_blank href=" + signPdf + - "> <button style='padding: 12px 12px 12px 12px;background-color: #d46b0f;color: white; border: 0px;box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px,rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;font-weight:bold;margin-top:30px'>Sign here</button></a> </div> <div style='display: flex; justify-content: center;margin-top: 10px;'> </div></div></div><div><p> This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender " + + "><button style='padding: 12px 12px 12px 12px;background-color:#d46b0f;color:white;border:0px;box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px,rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;font-weight:bold;margin-top:30px'>Sign here</button></a></div><div style='display: flex; justify-content: center;margin-top: 10px;'></div></div></div><div><p> This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender " + senderEmail + - " directly.If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href= " + + " directly.If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href= " + openSignUrl + - " target=_blank>here</a>.</p> </div></div></body> </html>" + " target=_blank>here</a>.</p></div></div></body></html>" }; sendMail = await axios.post(url, params, { headers: headers }); @@ -1211,12 +1288,25 @@ function PlaceHolderSign() { setMailStatus("success"); try { let data; - if (requestBody && requestSubject && isCustomize && isSubscribe) { + if ( + requestBody && + requestSubject && + isCustomize + ) { data = { RequestBody: htmlReqBody, RequestSubject: requestSubject, SendMail: true }; + } else if ( + tenantMailTemplate?.body && + tenantMailTemplate?.subject + ) { + data = { + RequestBody: tenantMailTemplate?.body, + RequestSubject: tenantMailTemplate?.subject, + SendMail: true + }; } else { data = { SendMail: true }; } @@ -1428,7 +1518,8 @@ function PlaceHolderSign() { fontColor: fontColor || currWidgetsDetails?.options?.fontColor || - "black" + "black", + ...(isReadOnly ? { isReadOnly: isReadOnly || false } : {}) } }; } @@ -1467,13 +1558,6 @@ function PlaceHolderSign() { setPdfDetails(updatedPdfDetails); setSignatureType(signtypes); } - const options = ["email", "number", "text"]; - let inputype; - if (defaultdata.textvalidate) { - inputype = options.includes(defaultdata.textvalidate) - ? defaultdata.textvalidate - : "regex"; - } const filterSignerPos = signerPos.filter((data) => data.Id === uniqueId); if (filterSignerPos.length > 0) { const getPlaceHolder = filterSignerPos[0].placeHolder; @@ -1497,19 +1581,14 @@ function PlaceHolderSign() { hint: defaultdata?.hint || "", defaultValue: defaultdata?.defaultValue || "", validation: - isSubscribe && inputype - ? { - type: inputype, - pattern: - inputype === "regex" ? defaultdata.textvalidate : "" - } - : {}, + {}, fontSize: fontSize || currWidgetsDetails?.options?.fontSize || 12, fontColor: fontColor || currWidgetsDetails?.options?.fontColor || - "black" + "black", + isReadOnly: defaultdata?.isReadOnly || false } }; } else { @@ -1607,43 +1686,61 @@ function PlaceHolderSign() { } }; const handleRecipientSign = () => { - navigate(`/recipientSignPdf/${documentId}/${currentId}`); + if (currentId) { + navigate(`/recipientSignPdf/${documentId}/${currentId}`); + } else { + navigate(`/recipientSignPdf/${documentId}`); + } }; const handleLinkUser = (id) => { setIsAddUser({ [id]: true }); }; - const handleAddUser = (data) => { - if (data && data.objectId) { - const signerPtr = { - __type: "Pointer", - className: "contracts_Contactbook", - objectId: data.objectId - }; - const updatePlaceHolder = signerPos.map((x) => { - if (x.Id === uniqueId) { - return { ...x, signerPtr: signerPtr, signerObjId: data.objectId }; - } - return { ...x }; - }); - setSignerPos(updatePlaceHolder); - const updateSigner = signersdata.map((x) => { - if (x.Id === uniqueId) { - return { ...x, ...data, className: "contracts_Contactbook" }; - } - return { ...x }; - }); - if (updateSigner && updateSigner.length > 0) { - const currEmail = pdfDetails[0].ExtUserPtr.Email; - const getCurrentUserDeatils = updateSigner.filter( - (x) => x.Email === currEmail - ); - if (getCurrentUserDeatils && getCurrentUserDeatils.length > 0) { - setCurrentId(getCurrentUserDeatils[0].Email); + //`handleAddUser` function to use add new user + const handleAddUser = (data, signerObjId) => { + const id = signerObjId ? signerObjId : isNewContact?.id || uniqueId; + if (isAddSigner) { + handleAddNewRecipients(data); + } else { + if (data && data.objectId) { + const signerPtr = { + __type: "Pointer", + className: "contracts_Contactbook", + objectId: data.objectId + }; + const updatePlaceHolder = signerPos.map((x) => { + if (x.Id === id) { + return { ...x, signerPtr: signerPtr, signerObjId: data.objectId }; + } + return { ...x }; + }); + setSignerPos(updatePlaceHolder); + const updateSigner = signersdata.map((x) => { + if (x.Id === id) { + return { ...x, ...data, className: "contracts_Contactbook" }; + } + return { ...x }; + }); + if (updateSigner && updateSigner.length > 0) { + const currEmail = pdfDetails[0].ExtUserPtr.Email; + const getCurrentUserDeatils = updateSigner.filter( + (x) => x.Email === currEmail + ); + if (getCurrentUserDeatils && getCurrentUserDeatils.length > 0) { + setCurrentId(getCurrentUserDeatils[0].Email); + } } + setSignersData(updateSigner); + const index = signersdata.findIndex((x) => x.Id === id); + setIsSelectId(index); + } + if (isNewContact.status) { + let newForm = [...forms]; + const label = `${data.Name}<${data.Email}>`; + const index = newForm.findIndex((x) => x.value === id); + newForm[index].label = label; + newForm[index].value = data?.objectId; + setForms(newForm); } - setSignersData(updateSigner); - const index = signersdata.findIndex((x) => x.Id === uniqueId); - setIsSelectId(index); } }; //function to add new signer in document signers list @@ -1669,12 +1766,13 @@ function PlaceHolderSign() { setSignerPos((prev) => [...prev, signerPosObj]); setUniqueId(newId); setIsSelectId(signersdata.length - 1); - setBlockColor(color[signersdata.length]); + setBlockColor(color[signersdata.length - 1]); }; const closePopup = () => { setIsAddUser({}); setIsAddSigner(false); + setIsNewContact({ status: false, id: "" }); }; //function for handle ontext change and save again text in delta in Request Email flow @@ -1701,6 +1799,14 @@ function PlaceHolderSign() { style: { fontSize: "13px" } } ]; + const signatureWidgetTour = [ + { + selector: '[data-tut="isSignatureWidget"]', + content: t("signature-field-widget", { signersName }), + position: "top", + style: { fontSize: "13px" } + } + ]; // `handleDeleteUser` function is used to delete record and placeholder when user click on delete which is place next user name in recipients list const handleDeleteUser = (Id) => { @@ -1741,30 +1847,98 @@ function PlaceHolderSign() { }; //`handleRotationFun` function is used to roatate pdf particular page const handleRotationFun = async (rotateDegree) => { - const isRotate = handleRotateWarning(signerPos, pageNumber); - if (isRotate) { - setIsRotate({ status: true, degree: rotateDegree }); + const rotatePlaceholderExist = handleRotateWarning(signerPos, pageNumber); + //show rotation alert if widgets already exist + if (rotatePlaceholderExist) { + setShowRotateAlert({ status: true, degree: rotateDegree }); } else { + setIsUploadPdf(true); const urlDetails = await rotatePdfPage( - pdfDetails[0].URL, rotateDegree, pageNumber - 1, - pdfRotateBase64 + pdfArrayBuffer ); - setPdfArrayBuffer && setPdfArrayBuffer(urlDetails.arrayBuffer); - setPdfRotatese64(urlDetails.base64); + setPdfArrayBuffer(urlDetails.arrayBuffer); + setPdfBase64Url(urlDetails.base64); } }; const handleRemovePlaceholder = async () => { - handleRemoveWidgets(setSignerPos, signerPos, pageNumber, setIsRotate); - const urlDetails = await rotatePdfPage( - pdfDetails[0].URL, - isRotate.degree, - pageNumber - 1, - pdfRotateBase64 + handleRemoveWidgets( + setSignerPos, + signerPos, + pageNumber, + setShowRotateAlert ); - setPdfArrayBuffer && setPdfArrayBuffer(urlDetails.arrayBuffer); - setPdfRotatese64(urlDetails.base64); + const urlDetails = await rotatePdfPage( + showRotateAlert.degree, + pageNumber - 1, + pdfArrayBuffer + ); + setPdfArrayBuffer(urlDetails.arrayBuffer); + setPdfBase64Url(urlDetails.base64); + }; + const handleSendDoc = () => { + setIsAttchSignerModal(false); + setCheckTourStatus(true); + alertSendEmail(); + }; + + //show modal to create new contact + const handleCreateNew = (e, id) => { + e.preventDefault(); + setIsNewContact({ status: true, id: id }); + }; + //`handleInputChange` function to get signers list from dropdown + const handleInputChange = (item, id) => { + const signerExist = forms.some((x) => x.value === item.value); + if (signerExist) { + alert(t("already-exist-signer")); + } else { + let newForm = [...forms]; + let signerId = newForm[id].value; + newForm[id].label = item?.label; + newForm[id].value = item?.value; + setForms(newForm); + const getSigner = userList.find((x) => x.objectId === item.value); + handleAddUser(getSigner, signerId); + } + }; + + //`loadOptions` function to use show all list of signer in dropdown + const loadOptions = async (inputValue) => { + try { + const baseURL = localStorage.getItem("baseUrl"); + const url = `${baseURL}functions/getsigners`; + const token = { + "X-Parse-Session-Token": localStorage.getItem("accesstoken") + }; + const headers = { + "Content-Type": "application/json", + "X-Parse-Application-Id": localStorage.getItem("parseAppId"), + ...token + }; + const search = inputValue; + const axiosRes = await axios.post(url, { search }, { headers }); + const contactRes = axiosRes?.data?.result || []; + if (contactRes) { + const res = JSON.parse(JSON.stringify(contactRes)); + const result = res; + setUserList(result); + return await result.map((item) => ({ + label: `${item.Name}<${item.Email}>`, + value: item.objectId + })); + } + } catch (error) { + console.log("err", error); + } + }; + const handleDisable = () => { + const isAllSigner = signerPos.some((x) => !x.signerObjId); + return isAllSigner; + }; + const handleCloseAttachSigner = () => { + setIsAttchSignerModal(false); }; return ( <> @@ -1786,7 +1960,7 @@ function PlaceHolderSign() { )} <div className="relative op-card overflow-hidden flex flex-col md:flex-row justify-between bg-base-300"> {/* this component used for UI interaction and show their functionality */} - {!checkTourStatus && ( + {!checkTourStatus && !isAttchSignerModal && ( //this tour component used in your html component where you want to put //onRequestClose function to close tour //steps is defined what will be your messages and style also @@ -1813,15 +1987,27 @@ function PlaceHolderSign() { rounded={5} closeWithMask={false} /> + <Tour + onRequestClose={() => handleCloseSendmailModal()} + steps={signatureWidgetTour} + isOpen={isSendAlert.mssg === "sure" && true} + rounded={5} + closeWithMask={false} + /> {/* this component used to render all pdf pages in left side */} <RenderAllPdfPage - signPdfUrl={pdfDetails[0].URL} allPages={allPages} setAllPages={setAllPages} setPageNumber={setPageNumber} setSignBtnPosition={setSignBtnPosition} pageNumber={pageNumber} - pdfRotateBase64={pdfRotateBase64} + pdfBase64Url={pdfBase64Url} + signedUrl={pdfDetails?.[0]?.SignedUrl || ""} + setPdfArrayBuffer={setPdfArrayBuffer} + setPdfBase64Url={setPdfBase64Url} + setIsUploadPdf={setIsUploadPdf} + pdfArrayBuffer={pdfArrayBuffer} + isMergePdfBtn={true} /> {/* pdf render view */} <div className=" w-full md:w-[57%] flex mr-4"> @@ -1829,84 +2015,88 @@ function PlaceHolderSign() { clickOnZoomIn={clickOnZoomIn} clickOnZoomOut={clickOnZoomOut} handleRotationFun={handleRotationFun} + pdfArrayBuffer={pdfArrayBuffer} + pageNumber={pageNumber} + setPdfBase64Url={setPdfBase64Url} + setPdfArrayBuffer={setPdfArrayBuffer} + setIsUploadPdf={setIsUploadPdf} + setSignerPos={setSignerPos} + signerPos={signerPos} + userId={uniqueId} + allPages={allPages} + setAllPages={setAllPages} + setPageNumber={setPageNumber} /> <div className=" w-full md:w-[95%] "> {/* this modal is used show alert set placeholder for all signers before send mail */} <ModalUi isOpen={ - isSendAlert.alert && isSendAlert.mssg !== textWidget - } - title={ - isSendAlert.mssg === "sure" || - (isSendAlert.mssg === "confirm" && t("send-mail")) + isSendAlert.alert && + isSendAlert.mssg !== textWidget && + isSendAlert.mssg === "confirm" } + title={isSendAlert.mssg === "confirm" && t("send-mail")} handleClose={() => handleCloseSendmailModal()} > <div className="max-h-96 overflow-y-scroll scroll-hide p-[20px] text-base-content"> - {isSendAlert.mssg === "sure" ? ( - <span>{t("placeholder-alert-1")}</span> - ) : ( - isSendAlert.mssg === "confirm" && ( - <> - {!isCustomize && ( - <span>{t("placeholder-alert-3")}</span> - )} - {isCustomize && isSubscribe && ( - <> - <EmailBody - editorRef={editorRef} - requestBody={requestBody} - requestSubject={requestSubject} - handleOnchangeRequest={handleOnchangeRequest} - setRequestSubject={setRequestSubject} - /> - <div - className="flex justify-end items-center gap-1 mt-2 op-link op-link-primary" - onClick={() => { - setRequestBody(defaultBody); - setRequestSubject(defaultSubject); - }} - > - <span>{t("reset-to-default")}</span> - </div> - </> - )} - <div className="flex flex-row md:items-center gap-2 md:gap-6 mt-2"> - <div className="flex flex-row gap-2"> - <button - onClick={() => sendEmailToSigners()} - className="op-btn op-btn-primary font-[500] text-sm shadow" - > - {t("send")} - </button> - {isCustomize && ( - <button - onClick={() => setIsCustomize(false)} - className="op-btn op-btn-ghost font-[500] text-sm" - > - {t("close")} - </button> - )} - </div> - {!isCustomize && isSubscribe && ( - <span - className="op-link op-link-accent text-sm" - onClick={() => setIsCustomize(!isCustomize)} - > - {t("cutomize-email")} - </span> - )} - {!isSubscribe && isEnableSubscription && ( - <div className="mt-2"> - <Upgrade - message={t("upgrade-to-customize-email")} - newWindow={true} + {isSendAlert.mssg === "confirm" && ( + <> + {!isCustomize && ( + <span>{t("placeholder-alert-3")}</span> + )} + { + isCustomize && ( + <> + <EmailBody + editorRef={editorRef} + requestBody={requestBody} + requestSubject={requestSubject} + handleOnchangeRequest={ + handleOnchangeRequest + } + setRequestSubject={setRequestSubject} /> - </div> + <div + className="flex justify-end items-center gap-1 mt-2 op-link op-link-primary" + onClick={() => { + setRequestBody(defaultBody); + setRequestSubject(defaultSubject); + }} + > + <span>{t("reset-to-default")}</span> + </div> + </> + ) + } + <div className="flex flex-row items-center gap-2 md:gap-6 mt-2"> + <div className="flex flex-row gap-2"> + <button + onClick={() => sendEmailToSigners()} + className="op-btn op-btn-primary font-[500] text-sm shadow" + > + {t("send")} + </button> + {isCustomize && ( + <button + onClick={() => setIsCustomize(false)} + className="op-btn op-btn-ghost font-[500] text-sm" + > + {t("close")} + </button> )} </div> - </> - ) + { + !isCustomize && ( + <span + className="op-link op-link-accent text-sm" + onClick={() => setIsCustomize(!isCustomize)} + > + {t("cutomize-email")} + </span> + ) + } + </div> + </> )} {isSendAlert.mssg === "confirm" && ( <> @@ -1920,7 +2110,6 @@ function PlaceHolderSign() { )} </div> </ModalUi> - {/* this modal is used show send mail message and after send mail success message */} <ModalUi isOpen={isSend} @@ -1941,19 +2130,19 @@ function PlaceHolderSign() { {mailStatus === "success" ? ( <div className="text-center mb-[10px]"> <LottieWithLoader /> - <p>{t("placeholder-alert-4")}</p> + {pdfDetails[0].SendinOrder ? ( + <p> + {t("placeholder-mail-alert", { + name: pdfDetails[0]?.Signers[0]?.Name + })} + </p> + ) : ( + <p>{t("placeholder-alert-4")}</p> + )} {isCurrUser && <p>{t("placeholder-alert-5")}</p>} </div> ) : mailStatus === "quotareached" ? ( <div className="flex flex-col gap-y-3"> - <QuotaCard - emailResetDate={emailResetDate} - handleClose={() => { - setIsSend(false); - setSignerPos([]); - navigate("/report/1MwEuxLEkF"); - }} - /> <div className="my-3">{handleShareList()}</div> </div> ) : ( @@ -2016,11 +2205,117 @@ function PlaceHolderSign() { </button> </div> </ModalUi> + <ModalUi + isOpen={isAttchSignerModal} + title={t("add-signer")} + handleClose={() => handleCloseAttachSigner()} + > + <div className="h-[100%] p-[20px]"> + {pdfDetails[0].Placeholders?.some( + (x) => !x.signerObjId + ) && ( + <> + {/* grid grid-cols-1 md:grid-cols-2 */} + <div className="min-h-max max-h-[250px] overflow-y-auto"> + <div className="p-3 op-card border-[1px] border-gray-400 mt-3 mx-4 mb-4 bg-base-200 text-base-content flex flex-col gap-2 relative"> + {forms?.map((field, id) => { + return ( + <div + className="flex flex-col" + key={field?.value} + > + <label>{field?.role}</label> + <div className="flex justify-between items-center gap-2"> + <div className="flex-1"> + <AsyncSelect + cacheOptions + defaultOptions + value={field} + loadingMessage={() => t("loading")} + noOptionsMessage={() => + t("contact-not-found") + } + loadOptions={loadOptions} + onChange={(item) => + handleInputChange(item, id) + } + unstyled + onFocus={() => loadOptions()} + classNames={{ + control: () => + "op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full h-full text-[11px]", + valueContainer: () => + "flex flex-row gap-x-[2px] gap-y-[2px] md:gap-y-0 w-full my-[2px]", + multiValue: () => + "op-badge op-badge-primary h-full text-[11px]", + multiValueLabel: () => "mb-[2px]", + menu: () => + "mt-1 shadow-md rounded-lg bg-base-200 text-base-content absolute z-9999", + menuList: () => + "shadow-md rounded-lg ", + option: () => + "bg-base-200 text-base-content rounded-lg m-1 hover:bg-base-300 p-2 ", + noOptionsMessage: () => + "p-2 bg-base-200 rounded-lg m-1 p-2" + }} + menuPortalTarget={document.getElementById( + "selectSignerModal" + )} + /> + </div> + <button + onClick={(e) => + handleCreateNew(e, field.value) + } + className="op-btn op-btn-accent op-btn-outline op-btn-sm " + > + <i className="fa-light fa-plus"></i> + </button> + </div> + </div> + ); + })} + </div> + </div> + <div className="w-full h-[1px] bg-[#9f9f9f] my-[15px]"></div> + <div className="flex mx-4 mb-4 gap-3"> + <button + disabled={handleDisable()} + onClick={() => handleSendDoc()} + type="submit" + className="op-btn op-btn-primary focus:outline-none" + > + <i className="fa-light fa-paper-plane"></i>{" "} + <span>{t("next")}</span> + </button> + <button + onClick={() => handleCloseAttachSigner()} + type="submit" + className="op-btn op-btn-secondary focus:outline-none" + > + <i className="fa-regular fa-pen-to-square"></i> + <span>{t("edit")}</span> + </button> + </div> + </> + )} + </div> + </ModalUi> + <ModalUi + title={""} + isOpen={isNewContact.status} + handleClose={closePopup} + > + <AddContact + details={handleAddUser} + closePopup={closePopup} + /> + </ModalUi> <PlaceholderCopy isPageCopy={isPageCopy} setIsPageCopy={setIsPageCopy} - xyPostion={signerPos} - setXyPostion={setSignerPos} + xyPosition={signerPos} + setXyPosition={setSignerPos} allPages={allPages} pageNumber={pageNumber} signKey={signKey} @@ -2039,11 +2334,11 @@ function PlaceHolderSign() { currWidgetsDetails={currWidgetsDetails} setCurrWidgetsDetails={setCurrWidgetsDetails} handleClose={handleNameModal} - isSubscribe={isSubscribe} fontSize={fontSize} setFontSize={setFontSize} fontColor={fontColor} setFontColor={setFontColor} + isShowAdvanceFeature={true} /> <DropdownWidgetOption type="checkbox" @@ -2054,11 +2349,11 @@ function PlaceHolderSign() { currWidgetsDetails={currWidgetsDetails} setCurrWidgetsDetails={setCurrWidgetsDetails} handleClose={handleNameModal} - isSubscribe={isSubscribe} fontSize={fontSize} setFontSize={setFontSize} fontColor={fontColor} setFontColor={setFontColor} + isShowAdvanceFeature={true} /> <DropdownWidgetOption type="dropdown" @@ -2069,11 +2364,11 @@ function PlaceHolderSign() { currWidgetsDetails={currWidgetsDetails} setCurrWidgetsDetails={setCurrWidgetsDetails} handleClose={handleNameModal} - isSubscribe={isSubscribe} fontSize={fontSize} setFontSize={setFontSize} fontColor={fontColor} setFontColor={setFontColor} + isShowAdvanceFeature={true} /> {/* pdf header which contain funish back button */} @@ -2093,6 +2388,13 @@ function PlaceHolderSign() { handleRotationFun={handleRotationFun} clickOnZoomIn={clickOnZoomIn} clickOnZoomOut={clickOnZoomOut} + setIsUploadPdf={setIsUploadPdf} + pdfArrayBuffer={pdfArrayBuffer} + setPdfArrayBuffer={setPdfArrayBuffer} + setPdfBase64Url={setPdfBase64Url} + setSignerPos={setSignerPos} + userId={uniqueId} + pdfBase64={pdfBase64Url} /> <div @@ -2141,12 +2443,13 @@ function PlaceHolderSign() { setScale={setScale} scale={scale} setIsSelectId={setIsSelectId} - pdfRotateBase64={pdfRotateBase64} + pdfBase64Url={pdfBase64Url} fontSize={fontSize} setFontSize={setFontSize} fontColor={fontColor} setFontColor={setFontColor} unSignedWidgetId={unSignedWidgetId} + divRef={divRef} /> )} </div> @@ -2160,14 +2463,8 @@ function PlaceHolderSign() { <div> <WidgetComponent pdfUrl={isMailSend} - dragSignature={dragSignature} - signRef={signRef} handleDivClick={handleDivClick} handleMouseLeave={handleMouseLeave} - isDragSign={isDragSign} - dragStamp={dragStamp} - dragRef={dragRef} - isDragStamp={isDragStamp} isSignYourself={false} addPositionOfSignature={addPositionOfSignature} signerPos={signerPos} @@ -2189,6 +2486,8 @@ function PlaceHolderSign() { setIsAddSigner={setIsAddSigner} handleDeleteUser={handleDeleteUser} uniqueId={uniqueId} + setSignerPos={setSignerPos} + setSelectWidgetId={setSelectWidgetId} /> </div> ) : ( @@ -2219,14 +2518,8 @@ function PlaceHolderSign() { <div data-tut="addWidgets"> <WidgetComponent isMailSend={isMailSend} - dragSignature={dragSignature} - signRef={signRef} handleDivClick={handleDivClick} handleMouseLeave={handleMouseLeave} - isDragSign={isDragSign} - dragStamp={dragStamp} - dragRef={dragRef} - isDragStamp={isDragStamp} isSignYourself={false} addPositionOfSignature={addPositionOfSignature} initial={true} @@ -2257,19 +2550,15 @@ function PlaceHolderSign() { </button> </div> </ModalUi> - <LinkUserModal - handleAddUser={handleAddUser} - isAddUser={isAddUser} - uniqueId={uniqueId} - closePopup={closePopup} - signersData={signersdata} - /> - <LinkUserModal - handleAddUser={handleAddNewRecipients} - isAddSigner={isAddSigner} - closePopup={closePopup} - signersData={signersdata} - /> + {(isAddSigner || (isAddUser && isAddUser[uniqueId])) && ( + <LinkUserModal + handleAddUser={handleAddUser} + uniqueId={uniqueId} + closePopup={closePopup} + signersData={signersdata} + signerPos={signerPos} + /> + )} <WidgetNameModal signatureType={signatureType} widgetName={widgetName} @@ -2277,7 +2566,6 @@ function PlaceHolderSign() { isOpen={isNameModal} handleClose={handleNameModal} handleData={handleWidgetdefaultdata} - isSubscribe={isSubscribe} isTextSetting={isTextSetting} setIsTextSetting={setIsTextSetting} fontSize={fontSize} @@ -2286,8 +2574,8 @@ function PlaceHolderSign() { setFontColor={setFontColor} /> <RotateAlert - isRotate={isRotate.status} - setIsRotate={setIsRotate} + showRotateAlert={showRotateAlert.status} + setShowRotateAlert={setShowRotateAlert} handleRemoveWidgets={handleRemovePlaceholder} /> </DndProvider> diff --git a/apps/OpenSign/src/pages/PlanSubscriptions.js b/apps/OpenSign/src/pages/PlanSubscriptions.js deleted file mode 100644 index 96d283ccb..000000000 --- a/apps/OpenSign/src/pages/PlanSubscriptions.js +++ /dev/null @@ -1,314 +0,0 @@ -import React, { useState, useEffect } from "react"; -import { useNavigate } from "react-router-dom"; -import checkmark from "../assets/images/checkmark.png"; -import plansArr from "../json/plansArr"; -import Title from "../components/Title"; -import Parse from "parse"; -import { openInNewTab, saveLanguageInLocal } from "../constant/Utils"; -import Loader from "../primitives/Loader"; -import { useTranslation } from "react-i18next"; -const listItemStyle = { - paddingLeft: "20px", // Add padding to create space for the image - backgroundImage: `url(${checkmark})`, // Set your image as the list style image - backgroundPosition: "left", - backgroundRepeat: "no-repeat", - backgroundSize: "16px 16px" // Adjust the size of the image -}; - -const PlanSubscriptions = () => { - const { t, i18n } = useTranslation(); - const navigate = useNavigate(); - const [yearlyVisible, setYearlyVisible] = useState(true); - const [isLoader, setIsLoader] = useState(true); - const extUser = - localStorage.getItem("Extand_Class") && - JSON.parse(localStorage.getItem("Extand_Class"))?.[0]; - const user = { - name: extUser?.Name, - email: extUser?.Email, - company: extUser?.Company, - phone: extUser?.Phone - }; - const userDetails = JSON.parse(localStorage.getItem("userDetails")) || user; - // console.log("userDetails ", userDetails); - const fullname = - userDetails && userDetails.name ? userDetails.name.split(" ") : ""; - const firstname = fullname?.[0] - ? "first_name=" + encodeURIComponent(fullname?.[0]) - : ""; - const lastname = fullname?.[1] - ? "&last_name=" + encodeURIComponent(fullname?.[1]) - : ""; - const name = firstname ? firstname + lastname : ""; - const email = - userDetails && userDetails.email - ? "&email=" + encodeURIComponent(userDetails.email) - : ""; - const company = - userDetails && userDetails.company - ? "&company_name=" + encodeURIComponent(userDetails.company) - : ""; - const phone = - userDetails && userDetails.phone - ? "&mobile=" + encodeURIComponent(userDetails.phone) - : ""; - - useEffect(() => { - setIsLoader(false); - detectLanguage(); - // eslint-disable-next-line - }, []); - const detectLanguage = () => { - const detectedLanguage = i18n.language || "en"; - i18n.changeLanguage(detectedLanguage); - localStorage.setItem("i18nextLng", detectedLanguage); - }; - - const handleFreePlan = async (item) => { - if (item.url) { - const code = yearlyVisible ? item.code.yearly : item.code.monthly; - const allowedUsers = - localStorage.getItem("allowedUsers") && - localStorage.getItem("allowedUsers") > 0 - ? localStorage.getItem("allowedUsers") - 1 - : ""; - const teamperiod = { - "team-weekly": "monthly", - "team-yearly": "yearly", - "teams-monthly": "monthly", - "teams-yearly": "yearly" - }; - const period = teamperiod[code] || ""; - - const quantity = - allowedUsers && period - ? `addon_code%5B0%5D=extra-teams-users-${period}&addon_quantity%5B0%5D=${allowedUsers}&` - : ""; - - const details = - "?shipping_country_code=US&billing_country_code=US&billing_state_code=CA&" + - quantity + - name + - email + - company + - phone; - const url = yearlyVisible ? item.yearlyUrl + details : item.url + details; - if (user) { - localStorage.setItem("userDetails", JSON.stringify(user)); - } - openInNewTab(url, item?.target); - } else { - setIsLoader(true); - try { - const params = { userId: Parse.User.current().id }; - const res = await Parse.Cloud.run("freesubscription", params); - if (res.status === "success" && res.result === "already subscribed!") { - setIsLoader(false); - alert(t("subscribed-alert")); - } else if (res.status === "success") { - setIsLoader(false); - navigate("/"); - } else if (res.status === "error") { - setIsLoader(false); - alert(res.result); - } - } catch (err) { - setIsLoader(false); - console.log("err in free subscribe", err.message); - alert(t("something-went-wrong-mssg")); - } - } - }; - const handleLogout = async () => { - try { - await Parse?.User?.logOut(); - } catch (err) { - console.log("Err while logging out", err); - } - let appdata = localStorage.getItem("userSettings"); - let applogo = localStorage.getItem("appLogo"); - let defaultmenuid = localStorage.getItem("defaultmenuid"); - let PageLanding = localStorage.getItem("PageLanding"); - let baseUrl = localStorage.getItem("baseUrl"); - let appid = localStorage.getItem("parseAppId"); - - localStorage.clear(); - saveLanguageInLocal(i18n); - localStorage.setItem("appLogo", applogo); - localStorage.setItem("defaultmenuid", defaultmenuid); - localStorage.setItem("PageLanding", PageLanding); - localStorage.setItem("userSettings", appdata); - localStorage.setItem("baseUrl", baseUrl); - localStorage.setItem("parseAppId", appid); - - navigate("/"); - }; - return ( - <> - <Title title={"Subscriptions"} /> - {isLoader ? ( - <div className="flex items-center justify-center h-screen"> - <Loader /> - </div> - ) : ( - <div className="overflow-y-auto max-h-full"> - <div className="block my-2"> - <div className="flex flex-col justify-center items-center w-full relative"> - <button - className="md:hidden op-btn op-btn-primary op-btn-sm h-[40px] w-[250px] shadow-lg" - onClick={() => handleLogout()} - > - Log out - </button> - <div - role="tablist" - className="op-tabs op-tabs-boxed bg-base-100 my-2 shadow-lg transition-all" - > - <a - onClick={() => setYearlyVisible(false)} - role="tab" - className={`${!yearlyVisible ? "op-tab-active" : ""} op-tab`} - > - {t("monthly")} - </a> - <a - onClick={() => setYearlyVisible(true)} - role="tab" - className={`${yearlyVisible ? "op-tab-active" : ""} op-tab`} - > - {t("yearly-upto")} - </a> - </div> - <ul className="op-card flex flex-col md:flex-row h-full bg-base-100 justify-center shadow-lg"> - <button - className="hidden md:block -top-12 right-1 absolute w-[150px] h-[40px] op-btn op-btn-primary op-btn-sm shadow-lg" - onClick={() => handleLogout()} - > - {t("log-out")} - </button> - {plansArr.map((item) => ( - <li - className="flex flex-col text-center border-collapse border-[1px] border-gray-300 max-w-[250px]" - key={item.planName} - > - <div className="p-2 flex flex-col justify-center items-center max-h-[310px]"> - <h3 className="text-[#002862] uppercase"> - {item.planName} - </h3> - <div className="w-[120px] h-[120px] overflow-hidden"> - <img - className="w-full h-full object-contain" - src={require(`../assets/images/${item?.img}`)} - alt="img" - /> - </div> - <div> - <span className="text-3xl"> - {item.currency && <small>{item.currency}</small>} - {yearlyVisible ? ( - <> - {item?.yearlyPrice.includes("<") ? ( - <div - className="inline-block" - dangerouslySetInnerHTML={{ - __html: item?.yearlyPrice - }} - /> - ) : ( - <span>{item?.yearlyPrice}</span> - )} - </> - ) : ( - <> - {item?.monthlyPrice.includes("<") ? ( - <div - className="inline-block" - dangerouslySetInnerHTML={{ - __html: item?.monthlyPrice - }} - /> - ) : ( - <span>{item?.monthlyPrice}</span> - )} - </> - )} - </span> - <p className="font-semibold pt-2 text-sm"> - {yearlyVisible - ? t("billed-yearly") - : t("billed-monthly")} - </p> - <div className="max-w-[250px] h-[40px] text-center text-sm my-2"> - <div - style={{ - textAlign: "center", - backgroundColor: item.subtitlecolor - ? item.subtitlecolor - : "white" - }} - > - {item.subtitle.includes("<") ? ( - <div - dangerouslySetInnerHTML={{ - __html: item.subtitle - }} - /> - ) : ( - <span>{item.subtitle}</span> - )} - </div> - </div> - </div> - <button - className={`${ - item?.btn?.color ? item?.btn?.color : "op-btn-primary" - } w-full text-white py-2 op-btn uppercase hover:text-white cursor-pointer`} - onClick={() => handleFreePlan(item)} - > - {item?.btn?.text} - </button> - </div> - <hr className="w-full bg-gray-300 h-[0.5px]" /> - <ul className="mx-1 p-3 text-left break-words text-sm list-none"> - {!yearlyVisible && - item.benefits.map((subitem, index) => ( - <li style={listItemStyle} key={index} className="m-1"> - <span className="relative">{subitem}</span> - </li> - ))} - {yearlyVisible && - item?.yearlyBenefits?.map((subitem, index) => ( - <li style={listItemStyle} key={index} className="m-1"> - <span className="relative">{subitem}</span> - </li> - ))} - </ul> - </li> - ))} - </ul> - </div> - <div className="text-sm flex justify-center items-center mt-3 mb-2"> - <hr className="border-[2px] border-gray-350 w-[20%]" /> - <span className="px-2 text-base-content cursor-default">or</span> - <hr className="border-[2px] border-gray-350 w-[20%]" /> - </div> - <div className="flex flex-col justify-center items-center"> - <h3 className="text-[#002862] mt-1 mb-2"> - {t("plansubscription-1")} - </h3> - <div - className="op-btn op-btn-primary w-[200px]" - onClick={() => - openInNewTab("https://github.com/OpenSignLabs/OpenSign") - } - > - {t("visit-github")} - </div> - </div> - </div> - </div> - )} - </> - ); -}; -export default PlanSubscriptions; diff --git a/apps/OpenSign/src/pages/Preferences.js b/apps/OpenSign/src/pages/Preferences.js index c66e1dc09..4bb1b1206 100644 --- a/apps/OpenSign/src/pages/Preferences.js +++ b/apps/OpenSign/src/pages/Preferences.js @@ -1,40 +1,63 @@ -import React, { useEffect, useState } from "react"; +import React, { useEffect, useState, useRef } from "react"; import Title from "../components/Title"; import Alert from "../primitives/Alert"; import { useTranslation } from "react-i18next"; import Loader from "../primitives/Loader"; import Tooltip from "../primitives/Tooltip"; import { - checkIsSubscribed, getTenantDetails, handleSignatureType, - signatureTypes + signatureTypes, + usertimezone } from "../constant/Utils"; import Parse from "parse"; import { Tooltip as ReactTooltip } from "react-tooltip"; -import { isEnableSubscription } from "../constant/const"; -import Upgrade from "../primitives/Upgrade"; +import TimezoneSelector from "../components/shared/fields/TimezoneSelector"; +import ReactQuill from "react-quill-new"; +import "../styles/quill.css"; +import EditorToolbar, { + module1, + module2, + formats +} from "../components/pdf/EditorToolbar"; + const Preferences = () => { const { t } = useTranslation(); + const editorRef = useRef(); + const editorRefCom = useRef(); + const Extand_Class = localStorage.getItem("Extand_Class"); + const extClass = Extand_Class && JSON.parse(Extand_Class); + const [requestSubject, setRequestSubject] = useState(""); + const [completionBody, SetCompletionBody] = useState(""); + const [completionsubject, setCompletionSubject] = useState(""); + const [requestBody, setRequestBody] = useState(""); + const [defaultCompHtml, setDefaultCompHtml] = useState({}); + const [tenantId, setTenantId] = useState(""); + const [defaultReqHtml, setDefaultReqHtml] = useState({}); const [isalert, setIsAlert] = useState({ type: "success", msg: "" }); const [isTopLoader, setIsTopLoader] = useState(false); const [isLoader, setIsLoader] = useState(false); const [signatureType, setSignatureType] = useState([]); const [errMsg, setErrMsg] = useState(""); const [isNotifyOnSignatures, setIsNotifyOnSignatures] = useState(); - const [isSubscribe, setIsSubscribe] = useState(false); + const [timezone, setTimezone] = useState(usertimezone); + const [activeTab, setactiveTab] = useState(0); + const generaltab = { title: t("general"), icon: "fa-light fa-gears" }; + const [tab, setTab] = useState([generaltab]); + useEffect(() => { fetchSignType(); + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const fetchSignType = async () => { - if (isEnableSubscription) { - const subscribe = await checkIsSubscribed(); - setIsSubscribe(subscribe.isValid); - } else { - setIsSubscribe(true); - } setIsTopLoader(true); + const EmailTab = + extClass?.[0]?.UserRole === "contracts_Admin" + ? [{ title: t("email"), icon: "fa-light fa-envelope" }] + : []; + const arr = [generaltab, ...EmailTab]; + setTab(arr); try { const user = JSON.parse( localStorage.getItem( @@ -42,6 +65,7 @@ const Preferences = () => { ) ); const tenantDetails = await getTenantDetails(user?.objectId); + await tenantEmailTemplate(tenantDetails); const signatureType = tenantDetails?.SignatureType || []; const tenantSignTypes = signatureType?.filter((x) => x.enabled === true); const getUser = await Parse.Cloud.run("getUserDetails"); @@ -50,8 +74,9 @@ const Preferences = () => { const notifyOnSignatures = _getUser?.NotifyOnSignatures !== undefined ? _getUser?.NotifyOnSignatures - : ""; + : true; setIsNotifyOnSignatures(notifyOnSignatures); + setTimezone(_getUser?.Timezone || usertimezone); if (tenantSignTypes?.length > 0) { const signatureType = _getUser?.SignatureType || signatureTypes; const updatedSignatureType = await handleSignatureType( @@ -85,8 +110,13 @@ const Preferences = () => { // `handleSave` is used save updated value signature type const handleSave = async () => { setIsLoader(true); - if (signatureType.length > 0 || isNotifyOnSignatures) { - let params = {}; + const Timezone = timezone || usertimezone; + if ( + signatureType.length > 0 || + isNotifyOnSignatures !== undefined || + Timezone + ) { + let params = { Timezone: Timezone }; if (signatureType.length > 0) { const enabledSignTypes = signatureType?.filter((x) => x.enabled); const isDefaultSignTypeOnly = @@ -106,7 +136,7 @@ const Preferences = () => { params = { ...params, SignatureType: signatureType }; } } - if (isNotifyOnSignatures) { + if (isNotifyOnSignatures !== undefined) { params = { ...params, NotifyOnSignatures: isNotifyOnSignatures }; } try { @@ -136,6 +166,122 @@ const Preferences = () => { const handleNotifySignChange = (value) => { setIsNotifyOnSignatures(value); }; + const tenantEmailTemplate = async (tenantRes) => { + if (tenantRes === "user does not exist!") { + alert("User does not exist"); + } else if (tenantRes) { + setIsLoader(true); + const updateRes = tenantRes; + setTenantId(updateRes?.objectId); + const defaultRequestBody = `<p>Hi {{receiver_name}},</p><br><p>We hope this email finds you well. {{sender_name}} has requested you to review and sign {{document_title}}.</p><p>Your signature is crucial to proceed with the next steps as it signifies your agreement and authorization.</p><br><p>{{signing_url}}</p><br><p>If you have any questions or need further clarification regarding the document or the signing process, please contact the sender.</p><br><p>Thanks</p><p> Team OpenSign™</p><br>`; + if (updateRes?.RequestBody) { + setRequestBody(updateRes?.RequestBody); + setRequestSubject(updateRes?.RequestSubject); + } else { + setRequestBody(defaultRequestBody); + setRequestSubject( + `{{sender_name}} has requested you to sign {{document_title}}` + ); + } + setDefaultReqHtml({ + body: defaultRequestBody, + subject: `{{sender_name}} has requested you to sign {{document_title}}` + }); + const defaultCompletionBody = `<p>Hi {{sender_name}},</p><br><p>All parties have successfully signed the document {{document_title}}. Kindly download the document from the attachment.</p><br><p>Thanks</p><p> Team OpenSign™</p><br>`; + if (updateRes?.CompletionBody) { + SetCompletionBody(updateRes?.CompletionBody); + setCompletionSubject(updateRes?.CompletionSubject); + } else { + SetCompletionBody(defaultCompletionBody); + setCompletionSubject( + `Document {{document_title}} has been signed by all parties` + ); + } + setDefaultCompHtml({ + body: defaultCompletionBody, + subject: `Document {{document_title}} has been signed by all parties` + }); + setIsLoader(false); + } + }; + //function to save completion email template + const handleSaveCompletionEmail = async (e) => { + e.preventDefault(); + try { + 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)); + SetCompletionBody(updateRes?.CompletionBody); + setCompletionSubject(updateRes?.CompletionSubject); + setIsAlert({ type: "success", msg: "Saved successfully." }); + setTimeout(() => setIsAlert({ type: "", msg: "" }), 1500); + } + } catch (err) { + console.log("Err", err); + setIsAlert({ type: "danger", msg: "Something went wrong." }); + setTimeout(() => setIsAlert({ type: "", msg: "" }), 1500); + } finally { + setIsLoader(false); + } + }; + //function to save request email template + const handleSaveRequestEmail = async (e) => { + e.preventDefault(); + try { + 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)); + setRequestBody(updateRes?.RequestBody); + setRequestSubject(updateRes?.RequestSubject); + setIsAlert({ type: "success", msg: "Saved successfully." }); + setTimeout(() => setIsAlert({ type: "", msg: "" }), 1500); + } + } catch (err) { + console.log("Err", err); + setIsAlert({ type: "danger", msg: "Something went wrong." }); + setTimeout(() => setIsAlert({ type: "", msg: "" }), 1500); + } finally { + setIsLoader(false); + } + }; + + //function to use reset form + const handleReset = (request, completion) => { + if (request) { + setRequestBody(defaultReqHtml?.body); + setRequestSubject(defaultReqHtml?.subject); + } else if (completion) { + setCompletionSubject(defaultCompHtml?.subject); + SetCompletionBody(defaultCompHtml?.body); + } + }; + //function for handle ontext change and save again text in delta + const handleOnchangeRequest = () => { + if (editorRef.current) { + const html = editorRef.current.editor.root.innerHTML; + setRequestBody(html); + } + }; + const handleOnchangeCompletion = () => { + if (editorRefCom.current) { + const html = editorRefCom.current.editor.root.innerHTML; + SetCompletionBody(html); + } + }; return ( <React.Fragment> @@ -161,148 +307,315 @@ const Preferences = () => { <h1 className="ml-4 mt-3 mb-2 font-semibold"> OpenSign™ {t("Preferences")}{" "} <span> - <Tooltip - message={`OpenSign™ ${t("Preferences")}`} - isSubscribe={true} - /> + <Tooltip message={`OpenSign™ ${t("Preferences")}`} /> </span> </h1> - <div className="ml-4 mt-1 mb-2 flex flex-col"> - <div className="mb-[0.75rem]"> - <label - htmlFor="signaturetype" - className="text-[14px] mb-[0.7rem] font-medium" - > - {t("allowed-signature-types")} - <a data-tooltip-id="signtypes-tooltip" className="ml-1"> - <sup> - <i className="fa-light fa-question rounded-full border-[#33bbff] text-[#33bbff] text-[13px] border-[1px] py-[1.5px] px-[4px]"></i> - </sup> - </a> - <ReactTooltip id="signtypes-tooltip" className="z-[999]"> - <div className="max-w-[200px] md:max-w-[450px] text-[11px]"> - <p className="font-bold"> - {t("allowed-signature-types")} - </p> - <p>{t("allowed-signature-types-help.p1")}</p> - <p className="p-[5px] ml-2"> - <ol className="list-disc"> - <li> - <span className="font-bold">Draw: </span> - <span> - {t("allowed-signature-types-help.l1")} - </span> - </li> - <li> - <span className="font-bold">Typed: </span> - <span> - {t("allowed-signature-types-help.l2")} - </span> - </li> - <li> - <span className="font-bold">Upload: </span> - <span> - {t("allowed-signature-types-help.l3")} - </span> - </li> - <li> - <span className="font-bold">Default: </span> - <span> - {t("allowed-signature-types-help.l4")} - </span> - </li> - </ol> - </p> - </div> - </ReactTooltip> - </label> - <div className=" ml-[7px] flex flex-col md:flex-row gap-[10px] mb-[0.7rem]"> - {signatureType.map((type, i) => ( - <div - key={i} - className="flex flex-row gap-[5px] items-center" - > - <input - className="mr-[2px] op-checkbox op-checkbox-xs" - type="checkbox" - name="signaturetype" - onChange={() => handleCheckboxChange(i)} - checked={type.enabled} - /> - <div - className="text-[13px] font-medium hover:underline underline-offset-2 cursor-default capitalize" - title={`Enabling this allow signers to ${type.name} signature`} - > - {type.name} - </div> - </div> - ))} - </div> - </div> - <div className="mb-[0.75rem]"> - <label - className={`${ - isSubscribe ? "" : "text-gray-300" - } text-[14px] mb-[0.7rem] font-medium`} - > - {t("notify-on-signatures")} - <a data-tooltip-id="nos-tooltip" className="ml-1"> - <sup> - <i className="fa-light fa-question rounded-full border-[#33bbff] text-[#33bbff] text-[13px] border-[1px] py-[1.5px] px-[4px]"></i> - </sup> - </a> - <ReactTooltip id="nos-tooltip" className="z-[999]"> - <div className="max-w-[200px] md:max-w-[450px] text-[11px]"> - <p className="font-bold">{t("notify-on-signatures")}</p> - <p>{t("notify-on-signatures-help.p1")}</p> - <p>{t("notify-on-signatures-help.note")}</p> - </div> - </ReactTooltip> - {!isSubscribe && isEnableSubscription && <Upgrade />} - </label> - <div className="flex flex-col md:flex-row md:gap-4"> + <div className="flex justify-center items-center mt-2"> + <div + role="tablist" + className="op-tabs op-tabs-bordered op-tabs-sm md:op-tabs-md" + > + {tab.map((tabData, ind) => ( <div - className={`${ - isSubscribe ? "" : "pointer-events-none opacity-50" - } flex items-center gap-2 ml-2 mb-1`} + onClick={() => setactiveTab(ind)} + key={ind} + role="tab" + className={`${activeTab === ind ? "op-tab-active" : ""} op-tab text-xs md:text-base pb-2 md:pb-0 }`} > - <input - className="mr-[2px] op-radio op-radio-xs" - type="radio" - onChange={() => handleNotifySignChange(true)} - checked={isNotifyOnSignatures === true} - /> - <div className="text-[13px] font-medium cursor-default capitalize"> - {t("yes")} + <i className={tabData.icon}></i> + <span className="ml-1 md:ml-2">{tabData.title}</span> + </div> + ))} + </div> + </div> + <div className="flex justify-center md:justify-start mt-3 md:mt-4 break-all"> + {activeTab === 0 ? ( + <> + <div className="ml-4 mt-1 mb-2 flex flex-col"> + <div className="mb-[0.75rem]"> + <label + htmlFor="signaturetype" + className="text-[14px] mb-[0.7rem] font-medium" + > + {t("allowed-signature-types")} + <a + data-tooltip-id="signtypes-tooltip" + className="ml-1" + > + <sup> + <i className="fa-light fa-question rounded-full border-[#33bbff] text-[#33bbff] text-[13px] border-[1px] py-[1.5px] px-[4px]"></i> + </sup> + </a> + <ReactTooltip + id="signtypes-tooltip" + className="z-[999]" + > + <div className="max-w-[200px] md:max-w-[450px] text-[11px]"> + <p className="font-bold"> + {t("allowed-signature-types")} + </p> + <p>{t("allowed-signature-types-help.p1")}</p> + <p className="p-[5px] ml-2"> + <ol className="list-disc"> + <li> + <span className="font-bold">Draw: </span> + <span> + {t("allowed-signature-types-help.l1")} + </span> + </li> + <li> + <span className="font-bold">Type: </span> + <span> + {t("allowed-signature-types-help.l2")} + </span> + </li> + <li> + <span className="font-bold">Upload: </span> + <span> + {t("allowed-signature-types-help.l3")} + </span> + </li> + <li> + <span className="font-bold">Default: </span> + <span> + {t("allowed-signature-types-help.l4")} + </span> + </li> + </ol> + </p> + </div> + </ReactTooltip> + </label> + <div className=" ml-[7px] flex flex-col md:flex-row gap-[10px] mb-[0.7rem]"> + {signatureType.map((type, i) => ( + <div + key={i} + className="flex flex-row gap-[5px] items-center" + > + <input + className="mr-[2px] op-checkbox op-checkbox-xs" + type="checkbox" + name="signaturetype" + onChange={() => handleCheckboxChange(i)} + checked={type.enabled} + /> + <div + className="text-[13px] font-medium hover:underline underline-offset-2 cursor-default capitalize" + title={`Enabling this allow signers to ${type.name} signature`} + > + {type?.name === "typed" ? "type" : type?.name} + </div> + </div> + ))} + </div> + </div> + <div className="mb-[0.75rem]"> + <label + className={ + "text-[14px] mb-[0.7rem] font-medium" + } + > + {t("notify-on-signatures")} + <a data-tooltip-id="nos-tooltip" className="ml-1"> + <sup> + <i className="fa-light fa-question rounded-full border-[#33bbff] text-[#33bbff] text-[13px] border-[1px] py-[1.5px] px-[4px]"></i> + </sup> + </a> + <ReactTooltip id="nos-tooltip" className="z-[999]"> + <div className="max-w-[200px] md:max-w-[450px] text-[11px]"> + <p className="font-bold"> + {t("notify-on-signatures")} + </p> + <p>{t("notify-on-signatures-help.p1")}</p> + <p>{t("notify-on-signatures-help.note")}</p> + </div> + </ReactTooltip> + </label> + <div className="flex flex-col md:flex-row md:gap-4"> + <div + className={ + "flex items-center gap-2 ml-2 mb-1" + } + > + <input + className="mr-[2px] op-radio op-radio-xs" + type="radio" + onChange={() => handleNotifySignChange(true)} + checked={isNotifyOnSignatures === true} + /> + <div className="text-[13px] font-medium cursor-default capitalize"> + {t("yes")} + </div> + </div> + <div className="flex flex-col md:flex-row md:gap-4"> + <div + className={ + "flex items-center gap-2 ml-2 mb-1" + } + > + <input + className="mr-[2px] op-radio op-radio-xs" + type="radio" + onChange={() => handleNotifySignChange(false)} + checked={isNotifyOnSignatures === false} + /> + <div className="text-[13px] font-medium cursor-default capitalize"> + {t("no")} + </div> + </div> + </div> + </div> + </div> + <div className="mb-[0.75rem]"> + <TimezoneSelector + timezone={timezone} + setTimezone={setTimezone} + /> + </div> + <div className="mb-[0.75rem]"> + <button + className="op-btn op-btn-primary" + onClick={handleSave} + > + {t("save")} + </button> </div> </div> - <div className="flex flex-col md:flex-row md:gap-4"> - <div - className={`${ - isSubscribe ? "" : "pointer-events-none opacity-50" - } flex items-center gap-2 ml-2 mb-1`} - > - <input - className="mr-[2px] op-radio op-radio-xs" - type="radio" - onChange={() => handleNotifySignChange(false)} - checked={isNotifyOnSignatures === false} - /> - <div className="text-[13px] font-medium cursor-default capitalize"> - {t("no")} - </div> + </> + ) : ( + <div className="flex flex-col mx-4 mb-4"> + <div className="flex flex-col"> + <h1 className="text-[14px] mb-[0.7rem] font-medium"> + {t("request-email")} + </h1> + <div className="relative mt-2 mb-4"> + <form + onSubmit={handleSaveRequestEmail} + className="p-3 border-[1px] border-base-content rounded-box" + > + <div className="text-lg font-normal"> + <label className="text-sm"> + {t("subject")} + <Tooltip + id={"request-sub-tooltip"} + message={`${t("variables-use")}: {{sender_name}} {{document_title}}`} + /> + </label> + <input + required + value={requestSubject} + onChange={(e) => + setRequestSubject(e.target.value) + } + placeholder={`{{sender_name}} ${t("send-to-sign")} {{document_title}}`} + className="w-full op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content text-xs" + /> + </div> + <div className="text-lg font-normal py-2"> + <label className="text-sm mt-3"> + {t("body")} + <Tooltip + id={"request-body-tooltip"} + message={`${t("variables-use")}: {{sender_name}} {{document_title}}`} + /> + </label> + <EditorToolbar containerId="toolbar1" /> + <ReactQuill + theme="snow" + value={requestBody} + placeholder="add body of email" + // onChangeSelection={handleTextSelection} // Listen for text selection + ref={editorRef} + modules={module1} + formats={formats} + onChange={handleOnchangeRequest} + /> + </div> + <div className="flex items-center mt-3 gap-2"> + <button + disabled={!requestBody || !requestSubject} + className="op-btn op-btn-primary" + type="submit" + > + {t("save")} + </button> + <button + type="button" + className="op-btn op-btn-secondary" + onClick={() => handleReset("request")} + > + {t("reset")} + </button> + </div> + </form> + </div> + <h1 className="text-[14px] mb-[0.7rem] font-medium"> + {t("completion-email")} + </h1> + <div className="relative my-2"> + <form + onSubmit={handleSaveCompletionEmail} + className="p-3 border-[1px] border-base-content rounded-box" + > + <div className="text-lg font-normal"> + <label className="text-sm"> + {t("subject")} + <Tooltip + id={"complete-sub-tooltip"} + message={`${t("variables-use")}:{{sender_name}} {{document_title}}`} + /> + </label> + <input + required + value={completionsubject} + onChange={(e) => + setCompletionSubject(e.target.value) + } + placeholder={`{{sender_name}} ${t("send-to-sign")} {{document_title}}`} + className="w-full op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content text-xs" + /> + </div> + <div className="text-lg font-normal py-2"> + <label className="text-sm mt-3"> + {t("body")} + <Tooltip + id={"complete-body-tooltip"} + message={`${t("variables-use")}:{{sender_name}} {{document_title}} {{signing_url}}`} + /> + </label> + <EditorToolbar containerId="toolbar2" /> + <ReactQuill + theme="snow" + value={completionBody} + placeholder="add body of email " + // onChangeSelection={handleTextSelection} // Listen for text selection + ref={editorRefCom} + modules={module2} + formats={formats} + onChange={handleOnchangeCompletion} + /> + </div> + <div className="flex items-center mt-3 gap-2"> + <button + disabled={!completionBody || !completionsubject} + className="op-btn op-btn-primary" + type="submit" + > + {t("save")} + </button> + <button + type="button" + className="op-btn op-btn-secondary" + onClick={() => handleReset(null, "completion")} + > + {t("reset")} + </button> + </div> + </form> </div> </div> </div> - </div> - <div className="mb-[0.75rem]"> - <button - className="op-btn op-btn-primary" - onClick={handleSave} - > - Save - </button> - </div> + )} </div> </div> )} diff --git a/apps/OpenSign/src/pages/Report.js b/apps/OpenSign/src/pages/Report.js index 4a28898bc..6b96481f8 100644 --- a/apps/OpenSign/src/pages/Report.js +++ b/apps/OpenSign/src/pages/Report.js @@ -3,7 +3,7 @@ import ReportTable from "../primitives/GetReportDisplay"; import Parse from "parse"; import axios from "axios"; import reportJson from "../json/ReportJson"; -import { useParams } from "react-router-dom"; +import { useParams } from "react-router"; import Title from "../components/Title"; import PageNotFound from "./PageNotFound"; import TourContentWithBtn from "../primitives/TourContentWithBtn"; @@ -24,7 +24,7 @@ const Report = () => { const [form, setForm] = useState(""); const [tourData, setTourData] = useState([]); const [isDontShow, setIsDontShow] = useState(false); - const [isPublic, setIsPublic] = useState({}); + const [isImport, setIsImport] = useState(false); const abortController = new AbortController(); const docPerPage = 10; @@ -48,7 +48,7 @@ const Report = () => { // below useEffect call when isNextRecord state is true and fetch next record useEffect(() => { if (isNextRecord) { - getReportData(List.length, 200); + getReportData(List.length, 20); } // eslint-disable-next-line }, [isNextRecord]); @@ -56,7 +56,7 @@ const Report = () => { const handleDontShow = (isChecked) => { setIsDontShow(isChecked); }; - const getReportData = async (skipUserRecord = 0, limit = 200) => { + const getReportData = async (skipUserRecord = 0, limit = 20) => { // setIsLoader(true); const json = reportJson(id); if (json) { @@ -65,6 +65,7 @@ const Report = () => { setReportName(json.reportName); setForm(json.form); setReportHelp(json?.helpMsg); + setIsImport(json?.import || false); const currentUser = Parse.User.current().id; const headers = { @@ -73,8 +74,10 @@ const Report = () => { sessiontoken: localStorage.getItem("accesstoken") }; try { - const params = { reportId: id, skip: skipUserRecord, limit: limit }; - const url = `${localStorage.getItem("baseUrl")}/functions/getReport`; + const skipRecord = id === "4Hhwbp482K" ? 0 : skipUserRecord; + const limitRecord = id === "4Hhwbp482K" ? 200 : limit; + const params = { reportId: id, skip: skipRecord, limit: limitRecord }; + const url = `${localStorage.getItem("baseUrl")}functions/getReport`; const res = await axios.post(url, params, { headers: headers, signal: abortController.signal // is used to cancel fetch query @@ -145,7 +148,7 @@ const Report = () => { prevRecord.length > 0 ? [...prevRecord, ...arr] : arr ); } else { - if (res.data.result.length === docPerPage) { + if (res.data.result.length >= docPerPage) { setIsMoreDocs(true); } else { setIsMoreDocs(false); @@ -157,13 +160,6 @@ const Report = () => { ? [...prevRecord, ...res.data.result] : res.data.result ); - const listData = res.data.result; - setIsPublic( - listData.reduce((acc, item) => { - acc[item.objectId] = item?.IsPublic || false; - return acc; - }, {}) - ); } } setIsLoader(false); @@ -201,8 +197,7 @@ const Report = () => { report_help={reporthelp} tourData={tourData} isDontShow={isDontShow} - setIsPublic={setIsPublic} - isPublic={isPublic} + isImport={isImport} /> ) : ( <PageNotFound prefix={"Report"} /> diff --git a/apps/OpenSign/src/pages/SSOVerify.js b/apps/OpenSign/src/pages/SSOVerify.js deleted file mode 100644 index d6961e15d..000000000 --- a/apps/OpenSign/src/pages/SSOVerify.js +++ /dev/null @@ -1,362 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { useLocation, useNavigate } from "react-router-dom"; -import Parse from "parse"; -import { appInfo } from "../constant/appinfo"; -import { emailRegex, isEnableSubscription } from "../constant/const"; -import { fetchSubscription } from "../constant/Utils"; -import { useDispatch } from "react-redux"; -import { showTenant } from "../redux/reducers/ShowTenant"; -import ModalUi from "../primitives/ModalUi"; -import Loader from "../primitives/Loader"; -import { useTranslation } from "react-i18next"; - -const SSOVerify = () => { - const { t } = useTranslation(); - const location = useLocation(); - const navigate = useNavigate(); - const dispatch = useDispatch(); - const [isModal, setIsModal] = useState(false); - const [message, setMessage] = useState("Verifying SSO..."); - const [isLoader, setIsLoader] = useState(false); - const [userDetails, setUserDetails] = useState({ - name: "", - email: "", - phone: "", - Destination: "", - Company: "" - }); - - useEffect(() => { - linkUserWithSSO(); - // eslint-disable-next-line - }, []); - - // `linkUserWithSSO` is used to sign in or sign up a user using an SSO code and check if the user is present in the extended class - const linkUserWithSSO = async () => { - const param = new URLSearchParams(location.search); - const code = param?.get("code"); - const state = param?.get("state"); - try { - // The `ssosign` cloud function is used to sign in or sign up a user - const ssosign = await Parse.Cloud.run("ssosign", { - code: code, - email: state - }); - localStorage.setItem("accesstoken", ssosign.sessiontoken); - // `checkExtUser` checks if the user is present in the extended class `contracts_Users` and if not, initiates the new user flow - await checkExtUser(ssosign); - } catch (err) { - setMessage("Error: " + err.message); - console.log("err", err.message); - } - }; - const handlePaidRoute = () => { - navigate("/subscription"); - }; - const checkExtUser = async (ssosign) => { - const params = { email: ssosign?.email }; - try { - // `isextenduser` checks if the current user is present in the extended class - const extRes = await Parse.Cloud.run("isextenduser", params); - if (extRes?.isUserExist) { - // `getUserDetails` retrieves the current user's details from the extended class - const extRes = await Parse.Cloud.run("getUserDetails", params); - if (ssosign && ssosign.sessiontoken) { - const LocalUserDetails = { - name: extRes.Name, - email: extRes.email, - phone: extRes?.get("Phone") || "", - company: extRes.get("Company") - }; - localStorage.setItem("userDetails", JSON.stringify(LocalUserDetails)); - thirdpartyLoginfn(ssosign.sessiontoken); - } - } else { - setIsModal(true); - setUserDetails((prev) => ({ - ...prev, - name: ssosign.name, - email: ssosign.email, - phone: ssosign?.phone || "" - })); - } - } catch (err) { - console.log("Err in isextenduser or getuserdetails cloud function", err); - setMessage("Error: " + err.message); - } - }; - // `handleSubmitbtn` is used to create a user in the extended class - const handleSubmitbtn = async (e) => { - e.preventDefault(); - if (!emailRegex.test(userDetails.email)) { - alert("Please enter a valid email address."); - } else { - setIsLoader(true); - let phone; - if (userDetails?.phone) { - phone = validateInput(userDetails?.phone); - } else { - phone = true; - } - if (userDetails.Destination && userDetails.Company && phone) { - const payload = { sessionToken: localStorage.getItem("accesstoken") }; - if (payload && payload.sessionToken) { - const params = { - userDetails: { - name: userDetails.name, - email: userDetails.email, - phone: userDetails?.phone || "", - role: "contracts_User", - company: userDetails.Company, - jobTitle: userDetails.Destination - } - }; - try { - const userSignUp = await Parse.Cloud.run("usersignup", params); - if (userSignUp && userSignUp.sessionToken) { - const LocalUserDetails = params.userDetails; - localStorage.setItem( - "userDetails", - JSON.stringify(LocalUserDetails) - ); - await thirdpartyLoginfn(userSignUp.sessionToken); - setIsLoader(false); - } else { - alert(userSignUp.message); - setIsLoader(false); - } - } catch (err) { - console.log("error in usersignup", err); - localStorage.removeItem("accesstoken"); - alert(t("something-went-wrong-mssg")); - setIsLoader(false); - } - } else { - localStorage.removeItem("accesstoken"); - alert(t("server-error")); - setIsLoader(false); - } - } else { - alert(t("filed-required-correctly")); - setIsLoader(false); - } - } - }; - // `thirdpartyLoginfn` is used to save necessary parameters locally for the logged-in user - const thirdpartyLoginfn = async (sessionToken) => { - try { - const validUser = await Parse.User.become(sessionToken); - if (validUser) { - localStorage.setItem("accesstoken", sessionToken); - const _user = JSON.parse(JSON.stringify(validUser)); - localStorage.setItem("UserInformation", JSON.stringify(_user)); - if (_user.ProfilePic) { - localStorage.setItem("profileImg", _user.ProfilePic); - } else { - localStorage.setItem("profileImg", ""); - } - // Check extended class user role and tenentId - try { - const userSettings = appInfo.settings; - await Parse.Cloud.run("getUserDetails") - .then(async (extUser) => { - if (extUser) { - const IsDisabled = extUser?.get("IsDisabled") || false; - if (!IsDisabled) { - const userRole = extUser?.get("UserRole"); - const menu = - userRole && - userSettings.find((menu) => menu.role === userRole); - if (menu) { - const _currentRole = userRole; - const redirectUrl = - location?.state?.from || - `/${menu.pageType}/${menu.pageId}`; - const _role = _currentRole.replace("contracts_", ""); - localStorage.setItem("_user_role", _role); - const extUser_stringify = JSON.stringify([extUser]); - localStorage.setItem("Extand_Class", extUser_stringify); - const _extUser = JSON.parse(JSON.stringify(extUser)); - localStorage.setItem("userEmail", _extUser.Email); - localStorage.setItem("username", _extUser.Name); - localStorage.setItem("scriptId", true); - if (_extUser.TenantId) { - const tenant = { - Id: _extUser?.TenantId?.objectId || "", - Name: _extUser?.TenantId?.TenantName || "" - }; - localStorage.setItem("TenantId", tenant?.Id); - dispatch(showTenant(tenant?.Name)); - localStorage.setItem("TenantName", tenant?.Name); - } - localStorage.setItem("PageLanding", menu.pageId); - localStorage.setItem("defaultmenuid", menu.menuId); - localStorage.setItem("pageType", menu.pageType); - if (isEnableSubscription) { - const res = await fetchSubscription(); - const plan = res.plan; - const billingDate = res.billingDate; - if (plan === "freeplan") { - navigate(redirectUrl); - } else if (billingDate) { - if (new Date(billingDate) > new Date()) { - localStorage.removeItem("userDetails"); - navigate(redirectUrl); - } else { - handlePaidRoute(plan); - } - } else { - handlePaidRoute(plan); - } - } else { - navigate(redirectUrl); - } - } - } else { - alert(t("do-not-access-contact-admin")); - setMessage(t("do-not-access-contact-admin")); - } - } - }) - .catch((error) => { - console.error("Err in fetch extuser", error); - alert(t("user-not-exist")); - setMessage(t("user-not-exist")); - }); - } catch (err) { - console.log("err in getuserdetails", err); - } - } - } catch (err) { - console.log("Err in become method", err); - } - }; - // `handleCloseModal` is triggered when the user wants to close the new user flow modal - const handleCloseModal = async () => { - setIsModal(false); - try { - await Parse.User.logOut(); - } catch (err) { - console.log("Err while logging out", err); - } - }; - - // `validateInput` is used to verify the phone pattern - function validateInput(input) { - if (input) { - const pattern = /^(?!.*\+.*\+)[\d+-]*$/; - return pattern.test(input); - } else { - return true; - } - } - return ( - <div> - <div className="w-full h-screen flex flex-col justify-center items-center text-sm md:text-xl "> - {message === "Verifying SSO..." && <Loader />} - <div className="text-base-content">{message}</div> - </div> - <ModalUi isOpen={isModal} title="Additional Info" showClose={false}> - <div className="relative"> - {isLoader && ( - <div className="absolute w-full h-full bg-black bg-opacity-25 flex justify-center items-center"> - <Loader /> - </div> - )} - <form - className="px-4 py-3 text-base-content" - onSubmit={handleSubmitbtn} - > - <div className="mb-3"> - <label htmlFor="Company" className="block text-xs font-semibold"> - {t("phone")} <span className="text-[13px] text-[red]">*</span> - </label> - <input - type="tel" - className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" - id="Phone" - value={userDetails.phone} - onChange={(e) => - setUserDetails({ - ...userDetails, - phone: e.target.value - }) - } - disabled={isLoader} - onInvalid={(e) => - e.target.setCustomValidity(t("input-required")) - } - onInput={(e) => e.target.setCustomValidity("")} - required - /> - <p className="text-[10px] text-[red] ml-2"> - {!validateInput(userDetails.phone) && "Invalid phone value"} - </p> - </div> - <div className="mb-3"> - <label htmlFor="Company" className="block text-xs font-semibold"> - {t("company")} <span className="text-[13px] text-[red]">*</span> - </label> - <input - type="text" - className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" - id="Company" - value={userDetails.Company} - onChange={(e) => - setUserDetails({ - ...userDetails, - Company: e.target.value - }) - } - disabled={isLoader} - onInvalid={(e) => - e.target.setCustomValidity(t("input-required")) - } - onInput={(e) => e.target.setCustomValidity("")} - required - /> - </div> - <div className="mb-3"> - <label htmlFor="JobTitle" className="block text-xs font-semibold"> - {t("job-title")} - <span className="text-[13px] text-[red]">*</span> - </label> - <input - type="text" - className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" - id="JobTitle" - value={userDetails.Destination} - onChange={(e) => - setUserDetails({ - ...userDetails, - Destination: e.target.value - }) - } - disabled={isLoader} - onInvalid={(e) => - e.target.setCustomValidity(t("input-required")) - } - onInput={(e) => e.target.setCustomValidity("")} - required - /> - </div> - <div className="mt-4"> - <button type="submit" className="op-btn op-btn-primary"> - {t("login")} - </button> - <button - type="button" - className="op-btn op-btn-ghost ml-2" - onClick={handleCloseModal} - > - {t("cancel")} - </button> - </div> - </form> - </div> - </ModalUi> - </div> - ); -}; - -export default SSOVerify; diff --git a/apps/OpenSign/src/pages/Signup.js b/apps/OpenSign/src/pages/Signup.js deleted file mode 100644 index 787e166ab..000000000 --- a/apps/OpenSign/src/pages/Signup.js +++ /dev/null @@ -1,566 +0,0 @@ -import React, { useState, useEffect } from "react"; -import Parse from "parse"; -import axios from "axios"; -import Title from "../components/Title"; -import { useNavigate, useLocation } from "react-router-dom"; -import login_img from "../assets/images/login_img.svg"; -import { useWindowSize } from "../hook/useWindowSize"; -import Alert from "../primitives/Alert"; -import { appInfo } from "../constant/appinfo"; -import { useDispatch } from "react-redux"; -import { fetchAppInfo } from "../redux/reducers/infoReducer"; -import { showTenant } from "../redux/reducers/ShowTenant"; -import { emailRegex, isEnableSubscription } from "../constant/const"; -import { - getAppLogo, - openInNewTab, - saveLanguageInLocal -} from "../constant/Utils"; -import Loader from "../primitives/Loader"; -import { useTranslation } from "react-i18next"; -import SelectLanguage from "../components/pdf/SelectLanguage"; -const Signup = () => { - const { width } = useWindowSize(); - const { t, i18n } = useTranslation(); - const navigate = useNavigate(); - const location = useLocation(); - const dispatch = useDispatch(); - const [name, setName] = useState(""); - const [phone, setPhone] = useState(""); - const [password, setPassword] = useState(""); - const [email, setEmail] = useState(""); - const [company, setCompany] = useState(""); - const [jobTitle, setJobTitle] = useState(""); - const [image, setImage] = useState(); - const [state, setState] = useState({ - loading: false, - alertType: "success", - alertMsg: "" - }); - const [showPassword, setShowPassword] = useState(false); - const [lengthValid, setLengthValid] = useState(false); - const [caseDigitValid, setCaseDigitValid] = useState(false); - const [specialCharValid, setSpecialCharValid] = useState(false); - const [isAuthorize, setIsAuthorize] = useState(false); - const togglePasswordVisibility = () => setShowPassword(!showPassword); - - const clearStorage = async () => { - try { - await Parse.User.logOut(); - } catch (err) { - console.log("Err while logging out", err); - } - let baseUrl = localStorage.getItem("baseUrl"); - let appid = localStorage.getItem("parseAppId"); - let applogo = localStorage.getItem("appLogo"); - let defaultmenuid = localStorage.getItem("defaultmenuid"); - let PageLanding = localStorage.getItem("PageLanding"); - let userSettings = localStorage.getItem("userSettings"); - - localStorage.clear(); - saveLanguageInLocal(i18n); - localStorage.setItem("baseUrl", baseUrl); - localStorage.setItem("parseAppId", appid); - localStorage.setItem("appLogo", applogo); - localStorage.setItem("defaultmenuid", defaultmenuid); - localStorage.setItem("PageLanding", PageLanding); - localStorage.setItem("userSettings", userSettings); - localStorage.setItem("baseUrl", baseUrl); - localStorage.setItem("parseAppId", appid); - }; - - const handleFreePlan = async (id) => { - try { - const params = { userId: id }; - const res = await Parse.Cloud.run("freesubscription", params); - if (res.status === "error") { - alert(res.result); - } - } catch (err) { - console.log("err in free subscribe", err.message); - alert(t("something-went-wrong-mssg")); - } - }; - const handleSubmit = (event) => { - event.preventDefault(); - if (!emailRegex.test(email)) { - alert("Please enter a valid email address."); - } else { - if (lengthValid && caseDigitValid && specialCharValid) { - clearStorage(); - setState({ loading: true }); - const userDetails = { - name: name, - email: email, - phone: phone, - company: company, - jobTitle: jobTitle - }; - localStorage.setItem("userDetails", JSON.stringify(userDetails)); - try { - event.preventDefault(); - var user = new Parse.User(); - user.set("name", name); - user.set("email", email); - user.set("password", password); - user.set("phone", phone); - user.set("username", email); - let res = user.save(); - res - .then(async (r) => { - if (r) { - let roleData = appInfo.settings; - if (roleData && roleData.length > 0) { - const params = { - userDetails: { - jobTitle: jobTitle, - company: company, - name: name, - email: email, - phone: phone, - role: appInfo.defaultRole - } - }; - try { - const usersignup = await Parse.Cloud.run( - "usersignup", - params - ); - if (usersignup) { - const param = new URLSearchParams(location.search); - const isFreeplan = - param?.get("subscription") === "freeplan"; - if (isFreeplan) { - await handleFreePlan(r.id); - } - handleNavigation(r.getSessionToken(), isFreeplan); - } - } catch (err) { - alert(err.message); - setState({ loading: false }); - } - } - } - }) - .catch(async (err) => { - if (err.code === 202) { - const params = { email: email }; - const res = await Parse.Cloud.run("getUserDetails", params); - // console.log("Res ", res); - if (res) { - alert(t("user-already-exist-name")); - setState({ loading: false }); - } else { - // console.log("state.email ", email); - try { - await Parse.User.requestPasswordReset(email).then( - async function (res1) { - if (res1.data === undefined) { - alert(t("verification-code-sent")); - } - } - ); - } catch (err) { - console.log(err); - } - setState({ loading: false }); - } - } else { - alert(err.message); - setState({ loading: false }); - } - }); - } catch (error) { - console.log("err ", error); - } - } - } - }; - - const handleNavigation = async (sessionToken, isFreeplan = false) => { - const baseUrl = localStorage.getItem("baseUrl"); - const parseAppId = localStorage.getItem("parseAppId"); - const res = await axios.get(baseUrl + "users/me", { - headers: { - "X-Parse-Session-Token": sessionToken, - "X-Parse-Application-Id": parseAppId - } - }); - await Parse.User.become(sessionToken).then(() => { - window.localStorage.setItem("accesstoken", sessionToken); - }); - // console.log("me res ", res); - if (res.data) { - let _user = res.data; - localStorage.setItem("UserInformation", JSON.stringify(_user)); - localStorage.setItem("accesstoken", _user.sessionToken); - localStorage.setItem("scriptId", true); - if (_user.ProfilePic) { - localStorage.setItem("profileImg", _user.ProfilePic); - } else { - localStorage.setItem("profileImg", ""); - } - // Check extended class user role and tenentId - try { - const userSettings = appInfo.settings; - await Parse.Cloud.run("getUserDetails") - .then(async (extUser) => { - if (extUser) { - const IsDisabled = extUser?.get("IsDisabled") || false; - if (!IsDisabled) { - const userRole = extUser?.get("UserRole"); - const menu = - userRole && - userSettings.find((menu) => menu.role === userRole); - if (menu) { - const _currentRole = userRole; - const _role = _currentRole.replace("contracts_", ""); - localStorage.setItem("_user_role", _role); - const extInfo_stringify = JSON.stringify([extUser]); - localStorage.setItem("Extand_Class", extInfo_stringify); - const extInfo = JSON.parse(JSON.stringify(extUser)); - localStorage.setItem("userEmail", extInfo?.Email); - localStorage.setItem("username", extInfo?.Name); - if (extInfo?.TenantId) { - const tenant = { - Id: extInfo?.TenantId?.objectId || "", - Name: extInfo?.TenantId?.TenantName || "" - }; - localStorage.setItem("TenantId", tenant?.Id); - dispatch(showTenant(tenant?.Name)); - localStorage.setItem("TenantName", tenant?.Name); - } - localStorage.setItem("PageLanding", menu.pageId); - localStorage.setItem("defaultmenuid", menu.menuId); - localStorage.setItem("pageType", menu.pageType); - setState({ loading: false }); - if (isEnableSubscription) { - if (isFreeplan) { - navigate(`/${menu.pageType}/${menu.pageId}`); - } else { - navigate(`/subscription`, { replace: true }); - } - } else { - alert(t("registered-user-successfully")); - navigate(`/${menu.pageType}/${menu.pageId}`); - } - } else { - setState({ - loading: false, - alertType: "danger", - alertMsg: t("role-not-found") - }); - setTimeout(() => { - setState({ loading: false, alertMsg: "" }); - }, 2000); - } - } else { - setState({ - loading: false, - alertType: "danger", - alertMsg: t("do-not-access-contact-admin") - }); - setTimeout(() => { - setState({ loading: false, alertMsg: "" }); - }, 2000); - } - } - }) - .catch((error) => { - console.log("error in fetch extuser", error); - setState({ - loading: false, - alertType: "danger", - alertMsg: t("do-not-access-contact-admin") - }); - setTimeout(() => { - setState({ loading: false, alertMsg: "" }); - }, 2000); - }); - } catch (error) { - // alert(`${error.message}`); - setState({ - loading: false, - alertType: "danger", - alertMsg: `${error.message}` - }); - setTimeout(() => { - setState({ loading: false, alertMsg: "" }); - }, 2000); - console.log(error); - } - } - }; - useEffect(() => { - dispatch(fetchAppInfo()); - saveLogo(); - // eslint-disable-next-line - }, []); - - const saveLogo = async () => { - if (isEnableSubscription) { - const app = await getAppLogo(); - if (app?.logo) { - setImage(app?.logo); - } else { - setImage(appInfo?.applogo || undefined); - } - } else { - setImage(appInfo?.applogo || undefined); - } - }; - - const handlePasswordChange = (e) => { - const newPassword = e.target.value; - setPassword(newPassword); - - // Check conditions separately - setLengthValid(newPassword.length >= 8); - setCaseDigitValid( - /[a-z]/.test(newPassword) && - /[A-Z]/.test(newPassword) && - /\d/.test(newPassword) - ); - setSpecialCharValid(/[!@#$%^&*()\-_=+{};:,<.>]/.test(newPassword)); - }; - return ( - <div className=""> - {state.loading && ( - <div className="fixed w-full h-full flex justify-center items-center bg-black bg-opacity-30 z-50"> - <Loader /> - </div> - )} - <Title title="Signup page" /> - {appInfo && appInfo.applogo ? ( - <div className="md:p-10 lg:p-16"> - <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"> - {image && ( - <img src={image} className="object-contain h-full" alt="logo" /> - )} - </div> - <div className="grid grid-cols-1 md:grid-cols-2 gap-x-2"> - <div> - <form onSubmit={handleSubmit}> - <h2 className="text-[30px] mt-6">{t("create-account")}!</h2> - <div className="w-full my-4 op-card bg-base-100 shadow-md outline outline-1 outline-slate-300/50"> - <div className="px-6 py-4 text-xs"> - <label className="block "> - {t("name")}{" "} - <span className="text-[red] text-[13px]">*</span> - </label> - <input - type="text" - className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" - value={name} - onChange={(e) => setName(e.target.value)} - onInvalid={(e) => - e.target.setCustomValidity(t("input-required")) - } - onInput={(e) => e.target.setCustomValidity("")} - required - /> - <hr className="my-2 border-none" /> - <label> - {t("email")}{" "} - <span className="text-[red] text-[13px]">*</span> - </label> - <input - id="email" - type="email" - className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" - value={email} - onChange={(e) => - setEmail( - e.target.value?.toLowerCase()?.replace(/\s/g, "") - ) - } - onInvalid={(e) => - e.target.setCustomValidity(t("input-required")) - } - onInput={(e) => e.target.setCustomValidity("")} - required - /> - <hr className="my-2 border-none" /> - <label> - {t("phone")}{" "} - <span className="text-[red] text-[13px]">*</span> - </label> - <input - type="tel" - className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" - value={phone} - onChange={(e) => setPhone(e.target.value)} - onInvalid={(e) => - e.target.setCustomValidity(t("input-required")) - } - onInput={(e) => e.target.setCustomValidity("")} - required - /> - <hr className="my-2 border-none" /> - <label> - {t("company")}{" "} - <span className="text-[red] text-[13px]">*</span> - </label> - <input - type="text" - className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" - value={company} - onChange={(e) => setCompany(e.target.value)} - onInvalid={(e) => - e.target.setCustomValidity(t("input-required")) - } - onInput={(e) => e.target.setCustomValidity("")} - required - /> - <hr className="my-2 border-none" /> - <label> - {t("job-title")}{" "} - <span className="text-[red] text-[13px]">*</span> - </label> - <input - type="text" - className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" - value={jobTitle} - onChange={(e) => setJobTitle(e.target.value)} - onInvalid={(e) => - e.target.setCustomValidity(t("input-required")) - } - onInput={(e) => e.target.setCustomValidity("")} - required - /> - <hr className="my-2 border-none" /> - <label> - {t("password")}{" "} - <span className="text-[red] text-[13px]">*</span> - </label> - <div className="relative"> - <input - type={showPassword ? "text" : "password"} - className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" - name="password" - value={password} - onChange={(e) => handlePasswordChange(e)} - onInvalid={(e) => - e.target.setCustomValidity(t("input-required")) - } - onInput={(e) => e.target.setCustomValidity("")} - required - /> - <span - className={`absolute top-[50%] right-[10px] -translate-y-[50%] cursor-pointer text-base-content`} - onClick={togglePasswordVisibility} - > - {showPassword ? ( - <i className="fa-light fa-eye-slash" /> // Close eye icon - ) : ( - <i className="fa-light fa-eye" /> // Open eye icon - )} - </span> - </div> - {password.length > 0 && ( - <div className="mt-1 text-[11px]"> - <p - className={`${ - lengthValid ? "text-green-600" : "text-red-600" - }`} - > - {lengthValid ? "✓" : "✗"} - {t("password-length")} - </p> - <p - className={`${ - caseDigitValid ? "text-green-600" : "text-red-600" - }`} - > - {caseDigitValid ? "✓" : "✗"} - {t("password-case")} - </p> - <p - className={`${ - specialCharValid - ? "text-green-600" - : "text-red-600" - }`} - > - {specialCharValid ? "✓" : "✗"}{" "} - {t("password-special-char")} - </p> - </div> - )} - <div className="mt-2.5 ml-1 flex flex-row items-center"> - <input - type="checkbox" - className="op-checkbox op-checkbox-sm" - id="termsandcondition" - checked={isAuthorize} - onChange={(e) => setIsAuthorize(e.target.checked)} - onInvalid={(e) => - e.target.setCustomValidity(t("input-required")) - } - onInput={(e) => e.target.setCustomValidity("")} - required - /> - <label - className="text-xs cursor-pointer ml-1 mb-0" - htmlFor="termsandcondition" - > - {t("agreee")} - </label> - <span - className="underline cursor-pointer ml-1" - onClick={() => - openInNewTab( - "https://www.opensignlabs.com/terms-and-conditions" - ) - } - > - {t("term")} - </span> - <span>.</span> - </div> - </div> - </div> - <div className="grid grid-cols-1 md:grid-cols-2 gap-2 text-center text-xs font-bold mt-2"> - <button - type="submit" - className="op-btn op-btn-primary" - disabled={state.loading} - > - {state.loading ? t("loading") : t("register")} - </button> - <button - type="button" - className="op-btn op-btn-secondary" - disabled={state.loading} - onClick={() => - navigate(location.search ? "/" + location.search : "/") - } - > - {t("login")} - </button> - </div> - </form> - </div> - {width >= 768 && ( - <div className="self-center"> - <div className="mx-auto md:w-[300px] lg:w-[400px] xl:w-[500px]"> - <img src={login_img} alt="loader" width="100%" /> - </div> - </div> - )} - </div> - </div> - <SelectLanguage /> - <Alert type={state.alertType}>{state.alertMsg}</Alert> - </div> - ) : ( - <div className="fixed w-full h-full flex justify-center items-center z-50"> - <Loader /> - </div> - )} - </div> - ); -}; - -export default Signup; diff --git a/apps/OpenSign/src/pages/SignyourselfPdf.js b/apps/OpenSign/src/pages/SignyourselfPdf.js index 721343130..dc03a2939 100644 --- a/apps/OpenSign/src/pages/SignyourselfPdf.js +++ b/apps/OpenSign/src/pages/SignyourselfPdf.js @@ -7,15 +7,15 @@ import axios from "axios"; import RenderAllPdfPage from "../components/pdf/RenderAllPdfPage"; import { DndProvider } from "react-dnd"; import { HTML5Backend } from "react-dnd-html5-backend"; -import { useDrag, useDrop } from "react-dnd"; +import { useDrop } from "react-dnd"; import SignPad from "../components/pdf/SignPad"; import EmailComponent from "../components/pdf/EmailComponent"; import WidgetComponent from "../components/pdf/WidgetComponent"; import { + getTenantDetails, contractDocument, embedDocId, multiSignEmbed, - onImageSelect, calculateInitialWidthHeight, defaultWidthHeight, onSaveImage, @@ -25,8 +25,6 @@ import { randomId, getDate, textWidget, - getTenantDetails, - checkIsSubscribed, convertPdfArrayBuffer, textInputWidget, fetchImageBase64, @@ -37,9 +35,14 @@ import { onClickZoomIn, onClickZoomOut, rotatePdfPage, - signatureTypes + signatureTypes, + getBase64FromUrl, + convertBase64ToFile, + generatePdfName, + handleRemoveWidgets, + compressedFileSize } from "../constant/Utils"; -import { useParams } from "react-router-dom"; +import { useParams } from "react-router"; import Tour from "reactour"; import Signedby from "../components/pdf/Signedby"; import Header from "../components/pdf/PdfHeader"; @@ -62,13 +65,18 @@ import LoaderWithMsg from "../primitives/LoaderWithMsg"; //For signYourself inProgress section signer can add sign and complete doc sign. function SignYourSelf() { const { t } = useTranslation(); + const { docId } = useParams(); + const divRef = useRef(null); + const nodeRef = useRef(null); + const imageRef = useRef(null); + const pdfRef = useRef(); + const numPages = 1; const [pdfDetails, setPdfDetails] = useState([]); const [isSignPad, setIsSignPad] = useState(false); const [allPages, setAllPages] = useState(null); const [pdfUrl, setPdfUrl] = useState(); - const [xyPostion, setXyPostion] = useState([]); + const [xyPosition, setXyPosition] = useState([]); const [defaultSignImg, setDefaultSignImg] = useState(); - const numPages = 1; const [pageNumber, setPageNumber] = useState(1); const [image, setImage] = useState(null); const [isImageSelect, setIsImageSelect] = useState(false); @@ -77,8 +85,6 @@ function SignYourSelf() { const [isEmail, setIsEmail] = useState(false); const [signBtnPosition, setSignBtnPosition] = useState([]); const [xySignature, setXYSignature] = useState({}); - const signRef = useRef(null); - const dragRef = useRef(null); const [dragKey, setDragKey] = useState(); const [fontSize, setFontSize] = useState(); const [fontColor, setFontColor] = useState(); @@ -87,7 +93,6 @@ function SignYourSelf() { const [pdfNewWidth, setPdfNewWidth] = useState(); const [pdfOriginalWH, setPdfOriginalWH] = useState([]); const [successEmail, setSuccessEmail] = useState(false); - const imageRef = useRef(null); const [myInitial, setMyInitial] = useState(""); const [isInitial, setIsInitial] = useState(false); const [isUiLoading, setIsUiLoading] = useState(false); @@ -99,7 +104,6 @@ function SignYourSelf() { const [handleError, setHandleError] = useState(""); const [isDragging, setIsDragging] = useState(false); const [signTour, setSignTour] = useState(true); - const { docId } = useParams(); const [checkTourStatus, setCheckTourStatus] = useState(false); const [signerUserId, setSignerUserId] = useState(); const [tourStatus, setTourStatus] = useState([]); @@ -122,38 +126,30 @@ function SignYourSelf() { const [isCompleted, setIsCompleted] = useState(false); const [isCelebration, setIsCelebration] = useState(false); const [pdfArrayBuffer, setPdfArrayBuffer] = useState(""); - const [activeMailAdapter, setActiveMailAdapter] = useState(""); const [isEmailVerified, setIsEmailVerified] = useState(true); const [isVerifyModal, setIsVerifyModal] = useState(false); const [otp, setOtp] = useState(""); const [zoomPercent, setZoomPercent] = useState(0); const isHeader = useSelector((state) => state.showHeader); const [scale, setScale] = useState(1); - const [pdfRotateBase64, setPdfRotatese64] = useState(""); - const [isRotate, setIsRotate] = useState({ status: false, degree: 0 }); - const [isSubscribe, setIsSubscribe] = useState({ plan: "", isValid: true }); + const [pdfBase64Url, setPdfBase64Url] = useState(""); + const [showRotateAlert, setShowRotateAlert] = useState({ + status: false, + degree: 0 + }); const [isDownloadModal, setIsDownloadModal] = useState(false); const [isResize, setIsResize] = useState(false); - const divRef = useRef(null); - const nodeRef = useRef(null); + const [isUploadPdf, setIsUploadPdf] = useState(false); + const [saveSignCheckbox, setSaveSignCheckbox] = useState({ + isVisible: false, + signId: "" + }); const [, drop] = useDrop({ accept: "BOX", drop: (item, monitor) => addPositionOfSignature(item, monitor), collect: (monitor) => ({ isOver: !!monitor.isOver() }) }); - const pdfRef = useRef(); - const [{ isDragSign }, dragSignature] = useDrag({ - type: "BOX", - item: { id: 1, text: "signature" }, - collect: (monitor) => ({ isDragSign: !!monitor.isDragging() }) - }); - const [{ isDragStamp }, dragStamp] = useDrag({ - type: "BOX", - item: { id: 2, text: "stamp" }, - collect: (monitor) => ({ isDragStamp: !!monitor.isDragging() }) - }); - - const index = xyPostion?.findIndex((object) => { + const index = xyPosition?.findIndex((object) => { return object.pageNumber === pageNumber; }); const rowLevel = @@ -202,12 +198,6 @@ function SignYourSelf() { //function for get document details for perticular signer with signer'object id const getDocumentDetails = async (showComplete) => { - try { - const subscribe = await checkIsSubscribed(); - setIsSubscribe(subscribe); - } catch (err) { - console.log("err in fetch sub", err); - } try { let isCompleted; //getting document details @@ -220,15 +210,19 @@ function SignYourSelf() { documentData[0]?.Placeholders?.length > 0 ? documentData[0]?.Placeholders : []; - setXyPostion(placeholders); - const url = documentData[0] && documentData[0]?.URL; + setXyPosition(placeholders); + const url = + documentData[0] && + (documentData[0]?.SignedUrl || documentData[0]?.URL); if (url) { //convert document url in array buffer format to use embed widgets in pdf using pdf-lib const arrayBuffer = await convertPdfArrayBuffer(url); + const base64Pdf = await getBase64FromUrl(url); if (arrayBuffer === "Error") { setHandleError(t("something-went-wrong-mssg")); } else { setPdfArrayBuffer(arrayBuffer); + setPdfBase64Url(base64Pdf); } } else { setHandleError(t("something-went-wrong-mssg")); @@ -248,7 +242,7 @@ function SignYourSelf() { setIsUiLoading(false); setIsSignPad(false); setIsEmail(true); - setXyPostion([]); + setXyPosition([]); setSignBtnPosition([]); } } @@ -265,20 +259,22 @@ function SignYourSelf() { //function to get default signatur eof current user from `contracts_Signature` class const defaultSignRes = await getDefaultSignature(jsonSender.objectId); if (defaultSignRes?.status === "success") { + setSaveSignCheckbox((prev) => ({ + ...prev, + isVisible: true, + signId: defaultSignRes?.res?.id + })); setDefaultSignImg(defaultSignRes?.res?.defaultSignature); setMyInitial(defaultSignRes?.res?.defaultInitial); - } else if (defaultSignRes?.status === "error") { - setHandleError("Error: Something went wrong!"); - setIsLoading({ isLoad: false }); } const contractUsersRes = await contractUsers(); if (contractUsersRes === "Error: Something went wrong!") { setHandleError(t("something-went-wrong-mssg")); setIsLoading({ isLoad: false }); } else if (contractUsersRes[0] && contractUsersRes.length > 0) { - setActiveMailAdapter(contractUsersRes[0]?.active_mail_adapter); setContractName("_Users"); setSignerUserId(contractUsersRes[0].objectId); + setSaveSignCheckbox((prev) => ({ ...prev, isVisible: true })); const tourstatuss = contractUsersRes[0].TourStatus && contractUsersRes[0].TourStatus; if (tourstatuss && tourstatuss.length > 0 && !isCompleted) { @@ -327,9 +323,7 @@ function SignYourSelf() { } catch (err) { console.log("Error: error in getDocumentDetails", err); setHandleError("Error: Something went wrong!"); - setIsLoading({ - isLoad: false - }); + setIsLoading({ isLoad: false }); } }; const getWidgetValue = (type) => { @@ -405,7 +399,7 @@ function SignYourSelf() { const key = randomId(); let dropData = []; let dropObj = {}; - let filterDropPos = xyPostion?.filter( + let filterDropPos = xyPosition?.filter( (data) => data.pageNumber === pageNumber ); const dragTypeValue = item?.text ? item.text : monitor.type; @@ -472,16 +466,16 @@ function SignYourSelf() { dropData.push(dropObj); } if (filterDropPos?.length > 0) { - const index = xyPostion?.findIndex((object) => { + const index = xyPosition?.findIndex((object) => { return object.pageNumber === pageNumber; }); const updateData = filterDropPos?.[0].pos; const newSignPos = updateData.concat(dropData); let xyPos = { pageNumber: pageNumber, pos: newSignPos }; - xyPostion?.splice(index, 1, xyPos); + xyPosition?.splice(index, 1, xyPos); } else { const xyPos = { pageNumber: pageNumber, pos: dropData }; - setXyPostion((prev) => [...prev, xyPos]); + setXyPosition((prev) => [...prev, xyPos]); } if ( @@ -556,22 +550,61 @@ function SignYourSelf() { }; useEffect(() => { const timer = setTimeout(() => { - if (xyPostion?.length > 0 && !pdfDetails?.[0]?.IsCompleted) { + if (!pdfDetails?.[0]?.IsCompleted) { autosavedetails(); } }, 2000); return () => clearTimeout(timer); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [xyPostion]); - + }, [xyPosition, pdfBase64Url]); // `autosavedetails` is used to save doc details after every 2 sec when changes are happern in placeholder like drag-drop widgets, remove signers const autosavedetails = async () => { + let pdfUrl; + if (isUploadPdf) { + const pdfName = generatePdfName(16); + pdfUrl = await convertBase64ToFile( + pdfName, + pdfBase64Url, + "", + ); + } + const widgetsType = ["signature", "stamp", "image", "initials"]; + let updatedXYPosition; + if (xyPosition.length > 0) { + updatedXYPosition = xyPosition.map((item) => ({ + ...item, + pos: item.pos.map((posItem) => { + if (widgetsType.includes(posItem.type)) { + // eslint-disable-next-line + const { SignUrl, ...rest } = posItem; + // eslint-disable-next-line + const { response, ...filteredOptions } = rest.options; + return { + ...rest, + options: filteredOptions + }; + } else { + return posItem; + } + }) + })); + } try { const docCls = new Parse.Object("contracts_Document"); docCls.id = documentId; - docCls.set("Placeholders", xyPostion); + if (xyPosition?.length > 0) { + docCls.set("Placeholders", updatedXYPosition); + } docCls.set("IsSignyourself", true); - await docCls.save(); + if (pdfUrl) { + docCls.set("URL", pdfUrl); + } + const res = await docCls.save(); + if (res) { + if (res) { + pdfDetails[0] = { ...pdfDetails[0], URL: pdfUrl }; + } + } } catch (e) { console.log("error", e); alert(t("something-went-wrong-mssg")); @@ -583,28 +616,31 @@ function SignYourSelf() { const currentUser = JSON.parse(JSON.stringify(Parse.User.current())); let isEmailVerified; isEmailVerified = currentUser?.emailVerified; - if (isEmailVerified) { - setIsEmailVerified(isEmailVerified); - } else { - try { - const userQuery = new Parse.Query(Parse.User); - const user = await userQuery.get(currentUser.objectId, { - sessionToken: localStorage.getItem("accesstoken") - }); - if (user) { - isEmailVerified = user?.get("emailVerified"); - setIsEmailVerified(isEmailVerified); + const isEnableOTP = pdfDetails?.[0]?.IsEnableOTP || false; + if (isEnableOTP) { + if (isEmailVerified) { + setIsEmailVerified(isEmailVerified); + } else { + try { + const userQuery = new Parse.Query(Parse.User); + const user = await userQuery.get(currentUser.objectId, { + sessionToken: localStorage.getItem("accesstoken") + }); + if (user) { + isEmailVerified = user?.get("emailVerified"); + setIsEmailVerified(isEmailVerified); + } + } catch (e) { + setHandleError(t("something-went-wrong-mssg")); } - } catch (e) { - setHandleError(t("something-went-wrong-mssg")); } } - if (isEmailVerified) { + if (!isEnableOTP || isEmailVerified) { let showAlert = false, isSignatureExist = false; try { - for (let i = 0; i < xyPostion?.length; i++) { - const requiredWidgets = xyPostion[i].pos.filter( + for (let i = 0; i < xyPosition?.length; i++) { + const requiredWidgets = xyPosition[i].pos.filter( (position) => position.type !== "checkbox" ); if (requiredWidgets && requiredWidgets?.length > 0) { @@ -623,12 +659,12 @@ function SignYourSelf() { } //condition to check exist signature widget or not if (!isSignatureExist) { - isSignatureExist = xyPostion[i].pos.some( + isSignatureExist = xyPosition[i].pos.some( (data) => data?.type === "signature" ); } } - if (xyPostion.length === 0 || !isSignatureExist) { + if (xyPosition.length === 0 || !isSignatureExist) { setIsAlert({ header: t("fields-required"), isShow: true, @@ -655,7 +691,7 @@ function SignYourSelf() { } //embed multi signature in pdf const pdfBytes = await multiSignEmbed( - xyPostion, + xyPosition, pdfDoc, isSignYourSelfFlow, scale @@ -712,15 +748,13 @@ function SignYourSelf() { //function for get digital signature const signPdfFun = async (base64Url, documentId) => { let isCustomCompletionMail = false; - const tenantDetails = await getTenantDetails(jsonSender.objectId); if (tenantDetails && tenantDetails === "user does not exist!") { alert(t("user-not-exist")); } else { if ( tenantDetails?.CompletionBody && - tenantDetails?.CompletionSubject && - isSubscribe?.isValid + tenantDetails?.CompletionSubject ) { isCustomCompletionMail = true; } @@ -728,7 +762,7 @@ function SignYourSelf() { // below for loop is used to get first signature of user to send if to signpdf // for adding it in completion certificate let getSignature; - for (let item of xyPostion) { + for (let item of xyPosition) { if (!getSignature) { const typeExist = item.pos.some((data) => data?.type); if (typeExist) { @@ -757,7 +791,6 @@ function SignYourSelf() { pdfFile: base64Url, docId: documentId, isCustomCompletionMail: isCustomCompletionMail, - mailProvider: activeMailAdapter, signature: suffixbase64 }; const resSignPdf = await Parse.Cloud.run("signPdf", params); @@ -765,7 +798,6 @@ function SignYourSelf() { const signedpdf = JSON.parse(JSON.stringify(resSignPdf)); setPdfUrl(signedpdf); getDocumentDetails(false); - setPdfRotatese64(""); } }; @@ -786,11 +818,11 @@ function SignYourSelf() { containerWH ); if (dragKey >= 0) { - const filterDropPos = xyPostion?.filter( + const filterDropPos = xyPosition?.filter( (data) => data.pageNumber === pageNumber ); if (filterDropPos?.length > 0) { - const getXYdata = xyPostion[index].pos; + const getXYdata = xyPosition[index].pos; const getPosData = getXYdata; const addSign = getPosData.map((url) => { if (url.key === dragKey) { @@ -803,13 +835,13 @@ function SignYourSelf() { return url; }); - const newUpdateUrl = xyPostion.map((obj, ind) => { + const newUpdateUrl = xyPosition.map((obj, ind) => { if (ind === index) { return { ...obj, pos: addSign }; } return obj; }); - setXyPostion(newUpdateUrl); + setXyPosition(newUpdateUrl); } } } @@ -838,18 +870,19 @@ function SignYourSelf() { //function for image upload or update const onImageChange = (event) => { if (event.target.files && event.target.files[0]) { - onImageSelect(event, setImgWH, setImage); + const file = event.target.files[0]; + compressedFileSize(file, setImgWH, setImage); } }; //function for upload stamp or image const saveImage = () => { - const getImage = onSaveImage(xyPostion, index, signKey, imgWH, image); - setXyPostion(getImage); + const getImage = onSaveImage(xyPosition, index, signKey, imgWH, image); + setXyPosition(getImage); }; //function for save button to save signature or image url - const saveSign = (type, isDefaultSign, width, height) => { + const saveSign = (type, isDefaultSign, width, height, typedSignature) => { const isTypeText = width && height ? true : false; const signatureImg = isDefaultSign ? isDefaultSign === "initials" @@ -869,16 +902,17 @@ function SignYourSelf() { } const getUpdatePosition = onSaveSign( type, - xyPostion, + xyPosition, index, signKey, signatureImg, imgWH, isDefaultSign, - isTypeText + isTypeText, + typedSignature ); - setXyPostion(getUpdatePosition); + setXyPosition(getUpdatePosition); }; //function for capture position on hover or touch widgets button const handleDivClick = (e) => { @@ -902,36 +936,31 @@ function SignYourSelf() { const handleMouseLeave = () => { setSignBtnPosition([xySignature]); }; - - const handleAllDelete = () => { - setXyPostion([]); - }; - //function for delete signature block const handleDeleteSign = (key) => { setCurrWidgetsDetails({}); const updateResizeData = []; - let filterData = xyPostion[index].pos.filter((data) => data.key !== key); + let filterData = xyPosition[index].pos.filter((data) => data.key !== key); //delete and update block position if (filterData.length > 0) { updateResizeData.push(filterData); - const newUpdatePos = xyPostion.map((obj, ind) => { + const newUpdatePos = xyPosition.map((obj, ind) => { if (ind === index) { return { ...obj, pos: updateResizeData[0] }; } return obj; }); - setXyPostion(newUpdatePos); + setXyPosition(newUpdatePos); } else { - const getRemainPage = xyPostion.filter( + const getRemainPage = xyPosition.filter( (data) => data.pageNumber !== pageNumber ); if (getRemainPage && getRemainPage.length > 0) { - setXyPostion(getRemainPage); + setXyPosition(getRemainPage); } else { - setXyPostion([]); + setXyPosition([]); } } }; @@ -1020,7 +1049,7 @@ function SignYourSelf() { defaultValue, isHideLabel ) => { - const getPageNumer = xyPostion.filter( + const getPageNumer = xyPosition.filter( (data) => data.pageNumber === pageNumber ); if (getPageNumer.length > 0) { @@ -1061,13 +1090,13 @@ function SignYourSelf() { } return position; }); - const updateXYposition = xyPostion.map((obj, ind) => { + const updateXYposition = xyPosition.map((obj, ind) => { if (ind === index) { return { ...obj, pos: addSignPos }; } return obj; }); - setXyPostion(updateXYposition); + setXyPosition(updateXYposition); if (!addOption && !deleteOption) { handleCloseModal(); } @@ -1083,7 +1112,7 @@ function SignYourSelf() { setIsTextSetting(value); }; const handleSaveFontSize = () => { - const getPageNumer = xyPostion.filter( + const getPageNumer = xyPosition.filter( (data) => data.pageNumber === pageNumber ); if (getPageNumer.length > 0) { @@ -1103,13 +1132,13 @@ function SignYourSelf() { } return position; }); - const updateXYposition = xyPostion.map((obj, ind) => { + const updateXYposition = xyPosition.map((obj, ind) => { if (ind === index) { return { ...obj, pos: addSignPos }; } return obj; }); - setXyPostion(updateXYposition); + setXyPosition(updateXYposition); setFontSize(); setFontColor(); handleTextSettingModal(false); @@ -1125,22 +1154,22 @@ function SignYourSelf() { const handleRotationFun = async (rotateDegree) => { const isPlaceholder = handleRotateWarning(); if (isPlaceholder) { - setIsRotate({ status: true, degree: rotateDegree }); + setShowRotateAlert({ status: true, degree: rotateDegree }); } else { + setIsUploadPdf(true); const urlDetails = await rotatePdfPage( - pdfUrl || pdfDetails[0].URL, rotateDegree, pageNumber - 1, - pdfRotateBase64 + pdfArrayBuffer ); - setPdfArrayBuffer && setPdfArrayBuffer(urlDetails.arrayBuffer); - setPdfRotatese64(urlDetails.base64); + setPdfArrayBuffer(urlDetails.arrayBuffer); + setPdfBase64Url(urlDetails.base64); } }; //function to show warning when user rotate page and there are some already widgets on that page const handleRotateWarning = () => { - const placeholderData = xyPostion?.filter( + const placeholderData = xyPosition?.filter( (data) => data.pageNumber === pageNumber ); if (placeholderData && placeholderData.length > 0) { @@ -1150,24 +1179,25 @@ function SignYourSelf() { } }; //function to use remove widgets from current page when user want to rotate page - const handleRemoveWidgets = async () => { - const updatePlaceholder = xyPostion.filter( - (data) => data.pageNumber !== pageNumber + const handleRemovePlaceholder = async () => { + handleRemoveWidgets( + setXyPosition, + xyPosition, + pageNumber, + setShowRotateAlert ); const urlDetails = await rotatePdfPage( - pdfUrl || pdfDetails[0].URL, - isRotate.degree, + showRotateAlert.degree, pageNumber - 1, - pdfRotateBase64 + pdfArrayBuffer ); - setPdfArrayBuffer && setPdfArrayBuffer(urlDetails.arrayBuffer); - setPdfRotatese64(urlDetails.base64); - setXyPostion(updatePlaceholder); - setIsRotate({ status: false, degree: 0 }); + setPdfArrayBuffer(urlDetails.arrayBuffer); + setPdfBase64Url(urlDetails.base64); + setShowRotateAlert({ status: false, degree: 0 }); }; return ( <DndProvider backend={HTML5Backend}> - <Title title={"Self Sign"} /> + <Title title={"signyourself"} /> {isLoading.isLoad ? ( <LoaderWithMsg isLoading={isLoading} /> ) : handleError ? ( @@ -1219,22 +1249,36 @@ function SignYourSelf() { {/* this component used to render all pdf pages in left side */} <RenderAllPdfPage - signPdfUrl={ - pdfDetails[0] && (pdfDetails[0].SignedUrl || pdfDetails[0].URL) - } allPages={allPages} setAllPages={setAllPages} setPageNumber={setPageNumber} setSignBtnPosition={setSignBtnPosition} pageNumber={pageNumber} containerWH={containerWH} - pdfRotateBase64={pdfRotateBase64} + pdfBase64Url={pdfBase64Url} + signedUrl={pdfDetails?.[0]?.SignedUrl || ""} + setPdfArrayBuffer={setPdfArrayBuffer} + setPdfBase64Url={setPdfBase64Url} + setIsUploadPdf={setIsUploadPdf} + pdfArrayBuffer={pdfArrayBuffer} + isMergePdfBtn={true} /> <div className=" w-full md:w-[57%] flex mr-4"> <PdfZoom clickOnZoomIn={clickOnZoomIn} clickOnZoomOut={clickOnZoomOut} handleRotationFun={handleRotationFun} + pdfArrayBuffer={pdfArrayBuffer} + pageNumber={pageNumber} + setPdfBase64Url={setPdfBase64Url} + setPdfArrayBuffer={setPdfArrayBuffer} + setIsUploadPdf={setIsUploadPdf} + setSignerPos={setXyPosition} + signerPos={xyPosition} + allPages={allPages} + setAllPages={setAllPages} + setPageNumber={setPageNumber} + isDisableEditTools={isCompleted} /> <div className="w-full md:w-[95%]"> <ModalUi @@ -1275,47 +1319,53 @@ function SignYourSelf() { handleSaveWidgetsOptions={handleSaveWidgetsOptions} currWidgetsDetails={currWidgetsDetails} setCurrWidgetsDetails={setCurrWidgetsDetails} - isSignYourself={true} handleClose={handleCloseModal} fontSize={fontSize} setFontSize={setFontSize} fontColor={fontColor} setFontColor={setFontColor} + isShowAdvanceFeature={false} /> <PlaceholderCopy isPageCopy={isPageCopy} setIsPageCopy={setIsPageCopy} - xyPostion={xyPostion} - setXyPostion={setXyPostion} + xyPosition={xyPosition} + setXyPosition={setXyPosition} allPages={allPages} pageNumber={pageNumber} signKey={signKey} widgetType={widgetType} /> {/* this is modal of signature pad */} - <SignPad - signatureTypes={signatureTypes} - isSignPad={isSignPad} - isStamp={isStamp} - setIsImageSelect={setIsImageSelect} - setIsSignPad={setIsSignPad} - setImage={setImage} - isImageSelect={isImageSelect} - imageRef={imageRef} - onImageChange={onImageChange} - setSignature={setSignature} - image={image} - onSaveImage={saveImage} - onSaveSign={saveSign} - defaultSign={defaultSignImg} - myInitial={myInitial} - isInitial={isInitial} - setIsInitial={setIsInitial} - setIsStamp={setIsStamp} - widgetType={widgetType} - currWidgetsDetails={currWidgetsDetails} - setCurrWidgetsDetails={setCurrWidgetsDetails} - /> + {isSignPad && ( + <SignPad + saveSignCheckbox={saveSignCheckbox} + setSaveSignCheckbox={setSaveSignCheckbox} + signatureTypes={signatureTypes} + isSignPad={isSignPad} + isStamp={isStamp} + setIsImageSelect={setIsImageSelect} + setIsSignPad={setIsSignPad} + setImage={setImage} + isImageSelect={isImageSelect} + imageRef={imageRef} + onImageChange={onImageChange} + setSignature={setSignature} + image={image} + onSaveImage={saveImage} + onSaveSign={saveSign} + defaultSign={defaultSignImg} + myInitial={myInitial} + setDefaultSignImg={setDefaultSignImg} + setMyInitial={setMyInitial} + isInitial={isInitial} + setIsInitial={setIsInitial} + setIsStamp={setIsStamp} + widgetType={widgetType} + currWidgetsDetails={currWidgetsDetails} + setCurrWidgetsDetails={setCurrWidgetsDetails} + /> + )} {/*render email component to send email after finish signature on document */} <EmailComponent isEmail={isEmail} @@ -1326,7 +1376,6 @@ function SignYourSelf() { sender={jsonSender} setIsAlert={setIsAlert} extUserId={extUserId} - activeMailAdapter={activeMailAdapter} setIsDownloadModal={setIsDownloadModal} /> {/* pdf header which contain funish back button */} @@ -1334,7 +1383,6 @@ function SignYourSelf() { pageNumber={pageNumber} allPages={allPages} changePage={changePage} - pdfUrl={pdfUrl} embedWidgetsData={embedWidgetsData} pdfDetails={pdfDetails} isShowHeader={true} @@ -1346,8 +1394,15 @@ function SignYourSelf() { handleRotationFun={handleRotationFun} clickOnZoomIn={clickOnZoomIn} clickOnZoomOut={clickOnZoomOut} - widgetsDetails={xyPostion} + widgetsDetails={xyPosition} setIsDownloadModal={setIsDownloadModal} + setIsUploadPdf={setIsUploadPdf} + pdfArrayBuffer={pdfArrayBuffer} + setPdfArrayBuffer={setPdfArrayBuffer} + setPdfBase64Url={setPdfBase64Url} + setSignerPos={setXyPosition} + signerPos={xyPosition} + pdfBase64={pdfBase64Url} /> <div ref={divRef} data-tut="reactourSecond" className="h-full"> {containerWH?.width && containerWH?.height && ( @@ -1367,14 +1422,14 @@ function SignYourSelf() { setSignKey={setSignKey} pdfDetails={pdfDetails} setIsDragging={setIsDragging} - xyPostion={xyPostion} + xyPosition={xyPosition} pdfRef={pdfRef} pdfUrl={pdfUrl} numPages={numPages} pageDetails={pageDetails} pdfLoad={pdfLoad} setPdfLoad={setPdfLoad} - setXyPostion={setXyPostion} + setXyPosition={setXyPosition} index={index} containerWH={containerWH} setIsPageCopy={setIsPageCopy} @@ -1388,13 +1443,14 @@ function SignYourSelf() { handleTextSettingModal={handleTextSettingModal} setScale={setScale} scale={scale} - pdfRotateBase64={pdfRotateBase64} + pdfBase64Url={pdfBase64Url} fontSize={fontSize} setFontSize={setFontSize} fontColor={fontColor} setFontColor={setFontColor} isResize={isResize} setIsResize={setIsResize} + divRef={divRef} /> )} </div> @@ -1406,19 +1462,13 @@ function SignYourSelf() { <div> <WidgetComponent pdfUrl={pdfUrl} - dragSignature={dragSignature} - signRef={signRef} handleDivClick={handleDivClick} handleMouseLeave={handleMouseLeave} - isDragSign={isDragSign} - dragStamp={dragStamp} - dragRef={dragRef} - isDragStamp={isDragStamp} - handleAllDelete={handleAllDelete} - xyPostion={xyPostion} + xyPosition={xyPosition} isSignYourself={true} addPositionOfSignature={addPositionOfSignature} isMailSend={false} + // setSelectWidgetId={setSelectWidgetId} /> </div> ) : ( @@ -1450,15 +1500,16 @@ function SignYourSelf() { </div> </ModalUi> <RotateAlert - isRotate={isRotate.status} - setIsRotate={setIsRotate} - handleRemoveWidgets={handleRemoveWidgets} + showRotateAlert={showRotateAlert.status} + setShowRotateAlert={setShowRotateAlert} + handleRemoveWidgets={handleRemovePlaceholder} /> <DownloadPdfZip setIsDownloadModal={setIsDownloadModal} isDownloadModal={isDownloadModal} pdfDetails={pdfDetails} isDocId={true} + pdfBase64={pdfBase64Url} /> <TextFontSetting isTextSetting={isTextSetting} diff --git a/apps/OpenSign/src/pages/TeamList.js b/apps/OpenSign/src/pages/TeamList.js deleted file mode 100644 index 1e8092983..000000000 --- a/apps/OpenSign/src/pages/TeamList.js +++ /dev/null @@ -1,490 +0,0 @@ -import React, { useEffect, useState } from "react"; -import Parse from "parse"; -import Alert from "../primitives/Alert"; -import Loader from "../primitives/Loader"; -import { useLocation } from "react-router-dom"; -import Tooltip from "../primitives/Tooltip"; -import ModalUi from "../primitives/ModalUi"; -import pad from "../assets/images/pad.svg"; -import AddTeam from "../components/AddTeam"; -import { isEnableSubscription } from "../constant/const"; -import { checkIsSubscribed } from "../constant/Utils"; -import SubscribeCard from "../primitives/SubscribeCard"; -import Title from "../components/Title"; -import { validplan } from "../json/plansArr"; -import { useTranslation } from "react-i18next"; - -const heading = ["Sr.No", "Name", "Parent Team", "Active"]; -const actions = [ - { - btnId: "1231", - hoverLabel: "Edit", - btnColor: "op-btn-primary", - btnIcon: "fa-light fa-pen", - redirectUrl: "", - action: "edit" - } -]; - -const TeamList = () => { - const { t } = useTranslation(); - const recordperPage = 10; - const [teamList, setTeamList] = useState([]); - const [isLoader, setIsLoader] = useState(false); - const [isModal, setIsModal] = useState(false); - const location = useLocation(); - const isDashboard = - location?.pathname === "/dashboard/35KBoSgoAK" ? true : false; - const [currentPage, setCurrentPage] = useState(1); - const [isActiveModal, setIsActiveModal] = useState({}); - const [isAlert, setIsAlert] = useState({ type: "success", msg: "" }); - const [isActLoader, setIsActLoader] = useState({}); - const [isSubscribe, setIsSubscribe] = useState({ plan: "", isValid: false }); - const [isEditModal, setIsEditModal] = useState({}); - const [isAdmin, setIsAdmin] = useState(false); - const startIndex = (currentPage - 1) * recordperPage; // user per page - - const getPaginationRange = () => { - const totalPageNumbers = 7; // Adjust this value to show more/less page numbers - const pages = []; - const totalPages = Math.ceil(teamList.length / recordperPage); - if (totalPages <= totalPageNumbers) { - for (let i = 1; i <= totalPages; i++) { - pages.push(i); - } - } else { - const leftSiblingIndex = Math.max(currentPage - 1, 1); - const rightSiblingIndex = Math.min(currentPage + 1, totalPages); - - const showLeftDots = leftSiblingIndex > 2; - const showRightDots = rightSiblingIndex < totalPages - 2; - - const firstPageIndex = 1; - const lastPageIndex = totalPages; - - if (!showLeftDots && showRightDots) { - let leftItemCount = 3; - let leftRange = Array.from({ length: leftItemCount }, (_, i) => i + 1); - - pages.push(...leftRange); - pages.push("..."); - pages.push(totalPages); - } else if (showLeftDots && !showRightDots) { - let rightItemCount = 3; - let rightRange = Array.from( - { length: rightItemCount }, - (_, i) => totalPages - rightItemCount + i + 1 - ); - - pages.push(firstPageIndex); - pages.push("..."); - pages.push(...rightRange); - } else if (showLeftDots && showRightDots) { - let middleRange = Array.from( - { length: 3 }, - (_, i) => leftSiblingIndex + i - ); - - pages.push(firstPageIndex); - pages.push("..."); - pages.push(...middleRange); - pages.push("..."); - pages.push(lastPageIndex); - } - } - - return pages; - }; - const pageNumbers = getPaginationRange(); - useEffect(() => { - fetchTeamList(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - async function fetchTeamList() { - try { - setIsLoader(true); - if (isEnableSubscription) { - const subscribe = await checkIsSubscribed(); - setIsSubscribe(subscribe); - } - const extUser = JSON.parse(localStorage.getItem("Extand_Class"))?.[0]; - if (extUser) { - const admin = - extUser?.UserRole && - (extUser?.UserRole === "contracts_Admin" || - extUser?.UserRole === "contracts_OrgAdmin") - ? true - : false; - setIsAdmin(admin); - } - const teams = await Parse.Cloud.run("getteams"); - if (teams.length > 0) { - const _teamRes = JSON.parse(JSON.stringify(teams)); - setTeamList(_teamRes); - } - } catch (err) { - console.log("Err in fetch teamlist", err); - setIsAlert({ type: "danger", msg: t("something-went-wrong-mssg") }); - } finally { - setTimeout(() => { - setIsAlert({ type: "success", msg: "" }); - }, 1500); - setIsLoader(false); - } - } - const handleFormModal = () => { - setIsModal(!isModal); - }; - // to slice out 10 objects from array for current page - const indexOfLastDoc = currentPage * recordperPage; - const indexOfFirstDoc = indexOfLastDoc - recordperPage; - const currentList = teamList?.slice(indexOfFirstDoc, indexOfLastDoc); - - const handleClose = () => { - setIsActiveModal({}); - setIsEditModal({}); - }; - - // Change page - const paginateFront = () => { - const lastValue = pageNumbers?.[pageNumbers?.length - 1]; - if (currentPage < lastValue) { - setCurrentPage(currentPage + 1); - } - }; - - const paginateBack = () => { - if (startIndex > 0) { - setCurrentPage(currentPage - 1); - } - }; - - const handleActionBtn = (act, item) => { - if (act.action === "edit") { - setIsEditModal({ [item.objectId]: true }); - } - }; - const handleToggleBtn = (team) => { - setIsActiveModal({ [team.objectId]: true }); - }; - const handleToggleSubmit = async (team) => { - const index = teamList.findIndex((obj) => obj.objectId === team.objectId); - if (index !== -1) { - setIsActiveModal({}); - setIsActLoader({ [team.objectId]: true }); - const newArray = [...teamList]; - const IsActive = newArray[index].IsActive; - newArray[index] = { ...newArray[index], IsActive: !IsActive }; - setTeamList(newArray); - try { - await Parse.Cloud.run("updateteam", { - IsActive: !IsActive === false ? "false" : "true", - TeamId: team.objectId - }); - // console.log("teamRes ", teamRes); - setIsAlert({ - type: !IsActive === false ? "danger" : "success", - msg: !IsActive === false ? t("team-disabled") : t("team-enabled") - }); - } catch (err) { - setIsAlert({ type: "danger", msg: t("something-went-wrong-mssg") }); - console.log("err in disable team", err); - } finally { - setIsActLoader({}); - setTimeout(() => setIsAlert({ type: "success", msg: "" }), 1500); - } - } - }; - const handleTeamInfo = (team) => { - setTeamList((prev) => [team, ...prev]); - }; - const handleEditChange = (e, team) => { - const index = teamList.findIndex((obj) => obj.objectId === team.objectId); - if (index !== -1) { - const newArray = [...teamList]; - newArray[index] = { ...newArray[index], Name: e.target.value }; - setTeamList(newArray); - } - }; - const updateTeamName = async (e, team) => { - e.preventDefault(); - e.stopPropagation(); - setIsActLoader({ [team.objectId]: true }); - setIsEditModal({}); - try { - const data = { Name: team.Name, TeamId: team.objectId }; - await Parse.Cloud.run("updateteam", data); - // console.log("updateTeamRes ", updateTeamRes); - setIsAlert({ type: "success", msg: t("Team-update-successfully") }); - } catch (Err) { - console.log("Err in update team name"), Err; - setIsAlert({ type: "danger", msg: t("something-went-wrong-mssg") }); - } finally { - setIsActLoader({}); - setTimeout(() => setIsAlert({ type: "success", msg: "" }), 1500); - } - }; - return ( - <div className="relative"> - <Title title={"Teams"} /> - {isLoader && ( - <div className="absolute w-full h-[300px] md:h-[400px] flex justify-center items-center z-30 rounded-box"> - <Loader /> - </div> - )} - {Object.keys(isActLoader)?.length > 0 && ( - <div className="absolute w-full h-full flex justify-center items-center bg-black bg-opacity-30 z-30 rounded-box"> - <Loader /> - </div> - )} - {validplan[isSubscribe.plan] && isEnableSubscription && !isLoader && ( - <> - {isAdmin ? ( - <div className="p-2 w-full bg-base-100 text-base-content op-card shadow-lg"> - {isAlert.msg && <Alert type={isAlert.type}>{isAlert.msg}</Alert>} - <div className="flex flex-row items-center justify-between my-2 mx-3 text-[20px] md:text-[23px]"> - <div className="font-light"> - {t("report-name.Teams")} - <span className="text-xs md:text-[13px] font-normal"> - <Tooltip message={t("report-heading.Team")} /> - </span> - </div> - <div - className="cursor-pointer" - onClick={() => handleFormModal()} - > - <i className="fa-light fa-square-plus text-accent text-[40px]"></i> - </div> - </div> - <div className={` overflow-x-auto w-full`}> - <table className="op-table border-collapse w-full"> - <thead className="text-[14px]"> - <tr className="border-y-[1px]"> - {heading?.map((item, index) => ( - <React.Fragment key={index}> - <th className="px-4 py-2"> - {t(`report-heading.${item}`)} - </th> - </React.Fragment> - ))} - </tr> - </thead> - <tbody className="text-[12px]"> - {teamList?.length > 0 && ( - <> - {currentList.map((item, index) => ( - <tr className="border-y-[1px]" key={index}> - {heading.includes("Sr.No") && ( - <th className="px-4 py-2"> - {startIndex + index + 1} - </th> - )} - <td className="px-4 py-2 font-semibold"> - {item?.Name} - </td> - <td className="px-4 py-2 font-semibold"> - {item?.ParentId?.Name || "-"} - </td> - <td className="px-4 py-2 font-semibold"> - {item?.Name !== "All Users" && ( - <> - <label className="cursor-pointer relative block items-center mb-0"> - <input - type="checkbox" - className="op-toggle transition-all op-toggle-secondary" - checked={item?.IsActive} - onChange={() => handleToggleBtn(item)} - /> - </label> - {isActiveModal[item.objectId] && ( - <ModalUi - isOpen - title={t("Team status")} - handleClose={handleClose} - > - <div className="m-[20px]"> - <div className="text-lg font-normal text-black"> - {t("are-you-sure")}{" "} - {item?.IsActive - ? t("disable") - : t("enable")}{" "} - {t("this-team")} - </div> - <hr className="bg-[#ccc] mt-4 " /> - <div className="flex items-center mt-3 gap-2 text-white"> - <button - onClick={() => - handleToggleSubmit(item) - } - className="op-btn op-btn-primary" - > - {t("yes")} - </button> - <button - onClick={handleClose} - className="op-btn op-btn-secondary" - > - {t("no")} - </button> - </div> - </div> - </ModalUi> - )} - </> - )} - </td> - <td className="px-3 py-2 text-white flex flex-wrap gap-1"> - {item?.Name !== "All Users" && ( - <> - {actions?.length > 0 && - actions.map((act, index) => ( - <button - key={index} - onClick={() => - handleActionBtn(act, item) - } - title={act.hoverLabel} - className={`${ - act?.btnColor ? act.btnColor : "" - } op-btn op-btn-sm w-[50px]`} - > - <i className={act.btnIcon}></i> - </button> - ))} - {isEditModal[item.objectId] && ( - <ModalUi - isOpen - title={t("edit-team")} - handleClose={handleClose} - > - <form - className="m-[20px]" - onSubmit={(e) => - updateTeamName(e, item) - } - > - <label className="text-xs font-semibold text-base-content ml-1"> - {t("name-of-team")}{" "} - <span className="text-[red] text-[13px]"> - * - </span> - </label> - <input - className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content text-base-content w-full text-xs" - value={item.Name} - onChange={(e) => - handleEditChange(e, item) - } - onInvalid={(e) => - e.target.setCustomValidity( - t("input-required") - ) - } - onInput={(e) => - e.target.setCustomValidity("") - } - required - /> - <button - type="submit" - className="op-btn op-btn-primary mt-3" - > - {t("save")} - </button> - </form> - </ModalUi> - )} - </> - )} - </td> - </tr> - ))} - </> - )} - </tbody> - </table> - </div> - <div className="op-join flex flex-wrap items-center p-2"> - {teamList.length > recordperPage && ( - <button - onClick={() => paginateBack()} - className="op-join-item op-btn op-btn-sm" - > - {t("prev")} - </button> - )} - {pageNumbers.map((x, i) => ( - <button - key={i} - onClick={() => setCurrentPage(x)} - disabled={x === "..."} - className={`${ - x === currentPage ? "op-btn-active" : "" - } op-join-item op-btn op-btn-sm`} - > - {x} - </button> - ))} - {teamList.length > recordperPage && ( - <button - onClick={() => paginateFront()} - className="op-join-item op-btn op-btn-sm" - > - {t("next")} - </button> - )} - </div> - {teamList?.length <= 0 && ( - <div - className={`${ - isDashboard ? "h-[317px]" : "" - } flex flex-col items-center justify-center w-ful bg-base-100 text-base-content rounded-xl py-4`} - > - <div className="w-[60px] h-[60px] overflow-hidden"> - <img - className="w-full h-full object-contain" - src={pad} - alt="img" - /> - </div> - <div className="text-sm font-semibold"> - {t("no-data-avaliable")} - </div> - </div> - )} - <ModalUi - title={t("add-team")} - isOpen={isModal} - handleClose={handleFormModal} - > - <AddTeam - setIsAlert={setIsAlert} - handleTeamInfo={handleTeamInfo} - closePopup={handleFormModal} - /> - </ModalUi> - </div> - ) : ( - <div className="flex items-center justify-center h-screen w-full bg-base-100 text-base-content rounded-box"> - <div className="text-center"> - <h1 className="text-[60px] lg:text-[120px] font-semibold"> - 404 - </h1> - <p className="text-[30px] lg:text-[50px]"> - {t("page-not-found")} - </p> - </div> - </div> - )} - </> - )} - {isEnableSubscription && !validplan[isSubscribe.plan] && !isLoader && ( - <div data-tut="apisubscribe"> - <SubscribeCard plan="TEAMS" /> - </div> - )} - </div> - ); -}; - -export default TeamList; diff --git a/apps/OpenSign/src/pages/TemplatePlaceholder.js b/apps/OpenSign/src/pages/TemplatePlaceholder.js index 20e534c80..9c6c0b5eb 100644 --- a/apps/OpenSign/src/pages/TemplatePlaceholder.js +++ b/apps/OpenSign/src/pages/TemplatePlaceholder.js @@ -1,12 +1,11 @@ import React, { useEffect, useState, useRef } from "react"; import RenderAllPdfPage from "../components/pdf/RenderAllPdfPage"; -import { useParams, useNavigate } from "react-router-dom"; +import { useParams, useNavigate } from "react-router"; import axios from "axios"; import "../styles/signature.css"; -import { isEnableSubscription } from "../constant/const"; import { DndProvider } from "react-dnd"; import { HTML5Backend } from "react-dnd-html5-backend"; -import { useDrag, useDrop } from "react-dnd"; +import { useDrop } from "react-dnd"; import WidgetComponent from "../components/pdf/WidgetComponent"; import Tour from "reactour"; import SignerListPlace from "../components/pdf/SignerListPlace"; @@ -22,7 +21,6 @@ import { addWidgetOptions, textInputWidget, radioButtonWidget, - fetchSubscription, getContainerScale, convertBase64ToFile, rotatePdfPage, @@ -33,7 +31,10 @@ import { color, signatureTypes, getTenantDetails, - handleSignatureType + handleSignatureType, + getBase64FromUrl, + convertPdfArrayBuffer, + generatePdfName } from "../constant/Utils"; import RenderPdf from "../components/pdf/RenderPdf"; import "../styles/AddUser.css"; @@ -55,13 +56,13 @@ import LinkUserModal from "../primitives/LinkUserModal"; const TemplatePlaceholder = () => { const { t } = useTranslation(); - const navigate = useNavigate(); - const isHeader = useSelector((state) => state.showHeader); const { templateId } = useParams(); - const [pdfDetails, setPdfDetails] = useState([]); - const [isMailSend, setIsMailSend] = useState(false); - const [allPages, setAllPages] = useState(null); + const divRef = useRef(null); + const navigate = useNavigate(); const numPages = 1; + const isHeader = useSelector((state) => state.showHeader); + const [pdfDetails, setPdfDetails] = useState([]); + const [allPages, setAllPages] = useState(null); const [pageNumber, setPageNumber] = useState(1); const [signBtnPosition, setSignBtnPosition] = useState([]); const [xySignature, setXYSignature] = useState({}); @@ -71,14 +72,17 @@ const TemplatePlaceholder = () => { const [isSelectListId, setIsSelectId] = useState(); const [isSendAlert, setIsSendAlert] = useState(false); const [isCreateDocModal, setIsCreateDocModal] = useState(false); - const [isSubscribe, setIsSubscribe] = useState(false); - const [isRotate, setIsRotate] = useState({ status: false, degree: 0 }); + //'signersName' variable used to show all signer's name that do not have a signature widget assigned + const [signersName, setSignersName] = useState(""); + const [showRotateAlert, setShowRotateAlert] = useState({ + status: false, + degree: 0 + }); const [isLoading, setIsLoading] = useState({ isLoad: true, message: t("loading-mssg") }); const [handleError, setHandleError] = useState(); - const [currentEmail, setCurrentEmail] = useState(); const [pdfNewWidth, setPdfNewWidth] = useState(); const [templateTour, setTemplateTour] = useState(true); const [checkTourStatus, setCheckTourStatus] = useState(false); @@ -86,9 +90,6 @@ const TemplatePlaceholder = () => { const [signerUserId, setSignerUserId] = useState(); const [pdfOriginalWH, setPdfOriginalWH] = useState([]); const [containerWH, setContainerWH] = useState(); - const signRef = useRef(null); - const dragRef = useRef(null); - const divRef = useRef(null); const [isShowEmail, setIsShowEmail] = useState(false); const [selectedEmail, setSelectedEmail] = useState(false); const [isResize, setIsResize] = useState(false); @@ -102,23 +103,14 @@ const TemplatePlaceholder = () => { const [isNameModal, setIsNameModal] = useState(false); const [isTextSetting, setIsTextSetting] = useState(false); const [pdfLoad, setPdfLoad] = useState(false); - const [pdfRotateBase64, setPdfRotatese64] = useState(""); + const [pdfBase64Url, setPdfBase64Url] = useState(""); + const [isUploadPdf, setIsUploadPdf] = useState(false); const isMobile = window.innerWidth < 767; const [, drop] = useDrop({ accept: "BOX", drop: (item, monitor) => addPositionOfSignature(item, monitor), collect: (monitor) => ({ isOver: !!monitor.isOver() }) }); - const [{ isDragSign }, dragSignature] = useDrag({ - type: "BOX", - item: { type: "BOX", id: 1, text: "signature" }, - collect: (monitor) => ({ isDragSign: !!monitor.isDragging() }) - }); - const [{ isDragStamp }, dragStamp] = useDrag({ - type: "BOX", - item: { type: "BOX", id: 2, text: "stamp" }, - collect: (monitor) => ({ isDragStamp: !!monitor.isDragging() }) - }); const [uniqueId, setUniqueId] = useState(""); const [isModalRole, setIsModalRole] = useState(false); const [roleName, setRoleName] = useState(""); @@ -139,7 +131,7 @@ const TemplatePlaceholder = () => { const [zoomPercent, setZoomPercent] = useState(0); const [scale, setScale] = useState(1); const [signatureType, setSignatureType] = useState([]); - + const [pdfArrayBuffer, setPdfArrayBuffer] = useState(""); useEffect(() => { fetchTemplate(); // eslint-disable-next-line react-hooks/exhaustive-deps @@ -166,26 +158,6 @@ const TemplatePlaceholder = () => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [divRef.current, isHeader]); - const handleNavigation = () => { - navigate("/subscription"); - }; - async function checkIsSubscribed() { - const res = await fetchSubscription(); - const plan = res.plan; - const billingDate = res.billingDate; - if (plan === "freeplan") { - return true; - } else if (billingDate) { - if (new Date(billingDate) > new Date()) { - setIsSubscribe(true); - return true; - } else { - handleNavigation(plan); - } - } else { - handleNavigation(plan); - } - } //function to fetch tenant Details const fetchTenantDetails = async () => { @@ -236,8 +208,16 @@ const TemplatePlaceholder = () => { : []; if (documentData && documentData.length > 0) { - if (isEnableSubscription) { - checkIsSubscribed(documentData[0]?.ExtUserPtr?.Email); + const url = documentData[0] && documentData[0]?.URL; + if (url) { + const arrayBuffer = await convertPdfArrayBuffer(url); + const base64Pdf = await getBase64FromUrl(url); + if (arrayBuffer === "Error") { + setHandleError(t("something-went-wrong-mssg")); + } else { + setPdfBase64Url(base64Pdf); + setPdfArrayBuffer(arrayBuffer); + } } const userSignatureType = documentData[0]?.ExtUserPtr?.SignatureType || signatureTypes; @@ -318,7 +298,6 @@ const TemplatePlaceholder = () => { const res = await contractUsers(); if (res[0] && res.length) { setSignerUserId(res[0].objectId); - setCurrentEmail(res[0].Email); const tourstatus = res[0].TourStatus && res[0].TourStatus; if (tourstatus && tourstatus.length > 0) { setTourStatus(tourstatus); @@ -478,7 +457,6 @@ const TemplatePlaceholder = () => { setWidgetType(dragTypeValue); setSignKey(key); setSelectWidgetId(key); - setIsMailSend(false); } else { setIsReceipent(false); } @@ -575,7 +553,6 @@ const TemplatePlaceholder = () => { } } } - setIsMailSend(false); setTimeout(() => setIsDragging(false), 200); }; //function for delete signature block @@ -680,23 +657,36 @@ const TemplatePlaceholder = () => { if (isPlaceholderExist) { handleSaveTemplate(); } else { + const signerList = signerPos.filter((data) => !data.placeHolder); + const getSigner = signerList.map((x) => { + return signersdata.find((y) => y.Id === x.Id).Role; + }); + const signersName = getSigner.join(", "); + setSignersName(signersName); setIsSendAlert(true); } }; useEffect(() => { const timer = setTimeout(() => { - if (signerPos?.length > 0) { - autosavedetails(); - } + autosavedetails(); }, 2000); return () => clearTimeout(timer); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [signerPos, signatureType]); + }, [signerPos, signatureType, pdfBase64Url]); // `autosavedetails` is used to save template details after every 2 sec when changes are happern in placeholder like drag-drop widgets, remove signers const autosavedetails = async () => { let signers = []; + let pdfUrl; + if (isUploadPdf) { + const pdfName = generatePdfName(16); + pdfUrl = await convertBase64ToFile( + pdfName, + pdfBase64Url, + "", + ); + } if (signersdata?.length > 0) { signersdata.forEach((x) => { if (x.objectId) { @@ -712,10 +702,26 @@ const TemplatePlaceholder = () => { try { const templateCls = new Parse.Object("contracts_Template"); templateCls.id = templateId; - templateCls.set("Placeholders", signerPos); + if (signerPos?.length > 0) { + templateCls.set("Placeholders", signerPos); + } templateCls.set("Signers", signers); templateCls.set("SignatureType", signatureType); - await templateCls.save(); + if (pdfUrl) { + templateCls.set("URL", pdfUrl); + } + if (pdfDetails[0]?.Bcc?.length) { + const Bcc = pdfDetails[0]?.Bcc.map((x) => ({ + __type: "Pointer", + className: "contracts_Contactbook", + objectId: x.objectId + })); + templateCls.set("Bcc", Bcc); + } + const res = await templateCls.save(); + if (res && pdfUrl) { + pdfDetails[0] = { ...pdfDetails[0], URL: pdfUrl }; + } } catch (err) { console.log("error in autosave template", err); } @@ -739,17 +745,31 @@ const TemplatePlaceholder = () => { }); } let pdfUrl = pdfDetails[0]?.URL; - if (pdfRotateBase64) { + if (pdfBase64Url) { try { + const pdfName = generatePdfName(16); pdfUrl = await convertBase64ToFile( - pdfDetails[0].Name, - pdfRotateBase64 + pdfName, + pdfBase64Url, + "", ); } catch (e) { console.log("error to convertBase64ToFile in placeholder flow", e); } } try { + const Bcc = pdfDetails[0]?.Bcc?.length + ? { + Bcc: pdfDetails[0]?.Bcc?.map((x) => ({ + __type: "Pointer", + className: "contracts_Contactbook", + objectId: x.objectId + })) + } + : {}; + const RedirectUrl = pdfDetails[0]?.RedirectUrl + ? { RedirectUrl: pdfDetails[0]?.RedirectUrl } + : {}; const data = { Placeholders: signerPos, Signers: signers, @@ -761,13 +781,16 @@ const TemplatePlaceholder = () => { RemindOnceInEvery: parseInt(pdfDetails[0]?.RemindOnceInEvery), NextReminderDate: pdfDetails[0]?.NextReminderDate, IsEnableOTP: pdfDetails[0]?.IsEnableOTP === true ? true : false, + AllowModifications: pdfDetails[0]?.AllowModifications || false, IsTourEnabled: pdfDetails[0]?.IsTourEnabled === true ? true : false, URL: pdfUrl, SignatureType: signatureType, NotifyOnSignatures: pdfDetails[0]?.NotifyOnSignatures !== undefined ? pdfDetails[0]?.NotifyOnSignatures - : false + : false, + ...Bcc, + ...RedirectUrl }; const updateTemplate = new Parse.Object("contracts_Template"); updateTemplate.id = templateId; @@ -776,7 +799,6 @@ const TemplatePlaceholder = () => { } await updateTemplate.save(); setIsCreateDocModal(true); - setIsMailSend(true); setIsLoading({ isLoad: false }); } catch (e) { setIsLoading(false); @@ -900,9 +922,14 @@ const TemplatePlaceholder = () => { setIsCreateDocModal(false); setIsCreateDoc(true); let pdfUrl = pdfDetails[0]?.URL; - if (pdfRotateBase64) { + if (pdfBase64Url) { try { - pdfUrl = await convertBase64ToFile(pdfDetails[0].Name, pdfRotateBase64); + const pdfName = generatePdfName(16); + pdfUrl = await convertBase64ToFile( + pdfName, + pdfBase64Url, + "", + ); } catch (e) { console.log("error to convertBase64ToFile in placeholder flow", e); } @@ -957,7 +984,6 @@ const TemplatePlaceholder = () => { setUniqueId(Id); setBlockColor(color[index]); setIsSelectId(index); - setIsMailSend(false); }; // `handleDeleteUser` function is used to delete record and placeholder when user click on delete which is place next user name in recipients list const handleDeleteUser = (Id) => { @@ -978,9 +1004,7 @@ const TemplatePlaceholder = () => { setIsSelectId(index); setBlockColor(color[index]); } - setSignerPos(updatePlaceholderUser); - setIsMailSend(false); }; // `handleLinkUser` is used to open Add/Choose Signer Modal when user can link existing or new User with placeholder @@ -988,6 +1012,25 @@ const TemplatePlaceholder = () => { const handleLinkUser = (id) => { setIsAddUser({ [id]: true }); }; + //function to use unlink signer from widgets + const handleUnlinkSigner = () => { + //remove existing signer's details from 'signerPos' array + const updatePlaceHolder = signerPos.map((x) => { + if (x.Id === uniqueId) { + return { ...x, signerPtr: {}, signerObjId: "" }; + } + return { ...x }; + }); + setSignerPos(updatePlaceHolder); + //remove existing signer's details from 'signersdata' array and keep role and id + const updateSigner = signersdata.map((item) => { + if (item.Id == uniqueId) { + return { Role: item.Role, Id: item.Id, blockColor: item.blockColor }; + } + return item; + }); + setSignersData(updateSigner); + }; // `handleAddUser` is used to adduser const handleAddUser = (data) => { const signerPtr = { @@ -1010,7 +1053,6 @@ const TemplatePlaceholder = () => { return { ...x }; }); setSignersData(updateSigner); - setIsMailSend(false); const index = signersdata.findIndex((x) => x.Id === uniqueId); setIsSelectId(index); }; @@ -1031,7 +1073,6 @@ const TemplatePlaceholder = () => { role.Id === roleId ? { ...role, Role: event.target.value } : role ); setSignerPos(updatedPlaceholder); - setIsMailSend(false); }; // `handleOnBlur` function is call when user click outside input box @@ -1053,13 +1094,50 @@ const TemplatePlaceholder = () => { setIsEditTemplate(!isEditTemplate); }; - const handleEditTemplateForm = (data) => { + const handleEditTemplateForm = async (data) => { setIsEditTemplate(false); const updateTemplate = pdfDetails.map((x) => { return { ...x, ...data }; }); setPdfDetails(updateTemplate); - setIsMailSend(false); + try { + const Bcc = updateTemplate?.[0]?.Bcc?.length + ? { + Bcc: updateTemplate?.[0]?.Bcc?.map((x) => ({ + __type: "Pointer", + className: "contracts_Contactbook", + objectId: x.objectId + })) + } + : {}; + const RedirectUrl = updateTemplate?.[0]?.RedirectUrl + ? { RedirectUrl: updateTemplate?.[0]?.RedirectUrl } + : {}; + const data = { + Name: updateTemplate?.[0]?.Name || "", + Note: updateTemplate?.[0]?.Note || "", + Description: updateTemplate?.[0]?.Description || "", + SendinOrder: updateTemplate?.[0]?.SendinOrder || false, + AutomaticReminders: updateTemplate?.[0]?.AutomaticReminders, + IsEnableOTP: updateTemplate?.[0]?.IsEnableOTP === true ? true : false, + IsTourEnabled: + updateTemplate?.[0]?.IsTourEnabled === true ? true : false, + NotifyOnSignatures: + updateTemplate?.[0]?.NotifyOnSignatures !== undefined + ? updateTemplate?.[0]?.NotifyOnSignatures + : false, + ...Bcc, + ...RedirectUrl + }; + const updateTemplateObj = new Parse.Object("contracts_Template"); + updateTemplateObj.id = templateId; + for (const key in data) { + updateTemplateObj.set(key, data[key]); + } + await updateTemplateObj.save(); + } catch (err) { + console.log("error in save template", err); + } }; const handleCloseRoleModal = () => { @@ -1179,7 +1257,8 @@ const TemplatePlaceholder = () => { fontColor: fontColor || currWidgetsDetails?.options?.fontColor || - "black" + "black", + ...(isReadOnly ? { isReadOnly: isReadOnly || false } : {}) } }; } @@ -1219,14 +1298,6 @@ const TemplatePlaceholder = () => { setPdfDetails(updatedPdfDetails); setSignatureType(signtypes); } - const options = ["email", "number", "text"]; - let inputype; - if (defaultdata.textvalidate) { - inputype = options.includes(defaultdata.textvalidate) - ? defaultdata.textvalidate - : "regex"; - } - const filterSignerPos = signerPos.filter((data) => data.Id === uniqueId); if (filterSignerPos.length > 0) { const getPlaceHolder = filterSignerPos[0].placeHolder; @@ -1250,13 +1321,7 @@ const TemplatePlaceholder = () => { hint: defaultdata?.hint || "", defaultValue: defaultdata?.defaultValue || "", validation: - isSubscribe && inputype - ? { - type: inputype, - pattern: - inputype === "regex" ? defaultdata.textvalidate : "" - } - : {}, + {}, fontSize: fontSize || currWidgetsDetails?.options?.fontSize || 12, fontColor: @@ -1323,29 +1388,43 @@ const TemplatePlaceholder = () => { }; //`handleRotationFun` function is used to roatate pdf particular page const handleRotationFun = async (rotateDegree) => { - const isRotate = handleRotateWarning(signerPos, pageNumber); - if (isRotate) { - setIsRotate({ status: true, degree: rotateDegree }); + const rotatePlaceholderExist = handleRotateWarning(signerPos, pageNumber); + if (rotatePlaceholderExist) { + setShowRotateAlert({ status: true, degree: rotateDegree }); } else { + setIsUploadPdf(true); const urlDetails = await rotatePdfPage( - pdfDetails[0].URL, rotateDegree, pageNumber - 1, - pdfRotateBase64 + pdfArrayBuffer ); - setPdfRotatese64(urlDetails.base64); + setPdfArrayBuffer(urlDetails.arrayBuffer); + setPdfBase64Url(urlDetails.base64); } }; const handleRemovePlaceholder = async () => { - handleRemoveWidgets(setSignerPos, signerPos, pageNumber, setIsRotate); - const urlDetails = await rotatePdfPage( - pdfDetails[0].URL, - isRotate.degree, - pageNumber - 1, - pdfRotateBase64 + handleRemoveWidgets( + setSignerPos, + signerPos, + pageNumber, + setShowRotateAlert ); - setPdfRotatese64(urlDetails.base64); + const urlDetails = await rotatePdfPage( + showRotateAlert.degree, + pageNumber - 1, + pdfArrayBuffer + ); + setPdfArrayBuffer(urlDetails.arrayBuffer); + setPdfBase64Url(urlDetails.base64); }; + const signatureWidgetTour = [ + { + selector: '[data-tut="isSignatureWidget"]', + content: t("signature-field-widget", { signersName }), + position: "top", + style: { fontSize: "13px" } + } + ]; return ( <> @@ -1381,14 +1460,27 @@ const TemplatePlaceholder = () => { closeWithMask={false} /> )} + <Tour + onRequestClose={() => setIsSendAlert(false)} + steps={signatureWidgetTour} + isOpen={isSendAlert} + rounded={5} + closeWithMask={false} + /> {/* this component used to render all pdf pages in left side */} <RenderAllPdfPage - signPdfUrl={pdfDetails[0].URL} allPages={allPages} setAllPages={setAllPages} setPageNumber={setPageNumber} setSignBtnPosition={setSignBtnPosition} pageNumber={pageNumber} + pdfBase64Url={pdfBase64Url} + signedUrl={pdfDetails?.[0]?.SignedUrl || ""} + setPdfArrayBuffer={setPdfArrayBuffer} + setPdfBase64Url={setPdfBase64Url} + setIsUploadPdf={setIsUploadPdf} + pdfArrayBuffer={pdfArrayBuffer} + isMergePdfBtn={true} /> {/* pdf render view */} @@ -1397,18 +1489,19 @@ const TemplatePlaceholder = () => { clickOnZoomIn={clickOnZoomIn} clickOnZoomOut={clickOnZoomOut} handleRotationFun={handleRotationFun} + pdfArrayBuffer={pdfArrayBuffer} + pageNumber={pageNumber} + setPdfBase64Url={setPdfBase64Url} + setPdfArrayBuffer={setPdfArrayBuffer} + setIsUploadPdf={setIsUploadPdf} + setSignerPos={setSignerPos} + signerPos={signerPos} + userId={uniqueId} + allPages={allPages} + setAllPages={setAllPages} + setPageNumber={setPageNumber} /> <div className="w-full md:w-[95%]"> - {/* this modal is used show alert set placeholder for all signers before send mail */} - <ModalUi - isOpen={isSendAlert} - title={t("fields-required")} - handleClose={() => setIsSendAlert(false)} - > - <div className="h-full p-[20px]"> - <p>{t("template-signature-field")}</p> - </div> - </ModalUi> <ModalUi isOpen={!IsReceipent} title={t("roles")} @@ -1422,32 +1515,23 @@ const TemplatePlaceholder = () => { <ModalUi isOpen={isCreateDocModal} title={t("create-document")} - handleClose={() => setIsCreateDocModal(false)} + handleClose={() => { + setIsCreateDocModal(false); + navigate("/report/6TeaPr321t"); + }} > - <div className="h-full p-[20px]"> + <div className="h-full p-[20px] mb-2"> <p>{t("template-created-alert")}</p> <div className="h-[1px] w-full my-[15px] bg-[#9f9f9f]"></div> - {currentEmail.length > 0 && ( - <> - <button - onClick={() => handleCreateDocModal()} - type="button" - className="op-btn op-btn-primary" - > - {t("yes")} - </button> - <button - onClick={() => { - setIsCreateDocModal(false); - navigate("/report/6TeaPr321t"); - }} - type="button" - className="op-btn op-btn-secondary ml-2" - > - {t("no")} - </button> - </> - )} + <div className="flex gap-1 flex-col md:flex-row"> + <button + onClick={() => handleCreateDocModal()} + type="button" + className="op-btn op-btn-sm op-btn-primary" + > + {t("create-document")} + </button> + </div> </div> </ModalUi> {isCreateDoc && <LoaderWithMsg isLoading={isLoading} />} @@ -1477,11 +1561,11 @@ const TemplatePlaceholder = () => { currWidgetsDetails={currWidgetsDetails} setCurrWidgetsDetails={setCurrWidgetsDetails} handleClose={handleNameModal} - isSubscribe={isSubscribe} fontSize={fontSize} setFontSize={setFontSize} fontColor={fontColor} setFontColor={setFontColor} + isShowAdvanceFeature={true} /> <DropdownWidgetOption type="checkbox" @@ -1492,11 +1576,11 @@ const TemplatePlaceholder = () => { currWidgetsDetails={currWidgetsDetails} setCurrWidgetsDetails={setCurrWidgetsDetails} handleClose={handleNameModal} - isSubscribe={isSubscribe} fontSize={fontSize} setFontSize={setFontSize} fontColor={fontColor} setFontColor={setFontColor} + isShowAdvanceFeature={true} /> <DropdownWidgetOption type="dropdown" @@ -1507,17 +1591,17 @@ const TemplatePlaceholder = () => { currWidgetsDetails={currWidgetsDetails} setCurrWidgetsDetails={setCurrWidgetsDetails} handleClose={handleNameModal} - isSubscribe={isSubscribe} fontSize={fontSize} setFontSize={setFontSize} fontColor={fontColor} setFontColor={setFontColor} + isShowAdvanceFeature={true} /> <PlaceholderCopy isPageCopy={isPageCopy} setIsPageCopy={setIsPageCopy} - xyPostion={signerPos} - setXyPostion={setSignerPos} + xyPosition={signerPos} + setXyPosition={setSignerPos} allPages={allPages} pageNumber={pageNumber} signKey={signKey} @@ -1533,7 +1617,6 @@ const TemplatePlaceholder = () => { pdfDetails={pdfDetails} signerPos={signerPos} signersdata={signersdata} - isMailSend={isMailSend} alertSendEmail={alertSendEmail} isShowHeader={true} currentSigner={true} @@ -1542,6 +1625,13 @@ const TemplatePlaceholder = () => { handleRotationFun={handleRotationFun} clickOnZoomIn={clickOnZoomIn} clickOnZoomOut={clickOnZoomOut} + setSignerPos={setSignerPos} + setIsUploadPdf={setIsUploadPdf} + pdfArrayBuffer={pdfArrayBuffer} + setPdfArrayBuffer={setPdfArrayBuffer} + setPdfBase64Url={setPdfBase64Url} + userId={uniqueId} + pdfBase64={pdfBase64Url} /> <div ref={divRef} @@ -1586,12 +1676,13 @@ const TemplatePlaceholder = () => { setScale={setScale} scale={scale} setIsSelectId={setIsSelectId} - pdfRotateBase64={pdfRotateBase64} + pdfBase64Url={pdfBase64Url} fontSize={fontSize} setFontSize={setFontSize} fontColor={fontColor} setFontColor={setFontColor} isResize={isResize} + divRef={divRef} /> )} </div> @@ -1602,15 +1693,8 @@ const TemplatePlaceholder = () => { <div> <WidgetComponent dataTut2="reactourSecond" - pdfUrl={isMailSend} - dragSignature={dragSignature} - signRef={signRef} handleDivClick={handleDivClick} handleMouseLeave={handleMouseLeave} - isDragSign={isDragSign} - dragStamp={dragStamp} - dragRef={dragRef} - isDragStamp={isDragStamp} isSignYourself={false} addPositionOfSignature={addPositionOfSignature} signerPos={signerPos} @@ -1619,7 +1703,6 @@ const TemplatePlaceholder = () => { setIsSelectId={setIsSelectId} isSigners={isSigners} setIsShowEmail={setIsShowEmail} - isMailSend={isMailSend} setSelectedEmail={setSelectedEmail} selectedEmail={selectedEmail} handleAddSigner={handleAddSigner} @@ -1635,13 +1718,15 @@ const TemplatePlaceholder = () => { setSignersData={setSignersData} blockColor={blockColor} setBlockColor={setBlockColor} + setSignerPos={setSignerPos} + uniqueId={uniqueId} + setSelectWidgetId={setSelectWidgetId} /> </div> ) : ( <div className="w-[23%] bg-base-100 min-h-screen overflow-y-auto hide-scrollbar"> <div className="max-h-screen"> <SignerListPlace - isMailSend={isMailSend} signerPos={signerPos} setSignerPos={setSignerPos} signersdata={signersdata} @@ -1662,15 +1747,8 @@ const TemplatePlaceholder = () => { /> <div data-tut="addWidgets"> <WidgetComponent - isMailSend={isMailSend} - dragSignature={dragSignature} - signRef={signRef} handleDivClick={handleDivClick} handleMouseLeave={handleMouseLeave} - isDragSign={isDragSign} - dragStamp={dragStamp} - dragRef={dragRef} - isDragStamp={isDragStamp} isSignYourself={false} addPositionOfSignature={addPositionOfSignature} title={t("roles")} @@ -1695,13 +1773,16 @@ const TemplatePlaceholder = () => { /> </div> <div> - <LinkUserModal - handleAddUser={handleAddUser} - isAddUser={isAddUser} - uniqueId={uniqueId} - closePopup={closePopup} - signersData={signersdata} - /> + {isAddUser && isAddUser[uniqueId] && ( + <LinkUserModal + handleAddUser={handleAddUser} + uniqueId={uniqueId} + closePopup={closePopup} + signersData={signersdata} + signerPos={signerPos} + handleUnlinkSigner={handleUnlinkSigner} + /> + )} </div> <ModalUi title={t("edit-template")} @@ -1720,7 +1801,6 @@ const TemplatePlaceholder = () => { isOpen={isNameModal} handleClose={handleNameModal} handleData={handleWidgetdefaultdata} - isSubscribe={isSubscribe} isTextSetting={isTextSetting} setIsTextSetting={setIsTextSetting} fontSize={fontSize} @@ -1729,8 +1809,8 @@ const TemplatePlaceholder = () => { setFontColor={setFontColor} /> <RotateAlert - isRotate={isRotate.status} - setIsRotate={setIsRotate} + showRotateAlert={showRotateAlert.status} + setShowRotateAlert={setShowRotateAlert} handleRemoveWidgets={handleRemovePlaceholder} /> </DndProvider> diff --git a/apps/OpenSign/src/pages/UpdateExistUserAdmin.js b/apps/OpenSign/src/pages/UpdateExistUserAdmin.js index c3b9aed01..0f06015f8 100644 --- a/apps/OpenSign/src/pages/UpdateExistUserAdmin.js +++ b/apps/OpenSign/src/pages/UpdateExistUserAdmin.js @@ -1,7 +1,7 @@ import React, { useEffect, useState } from "react"; import Loader from "../primitives/Loader"; import Parse from "parse"; -import { NavLink, useNavigate } from "react-router-dom"; +import { NavLink, useNavigate } from "react-router"; import Alert from "../primitives/Alert"; import Title from "../components/Title"; import { useTranslation } from "react-i18next"; @@ -153,23 +153,6 @@ const UpdateExistUserAdmin = () => { onInput={(e) => e.target.setCustomValidity("")} required /> - - {/* - <div className="mt-2.5 ml-1 flex flex-row items-center"> - <input - type="checkbox" - className="op-checkbox op-checkbox-sm" - id="termsandcondition" - checked={isSubscribeNews} - onChange={(e) => setIsSubscribeNews(e.target.checked)} - /> - <label - className="text-xs cursor-pointer ml-1 mb-0" - htmlFor="termsandcondition" - > - Subscribe to OpenSign newsletter - </label> - </div> */} </div> <div className="mx-4 text-center text-xs font-bold mb-3"> <button diff --git a/apps/OpenSign/src/pages/UserList.js b/apps/OpenSign/src/pages/UserList.js index 15de405fa..7e736b24a 100644 --- a/apps/OpenSign/src/pages/UserList.js +++ b/apps/OpenSign/src/pages/UserList.js @@ -2,16 +2,12 @@ import React, { useEffect, useState } from "react"; import Parse from "parse"; import Alert from "../primitives/Alert"; import Loader from "../primitives/Loader"; -import { useLocation } from "react-router-dom"; +import { useLocation } from "react-router"; import ModalUi from "../primitives/ModalUi"; import pad from "../assets/images/pad.svg"; import Tooltip from "../primitives/Tooltip"; import AddUser from "../components/AddUser"; -import SubscribeCard from "../primitives/SubscribeCard"; -import { isEnableSubscription } from "../constant/const"; -import { fetchSubscriptionInfo } from "../constant/Utils"; import Title from "../components/Title"; -import { validplan } from "../json/plansArr"; import { useTranslation } from "react-i18next"; const heading = ["Sr.No", "Name", "Email", "Phone", "Role", "Team", "Active"]; // const actions = []; @@ -31,16 +27,8 @@ const UserList = () => { const [isAlert, setIsAlert] = useState({ type: "success", msg: "" }); const [isActiveModal, setIsActiveModal] = useState({}); const [isActLoader, setIsActLoader] = useState({}); - const [isSubscribe, setIsSubscribe] = useState({ - plan: "", - isValid: false, - priceperUser: 0 - }); const [isAdmin, setIsAdmin] = useState(false); const [formHeader, setFormHeader] = useState(t("add-user")); - const [usersCount, setUserCounts] = useState({ allowed: 0, totalAllowed: 0 }); - const [amount, setAmount] = useState({ quantity: 1, price: 0 }); - const [isBuyLoader, setIsBuyLoader] = useState(false); const recordperPage = 10; const startIndex = (currentPage - 1) * recordperPage; // user per page @@ -109,39 +97,6 @@ const UserList = () => { const extUser = localStorage.getItem("Extand_Class") && JSON.parse(localStorage.getItem("Extand_Class"))?.[0]; - if (isEnableSubscription) { - const subscribe = await fetchSubscriptionInfo(); - if (subscribe?.plan_code?.includes("team")) { - const isSupAdmin = - subscribe?.adminId && extUser?.objectId === subscribe?.adminId; - setIsSubscribe({ - plan: subscribe.plan_code, - isValid: true, - adminId: subscribe.adminId, - priceperUser: subscribe.price, - isSuperAdmin: isSupAdmin - }); - setAmount((prev) => ({ ...prev, price: subscribe.price })); - try { - const res = await Parse.Cloud.run("allowedusers"); - setUserCounts((obj) => ({ - ...obj, - allowed: parseInt(res), - totalAllowed: parseInt(subscribe?.totalAllowedUser) || 0 - })); - } catch (err) { - console.log("err while get users", err); - } - } else { - setIsSubscribe({ - plan: subscribe.plan_code, - isValid: false, - adminId: subscribe.adminId - }); - } - } else { - setIsSubscribe({ plan: "teams-yearly", isValid: true }); - } if (extUser) { const admin = @@ -185,10 +140,6 @@ const UserList = () => { const handleUserData = (userData) => { if (userData) { - setUserCounts((obj) => ({ - ...obj, - allowed: obj?.allowed > 0 ? obj.allowed - 1 : 1 - })); setUserList((prev) => [userData, ...prev]); } }; @@ -240,48 +191,6 @@ const UserList = () => { setIsActiveModal({ [user.objectId]: true }); }; - const handleAddOnSubmit = async (e) => { - e.preventDefault(); - e.stopPropagation(); - setIsBuyLoader(true); - try { - const resAddon = await Parse.Cloud.run("buyaddonusers", { - users: parseInt(amount.quantity) - }); - if (resAddon) { - const _resAddon = JSON.parse(JSON.stringify(resAddon)); - if (_resAddon.status === "success") { - setUserCounts((obj) => ({ - ...obj, - allowed: parseInt(obj.allowed) + parseInt(amount.quantity), - totalAllowed: parseInt(_resAddon.addon) - })); - setAmount((obj) => ({ ...obj, quantity: 1 })); - } - } - } catch (err) { - console.log("Err in buy addon", err); - setIsAlert({ type: "danger", msg: t("something-went-wrong-mssg") }); - } finally { - setTimeout(() => setIsAlert({ type: "success", msg: "" }), 2000); - setIsBuyLoader(false); - handleModal("addseats"); - } - }; - const handlePricePerUser = (e) => { - const quantity = e.target.value; - const price = e.target?.value > 0 ? isSubscribe.priceperUser * quantity : 0; - setAmount((prev) => ({ ...prev, quantity: quantity, price: price })); - }; - const handleBuyUsers = (allowed, totalAllowed) => { - if (allowed && totalAllowed) { - setUserCounts((obj) => ({ - ...obj, - allowed: parseInt(obj.allowed) + parseInt(allowed), - totalAllowed: parseInt(totalAllowed) - })); - } - }; return ( <div className="relative"> <Title title={isAdmin ? "Users" : "Page not found"} /> @@ -295,268 +204,198 @@ const UserList = () => { <Loader /> </div> )} - {validplan[isSubscribe.plan] && !isLoader && ( - <> - {isAdmin ? ( - <div className="p-2 w-full bg-base-100 text-base-content op-card shadow-lg"> - {isAlert.msg && <Alert type={isAlert.type}>{isAlert.msg}</Alert>} - <div className="flex flex-row items-center justify-between my-2 mx-3 text-[20px] md:text-[23px]"> - <div className="font-light"> - {t("report-name.Users")}{" "} - <span className="text-xs md:text-[13px] font-normal"> - <Tooltip message={t("users-from-teams")} /> - </span> - </div> - <div className="flex flex-row gap-2 items-center"> - {isEnableSubscription && isSubscribe?.isSuperAdmin && ( - <div - className="hidden md:flex op-btn op-btn-sm h-[35px] op-btn-primary op-btn-outline text-xs mb-0.5" - onClick={() => handleModal("addseats")} - > - {t("buy-users")} - </div> + + { + !isLoader && ( + <> + {isAdmin ? ( + <div className="p-2 w-full bg-base-100 text-base-content op-card shadow-lg"> + {isAlert.msg && ( + <Alert type={isAlert.type}>{isAlert.msg}</Alert> )} - <div - className="cursor-pointer" - onClick={() => handleModal("form")} - > - <i className="fa-light fa-square-plus text-accent text-[30px] md:text-[40px]"></i> + <div className="flex flex-row items-center justify-between my-2 mx-3 text-[20px] md:text-[23px]"> + <div className="font-light"> + {t("report-name.Users")}{" "} + <span className="text-xs md:text-[13px] font-normal"> + <Tooltip message={t("users-from-teams")} /> + </span> + </div> + <div className="flex flex-row gap-2 items-center"> + <div + className="cursor-pointer" + onClick={() => handleModal("form")} + > + <i className="fa-light fa-square-plus text-accent text-[30px] md:text-[40px]"></i> + </div> + </div> </div> - {isEnableSubscription && isSubscribe?.isSuperAdmin && ( - <div - className="cursor-pointer relative md:hidden mb-0.5" - onClick={() => handleModal("options")} - > - <i className="fa-light fa-ellipsis-vertical fa-xl"></i> - {isModal?.options && ( - <ul className="absolute -right-3 top-auto z-[70] w-max op-menu op-menu-xs shadow bg-base-100 text-base-content rounded-box border"> - <li onClick={() => handleModal("addseats")}> - <span className="text-[13px] capitalize font-medium"> - {t("buy-users")} - </span> - </li> - </ul> + <div className="overflow-x-auto w-full"> + <table className="op-table border-collapse w-full"> + <thead className="text-[14px]"> + <tr className="border-y-[1px]"> + {heading?.map((item, index) => ( + <th key={index} className="px-4 py-2"> + {t(`report-heading.${item}`)} + </th> + ))} + </tr> + </thead> + <tbody className="text-[12px]"> + {userList?.length > 0 && ( + <> + {currentList.map((item, index) => ( + <tr className="border-y-[1px]" key={index}> + {heading.includes("Sr.No") && ( + <th className="px-4 py-2"> + {startIndex + index + 1} + </th> + )} + <td className="px-4 py-2 font-semibold"> + {item?.Name}{" "} + </td> + <td className="px-4 py-2 "> + {item?.Email || "-"} + </td> + <td className="px-4 py-2"> + {item?.Phone || "-"} + </td> + <td className="px-4 py-2"> + {item?.UserRole?.split("_").pop() || "-"} + </td> + <td className="px-4 py-2"> + {formatRow(item.TeamIds)} + </td> + {item.UserRole !== "contracts_Admin" && ( + <td className="px-4 py-2 font-semibold"> + <label className="cursor-pointer relative block items-center mb-0"> + <input + type="checkbox" + className="op-toggle transition-all op-toggle-secondary" + checked={item?.IsDisabled !== true} + onChange={() => handleToggleBtn(item)} + /> + </label> + {isActiveModal[item.objectId] && ( + <ModalUi + isOpen + title={t("user-status")} + handleClose={handleClose} + > + <div className="m-[20px]"> + <div className="text-lg font-normal text-black"> + {t("are-you-sure")}{" "} + {item?.IsDisabled + ? t("activate") + : t("deactivate")}{" "} + {t("this-user")}? + </div> + <hr className="bg-[#ccc] mt-4 " /> + <div className="flex items-center mt-3 gap-2 text-white"> + <button + onClick={() => + handleToggleSubmit(item) + } + className="op-btn op-btn-primary" + > + {t("yes")} + </button> + <button + onClick={handleClose} + className="op-btn op-btn-secondary" + > + {t("no")} + </button> + </div> + </div> + </ModalUi> + )} + </td> + )} + </tr> + ))} + </> + )} + </tbody> + </table> + </div> + <div className="flex flex-row justify-between items-center text-xs font-medium"> + <div className="op-join flex flex-wrap items-center p-2"> + {userList.length > recordperPage && ( + <button + onClick={() => paginateBack()} + className="op-join-item op-btn op-btn-sm" + > + {t("prev")} + </button> + )} + {pageNumbers.map((x, i) => ( + <button + key={i} + onClick={() => setCurrentPage(x)} + disabled={x === "..."} + className={`${ + x === currentPage ? "op-btn-active" : "" + } op-join-item op-btn op-btn-sm`} + > + {x} + </button> + ))} + {userList.length > recordperPage && ( + <button + onClick={() => paginateFront()} + className="op-join-item op-btn op-btn-sm" + > + {t("next")} + </button> )} </div> - )} - </div> - </div> - <div className="overflow-x-auto w-full"> - <table className="op-table border-collapse w-full"> - <thead className="text-[14px]"> - <tr className="border-y-[1px]"> - {heading?.map((item, index) => ( - <th key={index} className="px-4 py-2"> - {t(`report-heading.${item}`)} - </th> - ))} - </tr> - </thead> - <tbody className="text-[12px]"> - {userList?.length > 0 && ( - <> - {currentList.map((item, index) => ( - <tr className="border-y-[1px]" key={index}> - {heading.includes("Sr.No") && ( - <th className="px-4 py-2"> - {startIndex + index + 1} - </th> - )} - <td className="px-4 py-2 font-semibold"> - {item?.Name}{" "} - </td> - <td className="px-4 py-2 ">{item?.Email || "-"}</td> - <td className="px-4 py-2">{item?.Phone || "-"}</td> - <td className="px-4 py-2"> - {item?.UserRole?.split("_").pop() || "-"} - </td> - <td className="px-4 py-2"> - {formatRow(item.TeamIds)} - </td> - {item.UserRole !== "contracts_Admin" && ( - <td className="px-4 py-2 font-semibold"> - <label className="cursor-pointer relative block items-center mb-0"> - <input - type="checkbox" - className="op-toggle transition-all op-toggle-secondary" - checked={item?.IsDisabled !== true} - onChange={() => handleToggleBtn(item)} - /> - </label> - {isActiveModal[item.objectId] && ( - <ModalUi - isOpen - title={t("user-status")} - handleClose={handleClose} - > - <div className="m-[20px]"> - <div className="text-lg font-normal text-black"> - {t("are-you-sure")}{" "} - {item?.IsDisabled - ? t("activate") - : t("deactivate")}{" "} - {t("this-user")}? - </div> - <hr className="bg-[#ccc] mt-4 " /> - <div className="flex items-center mt-3 gap-2 text-white"> - <button - onClick={() => - handleToggleSubmit(item) - } - className="op-btn op-btn-primary" - > - {t("yes")} - </button> - <button - onClick={handleClose} - className="op-btn op-btn-secondary" - > - {t("no")} - </button> - </div> - </div> - </ModalUi> - )} - </td> - )} - </tr> - ))} - </> - )} - </tbody> - </table> - </div> - <div className="flex flex-row justify-between items-center text-xs font-medium"> - <div className="op-join flex flex-wrap items-center p-2"> - {userList.length > recordperPage && ( - <button - onClick={() => paginateBack()} - className="op-join-item op-btn op-btn-sm" - > - {t("prev")} - </button> - )} - {pageNumbers.map((x, i) => ( - <button - key={i} - onClick={() => setCurrentPage(x)} - disabled={x === "..."} + </div> + {userList?.length <= 0 && ( + <div className={`${ - x === currentPage ? "op-btn-active" : "" - } op-join-item op-btn op-btn-sm`} + isDashboard ? "h-[317px]" : "" + } flex flex-col items-center justify-center w-ful bg-base-100 text-base-content rounded-xl py-4`} > - {x} - </button> - ))} - {userList.length > recordperPage && ( - <button - onClick={() => paginateFront()} - className="op-join-item op-btn op-btn-sm" - > - {t("next")} - </button> + <div className="w-[60px] h-[60px] overflow-hidden"> + <img + className="w-full h-full object-contain" + src={pad} + alt="img" + /> + </div> + <div className="text-sm font-semibold"> + {t("no-data-avaliable")} + </div> + </div> )} - </div> - {isEnableSubscription && isSubscribe?.isSuperAdmin && ( - <div> - {t("available-seats")}: {usersCount.allowed}/ - {usersCount.totalAllowed} - </div> - )} - </div> - {userList?.length <= 0 && ( - <div - className={`${ - isDashboard ? "h-[317px]" : "" - } flex flex-col items-center justify-center w-ful bg-base-100 text-base-content rounded-xl py-4`} - > - <div className="w-[60px] h-[60px] overflow-hidden"> - <img - className="w-full h-full object-contain" - src={pad} - alt="img" + <ModalUi + isOpen={isModal.form} + title={formHeader} + handleClose={() => handleModal("form")} + > + <AddUser + setIsAlert={setIsAlert} + handleUserData={handleUserData} + closePopup={() => handleModal("form")} + setFormHeader={setFormHeader} /> - </div> - <div className="text-sm font-semibold"> - {t("no-data-avaliable")} + </ModalUi> + </div> + ) : ( + <div className="flex items-center justify-center h-screen w-full bg-base-100 text-base-content rounded-box"> + <div className="text-center"> + <h1 className="text-[60px] lg:text-[120px] font-semibold"> + 404 + </h1> + <p className="text-[30px] lg:text-[50px]"> + {t("page-not-found")} + </p> </div> </div> )} - <ModalUi - isOpen={isModal.form} - title={formHeader} - handleClose={() => handleModal("form")} - > - <AddUser - setIsAlert={setIsAlert} - handleUserData={handleUserData} - handleBuyUsers={handleBuyUsers} - closePopup={() => handleModal("form")} - setFormHeader={setFormHeader} - /> - </ModalUi> - <ModalUi - isOpen={isModal.addseats} - title="Add Seats" - handleClose={() => handleModal("addseats")} - > - {isBuyLoader && ( - <div className="absolute w-full h-full inset-0 flex justify-center items-center bg-base-content/30 z-50"> - <Loader /> - </div> - )} - <form onSubmit={handleAddOnSubmit} className=" px-3 pb-6 pt-6"> - <div className="mb-3 flex justify-between"> - <label - htmlFor="quantity" - className="block text-xs text-gray-700 font-semibold" - > - {t("Quantity-of-users")} - <span className="text-[red] text-[13px]"> *</span> - </label> - <input - type="number" - name="quantity" - value={amount.quantity} - onChange={(e) => handlePricePerUser(e)} - className="w-1/4 op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content text-xs" - required - /> - </div> - <div className="mb-3 flex justify-between"> - <label className="block text-xs text-gray-700 font-semibold"> - {t("Price")} (1 * {isSubscribe.priceperUser}) - </label> - <div className="w-1/4 flex justify-center items-center text-sm"> - USD {amount.price} - </div> - </div> - <hr className="text-base-content mb-3" /> - <button className="op-btn op-btn-primary w-full"> - {t("Proceed")} - </button> - </form> - </ModalUi> - </div> - ) : ( - <div className="flex items-center justify-center h-screen w-full bg-base-100 text-base-content rounded-box"> - <div className="text-center"> - <h1 className="text-[60px] lg:text-[120px] font-semibold"> - 404 - </h1> - <p className="text-[30px] lg:text-[50px]"> - {t("page-not-found")} - </p> - </div> - </div> - )} - </> - )} - {isEnableSubscription && !validplan[isSubscribe.plan] && !isLoader && ( - <div data-tut="apisubscribe"> - <SubscribeCard plan="TEAMS" /> - </div> - )} + </> + ) + } </div> ); }; diff --git a/apps/OpenSign/src/pages/UserProfile.js b/apps/OpenSign/src/pages/UserProfile.js index f05321f98..d738e696f 100644 --- a/apps/OpenSign/src/pages/UserProfile.js +++ b/apps/OpenSign/src/pages/UserProfile.js @@ -1,5 +1,8 @@ -import React, { useState, useEffect, useRef } from "react"; -import { Navigate, useNavigate } from "react-router-dom"; +import React, { + useState, + useEffect, +} from "react"; +import { Navigate, useNavigate } from "react-router"; import Parse from "parse"; import { SaveFileSize } from "../constant/saveFileSize"; import dp from "../assets/images/dp.png"; @@ -7,23 +10,14 @@ import Title from "../components/Title"; import sanitizeFileName from "../primitives/sanitizeFileName"; import axios from "axios"; import Tooltip from "../primitives/Tooltip"; -import { isEnableSubscription, isStaging } from "../constant/const"; import { - checkIsSubscribed, - copytoData, + getSecureUrl, handleSendOTP, - openInNewTab } from "../constant/Utils"; -import Upgrade from "../primitives/Upgrade"; import ModalUi from "../primitives/ModalUi"; import Loader from "../primitives/Loader"; -import { validplan } from "../json/plansArr"; import { useTranslation } from "react-i18next"; import SelectLanguage from "../components/pdf/SelectLanguage"; -import { RWebShare } from "react-web-share"; -import Alert from "../primitives/Alert"; -import Tour from "reactour"; -import TourContentWithBtn from "../primitives/TourContentWithBtn"; function UserProfile() { const navigate = useNavigate(); @@ -38,14 +32,6 @@ function UserProfile() { const [Image, setImage] = useState(localStorage.getItem("profileImg")); const [isLoader, setIsLoader] = useState(false); const [percentage, setpercentage] = useState(0); - const [isDisableDocId, setIsDisableDocId] = useState(false); - const [isSubscribe, setIsSubscribe] = useState(false); - const [isUpgrade, setIsUpgrade] = useState(false); - const [isAlert, setIsAlert] = useState({ type: "success", message: "" }); - const [publicUserName, setPublicUserName] = useState( - extendUser && extendUser?.[0]?.UserName - ); - const previousPublicUserName = useRef(publicUserName); const [company, setCompany] = useState( extendUser && extendUser?.[0]?.Company ); @@ -56,45 +42,12 @@ function UserProfile() { const [otp, setOtp] = useState(""); const [otpLoader, setOtpLoader] = useState(false); const [isEmailVerified, setIsEmailVerified] = useState(false); - const [tagLine, setTagLine] = useState( - extendUser && extendUser?.[0]?.Tagline - ); - const [isPlan, setIsPlan] = useState({ plan: "", isValid: false }); - const [tourStatus, setTourStatus] = useState([]); - const [isProfileTour, setIsProfileTour] = useState(false); - const [isDontShow, setIsDontShow] = useState(false); - const getPublicUrl = isStaging - ? `https://staging.opensign.me/${extendUser?.[0]?.UserName}` - : `https://opensign.me/${extendUser?.[0]?.UserName}`; useEffect(() => { getUserDetail(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const getUserDetail = async () => { setIsLoader(true); - const extClass = localStorage.getItem("Extand_Class"); - const jsonSender = JSON.parse(extClass); - const tourstatuss = jsonSender[0]?.TourStatus && jsonSender[0].TourStatus; - if (!isEnableSubscription) { - setIsProfileTour(true); - } else if (tourstatuss && tourstatuss.length > 0) { - setTourStatus(tourstatuss); - const checkTourRecipients = tourstatuss.filter( - (data) => data.profileTour - ); - if (checkTourRecipients && checkTourRecipients.length > 0) { - setIsProfileTour(checkTourRecipients[0]?.profileTour); - } - } - const HeaderDocId = jsonSender[0]?.HeaderDocId; - if (isEnableSubscription) { - const subscribe = await checkIsSubscribed(); - setIsSubscribe(subscribe.isValid); - setIsPlan(subscribe); - } - if (HeaderDocId) { - setIsDisableDocId(HeaderDocId); - } const currentUser = JSON.parse(JSON.stringify(Parse.User.current())); let isEmailVerified = currentUser?.emailVerified || false; if (isEmailVerified) { @@ -116,30 +69,11 @@ function UserProfile() { } } }; - //function to check public username already exist - const handleCheckPublicUserName = async () => { - try { - const res = await Parse.Cloud.run("getpublicusername", { - username: publicUserName - }); - if (res) { - setIsLoader(false); - setIsAlert({ type: "danger", message: t("user-name-exist") }); - setTimeout(() => setIsAlert({}), 3000); - return res; - } - } catch (e) { - console.log("error in getpublicusername cloud function"); - } - }; + const handleSubmit = async (e) => { e.preventDefault(); let phn = Phone, res = ""; - //condition to call cloud function when user change publicUserName - if (publicUserName && previousPublicUserName.current !== publicUserName) { - res = await handleCheckPublicUserName(); - } if (!res) { setIsLoader(true); try { @@ -191,12 +125,9 @@ function UserProfile() { const body = { Phone: obj?.Phone || "", Name: obj.Name, - HeaderDocId: isDisableDocId, JobTitle: jobTitle, Company: company, - UserName: publicUserName || "", - Tagline: tagLine || "", - Language: obj?.language || "" + Language: obj?.language || "", }; await axios.put( @@ -215,7 +146,6 @@ function UserProfile() { const json = JSON.parse(JSON.stringify([res])); const extRes = JSON.stringify(json); localStorage.setItem("Extand_Class", extRes); - previousPublicUserName.current = publicUserName; } catch (e) { console.log("error in save data in contracts_Users class"); } @@ -247,14 +177,15 @@ function UserProfile() { // // The response object will contain information about the uploaded file // console.log("File uploaded:", response); - // You can access the URL of the uploaded file using response.url() - // console.log("File URL:", response.url()); - if (response.url()) { - setImage(response.url()); - setpercentage(0); - const tenantId = localStorage.getItem("TenantId"); - SaveFileSize(size, response.url(), tenantId); - return response.url(); + if (response?.url()) { + const fileRes = await getSecureUrl(response?.url()); + if (fileRes?.url) { + setImage(fileRes?.url); + setpercentage(0); + const tenantId = localStorage.getItem("TenantId"); + SaveFileSize(size, fileRes?.url, tenantId); + return fileRes?.url; + } } } catch (error) { console.error("Error uploading file:", error); @@ -268,9 +199,6 @@ function UserProfile() { return <Navigate to={_redirect} />; } - const handleDisableDocId = () => { - setIsDisableDocId((prevChecked) => !prevChecked); - }; //`handleVerifyBtn` function is used to send otp on user mail const handleVerifyBtn = async () => { setIsVerifyModal(true); @@ -311,99 +239,16 @@ function UserProfile() { setOtpLoader(false); alert(t("otp-sent-alert")); }; - //function to handle onchange username and restrict 6-characters username for free users - const handleOnchangeUserName = (e) => { - const newValue = e.target.value.replace(/\s+/g, ""); - setPublicUserName(newValue); - }; - const handleOnchangeTagLine = (e) => { - setTagLine(e.target.value); - }; const handleCancel = () => { setEditMode(false); SetName(localStorage.getItem("username")); SetPhone(UserProfile && UserProfile.phone); setImage(localStorage.getItem("profileImg")); - setPublicUserName(extendUser && extendUser?.[0]?.UserName); setCompany(extendUser && extendUser?.[0]?.Company); setJobTitle(extendUser?.[0]?.JobTitle); - setIsDisableDocId(extendUser?.[0]?.HeaderDocId); - }; - const handlePaidRoute = () => { - navigate("/subscription"); }; - const copytoclipboard = () => { - copytoData(getPublicUrl); - setIsAlert({ type: "success", message: t("copied") }); - setTimeout(() => setIsAlert({}), 3000); - }; - - const tourConfig = [ - { - content: () => ( - <TourContentWithBtn - message={t("tour-mssg.public-template")} - isChecked={handleDontShow} - video="https://www.youtube.com/embed/_wB4UA7Jz5Q?si=I40CI3nVUWQzf42Y" - /> - ), - position: "top", - style: { fontSize: "13px" } - } - ]; - //function for update TourStatus - const closeTour = async () => { - try { - setIsProfileTour(true); - if (isDontShow) { - let updatedTourStatus = []; - if (tourStatus.length > 0) { - updatedTourStatus = [...tourStatus]; - const profileIndex = tourStatus.findIndex( - (obj) => obj["profileTour"] === false || obj["profileTour"] === true - ); - if (profileIndex !== -1) { - updatedTourStatus[profileIndex] = { profileTour: true }; - } else { - updatedTourStatus.push({ profileTour: true }); - } - } else { - updatedTourStatus = [{ profileTour: true }]; - } - - await axios.put( - `${localStorage.getItem("baseUrl")}classes/contracts_Users/${ - extendUser?.[0]?.objectId - }`, - { - TourStatus: updatedTourStatus - }, - { - headers: { - "Content-Type": "application/json", - "X-Parse-Application-Id": localStorage.getItem("parseAppId"), - sessionToken: localStorage.getItem("accesstoken") - } - } - ); - const res = await Parse.Cloud.run("getUserDetails"); - const json = JSON.parse(JSON.stringify([res])); - const extRes = JSON.stringify(json); - localStorage.setItem("Extand_Class", extRes); - } - } catch (err) { - console.log("axois err ", err); - alert(t("something-went-wrong-mssg")); - } - }; - const handleDontShow = (isChecked) => { - setIsDontShow(isChecked); - }; - const handleOnlickHelp = () => { - setIsProfileTour(false); - }; return ( <React.Fragment> <Title title={"Profile"} /> @@ -413,19 +258,6 @@ function UserProfile() { </div> ) : ( <div className="flex justify-center items-center w-full relative"> - {isAlert.message && ( - <Alert className="z-[1000] fixed top-[10%]" type={isAlert.type}> - {isAlert.message} - </Alert> - )} - <Tour - className="md:!min-w-[650px]" - onRequestClose={closeTour} - steps={tourConfig} - isOpen={!isProfileTour} - rounded={5} - closeWithMask={false} - /> <div className="bg-base-100 text-base-content flex flex-col justify-center shadow-md rounded-box w-[450px]"> <div className="flex flex-col justify-center items-center my-4"> <div className="w-[200px] h-[200px] overflow-hidden rounded-full"> @@ -463,7 +295,7 @@ function UserProfile() { </div> <ul className="w-full flex flex-col p-2 text-sm"> <li - className={`flex justify-between items-center border-t-[1px] border-gray-300 break-all ${ + className={`flex justify-between items-center border-y-[1px] border-gray-300 break-all ${ editmode ? "py-1.5" : "py-2" }`} > @@ -480,7 +312,7 @@ function UserProfile() { )} </li> <li - className={`flex justify-between items-center border-t-[1px] border-gray-300 break-all ${ + className={`flex justify-between items-center border-b-[1px] border-gray-300 break-all ${ editmode ? "py-1.5" : "py-2" }`} > @@ -496,12 +328,23 @@ function UserProfile() { <span>{UserProfile && UserProfile.phone}</span> )} </li> - <li className="flex justify-between items-center border-t-[1px] border-gray-300 py-2 break-all"> - <span className="font-semibold">{t("email")}:</span>{" "} + <li className="flex justify-between items-center border-b-[1px] border-gray-300 py-2 break-all"> + <span + data-tooltip-id="email-tooltip" + className="font-semibold flex gap-1" + > + {t("email")} :{" "} + {editmode && ( + <Tooltip + message={t("email-help")} + maxWidth="max-w-[250px]" + /> + )} + </span> <span>{UserProfile && UserProfile.email}</span> </li> <li - className={`flex justify-between items-center border-t-[1px] border-gray-300 break-all ${ + className={`flex justify-between items-center border-b-[1px] border-gray-300 break-all ${ editmode ? "py-1.5" : "py-2" }`} > @@ -518,7 +361,7 @@ function UserProfile() { )} </li> <li - className={`flex justify-between items-center border-t-[1px] border-gray-300 break-all ${ + className={`flex justify-between items-center border-b-[1px] border-gray-300 break-all ${ editmode ? "py-1.5" : "py-2" }`} > @@ -534,7 +377,7 @@ function UserProfile() { <span>{extendUser?.[0]?.JobTitle}</span> )} </li> - <li className="flex justify-between items-center border-t-[1px] border-gray-300 py-2 break-all"> + <li className="flex justify-between items-center border-b-[1px] border-gray-300 py-2 break-all"> <span className="font-semibold">{t("is-email-verified")}:</span>{" "} <span> {isEmailVerified ? ( @@ -553,118 +396,6 @@ function UserProfile() { )} </span> </li> - {isEnableSubscription && ( - <> - <li className="flex flex-row justify-between md:items-center border-t-[1px] border-gray-300 py-2 break-all"> - <span className="font-semibold flex gap-1"> - {t("public-profile")} :{" "} - <Tooltip handleOnlickHelp={handleOnlickHelp} /> - </span> - <div className="flex flex-row items-center gap-1"> - {editmode || !extendUser?.[0]?.UserName ? ( - <> - <input - maxLength={40} - onChange={handleOnchangeUserName} - value={publicUserName} - disabled={!editmode} - placeholder="enter user name" - className="op-input op-input-bordered op-input-sm w-[180px] focus:outline-none hover:border-base-content text-sm" - /> - </> - ) : ( - <div className="flex flex-row gap-1 items-center justify-between md:justify-start"> - <span - rel="noreferrer" - target="_blank" - onClick={() => openInNewTab(getPublicUrl)} - className="cursor-pointer underline hover:text-blue-800 w-[110px] md:w-[150px] whitespace-nowrap overflow-hidden text-ellipsis" - > - {isStaging - ? `staging.opensign.me/${extendUser?.[0]?.UserName}` - : `opensign.me/${extendUser?.[0]?.UserName}`} - </span> - <div className="flex items-center gap-2"> - <RWebShare - data={{ url: getPublicUrl, title: "Sign url" }} - > - <button className="op-btn op-btn-primary op-btn-outline op-btn-xs md:op-btn-sm "> - <i className="fa-light fa-share-from-square"></i>{" "} - </button> - </RWebShare> - <button - className="op-btn op-btn-primary op-btn-outline op-btn-xs md:op-btn-sm" - onClick={() => copytoclipboard()} - > - <i className="fa-light fa-copy" /> - </button> - </div> - </div> - )} - </div> - </li> - <li className="flex flex-row justify-between items-center border-t-[1px] border-gray-300 py-2 break-all"> - <span className="font-semibold flex gap-1"> - {t("tagline")} :{" "} - <Tooltip handleOnlickHelp={handleOnlickHelp} /> - </span> - <div className="flex flex-row md:items-center gap-1"> - {editmode || !extendUser?.[0]?.Tagline ? ( - <input - maxLength={100} - onChange={handleOnchangeTagLine} - value={tagLine} - disabled={!editmode} - placeholder="enter tagline" - className="op-input op-input-bordered op-input-sm w-[180px] focus:outline-none hover:border-base-content text-sm" - /> - ) : ( - <span>{extendUser?.[0]?.Tagline}</span> - )} - </div> - </li> - </> - )} - {isEnableSubscription && ( - <li className="border-y-[1px] border-gray-300 break-all"> - <div className="flex justify-between items-center py-2"> - <span - className={ - validplan[isPlan.plan] - ? "font-semibold" - : "font-semibold text-gray-300" - } - > - {t("disable-documentId")} :{" "} - <Tooltip - url={ - "https://docs.opensignlabs.com/docs/help/Settings/disabledocumentid" - } - /> - {!validplan[isPlan.plan] && isEnableSubscription && ( - <Upgrade /> - )} - </span> - <label - className={`${ - validplan[isPlan.plan] - ? `${editmode ? "cursor-pointer" : ""}` - : "pointer-events-none opacity-50" - } relative block items-center mb-0`} - > - <input - disabled={ - validplan[isPlan.plan] && editmode ? false : true - } - type="checkbox" - className="op-toggle transition-all checked:[--tglbg:#3368ff] checked:bg-white" - checked={isDisableDocId} - onChange={handleDisableDocId} - /> - </label> - </div> - </li> - )} <li className={`flex justify-between items-center border-b-[1px] border-gray-300 break-all ${ editmode ? "py-1.5" : "py-2" @@ -677,26 +408,13 @@ function UserProfile() { /> </li> </ul> - <div - className={`${ - !isEnableSubscription ? "border-t-[1px] border-gray-300" : "" - } flex justify-center gap-2 pt-2 pb-3 md:pt-3 md:pb-4`} - > + <div className="flex justify-center gap-2 pt-2 pb-3 md:pt-3 md:pb-4"> <button type="button" onClick={(e) => { - if ( - editmode && - !isSubscribe && - publicUserName?.length > 0 && - publicUserName?.length < 9 - ) { - setIsUpgrade(true); - } else { editmode ? handleSubmit(e) : setEditMode(true); - } }} - className="op-btn op-btn-primary" + className="op-btn op-btn-primary w-[100px]" > {editmode ? t("save") : t("edit")} </button> @@ -706,7 +424,7 @@ function UserProfile() { editmode ? handleCancel() : navigate("/changepassword") } className={`op-btn ${ - editmode ? "op-btn-ghost" : "op-btn-secondary" + editmode ? "op-btn-ghost w-[100px]" : "op-btn-secondary" }`} > {editmode ? t("cancel") : t("change-password")} @@ -756,38 +474,6 @@ function UserProfile() { )} </ModalUi> )} - - {isUpgrade && ( - <div className="op-modal op-modal-open"> - <div className="max-h-90 bg-base-100 w-[95%] md:max-w-[500px] rounded-box relative"> - <> - <div - className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-primary-content absolute right-2 top-2 z-40" - onClick={() => setIsUpgrade(false)} - > - ✕ - </div> - - <div className="op-card op-bg-primary text-primary-content w-full shadow-lg"> - <div className="op-card-body"> - <h2 className="op-card-title"> - {t("upgrade-to")} {t("plan")} - </h2> - <p>{t("user-name-limit-char")}</p> - <div className="op-card-actions justify-end"> - <button - onClick={() => handlePaidRoute()} - className="op-btn op-btn-accent" - > - {t("upgrade-now")} - </button> - </div> - </div> - </div> - </> - </div> - </div> - )} </div> )} </React.Fragment> diff --git a/apps/OpenSign/src/pages/Webhook.js b/apps/OpenSign/src/pages/Webhook.js deleted file mode 100644 index 6ee94a760..000000000 --- a/apps/OpenSign/src/pages/Webhook.js +++ /dev/null @@ -1,200 +0,0 @@ -import React, { useEffect, useState } from "react"; -import Title from "../components/Title"; -import axios from "axios"; -import Alert from "../primitives/Alert"; -import ModalUi from "../primitives/ModalUi"; -import { isEnableSubscription } from "../constant/const"; -import { checkIsSubscribed, openInNewTab } from "../constant/Utils"; -import Parse from "parse"; -import Tooltip from "../primitives/Tooltip"; -import Loader from "../primitives/Loader"; -import SubscribeCard from "../primitives/SubscribeCard"; -import Tour from "reactour"; -import { useTranslation } from "react-i18next"; - -function Webhook() { - const { t } = useTranslation(); - const [parseBaseUrl] = useState(localStorage.getItem("baseUrl")); - const [parseAppId] = useState(localStorage.getItem("parseAppId")); - const [webhook, setWebhook] = useState(); - const [isLoader, setIsLoader] = useState(true); - const [isModal, setIsModal] = useState(false); - const [isSubscribe, setIsSubscribe] = useState({ plan: "", isValid: true }); - const [error, setError] = useState(""); - const [isAlert, setIsAlert] = useState({ type: "success", msg: "" }); - const [isTour, setIsTour] = useState(false); - useEffect(() => { - fetchWebhook(); - // eslint-disable-next-line - }, []); - const tourSteps = [ - { - selector: '[data-tut="webhooksubscribe"]', - content: t("tour-mssg.webhook-1") - } - ]; - const fetchWebhook = async () => { - if (isEnableSubscription) { - const subscribe = await checkIsSubscribed(); - setIsSubscribe(subscribe); - } - try { - const extRes = await Parse.Cloud.run("getUserDetails"); - if (extRes) { - setWebhook(extRes.get("Webhook")); - } - setIsLoader(false); - } catch (err) { - setWebhook(); - setIsLoader(false); - console.log("Err", err); - } - }; - const handleSubmit = async (e) => { - e.preventDefault(); - if (webhook && webhook.startsWith("https://")) { - setIsLoader(true); - setIsModal(false); - try { - const params = { url: webhook }; - const url = parseBaseUrl + "functions/savewebhook"; - const headers = { - "Content-Type": "application/json", - "X-Parse-Application-Id": parseAppId, - sessiontoken: localStorage.getItem("accesstoken") - }; - const res = await axios.post(url, params, { headers: headers }); - if (res.data && res.data.result && res.data.result.Webhook) { - setWebhook(res.data.result.Webhook); - setIsAlert({ type: "success", msg: t("webhook-added") }); - } else { - console.error("Error while generating webhook"); - setIsAlert({ type: "danger", msg: t("something-went-wrong-mssg") }); - } - } catch (error) { - setIsAlert({ type: "danger", msg: t("something-went-wrong-mssg") }); - console.log("err while generating webhook", error); - } finally { - setIsLoader(false); - setTimeout(() => { - setIsAlert({ type: "success", msg: "" }); - }, 1500); - } - } else { - setError("The webhook url should always start with https://"); - setTimeout(() => { - setError(""); - }, 1500); - } - }; - - const handleModal = () => { - if (!isSubscribe?.isValid && isEnableSubscription) { - setIsTour(true); - } else { - setIsModal(!isModal); - } - }; - return ( - <React.Fragment> - <Title title={"Webhook"} /> - {isAlert.msg && <Alert type={isAlert.type}>{isAlert.msg}</Alert>} - {isLoader ? ( - <div className="h-[100vh] flex justify-center items-center"> - <Loader /> - </div> - ) : ( - <> - <div className="bg-base-100 text-base-content flex flex-col justify-center shadow-md rounded-box mb-3"> - <h1 className={"ml-4 mt-3 mb-2 font-semibold"}> - OpenSign™ {t("webhook")}{" "} - <Tooltip - url={"https://docs.opensignlabs.com/docs/API-docs/get-webhook"} - isSubscribe={true} - /> - </h1> - <ul className={"w-full flex flex-col p-2 text-sm"}> - <li className="flex flex-col md:flex-row justify-between items-center border-y-[1px] border-gray-300 break-all py-2"> - <div className="w-[70%] flex-col md:flex-row flex items-center gap-5"> - <span className="">{t("webhook")}:</span>{" "} - <span id="token" className=" md:text-end cursor-pointer"> - {webhook ? webhook : "_____"} - </span> - </div> - <button - type="button" - onClick={handleModal} - className="op-btn op-btn-primary" - > - {webhook ? t("update-webhook") : t("add-webhook")} - </button> - </li> - </ul> - <div className="flex items-center justify-center"> - <button - type="button" - onClick={() => - openInNewTab( - "https://docs.opensignlabs.com/docs/API-docs/save-update-webhook" - ) - } - className="op-btn op-btn-secondary mt-2 mb-3 px-7" - > - {t("view-docs")} - </button> - </div> - <ModalUi - isOpen={isModal} - title={t("add-webhook")} - handleClose={handleModal} - > - {error && <Alert type="danger">{error}</Alert>} - <div className="m-[20px]"> - <div className="text-lg font-normal text-base-content"> - <label className="text-sm ml-2">{t("webhook")}</label> - <input - value={webhook} - onChange={(e) => setWebhook(e.target.value)} - placeholder="Enter webhook url" - className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" - /> - </div> - <hr className="bg-[#ccc] mt-3" /> - <div className="flex items-center mt-3 gap-2"> - <button - onClick={handleSubmit} - className="op-btn op-btn-primary ml-[2px]" - > - {t("yes")} - </button> - <button - onClick={handleModal} - className="op-btn op-btn-secondary" - > - {t("no")} - </button> - </div> - </div> - </ModalUi> - </div> - {isEnableSubscription && !isSubscribe?.isValid && ( - <div data-tut="webhooksubscribe"> - <SubscribeCard /> - </div> - )} - </> - )} - <Tour - onRequestClose={() => setIsTour(false)} - steps={tourSteps} - isOpen={isTour} - closeWithMask={false} - disableKeyboardNavigation={["esc"]} - scrollOffset={-100} - rounded={5} - /> - </React.Fragment> - ); -} - -export default Webhook; diff --git a/apps/OpenSign/src/primitives/AddContact.js b/apps/OpenSign/src/primitives/AddContact.js index 69f8b2f8b..9c71e9177 100644 --- a/apps/OpenSign/src/primitives/AddContact.js +++ b/apps/OpenSign/src/primitives/AddContact.js @@ -12,6 +12,7 @@ const AddContact = (props) => { const [addYourself, setAddYourself] = useState(false); const [isLoader, setIsLoader] = useState(false); const [isUserExist, setIsUserExist] = useState(false); + useEffect(() => { checkUserExist(); // eslint-disable-next-line react-hooks/exhaustive-deps @@ -32,9 +33,8 @@ const AddContact = (props) => { try { const baseURL = localStorage.getItem("baseUrl"); const url = `${baseURL}functions/isuserincontactbook`; - const token = props?.jwttoken - ? { jwttoken: props?.jwttoken } - : { "X-Parse-Session-Token": localStorage.getItem("accesstoken") }; + const token = + { "X-Parse-Session-Token": localStorage.getItem("accesstoken") }; const headers = { "Content-Type": "application/json", "X-Parse-Application-Id": localStorage.getItem("parseAppId"), @@ -63,15 +63,18 @@ const AddContact = (props) => { ) ); const userId = user?.objectId || ""; - const tenantDetails = await getTenantDetails(userId, props.jwttoken); + const tenantDetails = await getTenantDetails( + userId, + ); const tenantId = tenantDetails?.objectId || ""; if (tenantId) { try { const baseURL = localStorage.getItem("baseUrl"); const url = `${baseURL}functions/savecontact`; - const token = props?.jwttoken - ? { jwttoken: props?.jwttoken } - : { "X-Parse-Session-Token": localStorage.getItem("accesstoken") }; + const token = + { + "X-Parse-Session-Token": localStorage.getItem("accesstoken") + }; const data = { name, email, phone, tenantId }; const headers = { "Content-Type": "application/json", @@ -121,6 +124,9 @@ const AddContact = (props) => { }; const handleReset = () => { setAddYourself(false); + setName(""); + setPhone(""); + setEmail(""); }; return ( diff --git a/apps/OpenSign/src/primitives/DownloadPdfZip.js b/apps/OpenSign/src/primitives/DownloadPdfZip.js index a5902fedb..46807c6f7 100644 --- a/apps/OpenSign/src/primitives/DownloadPdfZip.js +++ b/apps/OpenSign/src/primitives/DownloadPdfZip.js @@ -22,25 +22,30 @@ function DownloadPdfZip(props) { const handleDownload = async () => { if (selectType === 1) { - await handleDownloadPdf(props.pdfDetails, setIsDownloading); + await handleDownloadPdf( + props.pdfDetails, + setIsDownloading, + props?.pdfBase64 + ); setSelectType(1); props.setIsDownloadModal(false); } else if (selectType === 2) { setIsDownloading("pdf"); const zip = new JSZip(); const pdfDetails = props.pdfDetails; - const pdfName = pdfDetails?.[0]?.Name || "Document"; + const pdfName = + pdfDetails?.[0]?.Name?.length > 100 + ? pdfDetails?.[0]?.Name?.slice(0, 100) + : pdfDetails?.[0]?.Name || "Document"; const pdfUrl = pdfDetails?.[0]?.SignedUrl || ""; try { // Fetch the first PDF (Signed Document) const docId = pdfDetails?.[0]?.objectId || ""; - const fileAdapterId = pdfDetails?.[0]?.FileAdapterId - ? pdfDetails?.[0]?.FileAdapterId - : ""; - console.log("pdfDetails?.[0] ", pdfDetails?.[0]); - const signedUrl = await getSignedUrl(pdfUrl, docId, fileAdapterId); - console.log("signedUrl ", signedUrl); + const signedUrl = await getSignedUrl( + pdfUrl, + docId, + ); const pdf1Response = await fetch(signedUrl); if (!pdf1Response.ok) { throw new Error(`Failed to fetch PDF: ${signedUrl}`); @@ -118,17 +123,22 @@ function DownloadPdfZip(props) { </div> )} <ModalUi - isOpen={isDownloading === "certificate"} + isOpen={ + isDownloading === "certificate" || isDownloading === "certificate_err" + } title={ - isDownloading === "certificate" + isDownloading === "certificate" || isDownloading === "certificate_err" ? t("generating-certificate") : t("pdf-download") } handleClose={() => setIsDownloading("")} > <div className="p-3 md:p-5 text-[13px] md:text-base text-center text-base-content"> - {isDownloading === "certificate"}{" "} - <p>{t("generate-certificate-alert")}</p> + {isDownloading === "certificate" ? ( + <p>{t("generate-certificate-alert")}</p> + ) : ( + <p>{t("generate-certificate-err")}</p> + )} </div> </ModalUi> </ModalUi> diff --git a/apps/OpenSign/src/primitives/GetReportDisplay.js b/apps/OpenSign/src/primitives/GetReportDisplay.js index b75d0ddf3..c16c64499 100644 --- a/apps/OpenSign/src/primitives/GetReportDisplay.js +++ b/apps/OpenSign/src/primitives/GetReportDisplay.js @@ -1,27 +1,28 @@ import React, { useState, useEffect } from "react"; import pad from "../assets/images/pad.svg"; -import { useLocation, useNavigate } from "react-router-dom"; +import { useLocation, useNavigate } from "react-router"; import axios from "axios"; import ModalUi from "./ModalUi"; import AddSigner from "../components/AddSigner"; -import { isEnableSubscription, isStaging } from "../constant/const"; +import { + emailRegex, +} from "../constant/const"; import Alert from "./Alert"; import Tooltip from "./Tooltip"; import { RWebShare } from "react-web-share"; import Tour from "reactour"; import Parse from "parse"; import { - checkIsSubscribed, copytoData, fetchUrl, formatDate, + formatTimeInTimezone, getSignedUrl, getTenantDetails, handleSignatureType, replaceMailVaribles, signatureTypes } from "../constant/Utils"; -import Confetti from "react-confetti"; import EditorToolbar, { module1, formats @@ -30,13 +31,11 @@ import ReactQuill from "react-quill-new"; import "../styles/quill.css"; import BulkSendUi from "../components/BulkSendUi"; import Loader from "./Loader"; -import Select from "react-select"; -import SubscribeCard from "./SubscribeCard"; -import { validplan } from "../json/plansArr"; import { serverUrl_fn } from "../constant/appinfo"; import { useTranslation } from "react-i18next"; import DownloadPdfZip from "./DownloadPdfZip"; -import EmbedTab from "../components/pdf/EmbedTab"; +import * as XLSX from "xlsx"; +import EditContactForm from "../components/EditContactForm"; const ReportTable = (props) => { const { t } = useTranslation(); @@ -58,7 +57,6 @@ const ReportTable = (props) => { const [isTour, setIsTour] = useState(false); const [tourStatusArr, setTourStatusArr] = useState([]); const [isResendMail, setIsResendMail] = useState({}); - const [isMakePublicModal, setIsMakePublicModal] = useState({}); const [mail, setMail] = useState({ subject: "", body: "" }); const [userDetails, setUserDetails] = useState({}); const [isNextStep, setIsNextStep] = useState({}); @@ -67,24 +65,22 @@ const ReportTable = (props) => { const [placeholders, setPlaceholders] = useState([]); const [isLoader, setIsLoader] = useState({}); const [isShareWith, setIsShareWith] = useState({}); - const [teamList, setTeamList] = useState([]); const [selectedTeam, setSelectedTeam] = useState([]); - const onChange = (selectedOptions) => setSelectedTeam(selectedOptions); - const [selectedPublicRole, setSelectedPublicRole] = useState(""); - const [isCelebration, setIsCelebration] = useState(false); - const [isPublicProfile, setIsPublicProfile] = useState({}); - const [publicUserName, setIsPublicUserName] = useState(""); const [isViewShare, setIsViewShare] = useState({}); - const [isSubscribe, setIsSubscribe] = useState(true); const [isModal, setIsModal] = useState({}); const [reason, setReason] = useState(""); const [isDownloadModal, setIsDownloadModal] = useState(false); - const [isEmbed, setIsEmbed] = useState(false); - const [isPublicTour, setIsPublicTour] = useState(); const [signatureType, setSignatureType] = useState([]); const [expiryDate, setExpiryDate] = useState(""); const Extand_Class = localStorage.getItem("Extand_Class"); const extClass = Extand_Class && JSON.parse(Extand_Class); + const [importedData, setImportedData] = useState([]); + const [currentImportPage, setCurrentImportPage] = useState(1); + const [isShowAllSigners, setIsShowAllSigners] = useState({}); + const [invalidRecords, setInvalidRecords] = useState(0); + const [renameDoc, setRenameDoc] = useState(""); + const [contact, setContact] = useState({ Name: "", Email: "", Phone: "" }); + const recordsPerPage = 5; const startIndex = (currentPage - 1) * props.docPerPage; const { isMoreDocs, setIsNextRecord } = props; @@ -157,12 +153,6 @@ const ReportTable = (props) => { const teamtRes = await Parse.Cloud.run("getteams", { active: true }); if (teamtRes.length > 0) { const _teamRes = JSON.parse(JSON.stringify(teamtRes)); - const formatedList = _teamRes.map((x) => ({ - label: x.Name, - value: x.objectId - })); - setTeamList(formatedList); - if (!isEnableSubscription) { const selected = _teamRes.map( (x) => x.Name === "All Users" && { @@ -171,7 +161,6 @@ const ReportTable = (props) => { } ); setSelectedTeam(selected); - } } } } catch (err) { @@ -232,7 +221,7 @@ const ReportTable = (props) => { const handleURL = async (item, act) => { if (props.ReportName === "Templates") { if (act.hoverLabel === "Edit") { - navigate(`/${act.redirectUrl}/${item.objectId}`); + navigate(`/${act.redirectUrl}/${item.objectId}`); } else { setActLoader({ [`${item.objectId}_${act.btnId}`]: true }); try { @@ -267,7 +256,6 @@ const ReportTable = (props) => { }); } - // console.log("extClass ", extClass); let extUserId = Doc.ExtUserPtr.objectId; let creatorId = Doc.CreatedBy.objectId; if (extClass && extClass.length > 0) { @@ -291,9 +279,13 @@ const ReportTable = (props) => { ? { SignatureType: updatedSignatureType } : {}; const NotifyOnSignatures = - Doc.NotifyOnSignatures !== undefined + 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; @@ -320,9 +312,11 @@ const ReportTable = (props) => { AutomaticReminders: Doc?.AutomaticReminders || false, RemindOnceInEvery: Doc?.RemindOnceInEvery || 5, IsEnableOTP: Doc?.IsEnableOTP || false, - FileAdapterId: Doc?.FileAdapterId || "", + AllowModifications: Doc?.AllowModifications || false, ...SignatureType, - ...NotifyOnSignatures + ...NotifyOnSignatures, + ...Bcc, + ...RedirectUrl }; try { const res = await axios.post( @@ -403,12 +397,6 @@ const ReportTable = (props) => { } else if (act.action === "bulksend") { handleBulkSend(item); } else if (act.action === "sharewith") { - if (isEnableSubscription) { - const subscribe = await checkIsSubscribed(); - setIsSubscribe(subscribe); - } else { - setIsSubscribe({ plan: "teams-yearly", isValid: true }); - } if (item?.SharedWith && item?.SharedWith.length > 0) { // below code is used to get existing sharewith teams and formated them as per react-select const formatedList = item?.SharedWith.map((x) => ({ @@ -418,23 +406,14 @@ const ReportTable = (props) => { setSelectedTeam(formatedList); } setIsShareWith({ [item.objectId]: true }); - } else if (act.action === "Embed") { - handleEmbedFunction(item); - } else if (act.action === "CopyTemplateId") { - copyTemplateId(item.objectId); - } else if (act.action === "CopyPublicURL") { - const isPublic = item?.IsPublic; - if (isPublic) { - let publicUrl = ""; - if (isStaging) { - publicUrl = `https://staging.opensign.me/publicsign?templateid=${item.objectId}`; - } else { - publicUrl = `https://opensign.me/publicsign?templateid=${item.objectId}`; - } - copyTemplateId(publicUrl); - } else { - setIsPublicTour({ [item.objectId]: true }); - } + } + else if (act.action === "duplicate") { + setIsModal({ [`duplicate_${item.objectId}`]: true }); + } else if (act.action === "rename") { + setIsModal({ [`rename_${item.objectId}`]: true }); + } else if (act.action === "edit") { + setContact(item); + setIsModal({ [`edit_${item.objectId}`]: true }); } else if (act.action) { setIsModal({ [`extendexpiry_${item.objectId}`]: true }); } @@ -512,18 +491,10 @@ const ReportTable = (props) => { setActLoader({}); } }; - const handleClose = (item) => { + const handleClose = ( + ) => { setIsRevoke({}); setIsDeleteModal({}); - setIsMakePublicModal({}); - setSelectedPublicRole(""); - setIsPublicProfile({}); - if (item?.objectId) { - props.setIsPublic((prevStates) => ({ - ...prevStates, - [item.objectId]: !prevStates[item.objectId] - })); - } setReason(""); }; const handleShare = (item) => { @@ -599,41 +570,6 @@ const ReportTable = (props) => { (x) => x.objectId !== item.objectId ); props.setList(upldatedList); - const params = { - event: "declined", - body: { - objectId: item.objectId, - file: item?.SignedUrl || item?.URL, - name: item?.Name, - note: item?.Note || "", - description: item?.Description || "", - signers: item?.Signers?.map((x) => ({ - name: x?.Name, - email: x?.Email, - phone: x?.Phone - })), - declinedBy: jsonSender?.email, - declinedReason: reason, - declinedAt: new Date(), - createdAt: item?.createdAt - } - }; - - try { - await axios.post( - `${localStorage.getItem("baseUrl")}functions/callwebhook`, - params, - { - headers: { - "Content-Type": "application/json", - "X-Parse-Application-Id": localStorage.getItem("parseAppId"), - sessiontoken: localStorage.getItem("accesstoken") - } - } - ); - } catch (err) { - console.log("Err ", err); - } } setReason(""); }) @@ -700,12 +636,13 @@ const ReportTable = (props) => { const handleDownload = async (item) => { setActLoader({ [`${item.objectId}`]: true }); const url = item?.SignedUrl || item?.URL || ""; - const pdfName = item?.Name || "exported_file"; + const pdfName = + item?.Name?.length > 100 + ? item?.Name?.slice(0, 100) + : item?.Name || "Document"; const isCompleted = item?.IsCompleted || false; const templateId = props?.ReportName === "Templates" && item.objectId; const docId = props?.ReportName !== "Templates" && item.objectId; - const fileAdapterId = item?.FileAdapterId ? item?.FileAdapterId : ""; - if (url) { try { if (isCompleted) { @@ -714,7 +651,6 @@ const ReportTable = (props) => { const signedUrl = await getSignedUrl( url, docId, - fileAdapterId, templateId ); await fetchUrl(signedUrl, pdfName); @@ -743,10 +679,12 @@ const ReportTable = (props) => { const signPdf = `${window.location.origin}/login/${encodeBase64}`; const variables = { document_title: doc.Name, - sender_name: doc.ExtUserPtr.Name, - sender_mail: doc.ExtUserPtr.Email, + sender_name: + doc.ExtUserPtr.Name, + sender_mail: + doc.ExtUserPtr.Email, sender_phone: doc.ExtUserPtr?.Phone || "", - receiver_name: userDetails?.Name, + receiver_name: userDetails?.Name || "", receiver_email: userDetails?.Email, receiver_phone: userDetails?.Phone || "", expiry_date: localExpireDate, @@ -772,8 +710,10 @@ const ReportTable = (props) => { const signPdf = `${window.location.origin}/login/${encodeBase64}`; const variables = { document_title: doc.Name, - sender_name: doc.ExtUserPtr.Name, - sender_mail: doc.ExtUserPtr.Email, + sender_name: + doc.ExtUserPtr.Name, + sender_mail: + doc.ExtUserPtr.Email, sender_phone: doc.ExtUserPtr?.Phone || "", receiver_name: userDetails?.Name || "", receiver_email: userDetails?.Email || "", @@ -813,8 +753,10 @@ const ReportTable = (props) => { const signPdf = `${window.location.origin}/login/${encodeBase64}`; const variables = { document_title: doc.Name, - sender_name: doc.ExtUserPtr.Name, - sender_mail: doc.ExtUserPtr.Email, + sender_name: + doc.ExtUserPtr.Name, + sender_mail: + doc.ExtUserPtr.Email, sender_phone: doc.ExtUserPtr?.Phone || "", receiver_name: user?.signerPtr?.Name || "", receiver_email: user?.email ? user?.email : user?.signerPtr?.Email, @@ -844,11 +786,14 @@ const ReportTable = (props) => { sessionToken: localStorage.getItem("accesstoken") }; let params = { - mailProvider: doc?.ExtUserPtr?.active_mail_adapter || "", + replyto: + doc?.ExtUserPtr?.Email || + "", extUserId: doc?.ExtUserPtr?.objectId, recipient: userDetails?.Email, subject: mail.subject, - from: doc?.ExtUserPtr?.Email, + from: + doc?.ExtUserPtr?.Email, html: mail.body }; try { @@ -856,6 +801,7 @@ const ReportTable = (props) => { if (res?.data?.result?.status === "success") { setIsAlert(true); setAlertMsg({ type: "success", message: t("mail-sent-alert") }); + setIsResendMail({}); } else { setIsAlert(true); setAlertMsg({ @@ -968,189 +914,10 @@ const ReportTable = (props) => { setTimeout(() => setIsAlert(false), 1500); } }; - //function to make template public and set public role - const handlePublicTemplate = async (item) => { - if (selectedPublicRole || !props.isPublic[item.objectId]) { - setActLoader({ [item.objectId]: true }); - setIsMakePublicModal(false); - try { - const res = await Parse.Cloud.run("createpublictemplate", { - templateid: item.objectId, - ispublic: props.isPublic[item.objectId], - publicrole: [selectedPublicRole] - }); - - if (res.status === "success") { - setIsAlert(true); - setTimeout(() => setIsAlert(false), 1500); - if (props.isPublic[item.objectId]) { - setAlertMsg({ - type: "success", - message: t("template-public-alert-1") - }); - setIsCelebration(true); - setTimeout(() => { - setIsCelebration(false); - }, 5000); - setIsPublicProfile({ - [item.objectId]: props.isPublic[item.objectId] - }); - } else { - setAlertMsg({ - type: "success", - message: t("template-public-alert-2") - }); - setSelectedPublicRole(""); - } - const updateList = props.List.map((x) => - x.objectId === item.objectId - ? { ...x, IsPublic: props.isPublic[item.objectId] } - : x - ); - props.setList(updateList); - setActLoader({}); - } - } catch (e) { - console.log("error in createpublictemplate", e); - setIsAlert(true); - setAlertMsg({ - type: "danger", - message: t("something-went-wrong-mssg") - }); - setTimeout(() => setIsAlert(false), 1500); - props.setIsPublic((prevStates) => ({ - ...prevStates, - [item.objectId]: !prevStates[item.objectId] - })); - } - } else { - setIsAlert(true); - setAlertMsg({ - type: "danger", - message: t("template-public-alert-3") - }); - setTimeout(() => setIsAlert(false), 1500); - } - }; const handleViewSigners = (item) => { setIsViewShare({ [item.objectId]: true }); }; - //function to handle change template status is public or private - const handlePublicChange = async (e, item) => { - const getPlaceholder = item?.Placeholders; - //checking index for public role - const getIndex = getPlaceholder?.findIndex((obj) => !obj?.signerObjId); - //conditon to check empty role is exist or not - if (getPlaceholder && getPlaceholder.length > 0 && getIndex >= 0) { - const signers = item?.Signers; - //condition to check that every role is attached to signers except the public role. - if (getPlaceholder.length - 1 === signers?.length) { - //check template send in order - const IsSendInOrder = item?.SendinOrder; - //condition for if send in order true then the public role order should be prioritized. - //When send in order is false and there's no need to verify the public role's order - if ((IsSendInOrder && getIndex === 0) || !IsSendInOrder) { - const checkIsSignatureExist = getPlaceholder?.every( - (placeholderObj) => - placeholderObj?.placeHolder?.some((holder) => - holder?.pos?.some((posItem) => posItem?.type === "signature") - ) - ); - //condition for validate signature widgets should be all signers - if (checkIsSignatureExist) { - let extendUser = JSON.parse(localStorage.getItem("Extand_Class")); - const userName = extendUser[0]?.UserName; - setIsPublicUserName(extendUser[0]?.UserName); - //condition to check user have public url or not - if (userName) { - //`setIsPublic` variable is used to collect all template public status - props.setIsPublic((prevStates) => ({ - ...prevStates, - [item.objectId]: e.target.checked - })); - if (getPlaceholder[getIndex]?.Role) { - setSelectedPublicRole(getPlaceholder[getIndex].Role); - } - //`setIsMakePublicModal` is used to open modal after succesfully make public - setIsMakePublicModal({ [item.objectId]: true }); - } else { - setIsPublicProfile({ [item.objectId]: true }); - } - } else { - setIsAlert(true); - setAlertMsg({ - type: "danger", - message: t("template-public-alert-4") - }); - setTimeout(() => setIsAlert(false), 5000); - } - } else if (IsSendInOrder) { - setIsAlert(true); - setAlertMsg({ - type: "danger", - message: t("template-public-alert-5") - }); - setTimeout(() => setIsAlert(false), 5000); - } - } else { - setIsAlert(true); - setAlertMsg({ - type: "danger", - message: t("template-public-alert-6") - }); - setTimeout(() => setIsAlert(false), 5000); - } - } else { - setIsAlert(true); - setAlertMsg({ - type: "danger", - message: t("template-public-alert-7") - }); - setTimeout(() => setIsAlert(false), 5000); - } - }; - - const publicUrl = () => { - const subDomain = isStaging - ? `https://staging.opensign.me/` - : `https://opensign.me/`; - const url = `${subDomain}${publicUserName}`; - return url; - }; - // function to copy public profile links - const copytoProfileLink = () => { - const url = publicUrl(); - copytoData(url); - setIsAlert(true); - setAlertMsg({ - type: "success", - message: t("copied") - }); - setCopied({ ...copied, publicprofile: true }); - setTimeout(() => { - setIsAlert(false); - setCopied(false); - }, 1500); - }; - - const copyTemplateId = (templateid) => { - copytoData(templateid); - setIsAlert(true); - setAlertMsg({ - type: "success", - message: t("copied") - }); - setCopied({ ...copied, templateid: true }); - setTimeout(() => { - setIsAlert(false); - setCopied(false); - }, 1500); - }; - const handleShowRole = (item) => { - const getRole = item.Placeholders.find((data) => !data.signerObjId); - return getRole?.Role; - }; // `handleShareWith` is used to save teams in sharedWith field const handleShareWith = async (e, template) => { e.preventDefault(); @@ -1185,26 +952,7 @@ const ReportTable = (props) => { setTimeout(() => setIsAlert(false), 1500); } }; - const handleEmbedFunction = async (item) => { - setIsEmbed(true); - setIsPublicProfile({ - [item.objectId]: true - }); - let extendUser = JSON.parse(localStorage.getItem("Extand_Class")); - setIsPublicUserName(extendUser[0]?.UserName || ""); - }; - const publicTourConfig = [ - { - selector: '[data-tut="IsPublic"]', - content: t("public-tour-message"), - position: "top", - style: { fontSize: "13px" } - } - ]; - const closePublicTour = () => { - setIsPublicTour(); - }; const handleUpdateExpiry = async (e, item) => { e.preventDefault(); e.stopPropagation(); @@ -1273,16 +1021,19 @@ const ReportTable = (props) => { (audit) => audit?.UserPtr?.objectId === x.signerObjId ); if (matchSigner) { + const timezone = extClass?.[0]?.Timezone || ""; + const signedon = matchSigner?.SignedOn + ? formatTimeInTimezone(new Date(matchSigner?.SignedOn), timezone) + : "-"; + const viewedon = matchSigner?.ViewedOn + ? formatTimeInTimezone(new Date(matchSigner?.ViewedOn), timezone) + : "-"; return { id: i, Email: matchSigner.UserPtr.Email, Activity: matchSigner?.Activity?.toUpperCase() || "-", - SignedOn: matchSigner?.SignedOn - ? new Date(matchSigner?.SignedOn)?.toUTCString() - : "-", - ViewedOn: matchSigner?.ViewedOn - ? new Date(matchSigner?.ViewedOn)?.toUTCString() - : "-" + SignedOn: signedon, + ViewedOn: viewedon }; } else { return { @@ -1294,39 +1045,357 @@ const ReportTable = (props) => { }; } }); - return signers?.map((x, i) => ( - <div - key={i} - className="text-sm font-medium flex flex-row gap-2 items-center" - > - <button - onClick={() => setIsModal({ [`${item.objectId}_${i}`]: true })} - className={`${ - x.Activity === "SIGNED" - ? "op-border-primary op-text-primary" - : x.Activity === "VIEWED" - ? "border-green-400 text-green-400" - : "border-black text-black" - } focus:outline-none border-2 w-[60px] h-[30px] text-[11px] rounded-full`} - > - {x?.Activity?.toUpperCase() || "-"} - </button> - <div className="py-2 font-bold text-[12px]">{x?.Email || "-"}</div> - {isModal[`${item.objectId}_${i}`] && ( - <ModalUi - isOpen - title={t("document-logs")} - handleClose={() => setIsModal({})} + // Decide how many signers to display based on `showAllSignes` state + const displaySigners = isShowAllSigners[item.objectId] + ? signers + : signers.slice(0, 3); + return ( + <> + {displaySigners?.map((x, i) => ( + <div + key={i} + className="text-sm font-medium flex flex-row gap-2 items-center" > - <div className="pl-3 first:mt-2 border-t-[1px] border-gray-600 text-[12px] py-2"> - <p className="font-bold"> {x?.Email}</p> - <p>Viewed on: {x?.ViewedOn}</p> - <p>Signed on: {x?.SignedOn}</p> - </div> - </ModalUi> + <button + onClick={() => setIsModal({ [`${item.objectId}_${i}`]: true })} + className={`${ + x.Activity === "SIGNED" + ? "op-border-primary op-text-primary" + : x.Activity === "VIEWED" + ? "border-green-400 text-green-400" + : "border-black text-black" + } focus:outline-none border-2 w-[60px] h-[30px] text-[11px] rounded-full`} + > + {x?.Activity?.toUpperCase() || "-"} + </button> + <div className="py-2 font-bold text-[12px]">{x?.Email || "-"}</div> + {isModal[`${item.objectId}_${i}`] && ( + <ModalUi + isOpen + title={t("document-logs")} + handleClose={() => setIsModal({})} + > + <div className="pl-3 first:mt-2 border-t-[1px] border-gray-600 text-[12px] py-2"> + <p className="font-bold"> {x?.Email}</p> + <p>Viewed on: {x?.ViewedOn}</p> + <p>Signed on: {x?.SignedOn}</p> + </div> + </ModalUi> + )} + </div> + ))} + {/* Show More / Hide button */} + {signers?.length > 3 && ( + <button + onClick={() => + setIsShowAllSigners({ + [item.objectId]: !isShowAllSigners[item.objectId] + }) + } + className="ml-2 text-xs font-medium text-blue-500 underline focus:outline-none" + > + {isShowAllSigners[item.objectId] ? "Hide" : "Show More"} + </button> )} - </div> - )); + </> + ); + }; + + // `handleImportBtn` is trigger when user click on upload icon from contactbook + const handleImportBtn = () => { + setIsModal({ export: true }); + }; + + // `capitalize` is used to make word capitalize + const capitalize = (s) => + s && String(s[0]).toUpperCase() + String(s).slice(1); + + // `checkRequiredHeaders` is used to check required headers present or not in csv/excel file + const checkRequiredHeaders = (headers) => { + const requiredHeaders = ["Name", "Email"]; + // Normalize headers to lowercase once + const headersSet = new Set(headers.map((header) => header.toLowerCase())); + + // Check all required headers + const allPresent = requiredHeaders.every((requiredHeader) => + headersSet.has(requiredHeader.toLowerCase()) + ); + return allPresent; + }; + + const processCSVFile = async (file, event) => { + const reader = new FileReader(); + reader.onload = (e) => { + const text = e.target.result; + // Parse CSV data + const rows = text.split("\n").map((row) => row.trim()); + const headers = rows[0].split(",").map((header) => header.trim()); + if (checkRequiredHeaders(headers)) { + const records = rows.slice(1).reduce((acc, row) => { + const values = row?.split(",").map((value) => value.trim()) || []; + if (values.length > 1) { + acc.push( + headers.reduce( + (obj, header, index) => ({ + ...obj, + [capitalize(header)]: values[index] || "" + }), + {} + ) + ); + } + return acc; + }, []); + if (records.length <= 100) { + const validRecords = records.length + ? records.filter((x) => emailRegex.test(x.Email)) + : []; + const invalidItems = records?.length - validRecords?.length; + setInvalidRecords(invalidItems); + setImportedData(validRecords); + } else { + alert(t("100-records-only")); + event.target.value = ""; + setImportedData([]); + } + } else { + alert(t("invalid-data")); + event.target.value = ""; + } + }; + reader.readAsText(file); + }; + + const processExcelFile = (file, event) => { + if (file) { + const reader = new FileReader(); + reader.onload = (e) => { + const arrayBuffer = e.target.result; + const workbook = XLSX.read(new Uint8Array(arrayBuffer), { + type: "array" + }); + + // Get the first sheet + const sheetName = workbook.SheetNames[0]; + const sheet = workbook.Sheets[sheetName]; + + // Convert sheet to JSON + const sheetData = XLSX.utils.sheet_to_json(sheet); + if (sheetData.length <= 100) { + // Get all unique keys from the data to handle missing fields + const headers = [ + ...new Set(sheetData.flatMap((item) => Object.keys(item))) + ]; + + if (checkRequiredHeaders(headers)) { + const updateSheetData = sheetData.map((obj) => { + for (let key in obj) { + const capitalizedKey = capitalize(key); + if (capitalizedKey !== key) { + obj[capitalizedKey] = obj[key]; + delete obj[key]; // delete the old key to avoid duplicates + } + } + return obj; + }); + const validRecords = updateSheetData.length + ? updateSheetData.filter((x) => emailRegex.test(x.Email)) + : []; + const invalidItems = updateSheetData?.length - validRecords?.length; + setInvalidRecords(invalidItems); + setImportedData(validRecords); + } else { + alert(t("invalid-data")); + event.target.value = ""; + } + } else { + alert(t("100-records-only")); + event.target.value = ""; + setImportedData([]); + } + }; + + reader.readAsArrayBuffer(file); + } + }; + // `handleFileUpload` is trigger when user upload excel file from contactbook + const handleFileUpload = (event) => { + const file = event.target?.files?.[0]; + if (file) { + const fileName = file.name; + const fileNameExt = fileName + .substr(fileName.lastIndexOf(".") + 1) + .toLowerCase(); + const isValidExt = ["csv", "xlsx", "xls"].includes(fileNameExt); + if (isValidExt) { + setCurrentImportPage(1); + if (fileNameExt !== "csv") { + processExcelFile(file, event); + } else { + processCSVFile(file, event); + } + } else { + event.target.value = ""; + alert(t("csv-excel-support-only")); + } + } else { + setImportedData([]); + setCurrentImportPage(1); + setInvalidRecords(0); + } + }; + + // Get all unique keys from the data to handle missing fields + const allKeys = importedData?.length + ? [...new Set(importedData.flatMap((item) => Object.keys(item)))] + : []; + + // Pagination logic for import data table in modal + const totalImportPages = Math.ceil(importedData.length / recordsPerPage); + const currentRecords = importedData.slice( + (currentImportPage - 1) * recordsPerPage, + currentImportPage * recordsPerPage + ); + + // `handleNextPage` is used to importdata table in modal + const handleNextPage = (e) => { + e.preventDefault(); + if (currentImportPage < totalImportPages) { + setCurrentImportPage(currentImportPage + 1); + } + }; + + // `handlePreviousPage` is used to importdata table in modal + const handlePreviousPage = (e) => { + e.preventDefault(); + if (currentImportPage > 1) { + setCurrentImportPage(currentImportPage - 1); + } + }; + // `handleImportData` is used to create batch in contact + const handleImportData = async (e) => { + e.preventDefault(); + e.stopPropagation(); + setActLoader({ import: true }); + try { + const filterdata = importedData.map((x) => ({ + Name: x.Name, + Email: x.Email, + Phone: x.Phone, + TenantId: localStorage.getItem("TenantId") + })); + const contacts = JSON.stringify(filterdata); + const res = await Parse.Cloud.run("createbatchcontact", { contacts }); + if (res) { + setIsAlert(true); + setAlertMsg({ + type: "info", + message: t("contact-imported", { + imported: res?.success || 0, + failed: res?.failed || 0 + }) + }); + if (res?.success > 0) { + setTimeout(() => window.location.reload(), 2000); + } + } + } catch (err) { + console.log("err while creating batch contact", err); + setIsAlert(true); + setAlertMsg({ type: "danger", message: t("something-went-wrong-mssg") }); + } finally { + setActLoader({}); + setIsModal({}); + setImportedData([]); + setInvalidRecords(0); + setTimeout(() => setIsAlert(false), 2000); + } + }; + + // `handleCreateDuplicate` is used to create duplicate from current entry using objectId + const handleCreateDuplicate = async (item) => { + setActLoader({ [item.objectId]: true }); + setIsModal({}); + try { + const duplicateRes = await Parse.Cloud.run("createduplicate", { + templateId: item.objectId + }); + if (duplicateRes) { + const newTemplate = JSON.parse(JSON.stringify(duplicateRes)); + props.setList((prevData) => [newTemplate, ...prevData]); + setIsAlert(true); + setAlertMsg({ + type: "success", + message: t("duplicate-template-created") + }); + } + } catch (err) { + setIsAlert(true); + setAlertMsg({ + type: "danger", + message: 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 + const handleRenameDoc = async (item) => { + setActLoader({ [item.objectId]: true }); + setIsModal({}); + const className = + props.ReportName === "Templates" + ? "contracts_Template" + : "contracts_Document"; + try { + const query = new Parse.Query(className); + const docObj = await query.get(item.objectId); + docObj.set("Name", renameDoc); + await docObj.save(); + //update report list data + const updateList = props.List.map((x) => + x.objectId === item.objectId ? { ...x, Name: renameDoc } : x + ); + props.setList(updateList); + setIsAlert(true); + setAlertMsg({ + type: "success", + message: "Document updated" + }); + setActLoader({}); + setTimeout(() => setIsAlert(false), 2000); + } catch (err) { + setIsAlert(true); + setAlertMsg({ + type: "danger", + message: t("something-went-wrong-mssg") + }); + setActLoader({}); + setTimeout(() => setIsAlert(false), 2000); + } + }; + const handleBtnVisibility = (act, item) => { + if (!act.restrictBtn) { + return true; + } else if ( + act.restrictBtn === true && + item.ExtUserPtr?.objectId === extClass?.[0]?.objectId + ) { + return true; + } + }; + + // `handleEditContact` is used to update contactas per old contact Id + const handleEditContact = async (updateContact) => { + const updateList = props.List.map((x) => + x.objectId === contact.objectId ? { ...x, ...updateContact } : x + ); + props.setList(updateList); + }; + const handleCloseModal = () => { + setIsModal({}); }; return ( <div className="relative"> @@ -1336,16 +1405,6 @@ const ReportTable = (props) => { </div> )} <div className="p-2 w-full bg-base-100 text-base-content op-card shadow-lg"> - {isCelebration && ( - <div className="relative z-[1000]"> - <Confetti - width={window.innerWidth} - height={window.innerHeight} - recycle={false} // Prevents confetti from repeating - gravity={0.1} // Adjust the gravity to control the speed - /> - </div> - )} {isAlert && <Alert type={alertMsg.type}>{alertMsg.message}</Alert>} {props.tourData && props.ReportName === "Templates" && ( <> @@ -1356,44 +1415,124 @@ const ReportTable = (props) => { // rounded={5} closeWithMask={false} /> - {isPublicTour && ( - <Tour - showNumber={false} - showNavigation={false} - showNavigationNumber={false} - onRequestClose={closePublicTour} - steps={publicTourConfig} - isOpen={true} - rounded={5} - closeWithMask={false} - /> - )} </> )} <div className="flex flex-row items-center justify-between my-2 mx-3 text-[20px] md:text-[23px]"> <div className="font-light"> {t(`report-name.${props.ReportName}`)} {props.report_help && ( - <span className="text-xs md:text-[13px] font-normal"> + <span className="text-xs md:text-[13px] font-normal ml-[2px]"> <Tooltip message={t(`report-help.${props.ReportName}`)} /> </span> )} </div> - {props.ReportName === "Templates" && ( - <i - data-tut="reactourFirst" - onClick={() => navigate("/form/template")} - className="fa-light fa-square-plus text-accent text-[40px]" - ></i> - )} - {props.form && ( - <div - className="cursor-pointer" - onClick={() => handleContactFormModal()} + <div className="flex flex-row justify-center items-center gap-3"> + {props.isImport && ( + <div className="cursor-pointer" onClick={() => handleImportBtn()}> + <i className="fa-light fa-upload op-text-secondary text-[23px] md:text-[30px]"></i> + </div> + )} + {props.form && ( + <div + className="cursor-pointer" + onClick={() => handleContactFormModal()} + > + <i className="fa-light fa-square-plus text-accent text-[30px] md:text-[35px]"></i> + </div> + )} + {props.ReportName === "Templates" && ( + <i + data-tut="reactourFirst" + onClick={() => navigate("/form/template")} + className="cursor-pointer fa-light fa-square-plus text-accent text-[30px] md:text-[35px]" + ></i> + )} + <ModalUi + isOpen={isModal?.export} + title={t("bulk-import")} + handleClose={() => { + setIsModal({}); + setImportedData([]); + setInvalidRecords(0); + }} > - <i className="fa-light fa-square-plus text-accent text-[40px]"></i> - </div> - )} + <div className="relative"> + {Object.keys(actLoader)?.length > 0 && ( + <div className="absolute w-full h-full flex justify-center items-center bg-black bg-opacity-30 z-30"> + <Loader /> + </div> + )} + <form onSubmit={handleImportData} className="p-[20px] h-full "> + <div className="text-xs"> + <label className="block ml-2"> + {t("contacts-file")} + <span className="text-red-500 text-[13px]"> *</span> + </label> + <input + type="file" + accept=".csv, .xlsx, .xls" + onChange={handleFileUpload} + required + className="op-file-input op-file-input-bordered op-file-input-sm focus:outline-none hover:border-base-content w-full text-xs" + /> + </div> + <div className="text-md m-2"> + <div className="flex flex-col md:flex-row gap-1"> + <span>Total records found: {importedData.length} </span> + <span>Invalid records found: {invalidRecords}</span> + </div> + <div className="overflow-x-auto p-1"> + {importedData?.length > 0 && ( + <> + <table className="op-table op-table-zebra w-full"> + <thead> + <tr> + {allKeys.map((key, index) => ( + <th key={index}>{key}</th> + ))} + </tr> + </thead> + <tbody> + {currentRecords.map((row, rowIndex) => ( + <tr key={rowIndex}> + {allKeys.map((key, colIndex) => ( + <td key={colIndex}>{row[key] || "-"}</td> + ))} + </tr> + ))} + </tbody> + </table> + <div className="flex justify-between items-center mt-4"> + <button + className="op-btn op-btn-primary op-btn-sm" + disabled={currentImportPage === 1} + onClick={handlePreviousPage} + > + Previous + </button> + <span> + Page {currentImportPage} of {totalImportPages} + </span> + <button + className="op-btn op-btn-primary op-btn-sm" + disabled={currentImportPage === totalImportPages} + onClick={handleNextPage} + > + Next + </button> + </div> + </> + )} + </div> + </div> + <div className="h-[1px] w-full my-[15px] bg-[#9f9f9f]"></div> + <button type="submit" className="op-btn op-btn-primary"> + Import + </button> + </form> + </div> + </ModalUi> + </div> </div> <div className={`overflow-auto w-full border-b ${ @@ -1414,9 +1553,6 @@ const ReportTable = (props) => { <th className="p-2">{t(`report-heading.${item}`)}</th> </React.Fragment> ))} - {props.ReportName === "Templates" && isEnableSubscription && ( - <th className="p-2">{t("public")}</th> - )} {props.actions?.length > 0 && ( <th className="p-2 text-transparent pointer-events-none"> {t("action")} @@ -1502,11 +1638,11 @@ const ReportTable = (props) => { {startIndex + index + 1} </th> )} - <td className="p-2 min-w-56 max-w-56 flex flex-col"> + <td className="p-2 min-w-56 max-w-56"> <div className="font-semibold">{item?.Name}</div> {item?.ExpiryDate?.iso && ( <div className="text-gray-500"> - Expire: {formatDate(item?.ExpiryDate?.iso)} + Expires {formatDate(item?.ExpiryDate?.iso)} </div> )} </td> @@ -1567,166 +1703,6 @@ const ReportTable = (props) => { )} </td> )} - {props.ReportName === "Templates" && - isEnableSubscription && ( - <td className=" pl-[20px] py-2"> - {props.ReportName === "Templates" && ( - <div - className="flex flex-row" - data-tut="IsPublic" - > - <label className="cursor-pointer relative inline-flex items-center mb-0"> - <input - checked={props.isPublic?.[item.objectId]} - onChange={(e) => { - setIsPublicTour(); - handlePublicChange(e, item); - }} - type="checkbox" - value="" - className="sr-only peer" - /> - <div className="w-9 h-5 bg-gray-200 peer-focus:outline-none peer-focus:ring-1 peer-focus:ring-black rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all dark:border-black peer-checked:bg-blue-600"></div> - </label> - </div> - )} - {isMakePublicModal[item.objectId] && ( - <ModalUi - isOpen - title={ - props.isPublic[item.objectId] - ? t("make-template-public") - : t("make-template-private") - } - handleClose={() => { - setIsMakePublicModal({}); - setSelectedPublicRole(""); - props.setIsPublic((prevStates) => ({ - ...prevStates, - [item.objectId]: - !prevStates[item.objectId] - })); - }} - > - <div className="m-[20px]"> - <div className="font-normal text-black"> - <p className="text-lg"> - {props.isPublic[item.objectId] - ? t("make-template-public-alert") - : t("make-template-private-alert")} - </p> - {props.isPublic[item.objectId] && ( - <div className="flex mt-2 gap-2 md:items-center"> - <p className="text-[15px]"> - {t("public-role")} :{" "} - </p> - - <input - className="op-input op-input-bordered focus:outline-none hover:border-base-content op-input-sm" - value={handleShowRole(item)} - /> - </div> - )} - </div> - <hr className="bg-[#ccc] mt-2 " /> - <div className="flex items-center mt-3 gap-2 text-white"> - <button - onClick={() => - handlePublicTemplate(item) - } - className="op-btn op-btn-primary" - > - {t("yes")} - </button> - <button - onClick={() => handleClose(item)} - className="op-btn op-btn-secondary" - > - {t("no")} - </button> - </div> - </div> - </ModalUi> - )} - {isPublicProfile[item.objectId] && ( - <ModalUi - isOpen - title={t("public-url")} - handleClose={() => { - setIsPublicProfile({}); - setIsEmbed(false); - }} - > - <div className="m-[20px]"> - {isEmbed && !item?.IsPublic ? ( - <> - <p>{t("public-template-mssg-6")}</p> - <EmbedTab templateId={item.objectId} /> - </> - ) : publicUserName ? ( - <div className="font-normal text-black"> - <span>{t("public-url-copy")}</span> - <div className=" flex items-center justify-between gap-3 p-[2px] "> - <div className="w-[280px] whitespace-nowrap overflow-hidden text-ellipsis"> - <a - rel="noreferrer" - target="_blank" - href={publicUrl()} - className="ml-[2px] underline underline-offset-2 cursor-pointer text-blue-800" - > - {publicUrl()} - </a> - </div> - <div className="flex items-center gap-2"> - <RWebShare - data={{ - url: publicUrl(), - title: "Public url" - }} - > - <button className="op-btn op-btn-primary op-btn-outline op-btn-xs md:op-btn-sm "> - <i className="fa-light fa-share-from-square"></i>{" "} - <span className="hidden md:inline-block"> - {t("btnLabel.Share")} - </span> - </button> - </RWebShare> - <button - className="op-btn op-btn-primary op-btn-outline op-btn-xs md:op-btn-sm md:w-[100px]" - onClick={() => - copytoProfileLink() - } - > - <i className="fa-light fa-copy" /> - <span className="hidden md:inline-block"> - {copied["publicprofile"] - ? t("copied") - : t("copy")} - </span> - </button> - </div> - </div> - <p className="text-[13px] mt-[5px]"> - {t("public-url-copy-mssg")} - </p> - <EmbedTab templateId={item.objectId} /> - </div> - ) : ( - <div className="font-normal text-black"> - <p>{t("add-public-url-alert")}</p> - <button - className="mt-3 op-btn op-btn-primary" - onClick={() => navigate("/profile")} - > - {t("Proceed")} - </button> - </div> - )} - </div> - </ModalUi> - )} - </td> - )} <td className="px-2 py-2"> <div className="text-base-content min-w-max flex flex-row gap-x-2 gap-y-1 justify-start items-center"> {props.actions?.length > 0 && @@ -1755,13 +1731,11 @@ const ReportTable = (props) => { <i className={act.btnIcon}></i> {act.btnLabel && ( <span className="uppercase font-medium"> - {act.btnLabel.includes( - "Quick send" - ) && isEnableSubscription - ? "Bulk Send" - : `${t( - `btnLabel.${act.btnLabel}` - )}`} + { + `${t( + `btnLabel.${act.btnLabel}` + )}` + } </span> )} {/* template report */} @@ -1799,59 +1773,94 @@ const ReportTable = (props) => { )} </div> )} + <ModalUi + title={t("btnLabel.Duplicate")} + isOpen={ + isModal["duplicate_" + item.objectId] + } + handleClose={() => setIsModal({})} + > + <div className=" flex flex-col px-4 pb-3 pt-2 "> + <p className="text-base"> + {t("duplicate-template-alert")} + </p> + <div className="flex flex-row gap-2 pt-3 mt-3 border-t-[1.5px] border-gray-500"> + <button + className="w-[100px] op-btn op-btn-primary op-btn-md" + onClick={() => + handleCreateDuplicate(item) + } + > + {t("yes")} + </button> + <button + className="w-[100px] op-btn op-btn-secondary op-btn-md" + onClick={() => setIsModal({})} + > + {t("no")} + </button> + </div> + </div> + </ModalUi> </React.Fragment> ) : ( - <div - role="button" - data-tut={act?.selector} - key={index} - onClick={() => handleActionBtn(act, item)} - title={t(`btnLabel.${act.hoverLabel}`)} - className={ - act.action !== "option" - ? `${ - act?.btnColor ? act.btnColor : "" - } op-btn op-btn-sm mr-1` - : "text-base-content focus:outline-none text-lg mr-2 relative" - } - > - <i className={act.btnIcon}></i> - {act.btnLabel && ( - <span className="uppercase font-medium"> - {t(`btnLabel.${act.btnLabel}`)} - </span> - )} - {/* doc report */} - {isOption[item.objectId] && - act.action === "option" && ( - <ul className="absolute -right-1 top-auto z-[70] w-max op-dropdown-content op-menu shadow-black/20 shadow bg-base-100 text-base-content rounded-box"> - {act.subaction?.map((subact) => ( - <li - key={subact.btnId} - onClick={() => - handleActionBtn(subact, item) - } - title={t( - `btnLabel.${subact.hoverLabel}` - )} - > - <span> - <i - className={`${subact.btnIcon} mr-1.5`} - ></i> - {subact.btnLabel && ( - <span className="text-[13px] capitalize font-medium"> - {t( - `btnLabel.${subact.btnLabel}` + <React.Fragment key={index}> + {handleBtnVisibility(act, item) && ( + <div + role="button" + data-tut={act?.selector} + onClick={() => + handleActionBtn(act, item) + } + title={t(`btnLabel.${act.hoverLabel}`)} + className={ + act.action !== "option" + ? `${act?.btnColor || ""} op-btn op-btn-sm mr-1` + : "text-base-content focus:outline-none text-lg mr-2 relative" + } + > + <i className={act.btnIcon}></i> + {act.btnLabel && ( + <span className="uppercase font-medium"> + {t(`btnLabel.${act.btnLabel}`)} + </span> + )} + {/* doc report */} + {isOption[item.objectId] && + act.action === "option" && ( + <ul className="absolute -right-1 top-auto z-[70] w-max op-dropdown-content op-menu shadow-black/20 shadow bg-base-100 text-base-content rounded-box"> + {act.subaction?.map((subact) => ( + <li + key={subact.btnId} + onClick={() => + handleActionBtn( + subact, + item + ) + } + title={t( + `btnLabel.${subact.hoverLabel}` + )} + > + <span> + <i + className={`${subact.btnIcon} mr-1.5`} + ></i> + {subact.btnLabel && ( + <span className="text-[13px] capitalize font-medium"> + {t( + `btnLabel.${subact.btnLabel}` + )} + </span> )} </span> - )} - </span> - </li> - ))} - </ul> - )} - </div> + </li> + ))} + </ul> + )} + </div> + )} + </React.Fragment> ) )} </div> @@ -1893,93 +1902,6 @@ const ReportTable = (props) => { {isShareWith[item.objectId] && ( <div className="op-modal op-modal-open"> <div className="max-h-90 bg-base-100 w-[95%] md:max-w-[500px] rounded-box relative"> - {validplan[isSubscribe.plan] && - isEnableSubscription && ( - <> - {item?.Signers?.length > 0 ? ( - <div className="h-[150px] flex justify-center items-center mx-2"> - <div - className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-base-content absolute right-2 top-2 z-40" - onClick={() => setIsShareWith({})} - > - ✕ - </div> - <div className="text-base-content text-base text-center"> - {t("share-with-alert")} - </div> - </div> - ) : ( - <> - <h3 className="text-base-content font-bold text-lg pt-[15px] px-[20px]"> - {t("share-with")} - </h3> - <div - className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-base-content absolute right-2 top-2 z-40" - onClick={() => setIsShareWith({})} - > - ✕ - </div> - <form - className="h-full w-full z-[1300] px-2 mt-3" - onSubmit={(e) => - handleShareWith(e, item) - } - > - <Select - // onSortEnd={onSortEnd} - distance={4} - isMulti - options={teamList} - value={selectedTeam} - onChange={onChange} - closeMenuOnSelect - required={true} - noOptionsMessage={() => - t("team-not-found") - } - unstyled - classNames={{ - control: () => - "op-input op-input-bordered op-input-sm border-gray-400 focus:outline-none hover:border-base-content w-full h-full text-[11px]", - valueContainer: () => - "flex flex-row gap-x-[2px] gap-y-[2px] md:gap-y-0 w-full my-[2px]", - multiValue: () => - "op-badge op-badge-primary h-full text-[11px]", - multiValueLabel: () => - "mb-[2px]", - menu: () => - "mt-1 shadow-md rounded-lg bg-base-200 text-base-content", - menuList: () => - "shadow-md rounded-lg overflow-hidden", - option: () => - "bg-base-200 text-base-content rounded-lg m-1 hover:bg-base-300 p-2", - noOptionsMessage: () => - "p-2 bg-base-200 rounded-lg m-1 p-2" - }} - /> - <button className="op-btn op-btn-primary ml-[10px] my-3"> - {t("submit")} - </button> - </form> - </> - )} - </> - )} - {isEnableSubscription && - !validplan[isSubscribe.plan] && ( - <> - <div - className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-primary-content absolute right-2 top-2 z-40" - onClick={() => setIsShareWith({})} - > - ✕ - </div> - <SubscribeCard plan="TEAMS" /> - </> - )} - {!isEnableSubscription && - validplan[isSubscribe.plan] && ( - <> <h3 className="text-base-content font-bold text-lg pt-[15px] px-[20px]"> {t("share-with")} </h3> @@ -2002,8 +1924,6 @@ const ReportTable = (props) => { > {t("submit")} </button> - </> - )} </div> </div> )} @@ -2097,9 +2017,7 @@ const ReportTable = (props) => { <ModalUi isOpen title={ - isEnableSubscription - ? "Bulk send" - : t("quick-send") + t("quick-send") } handleClose={() => setIsBulkSend({})} > @@ -2306,6 +2224,38 @@ const ReportTable = (props) => { </div> </ModalUi> )} + <ModalUi + title={t("btnLabel.Rename")} + isOpen={isModal["rename_" + item.objectId]} + handleClose={() => setIsModal({})} + > + <div className=" flex flex-col px-4 pb-3 pt-2 "> + <div className="flex flex-col gap-2"> + <input + maxLength={200} + autoFocus={true} + type="text" + defaultValue={renameDoc || item.Name} + onChange={(e) => setRenameDoc(e.target.value)} + className="op-input op-input-bordered op-input-sm w-full focus:outline-none hover:border-base-content text-[10px]" + /> + </div> + <div className="flex flex-row gap-2 pt-3 mt-3 border-t-[1.5px] border-gray-500"> + <button + className="w-[100px] op-btn op-btn-primary op-btn-md" + onClick={() => handleRenameDoc(item)} + > + {t("save")} + </button> + <button + className="w-[100px] op-btn op-btn-secondary op-btn-md" + onClick={() => setIsModal({})} + > + {t("cancel")} + </button> + </div> + </div> + </ModalUi> {isDownloadModal[item.objectId] && ( <DownloadPdfZip setIsDownloadModal={setIsDownloadModal} @@ -2381,6 +2331,19 @@ const ReportTable = (props) => { closePopup={handleContactFormModal} /> </ModalUi> + {isModal?.["edit_" + contact.objectId] && ( + <ModalUi + isOpen + title={t("edit-contact")} + handleClose={handleCloseModal} + > + <EditContactForm + contact={contact} + handleClose={handleCloseModal} + handleEditContact={handleEditContact} + /> + </ModalUi> + )} </div> </div> ); diff --git a/apps/OpenSign/src/primitives/LinkUserModal.js b/apps/OpenSign/src/primitives/LinkUserModal.js index dd7479ff9..c42c592f4 100644 --- a/apps/OpenSign/src/primitives/LinkUserModal.js +++ b/apps/OpenSign/src/primitives/LinkUserModal.js @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useEffect, useState } from "react"; import SelectSigners from "../components/shared/fields/SelectSigners"; import AddContact from "./AddContact"; import ModalUi from "./ModalUi"; @@ -6,29 +6,44 @@ import { useTranslation } from "react-i18next"; const LinkUserModal = (props) => { const { t } = useTranslation(); + const [isContact, setIsContact] = useState(false); + const [isExistSigner, setIsExistSIgner] = useState(false); + + useEffect(() => { + if (props.uniqueId) { + const isExistSigner = props.signerPos.find( + (x) => x.Id === props.uniqueId && x.signerObjId + ); + setIsExistSIgner(isExistSigner); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [props.signerPos]); return ( <ModalUi - title={t("add/choose-signer")} - isOpen={ - props?.isAddSigner || - (props?.isAddUser && props?.isAddUser[props?.uniqueId]) - } + title={isExistSigner ? t("change-signer") : t("add/choose-signer")} + isOpen={true} handleClose={props.closePopup} > <SelectSigners details={props.handleAddUser} closePopup={props.closePopup} signersData={props?.signersData} - jwttoken={props?.jwttoken} - /> - <div className="op-divider text-base-content mx-[25%] my-1"> - {t("or")} - </div> - <AddContact - details={props.handleAddUser} - closePopup={props.closePopup} - jwttoken={props?.jwttoken} + isContact={isContact} + setIsContact={setIsContact} + handleUnlinkSigner={props.handleUnlinkSigner} + isExistSigner={isExistSigner} /> + {isContact && ( + <> + <div className="op-divider text-base-content mx-[25%] my-1"> + {t("or")} + </div> + <AddContact + details={props.handleAddUser} + closePopup={props.closePopup} + /> + </> + )} </ModalUi> ); }; diff --git a/apps/OpenSign/src/primitives/ModalUi.js b/apps/OpenSign/src/primitives/ModalUi.js index 2f03c0d33..53cec36c0 100644 --- a/apps/OpenSign/src/primitives/ModalUi.js +++ b/apps/OpenSign/src/primitives/ModalUi.js @@ -1,4 +1,5 @@ import React from "react"; +import "../styles/signature.css"; const ModalUi = ({ children, @@ -13,7 +14,7 @@ const ModalUi = ({ return ( <> {isOpen && ( - <dialog className="op-modal op-modal-open"> + <dialog id="selectSignerModal" className="op-modal op-modal-open"> <div className={`${ width || "md:min-w-[500px]" diff --git a/apps/OpenSign/src/primitives/PdfDeclineModal.js b/apps/OpenSign/src/primitives/PdfDeclineModal.js index 836192511..bdb2592b1 100644 --- a/apps/OpenSign/src/primitives/PdfDeclineModal.js +++ b/apps/OpenSign/src/primitives/PdfDeclineModal.js @@ -52,7 +52,7 @@ function CustomModal(props) { )} {props.isDownloadBtn && ( <button - className="op-btn op-btn-primary ml-[10px] mb-3 mt-1" + className="op-btn op-btn-secondary ml-[10px] mb-3 mt-1" onClick={() => props.handleDownloadBtn()} > Download diff --git a/apps/OpenSign/src/primitives/QuotaCard.js b/apps/OpenSign/src/primitives/QuotaCard.js deleted file mode 100644 index 769bf0eba..000000000 --- a/apps/OpenSign/src/primitives/QuotaCard.js +++ /dev/null @@ -1,72 +0,0 @@ -import React from "react"; -import { Trans, useTranslation } from "react-i18next"; -import { useNavigate } from "react-router-dom"; - -const QuotaCard = ({ isPaidInfo, handlClose, emailResetDate }) => { - const { t } = useTranslation(); - const navigate = useNavigate(); - return isPaidInfo ? ( - <> - <div - className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-primary-content absolute right-2 top-2 z-40" - onClick={() => handlClose && handlClose()} - > - ✕ - </div> - <div className="op-card op-bg-primary text-primary-content w-full shadow-lg"> - <div className="op-card-body"> - <h2 className="op-card-title">{t("quota-mail-info-head")}</h2> - <p>{t("quota-mail-info")}</p> - {emailResetDate && ( - <p> - {t("quota-mail-reset")} {emailResetDate} - </p> - )} - <p> - <Trans i18nKey={"quota-mail-tip"}> - Tip: You can still sign <strong>unlimited documents</strong> by - manually sharing the signing request links. - </Trans> - </p> - <div className="op-card-actions justify-end"> - <button - onClick={() => navigate("/subscription")} - className="op-btn op-btn-accent" - > - {t("upgrade-now")} - </button> - </div> - </div> - </div> - </> - ) : ( - <> - <div className="op-card op-bg-primary text-primary-content w-full shadow-lg"> - <div className="op-card-body"> - <p>{t("quota-mail")}</p> - {emailResetDate && ( - <p> - {t("quota-mail-reset")} {emailResetDate} - </p> - )} - <div> - <Trans i18nKey={"quota-mail-tip"}> - Tip: You can still sign <strong>unlimited documents</strong> by - manually sharing the signing request links. - </Trans> - </div> - <div className="op-card-actions justify-end"> - <button - onClick={() => navigate("/subscription")} - className="op-btn op-btn-accent" - > - {t("upgrade-now")} - </button> - </div> - </div> - </div> - </> - ); -}; - -export default QuotaCard; diff --git a/apps/OpenSign/src/primitives/SubscribeCard.js b/apps/OpenSign/src/primitives/SubscribeCard.js deleted file mode 100644 index aff287090..000000000 --- a/apps/OpenSign/src/primitives/SubscribeCard.js +++ /dev/null @@ -1,36 +0,0 @@ -import React from "react"; -import { useTranslation } from "react-i18next"; -import { useNavigate } from "react-router-dom"; - -const SubscribeCard = ({ plan, price }) => { - const { t } = useTranslation(); - const navigate = useNavigate(); - const handlePaidRoute = () => navigate("/subscription"); - const premiumPrice = price ? "$" + price : "$9.99"; - const addonPrice = "$0.15"; - const plandName = plan ? plan.toLowerCase() : "Paid"; - return ( - <div className="op-card op-bg-primary text-primary-content w-full shadow-lg"> - <div className="op-card-body"> - <h2 className="op-card-title"> - {t("upgrade-to")} {plan ? plan : "Paid"} {t("plan")} - </h2> - <p> - {plandName?.includes("team") - ? t("subscribe-card-teamplan") - : t("subscribe-card-plan", { premiumPrice, addonPrice })} - </p> - <div className="op-card-actions justify-end"> - <button - onClick={() => handlePaidRoute()} - className="op-btn op-btn-accent" - > - {t("upgrade-now")} - </button> - </div> - </div> - </div> - ); -}; - -export default SubscribeCard; diff --git a/apps/OpenSign/src/primitives/TourContentWithBtn.js b/apps/OpenSign/src/primitives/TourContentWithBtn.js index 5da75dead..ada3768a9 100644 --- a/apps/OpenSign/src/primitives/TourContentWithBtn.js +++ b/apps/OpenSign/src/primitives/TourContentWithBtn.js @@ -12,7 +12,7 @@ export default function TourContentWithBtn({ message, isChecked, video }) { }; return ( <div> - <p>{message}</p> + <p className="p-1 md:p-0">{message}</p> {video && ( <div className="flex items-center justify-center w-full md:h-[300px] my-[10px] border-[1.3px] border-gray-400 rounded-sm"> <iframe diff --git a/apps/OpenSign/src/primitives/Upgrade.js b/apps/OpenSign/src/primitives/Upgrade.js deleted file mode 100644 index aa6100b7c..000000000 --- a/apps/OpenSign/src/primitives/Upgrade.js +++ /dev/null @@ -1,22 +0,0 @@ -import React from "react"; -import { openInNewTab } from "../constant/Utils"; -import { useTranslation } from "react-i18next"; - -function Upgrade({ message }) { - const { t } = useTranslation(); - return ( - <sup> - <span - onClick={() => { - const url = window.location.origin + "/subscription"; - openInNewTab(url); - }} - className="op-link op-link-accent text-sm" - > - {message ? message : t("upgrade-now")} - </span> - </sup> - ); -} - -export default Upgrade; diff --git a/apps/OpenSign/src/primitives/Validate.js b/apps/OpenSign/src/primitives/Validate.js index c7fe6de9b..d64f6fb2b 100644 --- a/apps/OpenSign/src/primitives/Validate.js +++ b/apps/OpenSign/src/primitives/Validate.js @@ -1,6 +1,6 @@ import React, { useState, useEffect } from "react"; import Parse from "parse"; -import { Outlet, useNavigate, useLocation } from "react-router-dom"; +import { Outlet, useNavigate, useLocation } from "react-router"; import ModalUi from "./ModalUi"; import { useTranslation } from "react-i18next"; const Validate = () => { diff --git a/apps/OpenSign/src/primitives/ValidateRoute.js b/apps/OpenSign/src/primitives/ValidateRoute.js index e0af692b6..5f5fdc425 100644 --- a/apps/OpenSign/src/primitives/ValidateRoute.js +++ b/apps/OpenSign/src/primitives/ValidateRoute.js @@ -1,6 +1,6 @@ import React, { useEffect } from "react"; import Parse from "parse"; -import { Outlet } from "react-router-dom"; +import { Outlet } from "react-router"; import { saveLanguageInLocal } from "../constant/Utils"; import { useTranslation } from "react-i18next"; const ValidateRoute = () => { diff --git a/apps/OpenSign/src/script/PublicTemplate.js b/apps/OpenSign/src/script/PublicTemplate.js deleted file mode 100644 index c684b00b0..000000000 --- a/apps/OpenSign/src/script/PublicTemplate.js +++ /dev/null @@ -1,73 +0,0 @@ -import React, { useEffect, useState } from "react"; -import Parse from "parse"; -import ReactDOM from "react-dom/client"; -import PdfRequestFiles from "../pages/PdfRequestFiles"; -import { pdfjs } from "react-pdf"; -import { Provider } from "react-redux"; -import { store } from "../redux/store"; -import "../index.css"; -import "./i18n"; -import { isPublicStaging } from "../constant/const"; -pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.min.mjs`; - -// Wrapper component to manage props -const PublicScriptFileWrapper = () => { - const [props, setProps] = useState(""); - - useEffect(() => { - // Assigns the function 'setProps' to the global 'window' object as 'updatePublicTemplateProps'. - // This allows 'setProps' to be accessed and called globally across different scripts or components, - // enabling dynamic updates to the public template's properties. - window.updatePublicTemplateProps = setProps; - const publicScript = document.getElementById("opensign-script"); - // condition for using plan js load opensign-script then get templateId - if (publicScript) { - // Get the custom templateId attribute - const templateId = publicScript.getAttribute("templateId"); - if (templateId) { - setProps({ templateId: templateId }); - } else { - const error = "error: TemplateId is missing"; - throw new Error(error); - } - } - return () => { - window.updatePublicTemplateProps = undefined; - }; - }, []); - return <PdfRequestFiles {...props} />; -}; - -const appId = isPublicStaging ? "opensign" : "legadranaxn"; -const serverUrl = isPublicStaging - ? "https://staging-app.opensignlabs.com/api/app" - : "https://app.opensignlabs.com/api/app"; - -localStorage.setItem("baseUrl", `${serverUrl}/`); -localStorage.setItem("parseAppId", appId); -Parse.initialize(appId); -Parse.serverURL = serverUrl; -// Create a new div element and append it to the body -const scriptComponent = document.createElement("div"); -scriptComponent.id = "script-component"; -document.body.appendChild(scriptComponent); -const link = document.createElement("link"); -link.href = "https://cdn.opensignlabs.com/fonts.css"; -link.rel = "stylesheet"; -document.head.appendChild(link); - -//add the Tailwind CSS file -const tailwindCssLink = document.createElement("link"); -tailwindCssLink.href = - "https://app.opensignlabs.com/static/js/public-template.bundle.css"; // css bundle file -tailwindCssLink.rel = "stylesheet"; -document.head.appendChild(tailwindCssLink); -// Create a root and render the wrapper component with initial props -const root = ReactDOM.createRoot(document.getElementById("script-component")); -root.render( - <div data-theme="opensigncss"> - <Provider store={store}> - <PublicScriptFileWrapper /> - </Provider> - </div> -); diff --git a/apps/OpenSign/src/script/i18n.js b/apps/OpenSign/src/script/i18n.js deleted file mode 100644 index c928352c0..000000000 --- a/apps/OpenSign/src/script/i18n.js +++ /dev/null @@ -1,37 +0,0 @@ -import i18n from "i18next"; -import { initReactI18next } from "react-i18next"; -import LanguageDetector from "i18next-browser-languagedetector"; -import en from "./locales/en/translation.json"; -import es from "./locales/es/translation.json"; -import fr from "./locales/fr/translation.json"; - -i18n - .use(LanguageDetector) - .use(initReactI18next) - .init({ - resources: { - en: { - translation: en - }, - es: { - translation: es - }, - fr: { - translation: fr - } - }, - - fallbackLng: "en", // fallback language - detection: { - // Specifies the default language to fall back to if the detected language is not available. - order: ["localStorage", "navigator"] - // Defines where the detected language should be cached. - }, - debug: false, - interpolation: { - escapeValue: false // React already does escaping - }, - whitelist: ["en", "es", "fr"] // List of allowed languages - }); - -export default i18n; diff --git a/apps/OpenSign/src/script/locales/en/translation.json b/apps/OpenSign/src/script/locales/en/translation.json deleted file mode 100644 index 0ac94fe60..000000000 --- a/apps/OpenSign/src/script/locales/en/translation.json +++ /dev/null @@ -1,713 +0,0 @@ -{ - "header-news": "New feature: Teams plan users can now integrate their own AWS S3 buckets for file storage", - "header-news-btn": "Setup Now", - "create-account": "Create Account", - "login": "Login", - "language": "Language", - "name": "Name", - "phone": "Phone", - "phone-optional": "optional", - "email": "Email", - "company": "Company", - "job-title": "Job title", - "profile": "Profile", - "log-out": "Log Out", - "is-email-verified": "Is Email verified", - "public-profile": "Public profile", - "tagline": "Tagline ", - "has-requested-you-to-sign": "has requested you to sign", - "has-requested-you-to-review-and-sign": " has requested you to review and sign", - "input-required": "Please fill out this field.", - "sort-order": { - "Ascending": "Ascending", - "Descending": "Descending", - "Name": "Name", - "Date": "Date" - }, - "context-menu": { - "Download": "Download", - "Rename": "Rename", - "Move": "Move", - "Delete": "Delete" - }, - "action": "Action", - "add": "Add", - "add-new-folder": "Add a new folder", - "disable-documentId": "Disable DocumentId", - "edit": "Edit", - "change-password": "Change Password", - "save": "Save", - "cancel": "Cancel", - "upgrade-now": "Upgrade now", - "upgrade-to": "Upgrade to", - "plan": "Plan", - "subscribe-card-teamplan": "Unlock the full power of collaboration! Create unlimited organizations, teams, and hierarchies. Share templates seamlessly across teams and assign custom user roles. Elevate your workflow today!", - "subscribe-card-plan": "Unlock premium features starting at just {{premiumPrice}}/month. Enjoy enhanced performance and only {{addonPrice}} per additional credit after your included premium credits.", - "user-name-limit-char": "To have a username less than 8 character please subscribe", - "tour-content": "Don't show this again", - "pro": "PRO", - "team": "TEAM", - "user": "User", - "docs": "Docs", - "session-expired": "Your session has expired.", - "public-profile-help": "This is your public URL. Copy or share it with the signer, and you will be able to see all your publicly set templates.", - "tagline-help": "This Tagline will appear on your OpenSign public profile for ex. https://opensign.me/alex", - "welcome": "Welcome Back!", - "Login-to-your-account": "Login to your account", - "password": "Password", - "forgot-password": "Forgot Password?", - "loading": "Loading...", - "of": "of", - "sign-SSO": "Sign in with SSO", - "login-page": "Login Page", - "or": "OR", - "signup-page": "Signup page", - "password-length": "Password should be 8 characters long", - "password-case": "Password should contain uppercase letter, lowercase letter, digit", - "password-special-char": " Password should contain special character", - "agreee": "I agree to the", - "term": "Terms of Service", - "subscribe-to-opensign": "Subscribe to OpenSign newsletter", - "register": "Register", - "sidebar": { - "Dashboard": "Dashboard", - "Sign yourself": "Sign yourself", - "Request signatures": "Request signatures", - "Templates": "Templates", - "Templates-Children": { - "Create template": "Create template", - "Manage templates": "Manage templates" - }, - "OpenSign™ Drive": "OpenSign™ Drive", - "Reports": "Reports", - "Reports-Children": { - "Need your sign": "Need your sign", - "In Progress": "In Progress", - "Completed": "Completed", - "Drafts": "Drafts", - "Declined": "Declined", - "Expired": "Expired", - "Contactbook": "Contactbook" - }, - "Settings": "Settings", - "Settings-Children": { - "My Signature": "My Signature", - "API Token": "API Token", - "Webhook": "Webhook", - "Preferences": "Preferences", - "Teams": "Teams", - "Team-update-successfully": "Team Updated successfully.", - "Users": "Users" - } - }, - "dashboard-card": { - "Need your Signature": "Need your Signature", - "Out for signatures": "Out for Signatures" - }, - "report-name": { - "Draft Documents": "Draft Documents", - "Need your sign": "Need your sign", - "In-progress documents": "In-progress documents", - "Completed Documents": "Completed Documents", - "Declined Documents": "Declined Documents", - "Expired Documents": "Expired Documents", - "Recently sent for signatures": "Recently sent for signatures", - "Recent signature requests": "Recent signature requests", - "Drafts": "Drafts", - "Contactbook": "Contactbook", - "Templates": "Templates", - "Teams": "Teams", - "Users": "Users" - }, - "btnLabel": { - "sign": "sign", - "Sign": "SIGN", - "Resend": "Resend", - "Revoke": "Revoke", - "Delete": "Delete", - "Use": "Use", - "Quick send": "Quick send", - "Edit": "Edit", - "Share with team": "Share with team", - "Share": "Share", - "View": "View", - "option": "Option", - "Embed": "Embed", - "Copy TemplateId": "Copy TemplateId", - "Copy Public URL": "Copy Public URL", - "extend-expiry-date": "Extend expiry date" - }, - "report-heading": { - "Sr.No": "Sr.No", - "Title": "Title", - "Email": "Email", - "Phone": "Phone", - "File": "File", - "Owner": "Owner", - "Signers": "Signers", - "Note": "Note", - "Folder": "Folder", - "Reason": "Reason", - "Parent Team": "Parent Team", - "Active": "Active", - "Role": "Role", - "Team": "Team", - "Name": "Name", - "Status": "Status", - "created-date": "Created Date", - "Type": "Type", - "Logs": "Logs", - "Expiry-date": "Expiry Date" - }, - "report-help": { - "Draft Documents": "These are documents you have started but have not finalized for sending.", - "Need your sign": "This is a list of documents that are waiting for your signature", - "In-progress documents": "This is a list of documents you've sent to other parties for signature.", - "Completed Documents": "This is a list of documents that have been signed by all parties.", - "Declined Documents": "This is a list of documents that have been declined by one of the signers.", - "Expired Documents": "This is a list of documents that have reached their expiration date.", - "Contactbook": "This is a list of contacts/signers added by you. These will appear as suggestions when you try to add signers to a new document.", - "Templates": "This is a list of templates that are available to you for creating documents. You can click the 'use' button to create a new document using a template, modify the document & add signers in the next step." - }, - "form-name": { - "Sign Yourself": "Sign Yourself", - "Request Signatures": "Request Signatures", - "New Template": "New Template" - }, - "file-type": "pdf, png, jpg, jpeg", - "docx": "docx", - "file-selected": "file selected", - "template-title": "Template Title", - "document-title": "Document Title", - "description": "Description", - "time-to-complete": "Time To Complete (Days)", - "send-in-order": "Send In Order", - "send-in-order-help": { - "p1": "Choose how you want the signing requests to be sent to the document signers:", - "p2": "Selecting this option will send the signing request to the first signer initially. Once the first signer completes their part, the next signer in the sequence will receive the request. This process continues until all signers have signed the document. This method ensures that the document is signed in a specific order.", - "p3": "Selecting this option will send the signing links to all signers simultaneously. Every signer can sign the document at their convenience, regardless of whether other signers have completed their signatures. This method is faster but does not enforce any signing order among the participants.", - "p4": "Select the option that best suits the needs of your document processing." - }, - "no": "No", - "auto-reminder": "Auto reminder", - "remind-once": " Remind once in every (Days)", - "next": "Next", - "select-folder": "Select Folder", - "OpenSign-drive": "OpenSign™ Drive", - "drive-document-status": { - "Completed": "Completed", - "Declined": "Declined", - "Draft": "Draft", - "Expired": "Expired", - "In Progress": "In Progress" - }, - "select-folder-help": "If you do not select a folder, your signed document will be saved in the Main OpenSign drive folder.", - "no-data": "No data found", - "save-here": "Save Here", - "back": "Back", - "add-folder": "Add folder", - "create-folder": "Create Folder", - "parent-folder": "Parent Folder", - "create": "Create", - "signers": "Signers", - "signers-help": "Begin typing a contact's name to see suggested signers from your saved contacts or add new ones. Arrange the signing order by adding signers in the desired sequence. Use the '+' button to include signers and the 'x' to remove them. Each signer will receive an email prompt to sign the document in the order listed.", - "add-signer": "Add Signer", - "contact-not-found": "Contact not found", - "add-yourself": "Add Yourself", - "submit": "Submit", - "reset": "Reset", - "my-signature": "My Signature", - "signature": "Signature", - "upload-image": " Upload image", - "clear": "Clear", - "upload-signature/Image": "Please upload signature/Image", - "initials": "Initials", - "API": "API", - "api-token": "API Token", - "regenerate-token": "Regenerate Live Token", - "generate-token": "Generate Live Token", - "view-docs": "View Docs", - "generate-token-alert": "Are you sure you want to regenerate token it will expire old token?", - "yes": "Yes", - "copied": "Copied", - "something-went-wrong-mssg": "Something went wrong, please try again later.", - "token-generated": "Token generated successfully.", - "webhook": "Webhook", - "update-webhook": "Update Webhook", - "add-webhook": "Add Webhook", - "webhook-added": "Webhook added successfully.", - "team-disabled": "Team disabled", - "Team enabled": "Team enabled", - "are-you-sure": "Are you sure you want to", - "disable": "disable", - "enable": "enable", - "this-team": " this team?", - "edit-team": "Edit Team", - "name-of-team": "Name of Team", - "prev": "Prev", - "no-data-avaliable": "No Data Available", - "add-team": "Add Team", - "page-not-found": "Page Not Found", - "users-from-teams": "users from Teams", - "user-status": "User status", - "activate": "activate", - "deactivate": "deactivate", - "this-user": " this user", - "delete-user": "Delete User", - "delete": "delete", - "add-user": "Add User", - "password-generateed": "Password will only be generated once; make sure to copy it.", - "Team status": "Team status", - "user-deactivated": "User deactivated.", - "user-activated": "User activated.", - "public": "Public", - "download": "Download", - "view": "View", - "make-template-public": "Make template public", - "make-template-private": "Make template private", - "make-template-public-alert": "Are you sure you want to make this template public?", - "make-template-private-alert": "Are you sure you want to make this template private? This will remove it from your public profile.", - "public-role": "Public role", - "public-url": "Public profile", - "embed-template": "Embed Template", - "public-url-copy": "Here’s your public URL: ", - "public-url-copy-mssg": "Copy it or share it with the signer, and you will be able to see all your publicly set templates.", - "add-public-url-alert": "Please complete your OpenSign public profile setup. Once done, you’ll be able to make templates public. This process only needs to be completed once.", - "share-with-alert": "You cannot share a template if any roles already have contacts assigned. Please remove all contact assignments from the roles before sharing the template.", - "share-with": "Share with", - "team-not-found": "Team not found", - "roles": "Roles", - "delete-document": "Delete Document", - "delete-document-alert": "Are you sure you want to delete this document?", - "quick-send": "Quick send", - "add-new": "Add new", - "send": "Send", - "quick-send-alert-1": "All roles in this document are currently linked to contacts. To quick send copies of this template to multiple signers, please ensure that at least one role is not linked to any contact.", - "quick-send-alert-2": "Please ensure there's at least one signature widget added for all recipients.", - "quick-send-alert-3": "Please add at least one role to this template in order to 'quick send' copies of it to multiple signers.", - "quick-send-alert-4": "Quick send reached limit.", - "copy-link": "Copy link", - "copy": "Copy", - "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}}.", - "subject": "Subject", - "body": "Body", - "add-contact": "Add Contact", - "add-signer-alert": "Contact already exist! Please select it from ‘Signers’ dropdown", - "record-delete-alert": "Record deleted successfully!", - "record-revoke-alert": "Record revoked successfully!", - "mail-sent-alert": "Mail sent successfully.", - "document-sent-alert": "Document sent successfully!", - "template-share-alert": "Template Shared successfully.", - "template-public-alert-1": "You have successfully made the template public.", - "template-public-alert-2": "You have successfully made the template private.", - "template-public-alert-3": "You need to select a role for the public signers.", - "template-public-alert-4": "Please ensure there's at least one signature widget added for all signers.", - "template-public-alert-5": "Since this template has send-in-order enabled, the public role must be positioned at the top.", - "template-public-alert-6": "Please attach signers to all roles except for the public role user.", - "template-public-alert-7": "Please assign at least one public role to make this template public.", - "loader": " This might take some time", - "pages": "Pages", - "document-signed": "Document signed", - "close": "Close", - "validation-alert": "Validation alert", - "validate-alert-mssg": " The input does not meet the criteria set by the regular expression.", - "otp-verification": "OTP verification", - "enter-otp": "Enter OTP", - "verify": "Verify", - "verify-email-1": "Verify email", - "resend": "Resend", - "contact-details": "Contact Details", - "verify-email": "Please verify your email !", - "send-otp": " Send OTP", - "otp-placeholder": "Enter verification code received over email", - "loading-doc": "Loading Document..", - "widgets-name": { - "signature": "signature", - "stamp": "stamp", - "initials": "initials", - "name": "name", - "job title": "job title", - "company": "company", - "date": "date", - "text": "text", - "text input": "text input", - "checkbox": "checkbox", - "dropdown": "dropdown", - "radio button": "radio button", - "image": "image", - "email": "email" - }, - "fields": "Fields", - "recipients": "Recipients", - "please-add": "Please add a", - "signed-by": "Signed By", - "more": "more", - "sent": "sent", - "print": "Print", - "certificate": "Certificate", - "decline": "Decline", - "finish": "Finish", - "mail": "Mail", - "sign-now": "Sign Now", - "successfully-signed": "Successfully signed!", - "email-mssg": " Recipients added here will get a copy of the signed document.", - "email-error-1": " please provide correct email address", - "email-error-2": "You can only send to ten recipients at a time.", - "Email-verified-alert-1": "Email is verified.", - "Email-verified-alert-2": "Email is already verified.", - "upload-stamp-image": "Upload stamp image", - "draw": "Draw", - "type": "Type", - "color-type": { - "red": "red", - "blue": "blue", - "black": "black", - "yellow": "yellow" - }, - "my-initials": "My Initials", - "upload": "Upload", - "initial-teb": "Initials", - "signature-tab": "Signature", - "your-signature": "Your signature", - "copy-title": "Copy widget to", - "contact-delete-alert": "Are you sure you want to delete this contact?", - "reset-password-alert-1": "Reset password link has been sent to your email id", - "reset-password-alert-2": "Please setup email adapter ", - "reset-password-alert-3": "Reset Your Password", - "faild-animation": "Failed to load animation", - "apply": "Apply", - "copy-type": { - "All pages": "All pages", - "All pages but last": "All pages but last", - "All pages but first": "All pages but first", - "Next to current widget": "Next to current widget" - }, - "options": "Options", - "minimun-check": "Minimun check", - "maximum-check": "Maximum check", - "default-value": "Default value", - "select": "Select", - "read-only": "Is read only", - "hide-labels": "Hide labels", - "checkbox": "Checkbox", - "alert": "Alert", - "zoom-in": "Zoom in", - "zoom-out": "Zoom out", - "document-signed-alert": "Congratulations! 🎉 This document has been successfully signed by you!", - "otp-sent-alert": "OTP sent on your email", - "fields-required": "Fields required", - "signature-widget-alert-1": "Please ensure there's at least one signature widget added", - "signature-widget-alert-2": "Please ensure all field is accurately filled and meets all requirements.", - "encrypted-pdf-alert": "Currently encrypted pdf files are not supported.", - "encrypted-pdf-alert-1": "PFX file password is invalid.", - "user-not-exist": "User does not exist", - "template-signature-field": "Please add at least one signature field for all roles.", - "template-role-alert": "Please add roles first", - "create-document": "Create Document", - "template-created-alert": "Do you want to create a document using the template you just created ?", - "signers-alert": "signers alert", - "template-creation-alert-1": "Please select signer for add placeholder!", - "ok": "Ok", - "radio-group": "Radio group", - "dropdown-options": "Dropdown options", - "add-role": "Add Role", - "role-ex": " e.g: Customer, Hr, Director, Manager, Student, etc", - "add/choose-signer": "Add/Choose Signer", - "choose-from-contacts": "Choose from contacts", - "select-signer": " Please select signer", - "edit-template": "Edit Template", - "widget-info": "Widget info", - "validation": "Validation", - "invalid-default-value": "invalid default value", - "hint": "Hint", - "color": "color", - "role-help": { - "p1": "What are template roles?", - "p2": "Begin by specifying each role needed for the completion of the document. Think about the parties involved in the signing process and what their responsibilities are. Common roles include HR for internal documents, Customer for agreements or Vendor for business agreements.", - "p3": "Why pre-attach users to some roles?", - "p4": "For roles that consistently involve the same individual (e.g., the CEO's signature on employee offer letters), you can pre-attach a user to a role within the template. This step is optional but recommended for efficiency and consistency across documents.", - "p5": "When do i specify the user attached to each role?", - "p6": "When you create a document from your template, you'll be prompted to attach users to each defined role. If a role already has a user attached, this will be pre-filled, but you can modify it as needed before sending out the document." - }, - "add-recipients": "Add recipients", - "loading-mssg": "This might take some time", - "send-mail": "Send Mail", - "placeholder-alert-1": "Please ensure there's at least one signature widget added for all recipients.", - "placeholder-alert-2": "Please confirm that you have filled the text field.", - "placeholder-alert-3": " Are you sure you want to send out this document for signatures?", - "placeholder-alert-4": "You have successfully sent mails to all recipients!", - "placeholder-alert-5": "Do you want to sign documents right now ?", - "placeholder-alert-6": "Please setup mail adapter to send mail!", - "placeholder-alert-7": "Please select signer for add placeholder!", - "email-subject": "email subject", - "email-body": "email body", - "email-placeholder": "add body of email", - "reset-to-default": "Reset to default", - "cutomize-email": "Cutomize Email", - "upgrade-to-customize-email": "Upgrade to customize Email", - "sign-url": "Sign url", - "mails-sent": "Mails Sent", - "mail-not-delivered": "Mail not delivered", - "document-alert": "Document Alert", - "owner-subscription-expired": "Owner's subscription has expired.", - "subscription-expired": "Subscription Expired", - "alert-message": "Alert message", - "document-decline": "Document decline", - "decline-alert-1": "Are you sure want to decline this document ?", - "decline-alert-2": "You have declined this document!", - "decline-alert-3": "You can not sign this document as it has been declined/revoked.", - "sign here": "Sign here", - "guest-email-alert": "verification code is sent to your email", - "get-otp-alert": "you will get a verification code via Email", - "user-already-exist": "User already exist.", - "server-error": "Internal server error !", - "fill-required-details!": "Please fill required details!", - "sign-up-form": "Sign up form", - "sign-up": "Sign up", - "folder-already-exist!": "folder already exist!", - "please-select-position!": "please select position!", - "default-sign-alert": "Are you sure you want to auto sign at requested all locations?", - "Your-Signature": "Your Signature", - "auto-sign-all": "Auto Sign All", - "generating-certificate": "Generating certificate", - "pdf-download": "PDF Download", - "generate-certificate-alert": " Your completion certificate is being generated. Please wait momentarily. If the download doesn't start shortly, click the button again.", - "folder-already-exist": "Folder already exist!", - "folder-created-successfully": "Folder created successfully!", - "fill-folder-name": "Please fill folder name", - "already-exists-this-username": "User already exists with this username!", - "verification-code-sent": "Verification mail has been sent to your E-mail!", - "registered-user-successfully": "Registered user successfully.", - "role-not-found": "Role not found.", - "do-not-access": "You don't have access, please contact the admin.", - "add-admin": "Add admin", - "opensign-setup": "OpenSign Setup", - "join-discord": "Join our discord server", - "admin-already-exist": "Admin already exist.", - "password-update-alert-1": "Password updated successfully.", - "password-update-alert-2": "Your current password is missing or incorrect.", - "password-update-alert-3": "Your current password is missing or incorrect.", - "password-update-alert-4": "Your password and confirmation password do not match.", - "current-password": "Current Password", - "new-password": "New Password", - "confirm-password": "Confirm Password", - "file-alert-1": "The selected file size is too large. Please select a file less than", - "file-alert-2": "Please select file.", - "file-alert-3": "Please wait while the document is being uploaded.", - "enter-pdf-password": "Enter Pdf Password", - "correct-password": "Please provide correct password", - "decrypting-pdf": " Decrypting pdf please wait...", - "invalid-otp": "Invalid Otp", - "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", - "enter-verification-code": "Enter Verification Code", - "provide-your-details": "Provide your details", - "provide-email": "Please provide email.", - "additional-info": "Additional Info", - "signature-saved-alert": "Signature saved successfully.", - "fill-field": "Please fill out this field", - "error-template": "Error: Template not found!", - "error": "Error", - "invalid-document": "Error: invalid document!", - "document-not-found": "Document not Found!", - "document-signed-alert-1": "You have successfully signed the document. You can download or print a copy of the partially signed document. A copy of the digitally signed document & completion certificate will be sent to the owner & all signers over email once it is signed by all signers.", - "encrypted-pdf-not-support": "Currently encrypted pdf files are not supported.", - "document-signed-alert-4": " Congratulations! 🎉 This document has been successfully signed by all participants!", - "document-signed-alert-5": "This document has been signed by all Signers.", - "document-signed-alert-6": "This document has been declined by one or more recipient(s).", - "document-signed-alert-7": "This Document is no longer available.", - "document-signed-alert-8": "The document has already been dispatched for signing.", - "yet-to-sign": "Yet to sign", - "validation-alert-1": "The input does not meet the criteria set by the regular expression.", - "account-already-exists": "Account already exists!", - "choose-password": "Choose Password", - "enter-password": "Enter Password", - "sure": "sure", - "subscribed-alert": "You have already subscribed to plan!", - "monthly": "Monthly", - "yearly-upto": "Yearly (upto 66% off)", - "billed-yearly": "Billed Yearly", - "billed-monthly": "Billed Monthly", - "plansubscription-1": "Host it yourself for free", - "visit-github": "Visit Github", - "user-already-exist-name": "User already exists with this username!", - "do-not-access-contact-admin": "You don't have access, please contact the admin.", - "filed-required-correctly": "Please fill required details correctly.", - "admin-created": "Admin created", - "invalid-masterkey": "Invalid masterkey", - "opensign-Setup": "OpenSign Setup", - "master-key": " Master key", - "profile-update-alert": "Profile updated successfully.", - "date": "Date", - "report-not-found": "Report Not Found", - "please-wait": "please wait", - "select-foler": "Select Folder", - "generated-on": "Generated On", - "text-field": "Text field", - "font-size": "Font size", - "widget-status": { - "Required": "Required", - "Optional": "Optional" - }, - "all-right": "All Rights Reserved", - "version": "version", - "social-media": { - "github": "Github", - "linked-in": "LinkedIn", - "twitter": "Twitter", - "discord": "Discord" - }, - "tour-mssg": { - "home-layout-1": "You have logged in successfully! Let's take a look.", - "home-layout-2": "To upload documents for self-signing or to request others’ signatures, simply select the respective buttons.", - "home-layout-3": "You are ready to start using OpenSign! If you need support feel free to contact us.", - "generate-token": "Upgrade now to generate production API token.", - "opensign-drive-1": "Click on the breadcrumb links to easily navigate through the folder hierarchy and view the documents within each folder.", - "opensign-drive-2": "Click the add button to create a new folder or document.", - "opensign-drive-3": "Sort your documents by Date or Name using this menu.", - "opensign-drive-4": "Click on this menu to display the documents in list view.", - "opensign-drive-5": "The document list is displayed according to the selected sorting option. Icons next to each document indicate its current status.", - "opensign-drive-6": "Right-click on a document to see options such as Download, Rename, Move, and Delete. Click on the document to open it.", - "opensign-drive-7": "Right-click on any folder to see options. Choose ‘Rename’ to change the folder’s name or click on the folder to navigate through its contents.", - "pdf-request-file-1": "List of signers who still need to sign the document .", - "pdf-request-file-2": "Click any of the placeholders appearing on the document to sign. You will then see options to draw your signature, type it, or upload an image .", - "pdf-request-file-3": "Click the Back, Decline, or Finish buttons to navigate your document. Use the ellipsis menu for additional options, including the Download button .", - "pdf-request-file-4": "List of signers who have already signed the document .", - "pdf-request-file-5": "You can click 'Auto Sign All' to automatically sign at all the locations meant to be signed by you. Make sure that you review the document properly before you click this button .", - "placeholder-sign-1": "Select a recipient from this list to add a place-holder where he is supposed to sign.The placeholder will appear in the same colour as the recipient name once you drop it on the document.", - "placeholder-sign-2": "Clicking 'Add recipients' button will allow you to add more signers.", - "placeholder-sign-3": "Click this button to add more recipients/signers to the document.", - "placeholder-sign-4": "Drag or click on a field to add it to the document.", - "placeholder-sign-5": "The PDF content area already displays the template's existing placeholders. For your convenience, these placeholders will match the color of the recipient's name, making them easily identifiable.", - "placeholder-sign-6": "Clicking 'Send' will save the document. In the next step you can customize the emails to be sent out to the recipients or copy the signing links and share those with the recipients yourself.", - "report-1": "Click the 'Add' button to create a new template. Templates are reusable documents designed to quickly generate new documents with the same structure and varying signers. For example, an HR template for onboarding could have predefined roles like ‘HR Manager’ and ‘New Employee’. Each time you use the template, you can assign the ‘New Employee’ role to different incoming staff members, while the ‘HR Manager’ role remains constant, facilitating a seamless onboarding process for each recruit. ", - "redirect": "Click the 'Use' button to create a new document from an existing template.", - "bulksend": "To quickly create and send multiple documents using an existing template, click the 'Quick Send' button.", - "option": "This menu reveals more options such as Edit & Delete. Use the 'Edit' button to add signer roles, modify fields, and update your template. Changes will apply to all future documents created from this template but won’t affect existing documents.Use the Delete button you can delete template. ", - "signyour-self-1": "Select and drag your preferred widgets onto the PDF to customize your document before signing. Choose the perfect spots for each modification to tailor the document to your needs.", - "signyour-self-2": "Drag and drop anywhere in this area. You can resize and move it later.", - "template-placeholder-1": "Clicking 'Add role' button will allow you to add various signer roles. You can attach users to each role in subsequent steps.", - "template-placeholder-2": "Once roles are added, select a role from list to add a place-holder where he is supposed to sign. The placeholder will appear in the same colour as the role name once you drop it on the document.", - "template-placeholder-3": "Drag or click on a field to add it to the document.", - "template-placeholder-4": "Drag the placeholder for a role anywhere on the document.Remember, it will appear in the same colour as the name of the recipient for easy reference.", - "template-placeholder-5": "Clicking 'Next' will store the current template. After saving, you’ll be prompted to create a new document from this template if you wish.", - "webhook-1": "Upgrade now to set webhook", - "Need your Signature": "Clicking on this card will take you to the list of documents awaiting your review.", - "Out for signatures": "Clicking on this card will take you to a list of documents awaiting signature.", - "Recent signature requests": "This is a list of documents that are waiting for your signature.", - "Recently sent for signatures": "This is a list of documents you've sent to other parties for signature.", - "Drafts": "This are documents you have started but have not finalized for sending.", - "public-template": "This video demonstrates how to set up your personalized public profile, such as ‘https://opensign.me/your-username’. You’ll also learn how to customize your tagline and make your templates available for public signing." - }, - "enter-email-plaholder": "Add an email address and hit enter", - "success-email-alert": "Email sent successfully!", - "expired-doc-title": "Expired Document", - "expired-on-mssg": "This document expired on {{expiredDate}} and is no longer available to sign.", - "signature-validate-alert": "Please confirm that you have selected at least {{minRequiredCount}} checkboxes.", - "signature-validate-alert-2": "Ensure this field is accurately filled and meets all requirements.", - "remaing-users": "Remaining users", - "Role": "Role", - "additional-users": "Please purchase add-on users.", - "Quantity-of-users": "Quantity of users", - "Price": "Price", - "Total-price-for-next-time": "Total price for next time", - "Proceed": "Proceed", - "Select": "Select", - "Add-seats": "Add Seats", - "user-name-exist": "user name already exist", - "format": "format", - "select-date-format": "Select a date format", - "quantity-of-credits": "Quantity of premium credits", - "remaining-credits": "Premium credits available:", - "remaining-credits-help": "Use premium credits for API document signing, bulk sending, or embedding OpenSign integration on your website. You have {{allowedcredits}} included credits and {{addoncredits}} additional purchased credits remaining.", - "additional-credits": "Please purchase premium credits", - "quota-err-quicksend": "Quota Reached, You don't have enough credits.", - "buy-credits": "Buy Premium Credits", - "rotate-right": "Rotate right", - "rotate-left": "Rotate left", - "rotate-alert-mssg": "All widgets on this page will be lost. Are you sure you want to proceed?", - "templateid": "Template-Id", - "bulk-send-subcription-alert": "Please upgrade to Professional or Team plan to use bulk send.", - "generate-test-token": "Generate Test Token", - "regenerate-test-token": "Regenerate Test Token", - "help-test-token": "This token can be used to test the APIs at the https://sandbox.opensignlabs.com/api/v1 endpoint, allowing you to conduct unlimited document signatures. Please note that the sandbox API will sign your documents with self-signed certificates, which may not be recognized as valid by Adobe. Once you’ve completed your testing, you can upgrade to one of our paid plans to generate a production token.", - "help-api-token": "This token can be used to access the production APIs at the {{origin}}/api/v1 endpoint. It can only be generated on one of our paid plans.", - "reason": "Reason", - "decline-by": "Declined/revoked by", - "document-declined": "Document declined", - "public-template-mssg-1": "To integrate OpenSign into your React or Next.js project, simply run the following command:", - "public-template-mssg-2": "Ensure you have npm or yarn set up in your project. If you’re using Yarn, you can replace npm install with yarn add @opensign/react.", - "public-template-mssg-3": "Need more details or examples?", - "public-template-mssg-4": "Visit the", - "public-template-mssg-5": " npm for the latest updates, detailed documentation, and version history.", - "public-template-mssg-6": "Before you can use this code snippet, you must make this template public.", - "copy-code": "COPY", - "copied-code": "COPIED", - "Installation": "Installation", - "Usage": "Usage", - "insufficient-credits": "Insufficient Signing Credits", - "insufficient-credits-mssg": "The owner of this document currently lacks the necessary OpenSign credits for you to sign. Please reach out to the owner if you require further details.", - "angular-npm-mssg-1": "To integrate OpenSign into your Angular project, simply run the following command:", - "quota-mail-info-head": "Monthly request signatures email limit", - "quota-mail-info": "You can send upto 15 signature request emails every month. Upgrade now to send unlimited signing requests directly.", - "quota-mail-reset": "Your signature request email credits will be reset on", - "quota-mail": "You've reached your limit of 15 signature request emails for this month. Upgrade now to continue sending emails directly.", - "quota-mail-tip": "Tip: You can still sign <1>unlimited documents</1> by manually sharing the signing request links.", - "quota-mail-head": "Quota Reached", - "unauthorized-modal": "You don't have permission to perform this action, please contact {{adminEmail}}.", - "sent-this-month": "Sent this month", - "available-seats": "Available seats", - "buy-users": "Buy more users", - "isenable-otp": "Enable OTP verification", - "isenable-otp-help": { - "p1": "Would you like to enable the verification process using a one-time password (OTP)?", - "p2": "Selecting this option will enable OTP verification. Users will receive a verification code via email, which they must enter to sign the document.", - "p3": "Selecting this option will disable OTP verification, allowing users to sign the document directly without additional steps.", - "p4": "Please choose the option that best suits your document signing requirements." - }, - "advanced-options": "Advanced options", - "hide-advanced-options": "Hide Advanced options", - "download-files": "Download files", - "download-pdf": "Download Pdf", - "pdf-certificate": "Download Pdf + Certificate", - "document-logs": "Document logs", - "server-down": "Unable to connect to the OpenSign server. If you are self-hosting OpenSign, please ensure that all the steps in the documentation have been followed correctly. If you're running OpenSign locally, you might be accessing it through an incorrect port number.", - "admin-exists": "Admin already exists. Please login to the application using admin credentials in order to manage users.", - "enable-tour": "Enable Tour", - "istourenabled-help": { - "p1": "This will enable a guided tour for signers, providing instructions during the signing process.", - "p2": "This will disable the guided tour, ensuring a faster, uninterrupted signing experience.", - "p3": "Tip: If your signers are familiar with OpenSign and frequently use it, you may want to disable the guided tour for a more seamless experience. Choose the option that best fits your document signing needs." - }, - "form-title-1": "Document Flow Setting", - "form-title-2": "Security Settings", - "public-tour-message": "The template needs to be public before you can generate a shareable link.", - "add-user-template": "You need to add a role before you can add fields for it.", - "pdf-uncompatible": "This pdf is not compatible with opensign, please contact <support@opensignlabs.com>", - "text-field-tour": "Fields of type 'Text' must be filled in advance before the document is sent. If you need the signers to provide input, use the 'Text Input' field instead.", - "attach-signer-tour": "You need to attach a Signer to every role. You can do that by clicking this icon. Once you select a Signer it will be attached to all the fields associated with that role which appear in the same colour.", - "allowed-signature-types": "Allowed signature types", - "at-least-one-signature-type": "At least one signature type should be enabled.", - "expect-default-one-signature-type": "Please enable one additional signature type apart from the default.", - "add-signer-note": "Note - This contact will be added to your contact list", - "allowed-signature-types-help": { - "p1": "This signature preference controls which signing options are available to your signers. Only the signature types you select will appear in the signature widget when a document is signed. For example, if you choose only the 'Draw' option in preferences, your signer will see only the 'Draw' option in the signature widget, while the other three options will not be available.", - "l1": "Create a handwritten signature directly on the screen using your finger or a stylus.", - "l2": "Enter your name and choose from various font styles to create a signature.", - "l3": "Upload an existing digital version of your signature.", - "l4": "Use a pre-set signature style saved under 'My Signature' in your settings." - }, - "notify-on-signatures": "Notify on signatures", - "notify-on-signatures-help": { - "p1": "The document creator will receive an email notification whenever a signer signs the document.", - "note": "Note: Notification email will not be sent for the last signer, as the document creator will receive a completion email instead." - }, - "expiry-date":"Expiry date", - "expiry-date-updated": "The expiry date has been successfully extended to {{newexpirydate}}", - "expiry-date-error": "Please provide a new expiry date that is later than the current one" -} diff --git a/apps/OpenSign/src/script/locales/es/translation.json b/apps/OpenSign/src/script/locales/es/translation.json deleted file mode 100644 index 6217deb97..000000000 --- a/apps/OpenSign/src/script/locales/es/translation.json +++ /dev/null @@ -1,713 +0,0 @@ -{ - "header-news": "Nueva característica: los usuarios del plan Teams ahora pueden integrar sus propios depósitos de AWS S3 para el almacenamiento de archivos", - "header-news-btn": "Configurar ahora", - "create-account": "Crear cuenta", - "login": "Iniciar sesión", - "language": "Idioma", - "name": "Nombre", - "phone": "Teléfono", - "phone-optional": "opcional", - "email": "Correo", - "company": "Compañía", - "job-title": "Título del puesto", - "profile": "Perfil", - "log-out": "Cerrar sesión", - "is-email-verified": "El correo está verificado", - "public-profile": "Perfil público", - "tagline": "Eslogan ", - "has-requested-you-to-sign": "ha solicitado que firmes", - "has-requested-you-to-review-and-sign": " ha solicitado que revises y firmes", - "input-required": "Por favor, rellena este campo.", - "sort-order": { - "Ascending": "Ascendente", - "Descending": "Descendente", - "Name": "Nombre", - "Date": "Fecha" - }, - "context-menu": { - "Download": "Descargar", - "Rename": "Renombrar", - "Move": "Mover", - "Delete": "Eliminar" - }, - "action": "Acción", - "add": "Agregar", - "add-new-folder": "Agregar nueva carpeta", - "disable-documentId": "Desactivar ID de documento", - "edit": "Editar", - "change-password": "Cambiar contraseña", - "save": "Guardar", - "cancel": "Cancelar", - "upgrade-now": "Mejorar ahora", - "upgrade-to": "Mejorar a", - "plan": "Plan", - "subscribe-card-teamplan": "¡Libera todo el poder de la colaboración! Crea organizaciones, equipos y jerarquías ilimitadas. Comparte plantillas sin problemas entre equipos y asigna funciones de usuario personalizadas. ¡Mejora tu flujo de trabajo hoy mismo!", - "subscribe-card-plan": "Desbloquea funciones premium desde solo {{premiumPrice}}/mes. Disfruta de un rendimiento mejorado y solo {{addonPrice}} por crédito adicional después de tus créditos premium incluidos.", - "user-name-limit-char": "Para tener un nombre de usuario menor a 8 caracteres por favor suscríbete", - "tour-content": "No mostrar esto otra vez", - "pro": "PRO", - "team": "EQUIPO", - "user": "Usuario", - "docs": "Documentación", - "session-expired": "Tu sesión ha expirado.", - "public-profile-help": "Esta es tu URL pública. Cópiala o compártela con el firmante, y podrás ver todas tus plantillas públicas.", - "tagline-help": "Este eslogan aparecerá en tu perfil público de OpenSign, por ejem. https://opensign.me/alex", - "welcome": "¡Bienvenido de nuevo!", - "Login-to-your-account": "Ingresa a tu cuenta", - "password": "Contraseña", - "forgot-password": "¿Olvidaste la contraseña?", - "loading": "Cargando...", - "of": "de", - "sign-SSO": "Ingresar con SSO", - "login-page": "Página de inicio de sesión", - "or": "O", - "signup-page": "Página de registro", - "password-length": "La contraseña debe tener 8 caracteres", - "password-case": "La contraseña debe incluir mayúsculas, minúsculas y números", - "password-special-char": " La contraseña debe incluir caracteres especiales", - "agreee": "Estoy de acuerdo con los", - "term": "Términos de Servicio", - "subscribe-to-opensign": "Suscribirse al boletín de OpenSign", - "register": "Registrarse", - "sidebar": { - "Dashboard": "Panel", - "Sign yourself": "Firma tu mismo", - "Request signatures": "Solicitar firmas", - "Templates": "Plantillas", - "Templates-Children": { - "Create template": "Crear plantilla", - "Manage templates": "Administrar plantillas" - }, - "OpenSign™ Drive": "OpenSign™ Drive", - "Reports": "Reportes", - "Reports-Children": { - "Need your sign": "Necesitan tu firma", - "In Progress": "En progreso", - "Completed": "Completado", - "Drafts": "Borradores", - "Declined": "Rechazados", - "Expired": "Expirados", - "Contactbook": "Agenda de contactos" - }, - "Settings": "Ajustes", - "Settings-Children": { - "My Signature": "Mi firma", - "API Token": "Token API", - "Webhook": "Webhook", - "Preferences": "Preferencias", - "Teams": "Equipos", - "Team-update-successfully": "Equipo actualizado correctamente.", - "Users": "Usuarios" - } - }, - "dashboard-card": { - "Need your Signature": "Necesitan tu firma", - "Out for signatures": "En espera de ser firmados" - }, - "report-name": { - "Draft Documents": "Documentos borradores", - "Need your sign": "Necesitan tu firma", - "In-progress documents": "Documentos en progreso", - "Completed Documents": "Documentos completados", - "Declined Documents": "Documentos rechazados", - "Expired Documents": "Documentos expirados", - "Recently sent for signatures": "Recientemente enviados para ser firmados", - "Recent signature requests": "Solicitudes de firma recientes", - "Drafts": "Borradores", - "Contactbook": "Agenda de contactos", - "Templates": "Plantillas", - "Teams": "Equipos", - "Users": "Usuarios" - }, - "btnLabel": { - "sign": "firmar", - "Sign": "FIRMAR", - "Resend": "Reenviar", - "Revoke": "Revocar", - "Delete": "Eliminar", - "Use": "Usar", - "Quick send": "Envío rápido", - "Edit": "Editar", - "Share with team": "Compartir con el equipo", - "Share": "Compartir", - "View": "Ver", - "option": "Opción", - "Embed": "Incrustar", - "Copy TemplateId": "Copiar ID de plantilla", - "Copy Public URL": "Copiar URL pública", - "Expiry-date": "Date d'expiration" - }, - "report-heading": { - "Sr.No": "Nº", - "Title": "Título", - "Email": "Correo", - "Phone": "Teléfono", - "File": "Archivo", - "Owner": "Propietario", - "Signers": "Firmantes", - "Note": "Nota", - "Folder": "Carpeta", - "Reason": "Razón", - "Parent Team": "Equipo padre", - "Active": "Activo", - "Role": "Rol", - "Team": "Equipo", - "Name": "Nombre", - "Status": "Estado", - "created-date": "Fecha de creación", - "Type": "Tipo", - "Logs": "Registros", - "Expiry-date": "Date d'expiration" - }, - "report-help": { - "Draft Documents": "Estos son documentos que has iniciado pero no has finalizado para su envío.", - "Need your sign": "Esta es una lista de documentos que esperan tu firma.", - "In-progress documents": "Esta es una lista de documentos que has enviado a otras partes para su firma.", - "Completed Documents": "Esta es una lista de documentos en los que todas las partes han firmado.", - "Declined Documents": "Esta es una lista de documentos que han sido rechazados por uno de los firmantes.", - "Expired Documents": "Esta es una lista de documentos que han alcanzado su fecha de caducidad.", - "Contactbook": "Esta es una lista de contactos/firmantes añadidos por ti. Aparecerán como sugerencias cuando intentes añadir firmantes a un nuevo documento.", - "Templates": "Esta es una lista de plantillas que están a tu disposición para crear documentos. Puedes hacer clic en el botón «usar» para crear un nuevo documento utilizando una plantilla, modifica el documento y añade firmantes en el siguiente paso." - }, - "form-name": { - "Sign Yourself": "Firmar", - "Request Signatures": "Solicitar firmas", - "New Template": "Nueva plantilla" - }, - "file-type": "pdf, png, jpg, jpeg", - "docx": "docx", - "file-selected": "archivo seleccionado", - "template-title": "Título de la plantilla", - "document-title": "Título del documento", - "description": "Descripción", - "time-to-complete": "Plazo de finalización (días)", - "send-in-order": "Enviar en orden", - "send-in-order-help": { - "p1": "Elige cómo quieres que se envíen las solicitudes de firma a los firmantes del documento:", - "p2": "Seleccionando esta opción se enviará inicialmente la solicitud de firma al primer firmante. Una vez que el primer firmante complete su parte, el siguiente firmante en la secuencia recibirá la solicitud. Este proceso continúa hasta que todos los firmantes hayan firmado el documento. Este método garantiza que el documento se firme en un orden específico.", - "p3": "Seleccionando esta opción se enviarán los enlaces para la firma a todos los firmantes simultáneamente. Cada firmante puede firmar el documento cuando le convenga, independientemente de si otros firmantes han completado sus firmas. Este método es más rápido, pero no impone ningún orden de firma entre los participantes.", - "p4": "Selecciona la opción que mejor se adapte a las necesidades de tu tramitación de documentos." - }, - "no": "No", - "auto-reminder": "Recordatorio automático", - "remind-once": " Recordar una vez cada (Días)", - "next": "Siguiente", - "select-folder": "Seleccionar carpeta", - "OpenSign-drive": "OpenSign™ Drive", - "drive-document-status": { - "Completed": "Completado", - "Declined": "Rechazado", - "Draft": "Borrador", - "Expired": "Expirado", - "In Progress": "En progreso" - }, - "select-folder-help": "Si no seleccionas una carpeta, tu documento firmado se guardará en la carpeta principal de OpenSign Drive.", - "no-data": "No se encontraron datos", - "save-here": "Guardar aquí", - "back": "Atrás", - "add-folder": "Añadir carpeta", - "create-folder": "Crear carpeta", - "parent-folder": "Carpeta superior", - "create": "Crear", - "signers": "Firmantes", - "signers-help": "Empieza a escribir el nombre de un contacto para ver los firmantes sugeridos entre tus contactos guardados o añade otros nuevos. Organiza el orden de firma añadiendo firmantes en la secuencia deseada. Utiliza el botón «+» para añadir nuevos firmantes y la «X» para quitar todos. Cada firmante recibirá una solicitud por correo electrónico para que firme el documento según el orden indicado.", - "add-signer": "Añadir firmante", - "contact-not-found": "Contacto no encontrado", - "add-yourself": "Añadirte a ti mismo", - "submit": "Enviar", - "reset": "Volver a empezar", - "my-signature": "Mi firma", - "signature": "Firma", - "upload-image": " Subir imagen", - "clear": "Limpiar", - "upload-signature/Image": "Por favor, sube la firma/imagen", - "initials": "Iniciales", - "API": "API", - "api-token": "Token API", - "regenerate-token": "Regenerar token activo", - "generate-token": "Generar token activo", - "view-docs": "Ver documentación", - "generate-token-alert": "¿En definitiva quieres regenerar el token? Esto expirará el token antiguo.", - "yes": "Sí", - "copied": "Copiado", - "something-went-wrong-mssg": "Algo salió mal, por favor, intenta de nuevo más tarde.", - "token-generated": "Token generado exitosamente.", - "webhook": "Webhook", - "update-webhook": "Actualizar webhook", - "add-webhook": "Agregar webhook", - "webhook-added": "Webhook agregado exitosamente.", - "team-disabled": "Equipo deshabilitado", - "Team enabled": "Equipo habilitado", - "are-you-sure": "¿En definitiva quieres ", - "disable": "deshabilitar", - "enable": "habilitar", - "this-team": " este equipo?", - "edit-team": "Editar equipo", - "name-of-team": "Nombre del equipo", - "prev": "Anterior", - "no-data-avaliable": "No hay datos disponibles", - "add-team": "Agregar equipo", - "page-not-found": "Página no encontrada", - "users-from-teams": "usuarios de equipos", - "user-status": "Estado del usuario", - "activate": "activar", - "deactivate": "desactivar", - "this-user": " este usuario", - "delete-user": "Eliminar usuario", - "delete": "eliminar", - "add-user": "Agregar usuario", - "password-generateed": "La contraseña solo será generada una vez; asegúrate de copiarla.", - "Team status": "Estado del equipo", - "user-deactivated": "Usuario desactivado.", - "user-activated": "Usuario activado.", - "public": "Público", - "download": "Descargar", - "view": "Ver", - "make-template-public": "Convertir la plantilla en pública", - "make-template-private": "Convertir la plantilla en privada", - "make-template-public-alert": "¿En definitiva quieres convertir esta plantilla en pública?", - "make-template-private-alert": "¿En definitiva quieres convertir esta plantilla en privada? Esto lo removerá de tu perfil público.", - "public-role": "Rol público", - "public-url": "Perfil publico", - "embed-template": "Insertar plantilla", - "public-url-copy": "Aquí está tu URL pública: ", - "public-url-copy-mssg": "Cópiala o compártela con el firmante y podrás ver todas tus plantillas públicas.", - "add-public-url-alert": "Por favor, completa la configuración de tu perfil público OpenSign. Una vez terminado, podrás crear plantillas públicas. Este proceso solo necesita ser completado una vez.", - "share-with-alert": "No puedes compartir una plantilla si alguno de los roles ya tiene contactos asignados. Elimina todas las asignaciones de contactos de los roles antes de compartir la plantilla.", - "share-with": "Compartir con", - "team-not-found": "Equipo no encontrado", - "roles": "Roles", - "delete-document": "Eliminar documento", - "delete-document-alert": "¿En definitiva quieres eliminar este documento?", - "quick-send": "Envío rápido", - "add-new": "Agregar nuevo", - "send": "Enviar", - "quick-send-alert-1": "Todos los roles de este documento están actualmente vinculados a contactos. Para enviar rápidamente copias de esta plantilla a varios firmantes, por favor, asegúrate de que al menos un rol no esté vinculado a ningún contacto.", - "quick-send-alert-2": "Por favor, asegúrate de que hay al menos un widget de firma añadido para cada destinatario.", - "quick-send-alert-3": "Por favor, añade al menos un rol a esta plantilla para poder hacer un «envío rápido» de copias a varios firmantes.", - "quick-send-alert-4": "El envío rápido ha alcanzado el límite.", - "copy-link": "Copiar enlace", - "copy": "Copiar", - "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}}.", - "subject": "Asunto", - "body": "Cuerpo", - "add-contact": "Agregar contacto", - "add-signer-alert": "¡El contacto ya existe! Selecciónelo en el menú desplegable 'Firmantes'", - "record-delete-alert": "¡Entrada eliminada exitosamente!", - "record-revoke-alert": "¡Entrada revocada exitosamente!", - "mail-sent-alert": "Correo enviado exitosamente.", - "document-sent-alert": "¡Documento enviado exitosamente!", - "template-share-alert": "Plantilla compartida exitosamente.", - "template-public-alert-1": "Has convertido exitosamente la plantilla en pública.", - "template-public-alert-2": "Has convertido exitosamente la plantilla en privada.", - "template-public-alert-3": "Tienes que seleccionar un rol para los firmantes públicos.", - "template-public-alert-4": "Por favor, asegúrate de que has añadido al menos un widget de firma para cada firmante.", - "template-public-alert-5": "Dado que esta plantilla tiene «enviar en orden» habilitado, el rol público debe estar posicionado arriba al inicio.", - "template-public-alert-6": "Por favor, enlaza firmantes a todos los roles excepto al usuario de rol público.", - "template-public-alert-7": "Por favor, asigna al menos un rol público para convertir está plantilla en pública.", - "loader": " Esto podría llevar algún tiempo", - "pages": "Páginas", - "document-signed": "Documento firmado", - "close": "Cerrar", - "validation-alert": "Alerta de validación", - "validate-alert-mssg": " Los datos ingresados no cumplen con los criterios establecidos por la expresión regular.", - "otp-verification": "Verificación OTP", - "enter-otp": "Ingresar OTP", - "verify": "Verificar", - "verify-email-1": "Verificar correo", - "resend": "Reenviar", - "contact-details": "Detalles del contacto", - "verify-email": "¡Por favor, verifica tu correo!", - "send-otp": " Enviar OTP", - "otp-placeholder": "Ingresa el código de verificación enviado por correo", - "loading-doc": "Cargando documento...", - "widgets-name": { - "signature": "firma", - "stamp": "sello", - "initials": "iniciales", - "name": "nombre", - "job title": "título del puesto", - "company": "compañía", - "date": "fecha", - "text": "texto", - "text input": "entrada de texto", - "checkbox": "casilla", - "dropdown": "desplegable", - "radio button": "botón de radio", - "image": "imagen", - "email": "correo" - }, - "fields": "Campos", - "recipients": "Destinatarios", - "please-add": "Por favor, agrega un", - "signed-by": "Firmado por", - "more": "más", - "sent": "enviado", - "print": "Imprimir", - "certificate": "Certificado", - "decline": "Rechazar", - "finish": "Finalizar", - "mail": "Correo", - "sign-now": "Firmar ahora", - "successfully-signed": "¡Firmado exitosamente!", - "email-mssg": " Los destinatarios agregados aquí recibirán una copia del documento firmado.", - "email-error-1": " por favor, proporciona una dirección de correo correcta", - "email-error-2": "Solo puedes enviar hasta a 10 destinatarios a la vez.", - "Email-verified-alert-1": "El correo está verificado.", - "Email-verified-alert-2": "El correo ya ha sido verificado.", - "upload-stamp-image": "Subir imagen del sello", - "draw": "Dibujar", - "type": "Escribir", - "color-type": { - "red": "rojo", - "blue": "azul", - "black": "negro", - "yellow": "amarillo" - }, - "my-initials": "Mis iniciales", - "upload": "Subir", - "initial-teb": "Iniciales", - "signature-tab": "Firma", - "your-signature": "Tu firma", - "copy-title": "Copiar widget a", - "contact-delete-alert": "¿En definitiva quieres eliminar este contacto?", - "reset-password-alert-1": "El enlace para restablecer la contraseña ha sido enviado a tu correo electrónico", - "reset-password-alert-2": "Por favor, configura un adaptador de correo ", - "reset-password-alert-3": "Restablece tu contraseña", - "faild-animation": "Error al cargar la animación", - "apply": "Aplicar", - "copy-type": { - "All pages": "Todas las páginas", - "All pages but last": "Todas las páginas menos la última", - "All pages but first": "Todas las páginas menos la primera", - "Next to current widget": "Junto al widget actual" - }, - "options": "Opciones", - "minimun-check": "Chequeo mínimo", - "maximum-check": "Chequeo máximo", - "default-value": "Valor por defecto", - "select": "Seleccionar", - "read-only": "Es de solo lectura", - "hide-labels": "Esconder etiquetas", - "checkbox": "Casilla", - "alert": "Alerta", - "zoom-in": "Acercar", - "zoom-out": "Alejar", - "document-signed-alert": "¡Felicitaciones! 🎉 ¡Este documento ha sido firmado por ti exitosamente!", - "otp-sent-alert": "OTP enviado a tu correo", - "fields-required": "Campos requeridos", - "signature-widget-alert-1": "Por favor, asegúrate de que hay al menos un widget de firma agregado", - "signature-widget-alert-2": "Por favor, asegúrate de que todos los campos están correctamente rellenados y de que cumplen todos los requisitos.", - "encrypted-pdf-alert": "Actualmente los archivos PDF encriptados no están soportados.", - "encrypted-pdf-alert-1": "La contraseña del archivo PFX es inválida.", - "user-not-exist": "El usuario no existe", - "template-signature-field": "Por favor, agrega al menos un campo de firma para todos los roles.", - "template-role-alert": "Por favor, primero agrega roles", - "create-document": "Crear documento", - "template-created-alert": "¿Quieres crear un documento usando la plantilla que acabas de crear?", - "signers-alert": "alerta de firmantes", - "template-creation-alert-1": "¡Por favor, selecciona un firmante para agregar un marcador de posición!", - "ok": "OK", - "radio-group": "Grupo de radio", - "dropdown-options": "Opciones del desplegable", - "add-role": "Agregar rol", - "role-ex": " por ejem.: Cliente, RRHH, Director, Administrador, Estudiante, etc.", - "add/choose-signer": "Agregar/Elegir firmante", - "choose-from-contacts": "Elegir desde los contactos", - "select-signer": " Por favor, selecciona el firmante", - "edit-template": "Editar plantilla", - "widget-info": "Información del widget", - "validation": "Validación", - "invalid-default-value": "valor por defecto inválido", - "hint": "Pista", - "color": "color", - "role-help": { - "p1": "¿Qué son los roles de una plantilla?", - "p2": "Empieza por especificar cada uno de los roles necesarios para completar el documento. Piensa en las partes implicadas en el proceso de firma y cuáles son sus responsabilidades. Los roles más habituales son RRHH para los documentos internos, Cliente para los contratos o Proveedor para los convenios comerciales.", - "p3": "¿Por qué preasignar usuarios a algunos roles?", - "p4": "Para los roles que consistentemente involucran al mismo individuo (por ejem., la firma del Gerente en las ofertas de empleo), puedes preasignar un usuario a un rol dentro de una plantilla. Este paso es opcional pero recomendado para la eficiencia y consistencia entre documentos", - "p5": "¿Cuando especifico el usuario asignado a cada rol?", - "p6": "Cuando crees un documento usando tu plantilla, se te pedirá que asignes usuarios a cada rol definido. Si un rol ya tiene un usuario asignado, este será rellenado con anticipación, pero puedes modificarlo según lo necesites antes de enviar el documento." - }, - "add-recipients": "Agregar destinatarios", - "loading-mssg": "Esto podría llevar algún tiempo", - "send-mail": "Enviar correo", - "placeholder-alert-1": "Por favor, asegúrate de que hay al menos un widget de firma para cada destinatario.", - "placeholder-alert-2": "Por favor, confirma que hayas rellenado el campo de texto.", - "placeholder-alert-3": " ¿En definitiva quieres enviar este documento para ser firmado?", - "placeholder-alert-4": "¡Has enviado exitosamente correos a todos los destinatarios!", - "placeholder-alert-5": "¿Quieres firmar documentos ahora mismo?", - "placeholder-alert-6": "¡Por favor, configura el adaptador de correo para enviar correos!", - "placeholder-alert-7": "¡Por favor, selecciona un firmante para agregar un marcador de posición!", - "email-subject": "asunto del correo", - "email-body": "cuerpo del correo", - "email-placeholder": "agregar cuerpo del correo", - "reset-to-default": "Restablecer a por defecto", - "cutomize-email": "Personalizar correo", - "upgrade-to-customize-email": "Mejora para personalizar el correo", - "sign-url": "URL de firma", - "mails-sent": "Correos enviados", - "mail-not-delivered": "correo no entregado", - "document-alert": "Alerta de documento", - "owner-subscription-expired": "La suscripción del propietario ha expirado.", - "subscription-expired": "Suscripción expirada", - "alert-message": "Mensaje de alerta", - "document-decline": "Rechazar documento", - "decline-alert-1": "¿En definitiva quieres rechazar este documento?", - "decline-alert-2": "¡Has rechazado este documento!", - "decline-alert-3": "No puedes firmar este documento ya que ha sido rechazado/revocado.", - "sign here": "Firma aquí", - "guest-email-alert": "el código de verificación ha sido enviado a tu correo", - "get-otp-alert": "recibirás un código de verificación por correo", - "user-already-exist": "El usuario ya existe.", - "server-error": "¡Error interno del servidor!", - "fill-required-details!": "¡Por favor, rellena los detalles requeridos!", - "sign-up-form": "Formulario de registro", - "sign-up": "Registrarse", - "folder-already-exist!": "¡la carpeta ya existe!", - "please-select-position!": "¡por favor, selecciona una posición!", - "default-sign-alert": "¿En definitiva quieres firmar automáticamente en todos los lugares solicitados?", - "Your-Signature": "Tu firma", - "auto-sign-all": "Firmar todo automáticamente", - "generating-certificate": "Generando certificado", - "pdf-download": "Descargar PDF", - "generate-certificate-alert": " Tu certificado de finalización se está generando. Por favor, espera un momento. Si la descarga no inicia pronto, presiona el botón otra vez.", - "folder-already-exist": "¡La carpeta ya existe!", - "folder-created-successfully": "¡Carpeta creada exitosamente!", - "fill-folder-name": "Por favor, rellena el nombre de la carpeta", - "already-exists-this-username": "¡Un usuario con este nombre de usuario ya existe!", - "verification-code-sent": "¡El correo de verificación ha sido enviado a tu correo!", - "registered-user-successfully": "Usuario registrado exitosamente.", - "role-not-found": "Rol no encontrado.", - "do-not-access": "No tienes acceso, por favor, contacta al administrador.", - "add-admin": "Agregar administrador", - "opensign-setup": "Instalación de OpenSign", - "join-discord": "Únete a nuestro servidor de Discord", - "admin-already-exist": "El administrador ya existe.", - "password-update-alert-1": "Contraseña actualizada exitosamente.", - "password-update-alert-2": "Tu contraseña actual es incorrecta o falta.", - "password-update-alert-3": "Tu contraseña actual es incorrecta o falta.", - "password-update-alert-4": "Tu contraseña y su confirmación no son iguales.", - "current-password": "Contraseña actual", - "new-password": "Contraseña nueva", - "confirm-password": "Confirmar contraseña", - "file-alert-1": "El tamaño del archivo seleccionado es muy grande. Por favor, selecciona un archivo con un tamaño menor a", - "file-alert-2": "Por favor, selecciona un archivo.", - "file-alert-3": "Por favor, espera mientras se sube el documento.", - "enter-pdf-password": "Ingresa la contraseña del PDF", - "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!", - "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", - "enter-verification-code": "Ingresar código de verificación", - "provide-your-details": "Proporciona tus detalles", - "provide-email": "Por favor, proporciona un correo.", - "additional-info": "Información adicional", - "signature-saved-alert": "Firma guardada exitosamente.", - "fill-field": "Por favor, rellena este campo", - "error-template": "Error: ¡Plantilla no encontrada!", - "error": "Error", - "invalid-document": "Error: ¡Documento inválido!", - "document-not-found": "¡Documento no encontrado!", - "document-signed-alert-1": "Ha firmado exitosamente el documento. Puede descargar o imprimir una copia del documento parcialmente firmado. Se enviará una copia del documento firmado digitalmente y del certificado de finalización al propietario y a todos los firmantes por correo electrónico una vez que todos los firmantes lo hayan firmado.", - "encrypted-pdf-not-support": "Los archivos PDF encriptados no están soportados actualmente.", - "document-signed-alert-4": " ¡Felicitaciones! 🎉 ¡Este documento ha sido firmado exitosamente por todos los participantes!", - "document-signed-alert-5": "Este documento ha sido firmado por todos los firmantes.", - "document-signed-alert-6": "Este documento ha sido rechazado por uno o más destinatarios.", - "document-signed-alert-7": "Este documento ya no está disponible.", - "document-signed-alert-8": "Este documento ya ha sido enviado para ser firmado.", - "yet-to-sign": "Todavía por firmar", - "validation-alert-1": "Los datos ingresados no cumplen con los criterios establecidos por la expresión regular.", - "account-already-exists": "¡La cuenta ya existe!", - "choose-password": "Elegir contraseña", - "enter-password": "Ingresar contraseña", - "sure": "claro", - "subscribed-alert": "¡Ya te has suscrito al plan!", - "monthly": "Mensual", - "yearly-upto": "Anual (hasta 66% de descuento)", - "billed-yearly": "Facturado anualmente", - "billed-monthly": "Facturado mensualmente", - "plansubscription-1": "Alójalo por tu cuenta gratuitamente", - "visit-github": "Visitar GitHub", - "user-already-exist-name": "¡Un usuario con este nombre de usuario ya existe!", - "do-not-access-contact-admin": "No tienes acceso, por favor, contacta a un administrador.", - "filed-required-correctly": "Por favor, rellena correctamente los detalles requeridos.", - "admin-created": "Administrador creado", - "invalid-masterkey": "Llave maestra inválida", - "opensign-Setup": "Instalación de OpenSign", - "master-key": " Llave maestra", - "profile-update-alert": "Perfil actualizado exitosamente.", - "date": "Fecha", - "report-not-found": "Reporte no encontrado", - "please-wait": "por favor, espera", - "select-foler": "Seleccionar carpeta", - "generated-on": "Generado el", - "text-field": "Campo de texto", - "font-size": "Tamaño de la fuente", - "widget-status": { - "Required": "Requerido", - "Optional": "Opcional" - }, - "all-right": "Todos los derechos reservados", - "version": "versión", - "social-media": { - "github": "GitHub", - "linked-in": "LinkedIn", - "twitter": "Twitter", - "discord": "Discord" - }, - "tour-mssg": { - "home-layout-1": "¡Has iniciado sesión exitosamente! Echemos un vistazo.", - "home-layout-2": "Para subir documentos para firmar tú mismo o para solicitar la firma de otros, simplemente selecciona los botones correspondientes.", - "home-layout-3": "¡Ya puedes empezar a utilizar OpenSign! Si necesitas soporte siéntete libre de contactarnos.", - "generate-token": "Mejora ahora para generar un token API de producción.", - "opensign-drive-1": "Haz clic en los enlaces para navegar fácilmente por la estructura jerárquica de carpetas y ver los documentos de cada carpeta.", - "opensign-drive-2": "Haz clic en el botón «Agregar» para crear una nueva carpeta o documento.", - "opensign-drive-3": "Ordena tus documentos por «Fecha» o «Nombre» usando este menú.", - "opensign-drive-4": "Haz clic en este menú para mostrar los documentos en vista de lista.", - "opensign-drive-5": "La lista de documentos es mostrada de acuerdo a la opción de ordenamiento seleccionada. Los íconos situados junto a cada documento indican su estado actual.", - "opensign-drive-6": "Haz clic con el botón derecho en un documento para ver opciones como «Descargar», «Renombrar», «Mover» y «Eliminar». Haz clic en el documento para abrirlo.", - "opensign-drive-7": "Haz clic con el botón derecho en cualquier carpeta para ver las opciones. Elige «Renombrar» para cambiar el nombre de la carpeta o haz clic en ella para navegar por su contenido.", - "pdf-request-file-1": "Lista de firmantes que todavía tienen que firmar este documento.", - "pdf-request-file-2": "Haz clic en cualquiera de los marcadores de posición que aparecen en el documento para firmar. A continuación, verás opciones para dibujar tu firma, escribirla o subir una imagen .", - "pdf-request-file-3": "Haz clic en los botones «Atrás», «Rechazar» o «Finalizar» para navegar por el documento. Utiliza el menú de tres puntos para ver otras opciones, como el botón «Descargar».", - "pdf-request-file-4": "Lista de firmantes que ya han firmado el documento.", - "pdf-request-file-5": "Puedes hacer clic en «Firmar todo automáticamente» para firmar de manera automática en todos los lugares que deban ser firmados por ti. Asegúrate de revisar correctamente el documento antes de hacer clic en ese botón.", - "placeholder-sign-1": "Selecciona un destinatario de esta lista para agregar un marcador de posición dónde este destinatario tendrá que firmar. El marcador de posición aparecerá con el mismo color que el nombre del destinatario una vez lo sueltes en el documento.", - "placeholder-sign-2": "Hacer clic en el botón «Agregar destinatarios» te permitirá añadir más firmantes.", - "placeholder-sign-3": "Haz clic en este botón para agregar más destinatarios/firmantes al documento.", - "placeholder-sign-4": "Arrastra o haz clic en un capo para agregarlo al documento.", - "placeholder-sign-5": "El área de contenido del PDF ya muestra los marcadores de posición existentes en la plantilla. Para tu comodidad, estos marcadores de posición coincidirán con el color del nombre del destinatario, haciéndolos fácilmente identificables.", - "placeholder-sign-6": "Hacer clic en «Enviar» guardará el documento. En el siguiente paso podrás personalizar los correos que serán enviados a los destinatarios o copiar los enlaces para firmar y compartirlos con los destinatarios por tu cuenta.", - "report-1": "Haz clic en el botón «Agregar» para crear una nueva plantilla. Las plantillas son documentos reusables diseñados para generar rápidamente nuevos documentos con la misma estructura pero diferentes firmantes. Por ejemplo, una plantilla de RR.HH. para el proceso de incorporación podría tener roles predefinidos como «Director de RR.HH.» y «Nuevo empleado». Cada vez que utilices la plantilla, puedes asignar el rol de «Nuevo empleado» a los distintos miembros del personal que se incorporen, mientras que el rol de « Director de RR.HH.» permanece constante, lo que facilita un proceso de incorporación fluido para cada persona contratada.", - "redirect": "Haz clic en el botón «Usar» para crear un nuevo documento desde una plantilla existente.", - "bulksend": "Para crear y enviar rápidamente múltiples documentos usando una plantilla existente, haz clic en el botón «Envío rápido».", - "option": "Este menú revela más opciones como «Editar» y «Eliminar». Usa el botón «Editar» para agregar roles, modificar campos y actualizar tu plantilla. Los cambios aplicarán para todos los documentos futuros que sean creados usando esta plantilla pero no afectarán a los documentos ya existentes. Con el botón «Eliminar» puedes eliminar la plantilla.", - "signyour-self-1": "Para personalizar el documento antes de que sea firmado, selecciona y arrastra al documento los widgets que prefieras. Escoge el espacio perfecto para cada modificación para adaptar el documento a tus necesidades.", - "signyour-self-2": "Arrastra y suelta en cualquier lugar de esta área. Después podrás cambiar el tamaño y moverlo.", - "template-placeholder-1": "Hacer clic en el botón «Agregar rol» te permitirá agregar varios roles de firmantes. Puedes asociar usuarios a cada rol en los siguientes pasos.", - "template-placeholder-2": "Una vez que los roles hayan sido agregados, selecciona un rol de la lista para agregar un marcador de posición donde éste tendrá que firmar. El marcador de posición aparecerá con el mismo color que el nombre del rol una vez lo sueltes en el documento.", - "template-placeholder-3": "Arrastra o haz clic en un capo para agregarlo al documento.", - "template-placeholder-4": "Arrastra el marcador de posición para un rol a cualquier lugar del documento. Recuerda, aparecerá con el mismo color que el nombre del rol para poder referenciarlo fácilmente.", - "template-placeholder-5": "Hacer clic en «Siguiente» guardará la plantilla actual. Luego de guardar, se te consultará si deseas crear un nuevo documento usando esta plantilla.", - "webhook-1": "Mejora ahora para configurar un webhook", - "Need your Signature": "Hacer clic en esta tarjeta te llevará a la lista de documentos que esperan por tu revisión.", - "Out for signatures": "Hacer clic en esta tarjeta te llevará a la lista de documentos que esperan tu firma.", - "Recent signature requests": "Esta es una lista de documentos que esperan por tu firma.", - "Recently sent for signatures": "Esta es una lista de documentos que has enviado a otras partes para que sea firmado.", - "Drafts": "Estos son documentos que has empezado pero que todavía no finalizas para su envío.", - "public-template": "Este video muestra cómo puedes configurar tu perfil público personalizado, como «https://opensign.me/tu-nombre-de-usuario». También aprenderás cómo personalizar tu eslogan y cómo hacer tus plantillas disponibles para su firmado público." - }, - "enter-email-plaholder": "Agrega una dirección de correo y presiona «Enter»", - "success-email-alert": "¡Correo enviado exitosamente!", - "expired-doc-title": "Documento expirado", - "expired-on-mssg": "Este documento expiro el {{expiredDate}} y ya no está disponible para ser firmado.", - "signature-validate-alert": "Por favor, confirma que has seleccionado al menos {{minRequiredCount}} casillas.", - "signature-validate-alert-2": "Asegúrate de que este campo esté correctamente rellenado y que cumpla con todos los requisitos.", - "remaing-users": "Usuarios restantes", - "Role": "Rol", - "additional-users": "Por favor, compra el complemento Usuarios.", - "Quantity-of-users": "Cantidad de usuarios", - "Price": "Precio", - "Total-price-for-next-time": "Precio total para la próxima vez", - "Proceed": "Proceder", - "Select": "Seleccionar", - "Add-seats": "Agregar plazas", - "user-name-exist": "el nombre de usuario ya existe", - "format": "formato", - "select-date-format": "Selecciona un formato de fecha", - "quantity-of-credits": "Cantidad de créditos premium", - "remaining-credits": "Créditos premium disponibles:", - "remaining-credits-help": "Usa créditos premium para la API para la firma de documentos, envío en masa, o para incorporar la integración de OpenSign en tu página web. Te quedan {{allowedcredits}} créditos incluidos y {{addoncredits}} créditos comprados adicionalmente.", - "additional-credits": "Por favor, compra créditos premium", - "quota-err-quicksend": "Cuota alcanzada, no tienes créditos suficientes.", - "buy-credits": "Comprar créditos premium", - "rotate-right": "Rotar a la derecha", - "rotate-left": "Rotar a la izquierda", - "rotate-alert-mssg": "Todos los widgets de esta página se perderán. ¿En definitiva quieres proceder?", - "templateid": "ID de plantilla", - "bulk-send-subcription-alert": "Por favor, mejora al plan a Professional o Team para usar envío en masa.", - "generate-test-token": "Generar token de prueba", - "regenerate-test-token": "Regenerar token de prueba", - "help-test-token": "Este token puede ser usado para probar las API en el punto de acceso «https://sandbox.opensignlabs.com/api/v1», permitiéndote realizar firmas de documentos ilimitadas. Por favor, ten en cuenta que el API de pruebas firmará tus documentos con certificados autofirmados, que podrían no ser reconocidos por Adobe como válidos. Una vez hayas completado tus pruebas, puedes mejorar a uno de nuestros planes de pago para generar un token de producción.", - "help-api-token": "Este token puede ser usado para acceder a las API de producción en el punto de acceso «{{origin}}/api/v1». Solo puede ser generado con uno de nuestros planes de pago.", - "reason": "Razón", - "decline-by": "Rechazado/revocado por", - "document-declined": "Documento rechazado", - "public-template-mssg-1": "Para integrar OpenSign a tu proyecto React o Next.js, simplemente ejecuta los siguientes comandos:", - "public-template-mssg-2": "Asegúrate de tener «npm» o «yarn» configurado en tu proyecto. Si estás usando «yarn», puedes reemplazar «npm install» con «yarn add @opensign/react».", - "public-template-mssg-3": "¿Necesitas más detalles o ejemplos?", - "public-template-mssg-4": "Visita la", - "public-template-mssg-5": " «npm» para las últimas actualizaciones, documentación detallada e historial de versiones.", - "public-template-mssg-6": "Antes de que puedas usar este fragmento de código, debes convertir esta plantilla en pública.", - "copy-code": "COPIAR", - "copied-code": "COPIADO", - "Installation": "Instalación", - "Usage": "Uso", - "insufficient-credits": "Créditos de firma insuficientes", - "insufficient-credits-mssg": "El propietario de este documento actualmente carece de los créditos OpenSign necesarios para que puedas firmarlo. Por favor, contacta al propietario si necesitas más detalles.", - "angular-npm-mssg-1": "Para integrar OpenSign a tu proyecto Angular, simplemente ejecuta los siguientes comandos:", - "quota-mail-info-head": "Límite mensual de solicitudes de firma por correo", - "quota-mail-info": "Puedes enviar hasta 15 solicitudes de firma por correo cada mes. Mejora ahora para enviar solicitudes de firma sin límite.", - "quota-mail-reset": "Los créditos de tu correo electrónico de solicitud de firma se restablecerán el", - "quota-mail": "Has alcanzado tu límite de 15 solicitudes de firma por correo para este mes. Mejora ahora para continuar enviando correos.", - "quota-mail-tip": "Consejo: Todavía puedes solciitar la firma de <1>documentos ilimitados</1> compartiendo manualmente los enlaces de solicitud de firma.", - "quota-mail-head": "Cuota alcanzada", - "unauthorized-modal": "No tienes permisos para realizar esta acción, por favor, contacta a {{adminEmail}}.", - "sent-this-month": "Enviados este mes", - "available-seats": "Plazas disponibles", - "buy-users": "Comprar más usuarios", - "isenable-otp": "Habilitar verificación con OTP", - "isenable-otp-help": { - "p1": "¿Te gustaría habilitar el proceso de verificación usando una contraseña de un solo uso (OTP)?", - "p2": "Seleccionar esta opción habilitará la verificación con OTP. Los usuarios recibirán un código de verificación por correo, la cual tendrán que ingresar para poder firmar el documento.", - "p3": "Seleccionar esta opción deshabilitará la verificación con OTP, lo cual permitirá a los usuarios firmar el documento directamente sin pasos adicionales.", - "p4": "Por favor, selecciona la opción que mejor se adapte a tus requisitos para la firma de documentos." - }, - "advanced-options": "Opciones avanzadas", - "hide-advanced-options": "Ocultar las opciones avanzadas", - "download-files": "Descargar archivos", - "download-pdf": "Descargar PDF", - "pdf-certificate": "Descargar PDF + Certificado", - "document-logs": "Registros de documentos", - "server-down": "No se pudo conectar al servidor de OpenSign. Si estás alojando OpenSign por tu cuenta, por favor, asegúrate de que todos los pasos de la documentación han sido seguidos correctamente. Si estás ejecutando OpenSign localmente, puedes estar accediendo a OpenSign por un número de puerto incorrecto.", - "admin-exists": "El administrador ya existe. Por favor, inicia sesión en la aplicación usando las credenciales de administrador para poder administrar los usuarios.", - "public-tour-message": "Por favor, convierte la plantilla en pública para copiar la URL pública", - "add-user-template": "Es necesario agregar un rol antes de poder agregarle campos.", - "pdf-uncompatible": "Este pdf no es compatible con opensign, comuníquese con <support@opensignlabs.com>", - "enable-tour": "Habilitar recorrido", - "istourenabled-help": { - "p1": "Esto permitirá realizar una visita guiada para los firmantes, brindando instrucciones durante el proceso de firma.", - "p2": "Esto desactivará la visita guiada, lo que garantizará una experiencia de firma más rápida e ininterrumpida.", - "p3": "Consejo: si sus firmantes están familiarizados con OpenSign y lo utilizan con frecuencia, es posible que desee desactivar la visita guiada para disfrutar de una experiencia más fluida. Elija la opción que mejor se adapte a sus necesidades de firma de documentos" - }, - "form-title-1": "Configuración del flujo de documentos", - "form-title-2": "Configuración de seguridad", - "text-field-tour": "Los campos de tipo 'Texto' deben completarse con anticipación antes de enviar el documento. Si necesita que los firmantes proporcionen información, utilice el campo 'Entrada de texto'", - "attach-signer-tour": "Debe adjuntar un firmante a cada función. Puede hacerlo haciendo clic en este icono. Una vez que seleccione un Firmante, se adjuntará a todos los campos asociados con ese rol que aparecen en el mismo color.", - "allowed-signature-types": "Tipos de firma permitidos", - "at-least-one-signature-type": "Se debe habilitar al menos un tipo de firma.", - "expect-default-one-signature-type": "Habilite un tipo de firma adicional aparte del predeterminado.", - "add-signer-note": "Nota - Este contacto se agregará a su lista de contactos", - "allowed-signature-types-help": { - "p1": "Esta preferencia de firma controla qué opciones de firma están disponibles para sus firmantes. Solo los tipos de firma que seleccione aparecerán en el widget de firma cuando se firme un documento. Por ejemplo, si elige sólo la opción 'Draw' en las preferencias, su firmante verá sólo la opción 'Draw' en el widget de firma, mientras que las otras tres opciones no estarán disponibles.", - "l1": "Cree una firma manuscrita directamente en la pantalla usando su dedo o un lápiz.", - "l2": "Ingrese su nombre y elija entre varios estilos de fuente para crear una firma.", - "l3": "Cargue una versión digital existente de su firma.", - "l4": "Utilice un estilo de firma preestablecido guardado en 'Mi firma' en su configuración." - }, - "notify-on-signatures": "Notificar sobre firmas", - "notify-on-signatures-help": { - "p1": "El creador del documento recibirá una notificación por correo electrónico cada vez que un firmante firme el documento.", - "note": "Nota: No se enviará un correo electrónico de notificación al último firmante, ya que el creador del documento recibirá un correo electrónico de finalización." - }, - "expiry-date": "Date d'expiration", - "expiry-date-updated": "La fecha de vencimiento se ha extendido con éxito hasta el {{newexpirydate}}", - "expiry-date-error": "Proporcione una nueva fecha de vencimiento que sea posterior a la actual" -} diff --git a/apps/OpenSign/src/script/locales/fr/translation.json b/apps/OpenSign/src/script/locales/fr/translation.json deleted file mode 100644 index 005bb76fc..000000000 --- a/apps/OpenSign/src/script/locales/fr/translation.json +++ /dev/null @@ -1,712 +0,0 @@ -{ - "header-news": "Nouvelle fonctionnalité : les utilisateurs du forfait Teams peuvent désormais intégrer leurs propres compartiments AWS S3 pour le stockage de fichiers", - "header-news-btn": "Configurer maintenant", - "create-account": "Créer un compte", - "login": "Se Connecter", - "language": "Langue", - "name": "Nom et Prénom", - "phone": "Téléphone", - "phone-optional": "(facultatif)", - "email": "E-mail", - "company": "Organisation", - "job-title": "Votre Fonction", - "profile": "Profil", - "is-email-verified": "L'e-mail est-il vérifié", - "log-out": "Déconnexion", - "public-profile": "Profil public", - "tagline": "Slogan", - "has-requested-you-to-sign": " vous a demandé de signer", - "has-requested-you-to-review-and-sign": "vous a demandé de consulter et de signer", - "input-required": "Veuillez remplir ce champ.", - "sort-order": { - "Ascending": "Ascendant", - "Descending": "Descendant", - "Name": "Nom et Prénom", - "Date": "Date" - }, - "context-menu": { - "Download": "Télécharger", - "Rename": "Renommer", - "Move": "Se déplacer", - "Delete": "Supprimer" - }, - "action": "Action", - "add": "Ajouter", - "add-new-folder": "Ajouter un nouveau dossier", - "disable-documentId": "Désactiver l'ID du document", - "edit": "Modifier", - "change-password": "Changer votre mot de passe", - "save": "Sauvegarder", - "cancel": "Annuler", - "upgrade-now": "Mettre à jour maintenant", - "upgrade-to": "Mettre à niveau vers", - "pro": "PRO", - "plan": "Offre", - "subscribe-card-teamplan": "Libérez toute la puissance de la collaboration ! Créez un nombre illimité d'organisations, d'équipes et de hiérarchies. Partagez des modèles de manière transparente entre les équipes et attribuez des rôles d'utilisateur personnalisés. Améliorez votre flux de travail dès aujourd'hui !", - "subscribe-card-plan": "Débloquez des fonctionnalités premium à partir de seulement {{premiumPrice}}/mois. Bénéficiez de performances améliorées et de seulement {{addonPrice}} par crédit supplémentaire après vos crédits premium inclus.", - "user-name-limit-char": "Pour avoir un nom d'utilisateur de moins de 8 caractères s'il vous plaît s'abonner", - "tour-content": "Ne plus afficher", - "team": "Équipe", - "docs": "Documents", - "session-expired": "Votre session a expiré.", - "user": "Utilisateur", - "public-profile-help": "Il s'agit de votre URL publique. Copiez-le ou partagez-le avec le signataire et vous pourrez voir tous vos modèles définis publiquement.", - "tagline-help": "Ce surnom apparaîtra sur votre profil public OpenSign par exemple. https://opensign.me/alex", - "welcome": "Content de te revoir!", - "Login-to-your-account": "Se connecter à son compte", - "password": "Mot de passe", - "forgot-password": "Mot de passe oublié?", - "loading": "Chargement...", - "of": "de", - "sign-SSO": "Connectez-vous avec SSO", - "login-page": "Page de connexion", - "or": "OU", - "signup-page": "Page d'inscription", - "password-length": "Le mot de passe doit être de plus de 8 caractères", - "password-case": "Le mot de passe doit contenir une lettre majuscule, minuscule et un chiffre ", - "password-special-char": "Le mot de passe doit contenir un caractère spécial", - "agreee": "Je suis d'accord avec le", - "term": "Conditions d'utilisation", - "subscribe-to-opensign": "Abonnez-vous à la newsletter OpenSign", - "register": "S'enregistrer ", - "sidebar": { - "Dashboard": "Tableau de bord", - "Sign yourself": "signez vous-même", - "Request signatures": "Demander des signatures", - "Templates": "Modèles", - "Templates-Children": { - "Create template": "Créer un modèle", - "Manage templates": "Gérer les modèles" - }, - "OpenSign™ Drive": "Lecteur OpenSign™", - "Reports": "Rapports", - "Reports-Children": { - "Need your sign": "Besoin de votre signature", - "In Progress": "En cours", - "Completed": "Complété", - "Drafts": "Brouillons", - "Declined": "Signature refusé", - "Expired": "Expiré", - "Contactbook": "Carnet de contacts" - }, - "Settings": "Paramètres", - "Settings-Children": { - "My Signature": "Ma signature", - "API Token": "Jeton API", - "Webhook": "Webhook", - "Preferences": "Préférences", - "Teams": "Équipe", - "Team-update-successfully": "Équipe mise à jour avec succès.", - "Users": "Utilisateurs" - } - }, - "dashboard-card": { - "Need your Signature": "Besoin de votre signature", - "Out for signatures": "En attente de Signature" - }, - "report-name": { - "Draft Documents": "Brouillons", - "Need your sign": "Besoin de votre signature", - "In-progress documents": "Documents en cours", - "Completed Documents": "Documents complétés", - "Declined Documents": "Documents refusés", - "Expired Documents": "Documents expirés", - "Recently sent for signatures": "Récemment envoyé pour signature", - "Recent signature requests": "Demandes de signature récentes", - "Drafts": "Brouillons", - "Contactbook": "Carnet de contacts", - "Templates": "Modèles", - "Teams": "Équipe", - "Users": "Utilisateurs" - }, - "report-heading": { - "Sr.No": "Numéro", - "Title": "Titre", - "Email": "E-mail", - "Phone": "Téléphone", - "File": "Fichier", - "Owner": "Propriétaire", - "Signers": "Signataires", - "Note": "Note", - "Folder": "Dossier", - "Reason": "Raison", - "Parent Team": "Équipe de parents", - "Active": "Actif", - "Role": "Rôle", - "Team": "Équipe", - "Name": "Nom", - "Status": "Statut", - "created-date": "Date de création", - "Type": "Saisir", - "Logs": "Journaux", - "Expiry-date": "Fecha de caducidad" - }, - "btnLabel": { - "sign": "Signer", - "Resend": "Relancer", - "Revoke": "Révoquer", - "Delete": "Supprimer", - "Use": "Utiliser", - "Quick send": "Envoi rapide", - "Edit": "Modifier", - "Share with team": "Partager avec l'équipe", - "Share": "Partager", - "View": "Voir", - "option": "Option", - "Embed": "Intégrer", - "Copy TemplateId": "Copier l'ID du modèle", - "Copy Public URL": "Copier l'URL publique", - "extend-expiry-date": "Prolonger la date d'expiration" - }, - "report-help": { - "Draft Documents": "Il s'agit de documents que vous avez commencés mais que vous n'avez pas finalisés pour envoi.", - "Need your sign": "Voici une liste de documents ou votre signature est requise", - "In-progress documents": "Il s'agit d'une liste de documents que vous avez envoyés à d'autres parties pour signature.", - "Completed Documents": "Il s'agit d'une liste de documents signés par toutes les parties.", - "Declined Documents": "Il s'agit d'une liste de documents qui ont été refusés par l'un des signataires.", - "Expired Documents": "Il s'agit d'une liste de documents qui ont atteint leur date d'expiration.", - "Contactbook": "Il s'agit d'une liste de contacts/signataires que vous avez ajoutés. Ceux-ci apparaîtront sous forme de suggestions lorsque vous tenterez d'ajouter des signataires à un nouveau document.", - "Templates": "Il s'agit d'une liste de modèles à votre disposition pour créer des documents. Vous pouvez cliquer sur le bouton 'Utiliser' pour créer un nouveau document à l'aide d'un modèle, modifier le document et ajouter des signataires à l'étape suivante." - }, - "form-name": { - "Sign Yourself": "signez vous-même", - "Request Signatures": "Demander des signatures", - "New Template": "Nouveau modèle" - }, - "file-type": "pdf, png, jpg, jpeg", - "docx": "docx", - "file-selected": "fichier sélectionné", - "template-title": "Titre du modèle", - "document-title": "Titre du document", - "description": "Description", - "time-to-complete": "Temps de réalisation (jours)", - "send-in-order": "Envoyer dans l'ordre ?", - "send-in-order-help": { - "p1": "Choisissez la manière dont vous souhaitez que les demandes de signature soient envoyées aux signataires du document :", - "p2": "La sélection de cette option enverra initialement la demande de signature au premier signataire. Une fois que le premier signataire a terminé sa partie, le prochain signataire de la séquence recevra la demande. Ce processus se poursuit jusqu'à ce que tous les signataires aient signé le document. Cette méthode garantit que le document est signé dans un ordre spécifique.", - "p3": "La sélection de cette option enverra les liens de signature à tous les signataires simultanément. Chaque signataire peut signer le document à sa convenance, que d'autres signataires aient ou non complété leur signature. Cette méthode est plus rapide mais n’impose aucun ordre de signature entre les participants.", - "p4": "Sélectionnez l'option qui correspond le mieux aux besoins de votre traitement de documents." - }, - "no": "Non", - "auto-reminder": "Rappel automatique", - "remind-once": "Rappeler une fois tous les (jours)", - "next": "Suivant", - "select-folder": "Sélectionner le dossier", - "OpenSign-drive": "Lecteur OpenSign™", - "drive-document-status": { - "Completed": "Complété", - "Declined": "Refuser", - "Draft": "Brouillon", - "Expired": "Expiré", - "In Progress": "En cours" - }, - "select-folder-help": "Si vous ne sélectionnez pas de dossier, votre document signé sera enregistré dans le dossier du lecteur principal OpenSign.", - "no-data": "Aucune données disponible", - "save-here": "Enregistrer ici", - "back": "Retour", - "add-folder": "Ajouter le dossier", - "create-folder": "Créer le dossier", - "parent-folder": "Dossier Parent", - "create": "Créer", - "signers": "Signataires", - "signers-help": "Commencez à saisir le nom d'un contact pour voir les signataires suggérés par vos contacts enregistrés ou en ajouter de nouveaux. Organisez l'ordre de signature en ajoutant des signataires dans l'ordre souhaité. Utilisez le bouton « + » pour inclure les signataires et le « x » pour les supprimer. Chaque signataire recevra un e-mail invité à signer le document dans l'ordre indiqué.", - "add-signer": "Ajouter un signataire", - "contact-not-found": "Contact introuvable", - "add-yourself": "Ajoutez-vous", - "submit": "Soumettre", - "reset": "Réinitialiser", - "my-signature": "Ma signature", - "signature": "Signature", - "upload-image": "Télécharger une image", - "clear": "Vider", - "upload-signature/Image": "télécharger-signature/Image", - "initials": "Initiales", - "API": "API", - "api-token": "Jeton API", - "regenerate-token": "Régénérer en direct jeton", - "generate-token": "Générer en direct jeton", - "view-docs": "Afficher les documents", - "generate-token-alert": "Êtes-vous sûr de vouloir régénérer le jeton, votre ancien jeton sera supprimer?", - "yes": "Oui", - "copied": "Copié", - "wrong-mssg": "Quelque chose c'est mal passé. Merci d'essayer plus tard.", - "token-generated": "Jeton généré avec succès.", - "webhook": "Webhook", - "update-webhook": "Mettre à jour le webhook", - "add-webhook": "Ajouter un webhook", - "webhook-added": "Webhook ajouté avec succès.", - "team-disabled": "Équipe: Désactivée", - "team-enabled": "Équipe activée", - "are-you-sure": "Êtes-vous sûr de vouloir", - "disable": "désactiver", - "enable": "activer", - "this-team": "cette équipe?", - "edit-team": "Modifier l'équipe", - "name-of-team": "Nom de l'équipe", - "prev": "précédent", - "no-data-avaliable": "pas de données disponibles", - "add-team": "Ajouter une équipe", - "page-not-found": "Page non trouvée", - "users-from-teams": "utilisateurs de votre Équipe", - "user-status": "Statut de l'utilisateur", - "activate": "Activer", - "deactivate": "désactiver", - "this-user": "cet utilisateur ", - "delete-user": "Supprimer l'utilisateur", - "delete": "supprimer", - "add-user": "Ajouter un utilisateur", - "password-generateed": "Le mot de passe ne sera généré qu'une seule fois ; assurez-vous de le copier.", - "Team status": "Statut de l'équipe", - "user-deactivated": "Utilisateur désactivé.", - "user-activated": "Activé par l'utilisateur.", - "public": "Public", - "download": "Téléchargement", - "view": "voir", - "make-template-public": "Rendre le modèle public", - "make-template-private": "Rendre le modèle privé", - "make-template-public-alert": "Êtes-vous sûr de vouloir rendre ce modèle public ?", - "make-template-private-alert": "Êtes-vous sûr de vouloir rendre ce modèle privé ? Cela le supprimera de votre profil public.", - "public-role": "Rôle public", - "public-url": "Profil public", - "embed-template": "Intégrer le modèle", - "public-url-copy": "Voici votre URL publique : ", - "public-url-copy-mssg": "copiez-la ou partagez-le avec le signataire et vous pouvoir voir tous vos paramètres publics modèles.", - "add-public-url-alert": "Veuillez terminer la configuration de votre profil public OpenSign. Une fois cela fait, vous pourrez rendre les modèles publics. Ce processus ne doit être effectué qu’une seule fois.", - "share-with-alert": "Vous ne pouvez pas partager un modèle si des contacts sont déjà attribués à des rôles. Veuillez supprimer toutes les attributions de contacts des rôles avant de partager le modèle.", - "share-with": "Partager avec", - "team-not-found": "Équipe introuvable", - "roles": "Les rôles", - "delete-document": "Supprimer un document", - "delete-document-alert": "Êtes-vous sûr de vouloir supprimer ce document ?", - "quick-send": "Envoi rapide", - "add-new": "Ajouter un nouveau", - "send": "envoyer", - "quick-send-alert-1": "Tous les rôles dans ce document sont actuellement liés à des contacts. Pour envoyer rapidement des copies de ce modèle à plusieurs signataires, veuillez vous assurer qu'au moins un rôle n'est lié à aucun contact.", - "quick-send-alert-2": "Veuillez vous assurer qu'au moins un widget de signature est ajouté pour tous les destinataires.", - "quick-send-alert-3": "Veuillez ajouter au moins un rôle à ce modèle afin d'en « envoyer rapidement » des copies à plusieurs signataires.", - "quick-send-alert-4": "L'envoi rapide a atteint la limite.", - "copy-link": "Copier le lien", - "copy": "Copier", - "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}}.", - "subject": "Sujet", - "body": "Corps", - "add-contact": "Ajouter le contact", - "add-signer-alert": "Le contact existe déjà ! Veuillez le sélectionner dans la liste déroulante 'Signataires'", - "record-delete-alert": "Enregistrement supprimé avec succès !", - "record-revoke-alert": " Enregistrement révoqué avec succès ! ", - "mail-sent-alert": "Courriel envoyé avec succès.", - "document-sent-alert": "Document envoyé avec succès !", - "template-share-alert": "Modèle partagé avec succès.", - "template-public-alert-1": "Vous avez rendu le modèle public avec succès.", - "template-public-alert-2": "Vous avez réussi à rendre le modèle privé.", - "template-public-alert-3": "Vous devez sélectionner un rôle pour les signataires publics.", - "template-public-alert-4": "Veuillez vous assurer qu'au moins un widget de signature est ajouté pour tous les signataires.", - "template-public-alert-5": "Étant donné que l'envoi dans l'ordre est activé sur ce modèle, le rôle public doit être positionné en haut.", - "template-public-alert-6": "Veuillez associer des signataires à tous les rôles, à l'exception du rôle d'utilisateur public.", - "template-public-alert-7": "Veuillez attribuer au moins un rôle public pour rendre ce modèle public.", - "loader": "Cela pourrait prendre un certain temps", - "pages": "Pages", - "document-signed": "Document signé", - "close": "Fermer", - "validation-alert": "Alerte de validation", - "validate-alert-mssg": "L'entrée ne répond pas aux critères définis par l'expression régulière.", - "otp-verification": "Vérification OTP", - "enter-otp": "Entrez OTP", - "verify": "Vérifier", - "verify-email-1": "Vérifier l'e-mail", - "resend": "Renvoyer", - "contact-details": "Coordonnées", - "verify-email": "Veuillez vérifier votre email!", - "send-otp": "envoyer un code à usage unique", - "otp-placeholder": "Entrez le code de vérification reçu par e-mail", - "loading-doc": "Chargement du document..", - "widgets-name": { - "signature": "signature", - "stamp": "tampon", - "initials": "initiales", - "name": "nom et Prénom", - "job title": "votre fonction", - "company": "organisation", - "date": "date", - "text": "texte", - "text input": "saisie de texte", - "checkbox": "case à cocher", - "dropdown": "dérouler", - "radio button": "bouton radio", - "image": "image", - "email": "e-mail" - }, - "fields": "Des champs", - "recipients": "Destinataires", - "please-add": "Veuillez ajouter un", - "signed-by": "Signé par", - "more": "plus", - "sent": "Envoyé", - "print": "imprimer", - "certificate": "Certificat", - "decline": "refusé", - "finish": "terminé", - "mail": "Mail", - "sign-now": "Signez maintenant", - "successfully-signed": "Signé avec succès !", - "email-mssg": "Les destinataires ajoutés ici recevront une copie du document signé.", - "email-error-1": "veuillez fournir une adresse e-mail correcte", - "email-error-2": "Vous ne pouvez envoyer qu'à dix destinataires à la fois.", - "Email-verified-alert-1": "L'e-mail est vérifié.", - "Email-verified-alert-2": "L'e-mail est déjà vérifié.", - "upload-stamp-image": "Télécharger l'image du tampon", - "draw": "Dessiner", - "type": "Taper", - "color-type": { - "red": "rouge", - "blue": "bleu", - "black": "noir", - "yellow": "jaune" - }, - "my-initials": "Mes initiales", - "upload": "Télécharger", - "initial-teb": "Initiales", - "signature-tab": "Signature", - "your-signature": "Votre signature", - "copy-title": "Copier le widget vers", - "contact-delete-alert": "Êtes-vous sûr de vouloir supprimer ce contact ?", - "reset-password": "Le lien de réinitialisation du mot de passe a été envoyé à votre identifiant de messagerie", - "reset-password-alert-2": "Veuillez configurer l'adaptateur de messagerie", - "reset-password-alert-3": "Réinitialisez votre mot de passe", - "faild-animation": "Échec du chargement de l'animation", - "apply": "Appliquer", - "copy-type": { - "All pages": "Toutes les pages", - "All pages but last": "Toutes les pages sauf la dernière", - "All pages but first": "Toutes les pages sauf la première", - "Next to current widget": "À côté du widget actuel" - }, - "options": "Possibilités", - "minimun-check": "Vérification minimale", - "maximum-check": "Contrôle maximum", - "default-value": "Valeur par défaut", - "select": "Sélectionner", - "read-only": "Est en lecture seule", - "hide-labels": "Masquer les étiquettes", - "checkbox": "Case à cocher", - "alert": "Alerte", - "zoom-in": "Agrandir", - "zoom-out": "Dézoomer", - "document-signed-alert": "Félicitations ! 🎉 Votre document à bien été signer!", - "otp-sent-alert": "Le code OTP a bien été envoyer sur votre adresse Email", - "fields-required": "Champs obligatoires", - "signature-widget-alert-1": "Veuillez vous assurer qu'au moins un widget de signature a été ajouté", - "signature-widget-alert-2": "Veuillez vous assurer que tous les champs sont remplis avec précision et répondent à toutes les exigences.", - "encrypted-pdf-alert": "Les fichiers PDF actuellement cryptés ne sont pas pris en charge.", - "encrypted-pdf-alert-1": "Le mot de passe du fichier PFX n'est pas valide.", - "user-not-exist": "L'utilisateur n'existe pas", - "template-signature-field": "Veuillez ajouter au moins un champ de signature pour tous les rôles.", - "template-role-alert": "Veuillez d'abord ajouter des rôles", - "create-document": "Créer un document", - "template-created-alert": "Voulez-vous créer un document en utilisant le modèle que vous vient de créer ?", - "signers-alert": "alerte des signataires", - "template-creation-alert-1": "Veuillez sélectionner le signataire pour ajouter un espace réservé !", - "ok": "D'accord", - "radio-group": "Groupe de radio", - "dropdown-options": "Options déroulantes", - "add-role": "Ajouter un rôle", - "role-ex": "Ex : Client, RH, Directeur, Manager, Étudiant, etc.", - "add/choose-signer": "Ajouter/Choisir un signataire", - "choose-from-contacts": "Choisissez parmis les contacts", - "select-signer": "Veuillez sélectionner le signataire", - "edit-template": "Modifier le modèle", - "widget-info": "Informations sur les widgets", - "validation": "Validation", - "invalid-default-value": "valeur par défaut invalide", - "hint": "Indice", - "color": "couleur", - "role-help": { - "p1": "Que sont les rôles modèles ?", - "p2": "Commencez par spécifier chaque rôle nécessaire à la finalisation du document. Pensez aux parties impliquées dans le processus de signature et à leurs responsabilités. Les rôles courants incluent les RH pour les documents internes, le Client pour les accords ou le Fournisseur pour les accords commerciaux.", - "p3": "Pourquoi pré-attacher les utilisateurs à certains rôles ?", - "p4": "Pour les rôles qui impliquent systématiquement la même personne (par exemple, la signature du PDG sur les lettres d'offre des employés), vous pouvez pré-attacher un utilisateur à un rôle dans le modèle. Cette étape est facultative mais recommandée pour des raisons d'efficacité et de cohérence entre les documents.", - "p5": "Quand dois-je spécifier l'utilisateur attaché à chaque rôle ?", - "p6": "Lorsque vous créez un document à partir de votre modèle, vous serez invité à attacher des utilisateurs à chaque rôle défini. Si un rôle est déjà associé à un utilisateur, celui-ci sera pré-rempli, mais vous pourrez le modifier si nécessaire avant d'envoyer le document." - }, - "add-recipients": "Ajouter des destinataires", - "loading-mssg": "Cela pourrait prendre du temps", - "send-mail": "Envoyer un mail", - "placeholder-alert-1": "Veuillez vous assurer qu'au moins un widget de signature est ajouté pour tous les destinataires.", - "placeholder-alert-2": "Veuillez confirmer que vous avez rempli le champ de texte.", - "placeholder-alert-3": "Etes-vous sûr de vouloir envoyer ce document pour signature ? ", - "placeholder-alert-4": "Vous avez envoyé avec succès des mails à tous les", - "placeholder-alert-5": "Voulez-vous signer des documents maintenant ?", - "placeholder-alert-6": "Veuillez configurer l'adaptateur de messagerie pour envoyer du courrier !", - "placeholder-alert-7": "Veuillez sélectionner le signataire pour ajouter un espace réservé !", - "email-subject": "Sujet du courriel", - "email-body": "corps de l'e-mail", - "email-placeholder": "Ajouter le corps de l'e-mail", - "reset-to-default": "Réinitialiser aux valeurs par défaut", - "cutomize-email": "Personnaliser l'e-mail", - "upgrade-to-customize-email": "Mise à niveau pour personnaliser l'e-mail", - "sign-url": "Signer l'URL", - "mails-sent": "Mails envoyés avec succès !", - "mail-not-delivered": "Courrier non distribué", - "document-alert": "Alerte document", - "owner-subscription-expired": "L'abonnement du propriétaire a expiré.", - "subscription-expired": "Abonnement expiré", - "alert-message": "Message d'alerte", - "document-decline": "Document-refusé", - "decline-alert-1": "Etes-vous sûr de vouloir refuser ce document ?", - "decline-alert-2": "Vous avez refusé ce document !", - "decline-alert-3": "Vous ne pouvez pas signer ce document car il a été refusé/révoqué.", - "sign here": "Signer ici", - "guest-email-alert": "le code de vérification a été envoyé sur votre e-mail", - "get-otp-alert": "vous recevrez un code de vérification par e-mail", - "user-already-exist": "L'utilisateur existe déjà.", - "server-error": "Erreur interne du serveur !", - "fill-required-details!": "Veuillez remplir les informations requises !", - "sign-up-form": "Formulaire d'inscription", - "sign-up": "S'inscrire", - "folder-already-exist!": "le dossier existe déjà !", - "please-select-position!": "Veuillez sélectionner un poste !", - "default-sign-alert": "Êtes-vous sûr de vouloir vous connecter automatiquement à tous les emplacements demandés ? ", - "Your-Signature": "Votre signature", - "auto-sign-all": "Tout signer automatiquement", - "generating-certificate": "Génération du certificat", - "pdf-download": "Téléchargement PDF", - "generate-certificate-alert": " Votre certificat d'achèvement est en cours de génération. Veuillez patienter quelques instants. Si le téléchargement ne démarre pas sous peu, cliquez à nouveau sur le bouton. ", - "folder-already-exist": "Le dossier existe déjà !", - "folder-created-successfully": "Dossier créé avec succès !", - "fill-folder-name": "Veuillez indiquer le nom du dossier", - "already-exists-this-username": "Un utilisateur existe déjà avec ce nom d'utilisateur !", - "verification-code-sent": "Un e-mail de vérification a été envoyé à votre adresse e-mail !", - "registered-user-successfully": "Utilisateur enregistré avec succès.", - "role-not-found": "Rôle introuvable.", - "do-not-access": "Vous n'y avez pas accès, veuillez contacter l'administrateur.", - "add-admin": "Ajouter un administrateur", - "opensign-setup": "Configuration d'OpenSign", - "join-discord": "Rejoignez notre serveur Discord", - "admin-already-exist": "L'administrateur existe déjà.", - "password-update-alert-1": "Mot de passe mis à jour avec succès.", - "password-update-alert-2": "Votre mot de passe actuel est manquant ou incorrect.", - "password-update-alert-3": "Votre mot de passe actuel est manquant ou incorrect.", - "password-update-alert-4": "Votre mot de passe et votre mot de passe de confirmation ne correspondent pas.", - "current-password": "mot de passe actuel", - "new-password": "nouveau mot de passe", - "confirm-password": "Confirmez le mot de passe", - "file-alert-1": "La taille du fichier sélectionné est trop grande. Veuillez sélectionner un fichier inférieur à", - "file-alert-2": "Veuillez sélectionner un fichier.", - "file-alert-3": "Veuillez patienter pendant le téléchargement du document.", - "enter-pdf-password": "Entrez le mot de passe PDF", - "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é!", - "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", - "enter-verification-code": "Entrez le code de vérification", - "provide-your-details": "Fournissez vos coordonnées", - "provide-email": "Veuillez fournir un e-mail.", - "additional-info": "Information additionnelle", - "signature-saved-alert": "Signature enregistrée avec succès.", - "fill-field": "Veuillez remplir ce champ", - "error-template": "Erreur : modèle introuvable ! ", - "error": "Erreur", - "invalid-document": "Erreur : document invalide !", - "document-not-found": "Document introuvable !", - "document-signed-alert-1": "Vous avez signé le document avec succès. Vous pouvez télécharger ou imprimer une copie du document partiellement signé. Une copie du document signé numériquement et du certificat d'achèvement sera envoyée au propriétaire et à tous les signataires par e-mail une fois qu'il aura été signé par tous les signataires.", - "encrypted-pdf-not-support": "Les fichiers PDF actuellement cryptés ne sont pas pris en charge. ", - "document-signed-alert-4": "Toutes nos félicitations! 🎉 Ce document a été signé avec succès par tous les participants !", - "document-signed-alert-5": "Ce document a été signé par tous les signataires.", - "document-signed-alert-6": "Ce document a été refusé par un ou plusieurs destinataire(s).", - "document-signed-alert-7": "Ce document n'est plus disponible.", - "document-signed-alert-8": "Le document a déjà été envoyé pour signature.", - "yet-to-sign": "Reste à signer", - "validation-alert-1": "L'entrée ne répond pas aux critères définis par l'expression régulière.", - "account-already-exists": "Le compte existe déjà!", - "choose-password": "Choisissez un mot de passe", - "enter-password": "Entrer le mot de passe", - "sure": "bien sûr", - "subscribed-alert": "Vous êtes déjà abonné au forfait !", - "monthly": "Mensuel", - "yearly-upto": "Annuel (jusqu'à 66 % de réduction)", - "billed-yearly": "Facturé annuellement", - "billed-monthly": "Facturé mensuellement", - "plansubscription-1": "Hébergez-le vous-même gratuitement", - "visit-github": "Visitez Github", - "user-already-exist-name": "Un utilisateur existe déjà avec ce nom d'utilisateur !", - "do-not-access-contact-admin": "Vous n'y avez pas accès, veuillez contacter l'administrateur.", - "filed-required-correctly": "Veuillez remplir correctement les informations requises.", - "admin-created": "Administrateur créé", - "invalid-masterkey": "Clé principale invalide", - "opensign-Setup": "Configuration d'OpenSign", - "master-key": "La clef maitresse", - "profile-update-alert": "Mise à jour du profil réussie.", - "date": "Date", - "report-not-found": "Rapport introuvable", - "please-wait": "S'il vous plaît, attendez", - "select-foler": "Sélectionner le dossier", - "generated-on": "Généré le", - "text-field": "Champ de texte", - "font-size": "Taille de police", - "widget-status": { - "Required": "Requis", - "Optional": "Facultative" - }, - "all-right": "Tous droits réservés", - "version": "version", - "social-media": { - "github": "Github", - "linked-in": "LinkedIn", - "twitter": "Twitter", - "discord": "Discorde" - }, - "tour-mssg": { - "home-layout-1": "Vous vous êtes connecté avec succès ! Jetons un coup d'oeil.", - "home-layout-2": "Pour télécharger des documents à auto-signature ou pour demander la signature d'autres personnes, sélectionnez simplement les boutons correspondants.", - "home-layout-3": "Vous êtes prêt à commencer à utiliser OpenSign ! Si vous avez besoin d'aide, n'hésitez pas à nous contacter.", - "generate-token": "Effectuez la mise à niveau maintenant pour générer un jeton API de production.", - "opensign-drive-1": "Cliquez sur les liens du fil d'Ariane pour naviguer facilement dans la hiérarchie des dossiers et afficher les documents dans chaque dossier.", - "opensign-drive-2": "Cliquez sur le bouton Ajouter pour créer un nouveau dossier ou document.", - "opensign-drive-3": "Triez vos documents par date ou par nom à l'aide de ce menu.", - "opensign-drive-4": "Cliquez sur ce menu pour afficher les documents sous forme de liste.", - "opensign-drive-5": "La liste des documents s'affiche selon l'option de tri sélectionnée. Les icônes à côté de chaque document indiquent son état actuel.", - "opensign-drive-6": "Faites un clic droit sur un document pour voir les options telles que Télécharger, Renommer, Déplacer et Supprimer. Cliquez sur le document pour l'ouvrir.", - "opensign-drive-7": "Faites un clic droit sur n'importe quel dossier pour voir les options. Choisissez 'Renommer' pour changer le nom du dossier ou cliquez sur le dossier pour naviguer dans son contenu.", - "pdf-request-file-1": "Liste des signataires qui doivent encore signer le document.", - "pdf-request-file-2": "Cliquez sur l'un des espaces réservés apparaissant sur le document pour signer. Vous verrez alors des options pour dessiner votre signature, la saisir ou télécharger une image.", - "pdf-request-file-3": "Cliquez sur les boutons Précédent, Refuser ou Terminer pour parcourir votre document. Utilisez le menu points de suspension pour des options supplémentaires, notamment le bouton Télécharger.", - "pdf-request-file-4": "Liste des signataires ayant déjà signé le document.", - "pdf-request-file-5": "Vous pouvez cliquer sur 'Signer automatiquement tout' pour signer automatiquement à tous les emplacements que vous êtes censé signer. Assurez-vous de lire correctement le document avant de cliquer sur ce bouton.", - "placeholder-sign-1": "Sélectionnez un destinataire dans cette liste pour ajouter un espace réservé à l'endroit où il est censé signer. L'espace réservé apparaîtra de la même couleur que le nom du destinataire une fois que vous le déposerez sur le document.", - "placeholder-sign-2": "Cliquer sur le bouton 'Ajouter des destinataires' vous permettra d'ajouter plus de signataires.", - "placeholder-sign-3": "Cliquez sur ce bouton pour ajouter plus de destinataires/signataires au document", - "placeholder-sign-4": "Faites glisser ou cliquez sur un champ pour l'ajouter au document.", - "placeholder-sign-5": "La zone de contenu PDF affiche déjà les espaces réservés existants du modèle. Pour votre commodité, ces espaces réservés correspondront à la couleur du nom du destinataire, ce qui les rendra facilement identifiables.", - "placeholder-sign-6": "Cliquer sur 'Envoyer' enregistrera le document. À l'étape suivante, vous pourrez personnaliser les e-mails à envoyer aux destinataires ou copier les liens de signature et les partager vous-même avec les destinataires.", - "report-1": "Cliquez sur le bouton 'Ajouter' pour créer un nouveau modèle. Les modèles sont des documents réutilisables conçus pour générer rapidement de nouveaux documents avec la même structure et différents signataires. Par exemple, un modèle RH pour l'intégration peut avoir des rôles prédéfinis tels que 'Responsable RH' et ' Nouvel employé'. Chaque fois que vous utilisez le modèle, vous pouvez attribuer le rôle 'Nouvel employé' à différents membres du personnel entrants, tandis que le rôle 'Responsable RH' reste constant, facilitant ainsi un processus d'intégration fluide pour chaque recrue", - "redirect": "Cliquez sur le bouton 'Utiliser' pour créer un nouveau document à partir d'un modèle existant.", - "bulksend": "Pour créer et envoyer rapidement plusieurs documents à l'aide d'un modèle existant, cliquez sur le bouton 'Envoi rapide'.", - "option": "Ce menu révèle plus d'options telles que Modifier et Supprimer. Utilisez le bouton « Modifier » pour ajouter des rôles de signataire, modifier les champs et mettre à jour votre modèle. Les modifications s'appliqueront à tous les futurs documents créés à partir de ce modèle mais n'affecteront pas les documents existants. Utilisez le bouton Supprimer, vous pouvez supprimer le modèle ", - "signyour-self-1": "Sélectionnez et faites glisser vos widgets préférés sur le PDF pour personnaliser votre document avant de le signer. Choisissez les endroits parfaits pour chaque modification afin d'adapter le document à vos besoins.", - "signyour-self-2": "Faites glisser et déposer n'importe où dans cette zone. Vous pourrez la redimensionner et la déplacer plus tard.", - "template-placeholder-1": "Cliquer sur le bouton 'Ajouter un rôle' vous permettra d'ajouter différents rôles de signataire. Vous pourrez attacher des utilisateurs à chaque rôle dans les étapes suivantes.", - "template-placeholder-2": "Une fois les rôles ajoutés, sélectionnez un rôle dans la liste pour ajouter un espace réservé à l'endroit où il est censé signer. L'espace réservé apparaîtra dans la même couleur que le nom du rôle une fois que vous l'aurez déposé sur le document.", - "template-placeholder-3": "Faites glisser ou cliquez sur un champ pour l'ajouter au document.", - "template-placeholder-4": "Faites glisser l'espace réservé pour un rôle n'importe où sur le document. N'oubliez pas qu'il apparaîtra dans la même couleur que le nom du destinataire pour une référence facile.", - "template-placeholder-5": "Cliquer sur 'Suivant' stockera le modèle actuel. Après l'enregistrement, vous serez invité à créer un nouveau document à partir de ce modèle si vous le souhaitez.", - "webhook-1": "Mettez à niveau maintenant pour définir le webhook", - "Need your Signature": "En cliquant sur cette carte, vous accéderez à la liste des documents en attente de révision.", - "Out for signatures": "En cliquant sur cette carte, vous accéderez à une liste de documents en attente de signature.", - "Recent signature requests": "Voici une liste de documents qui attendent votre signature.", - "Recently sent for signatures": "Il s'agit d'une liste de documents que vous avez envoyés à d'autres parties pour signature.", - "Drafts": "Il s'agit de documents que vous avez commencés mais que vous n'avez pas finalisés pour envoi.", - "public-template": "Cette vidéo montre comment configurer votre profil public personnalisé, tel que 'https://opensign.me/your-username'. Vous apprendrez également comment personnaliser votre slogan et rendre vos modèles disponibles pour la signature publique." - }, - "enter-email-plaholder": "Ajoutez une adresse email et appuyez sur Entrée", - "success-email-alert": "E-mail envoyé avec succès!", - "expired-doc-title": "Document expiré", - "expired-on-mssg": "Ce document a expiré le {{expiredDate}} et n'est plus disponible pour signature.", - "signature-validate-alert": "Veuillez confirmer que vous avez coché au moins {{minRequiredCount}} cases.", - "signature-validate-alert-2": "Assurez-vous que ce champ est rempli avec précision et répond à toutes les exigences.", - "user-name-exist": "le nom d'utilisateur existe déjà", - "remaing-users": "Utilisateurs restants", - "Role": "Rôle", - "additional-users": "Veuillez acheter des utilisateurs supplémentaires.", - "Quantity-of-users": "Quantité d'utilisateurs", - "Price": "Prix", - "Total-price-for-next-time": "Prix ​​total pour la prochaine fois", - "Proceed": "Procéder", - "Select": "sélectionner", - "Add-seats": "Ajouter des sièges", - "format": "format", - "select-date-format": "Sélectionnez un format de date", - "quantity-of-credits": "Quantité de crédits de prime", - "remaining-credits": "Crédits premium disponibles :", - "additional-credits": "Veuillez acheter des crédits premium", - "remaining-credits-help": "Utilisez des crédits premium pour la signature de documents API, l'envoi groupé ou l'intégration d'OpenSign sur votre site Web. Il vous reste {{allowedcredits}} crédits inclus et {{addoncredits}} crédits achetés supplémentaires.", - "quota-err-quicksend": "Quota atteint, vous n'avez pas assez de crédits.", - "buy-credits": "Acheter des crédits premium", - "rotate-right": "Faire pivoter à droite", - "rotate-left": "Faire pivoter à gauche", - "rotate-alert-mssg": "Tous les widgets de cette page seront perdus. Êtes-vous sûr de vouloir continuer ?", - "templateid": "ID de modèle", - "bulk-send-subcription-alert": "Veuillez passer au forfait Professionnel ou Équipe pour utiliser Quicksend.", - "generate-test-token": "Générer jeton de test", - "regenerate-test-token": "Régénérer le jeton de test", - "help-test-token": "Ce jeton peut être utilisé pour tester les API au niveau du point de terminaison https://sandbox.opensignlabs.com/api/v1, vous permettant ainsi d'effectuer un nombre illimité de signatures de documents. Veuillez noter que l'API sandbox signera vos documents avec des certificats auto-signés, qui peuvent ne pas être reconnus comme valides par Adobe. Une fois vos tests terminés, vous pouvez passer à l’un de nos forfaits payants pour générer un jeton de production.", - "help-api-token": "Ce jeton peut être utilisé pour accéder aux API de production au point de terminaison {{origin}}/api/v1. Il ne peut être généré que sur l'un de nos forfaits payants.", - "reason": "Raison", - "decline-by": "Refusé/révoqué par", - "document-declined": "document refusé", - "public-template-mssg-1": "Pour intégrer OpenSign dans votre projet React ou Next.js, exécutez simplement la commande suivante :", - "public-template-mssg-2": "Assurez-vous que npm ou Yarn est configuré dans votre projet. Si vous utilisez Yarn, vous pouvez remplacer npm install par Yarn Add @opensign/react.", - "public-template-mssg-3": "Besoin de plus de détails ou d'exemples ?", - "public-template-mssg-4": "Visitez le", - "public-template-mssg-5": "npm pour les dernières mises à jour, une documentation détaillée et l'historique des versions.", - "public-template-mssg-6": "Avant de pouvoir utiliser cet extrait de code, vous devez rendre ce modèle public.", - "copy-code": "COPIE", - "copied-code": "COPIÉ", - "Installation": "Installation", - "Usage": "Usage", - "insufficient-credits": "Crédits de signature insuffisants", - "insufficient-credits-mssg": "Le propriétaire de ce document ne dispose actuellement pas des crédits OpenSign nécessaires pour que vous puissiez le signer. Veuillez contacter le propriétaire si vous avez besoin de plus de détails.", - "angular-npm-mssg-1": "Pour intégrer OpenSign dans votre projet Angular, exécutez simplement la commande suivante :", - "quota-mail-info-head": "Limite mensuelle d'e-mails de signatures de demandes", - "quota-mail-info": "Vous pouvez envoyer jusqu'à 15 e-mails de demande de signature chaque mois. Mettez à niveau maintenant pour envoyer directement des demandes de signature illimitées.", - "quota-mail-reset": "Les crédits de votre email de demande de signature seront réinitialisés le", - "quota-mail": "Vous avez atteint votre limite de 15 e-mails de demande de signature pour ce mois. Mettez à niveau maintenant pour continuer à envoyer des e-mails directement.", - "quota-mail-tip-tip": "Astuce : Vous pouvez toujours signer un nombre <1>illimité de documents</1> en partageant manuellement les liens de demande de signature.", - "quota-mail-head": "Quota atteint", - "unauthorized-modal": "Vous n'êtes pas autorisé à effectuer cette action, veuillez contacter {{adminEmail}}.", - "sent-this-month": "envoyé ce mois-ci", - "available-seats": "Disponible sièges", - "buy-users": "Acheter plus d'utilisateurs", - "isenable-otp": "Activer la vérification OTP", - "isenable-otp-help": { - "p1": "Souhaitez-vous activer le processus de vérification à l'aide d'un mot de passe à usage unique (OTP)?", - "p2": "La sélection de cette option activera la vérification OTP. Les utilisateurs recevront un code de vérification par e-mail, qu'ils devront saisir pour signer le document.", - "p3": "La sélection de cette option désactivera la vérification OTP, permettant aux utilisateurs de signer le document directement sans étapes supplémentaires.", - "p4": "Veuillez choisir l'option qui correspond le mieux à vos exigences en matière de signature de documents." - }, - "advanced-options": "Options avancées", - "hide-advanced-options": "Masquer les options avancées", - "download-files": "Télécharger des fichiers", - "download-pdf": "Télécharger le PDF", - "pdf-certificate": "Télécharger Pdf + Certificat", - "document-logs": "Journaux de documents", - "server-down": "Impossible de se connecter au serveur OpenSign. Si vous hébergez vous-même OpenSign, veuillez vous assurer que toutes les étapes de la documentation ont été correctement suivies. Si vous exécutez OpenSign localement, vous y accédez peut-être via un numéro de port incorrect.", - "admin-exists": "L'administrateur existe déjà. Veuillez vous connecter à l'application en utilisant les informations d'identification de l'administrateur afin de gérer les utilisateurs.", - "enable-tour": "Activer la visite", - "istourenabled-otp-help": { - "p1": "Cela permettra une visite guidée pour les signataires, fournissant des instructions pendant le processus de signature.", - "p2": "Cela désactivera la visite guidée, garantissant ainsi une expérience de signature plus rapide et ininterrompue.", - "p3": "Conseil : si vos signataires connaissent OpenSign et l'utilisent fréquemment, vous souhaiterez peut-être désactiver la visite guidée pour une expérience plus fluide. Choisissez l'option qui correspond le mieux à vos besoins en matière de signature de documents." - }, - "form-title-1": "Paramètre du flux de documents", - "form-title-2": "Paramètre de sécurité", - "public-tour-message": "Le modèle doit être public avant que vous puissiez générer un lien partageable.", - "add-user-template": "Vous devez ajouter un rôle avant de pouvoir lui ajouter des champs. ", - "pdf-uncompatible": "Ce pdf n'est pas compatible avec opensign, veuillez contacter <support@opensignlabs.com>", - "text-field-tour": "Les champs de type 'Texte' doivent être remplis à l'avance avant l'envoi du document. Si vous avez besoin que les signataires fournissent des informations, utilisez plutôt le champ 'Saisie de texte'.", - "attach-signer-tour": "Vous devez associer un signataire à chaque rôle. Vous pouvez le faire en cliquant sur cette icône. Une fois que vous avez sélectionné un signataire, il sera attaché à tous les champs associés à ce rôle qui apparaissent dans la même couleur.", - "allowed-signature-types": "Types de signature autorisés", - "at-least-one-signature-type": "Au moins un type de signature doit être activé.", - "expect-default-one-signature-type": "Veuillez activer un type de signature supplémentaire en plus de celui par défaut.", - "add-signer-note": "Remarque - Ce contact sera ajouté à votre liste de contacts", - "allowed-signature-types-help": { - "p1": "Cette préférence de signature contrôle les options de signature disponibles pour vos signataires. Seuls les types de signature que vous sélectionnez apparaîtront dans le widget de signature lorsqu'un document est signé. Par exemple, si vous choisissez uniquement l'option 'Draw' dans les préférences, votre signataire ne verra que l'option 'Draw' dans le widget de signature, tandis que les trois autres options ne seront pas disponibles.", - "l1": "Créez une signature manuscrite directement sur l'écran à l'aide de votre doigt ou d'un stylet.", - "l2": "Entrez votre nom et choisissez parmi différents styles de police pour créer une signature.", - "l3": "Téléchargez une version numérique existante de votre signature.", - "l4": "Utilisez un style de signature prédéfini enregistré sous 'Ma signature' ​​dans vos paramètres." - }, - "notify-on-signatures": "Notifier les signatures", - "notify-on-signatures-help": { - "p1": "Le créateur du document recevra une notification par e-mail chaque fois qu'un signataire signera le document.", - "note": "Remarque : L'e-mail de notification ne sera pas envoyé pour le dernier signataire, car le créateur du document recevra à la place un e-mail de fin." - }, - "expiry-date": "Fecha de caducidad", - "expiry-date-updated": "La date d'expiration a été prolongée avec succès jusqu'au {{newexpirydate}}", - "expiry-date-error": "Veuillez fournir une nouvelle date d'expiration postérieure à la date actuelle" -} diff --git a/apps/OpenSign/src/styles/opensigndrive.css b/apps/OpenSign/src/styles/opensigndrive.css index 6e35e391c..0925a0e45 100644 --- a/apps/OpenSign/src/styles/opensigndrive.css +++ b/apps/OpenSign/src/styles/opensigndrive.css @@ -193,6 +193,12 @@ text-align: center; font-weight: 480; } +.select-none-cls{ + -webkit-user-select: none; + /* Disable text selection in WebKit browsers */ + -moz-user-select: none; + user-select: none; +} a { all: unset; diff --git a/apps/OpenSign/src/styles/signature.css b/apps/OpenSign/src/styles/signature.css index 2c6e8facf..0aab7bdc9 100644 --- a/apps/OpenSign/src/styles/signature.css +++ b/apps/OpenSign/src/styles/signature.css @@ -6,7 +6,12 @@ .react-datepicker__input-container { position: initial !important; } - +.select-none-cls{ + -webkit-user-select: none; + /* Disable text selection in WebKit browsers */ + -moz-user-select: none; + user-select: none; +} .widgets { -webkit-user-select: none; /* Disable text selection in WebKit browsers */ @@ -26,15 +31,11 @@ } .signatureCanvas { - border: 2px solid #888; - background-color: rgb(255, 255, 255); width: 460px; height: 184px; } .intialSignatureCanvas { - border: 2px solid #888; - background-color: rgb(255, 255, 255); width: 150px; height: 150px; } diff --git a/apps/OpenSign/tailwind.config.js b/apps/OpenSign/tailwind.config.js index 6950c4228..1df70df5e 100644 --- a/apps/OpenSign/tailwind.config.js +++ b/apps/OpenSign/tailwind.config.js @@ -1,6 +1,8 @@ /** @type {import('tailwindcss').Config} */ module.exports = { - content: ["./src/**/*.{js,jsx,ts,tsx}", "./src/script/PublicTemplate.js"], + content: [ + "./src/**/*.{js,jsx,ts,tsx}", + ], theme: { extend: {} }, diff --git a/apps/OpenSign/webpack.config.js b/apps/OpenSign/webpack.config.js deleted file mode 100644 index 99d06a680..000000000 --- a/apps/OpenSign/webpack.config.js +++ /dev/null @@ -1,70 +0,0 @@ -const path = require("path"); -const Dotenv = require("dotenv-webpack"); -const { CleanWebpackPlugin } = require("clean-webpack-plugin"); //used to clean directory -const TerserPlugin = require("terser-webpack-plugin"); //used to minify and optimize JavaScript files -const MiniCssExtractPlugin = require("mini-css-extract-plugin"); //used to extract css file into separate files -const isProduction = process.env.NODE_ENV; -module.exports = { - mode: isProduction ? "production" : "development", - entry: "./src/script/PublicTemplate.js", - output: { - path: path.resolve(__dirname, "public/static/js"), - filename: "public-template.bundle.js", - libraryTarget: "umd", - umdNamedDefine: true, - library: "PublicTemplate", - globalObject: "this" - }, - module: { - rules: [ - { - test: /\.(js|jsx)$/, - exclude: /node_modules/, - use: { - loader: "babel-loader", - options: { - presets: ["@babel/preset-react"] - } - } - }, - { - test: /\.css$/, - use: [ - isProduction ? MiniCssExtractPlugin.loader : "style-loader", - "css-loader", - "postcss-loader" - ] - }, - { - test: /\.(png|jpe?g|gif|svg)$/i, - use: [ - { - loader: "file-loader", - options: { - name: "assets/images/[name].[hash].[ext]" - } - } - ] - } - ] - }, - resolve: { - extensions: [".js", ".jsx", ".json"] - }, - plugins: [ - new Dotenv(), - new CleanWebpackPlugin(), - ...(isProduction - ? [ - new MiniCssExtractPlugin({ - filename: "public-template.bundle.css" - }) - ] - : []) - ], - optimization: { - minimize: isProduction ? true : false, - minimizer: [new TerserPlugin()] - }, - devtool: isProduction ? "source-map" : "inline-source-map" -}; diff --git a/apps/OpenSignServer/Utils.js b/apps/OpenSignServer/Utils.js index ad26a550e..ff1cb5c1f 100644 --- a/apps/OpenSignServer/Utils.js +++ b/apps/OpenSignServer/Utils.js @@ -1,4 +1,7 @@ import dotenv from 'dotenv'; +import { format, toZonedTime } from 'date-fns-tz'; +import { getSignedLocalUrl } from './cloud/parsefunction/getSignedUrl.js'; +import { PDFDocument } from 'pdf-lib'; dotenv.config(); export const cloudServerUrl = 'http://localhost:8080/app'; @@ -200,6 +203,7 @@ export function formatWidgetOptions(type, options) { validation: { type: 'regex', pattern: options?.regularexpression || '/^[a-zA-Z0-9s]+$/' }, fontColor: fontColor, fontSize: fontSize, + isReadOnly: options?.readonly || false, }; case 'checkbox': { const arr = options?.values; @@ -243,6 +247,7 @@ export function formatWidgetOptions(type, options) { defaultValue: defaultValue, fontColor: fontColor, fontSize: fontSize, + isReadOnly: options?.readonly || false, }; default: break; @@ -261,17 +266,79 @@ export const smtpsecure = process.env.SMTP_PORT && process.env.SMTP_PORT !== '46 export const smtpenable = process.env.SMTP_ENABLE && process.env.SMTP_ENABLE.toLowerCase() === 'true' ? true : false; -export const planCredits = { - 'pro-weekly': 100, - 'pro-yearly': 240, - 'professional-monthly': 100, - 'professional-yearly': 240, - 'team-weekly': 100, - 'team-yearly': 500, - 'teams-monthly': 100, - 'teams-yearly': 500, + +// `generateId` is used to unique Id for fileAdapter +export function generateId(length) { + const characters = 'abcdefghijklmnopqrstuvwxyz0123456789'; + let result = ''; + const charactersLength = characters.length; + for (let i = 0; i < length; i++) { + result += characters.charAt(Math.floor(Math.random() * charactersLength)); + } + return result; +} + +// Format date and time for the selected timezone +export const formatTimeInTimezone = (date, timezone) => { + const nyDate = timezone && toZonedTime(date, timezone); + const generatedDate = timezone + ? format(nyDate, 'EEE, dd MMM yyyy HH:mm:ss zzz', { timeZone: timezone }) + : new Date(date).toUTCString(); + return generatedDate; }; -export function parseJwt(token) { - return JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString()); -} +// `getSecureUrl` is used to return local secure url if local files +export const getSecureUrl = url => { + const fileUrl = new URL(url)?.pathname?.includes('files'); + if (fileUrl) { + try { + const file = getSignedLocalUrl(url); + if (file) { + return { url: file }; + } else { + return { url: '' }; + } + } catch (err) { + console.log('err while fileupload ', err); + return { url: '' }; + } + } else { + return { url: url }; + } +}; + +/** + * FlattenPdf is used to remove existing widgets if present any and flatten pdf. + * @param {string | Uint8Array | ArrayBuffer} pdfFile - pdf file. + * @returns {Promise<Uint8Array>} flatPdf - pdf file in unit8arry + */ +export const flattenPdf = async pdfFile => { + try { + const pdfDoc = await PDFDocument.load(pdfFile); + // Get the form + const form = pdfDoc.getForm(); + // fetch form fields + const fields = form.getFields(); + // remove form all existing fields and their widgets + if (fields && fields?.length > 0) { + try { + for (const field of fields) { + while (field.acroField.getWidgets().length) { + field.acroField.removeWidget(0); + } + form.removeField(field); + } + } catch (err) { + console.log('err while removing field from pdf', err); + } + } + // Updates the field appearances to ensure visual changes are reflected. + form.updateFieldAppearances(); + // Flattens the form, converting all form fields into non-editable, static content + form.flatten(); + const flatPdf = await pdfDoc.save({ useObjectStreams: false }); + return flatPdf; + } catch (err) { + throw new Error('error in pdf'); + } +}; diff --git a/apps/OpenSignServer/cloud/customRoute/LICENSE b/apps/OpenSignServer/cloud/customRoute/LICENSE deleted file mode 100644 index 2ff058aa3..000000000 --- a/apps/OpenSignServer/cloud/customRoute/LICENSE +++ /dev/null @@ -1,35 +0,0 @@ -The OpenSign Enterprise license (the “Enterprise License”) -Copyright (c) 2020-2024 Qik Innovations Private Limited. - -With regard to the OpenSign Software: - -This software and associated documentation files (the "Software") may only be -used in production, if you (and any entity that you represent) have agreed to, -and are in compliance with, the OpenSign Subscription Terms of Service(the “Enterprise Terms”), or other -agreement governing the use of the Software, as agreed by you and OpenSign, -and otherwise have a valid OpenSign Enterprise license for the -correct number of user seats. Subject to the foregoing sentence, you are free to -modify this Software and publish patches to the Software. You agree that OpenSign -and/or its licensors (as applicable) retain all right, title and interest in and -to all such modifications and/or patches, and all such modifications and/or -patches may only be used, copied, modified, displayed, distributed, or otherwise -exploited with a valid OpenSign Enterprise license for the correct -number of user seats. Notwithstanding the foregoing, you may copy and modify -the Software for development and testing purposes, without requiring a -subscription. You agree that OpenSign and/or its licensors (as applicable) retain -all right, title and interest in and to all such modifications. You are not -granted any other rights beyond what is expressly stated herein. Subject to the -foregoing, it is forbidden to copy, merge, publish, distribute, sublicense, -and/or sell the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -For all third party components incorporated into the OpenSign Software, those -components are licensed under the original license provided by the owner of the -applicable component. diff --git a/apps/OpenSignServer/cloud/customRoute/autoReminder.js b/apps/OpenSignServer/cloud/customRoute/autoReminder.js deleted file mode 100644 index 25f8c19f0..000000000 --- a/apps/OpenSignServer/cloud/customRoute/autoReminder.js +++ /dev/null @@ -1,192 +0,0 @@ -import axios from 'axios'; -import { cloudServerUrl } from '../../Utils.js'; - -// `replaceMailVaribles` is used to replace variables from mail with there actual values -function replaceMailVaribles(subject, body, variables) { - let replacedSubject = subject; - let replacedBody = body; - - for (const variable in variables) { - const regex = new RegExp(`{{${variable}}}`, 'g'); - if (subject) { - replacedSubject = replacedSubject.replace(regex, variables[variable]); - } - if (body) { - replacedBody = replacedBody.replace(regex, variables[variable]); - } - } - - const result = { - subject: replacedSubject, - body: replacedBody, - }; - return result; -} - -// `sendmail` is used to signing reminder mail to signer -async function sendMail(doc, signer) { - const subject = `{{sender_name}} has requested you to sign "{{document_title}}"`; - const body = `<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body><p>Hi {{receiver_name}},</p><br><p>We hope this email finds you well. {{sender_name}} has requested you to review and sign <b>"{{document_title}}"</b>.</p><p>Your signature is crucial to proceed with the next steps as it signifies your agreement and authorization.</p><br><p>{{signing_url}}</p><br><p>If you have any questions or need further clarification regarding the document or the signing process, please contact the sender.</p><br><p>Thanks</p><p> Team OpenSign™</p><br></body> </html>`; - const url = `${cloudServerUrl}/functions/sendmailv3`; - const headers = { - 'Content-Type': 'application/json', - 'X-Parse-Application-Id': process.env.APP_ID, - }; - - const baseUrl = new URL(process.env.PUBLIC_URL); - const encodeBase64 = btoa(`${doc.objectId}/${signer.Email}/${signer.objectId}`); - const expireDate = doc?.ExpiryDate?.iso; - const newDate = new Date(expireDate); - const localExpireDate = newDate.toLocaleDateString('en-US', { - day: 'numeric', - month: 'long', - year: 'numeric', - }); - const signPdf = `${baseUrl.origin}/login/${encodeBase64}`; - const variables = { - document_title: doc.Name, - sender_name: doc.ExtUserPtr.Name, - sender_mail: doc.ExtUserPtr.Email, - sender_phone: doc.ExtUserPtr?.Phone || '', - receiver_name: signer.Name, - receiver_email: signer.Email, - receiver_phone: signer?.Phone || '', - expiry_date: localExpireDate, - company_name: doc?.ExtUserPtr?.Company || '', - signing_url: `<a href=${signPdf} target=_blank>Sign here</a>`, - }; - const mail = replaceMailVaribles(subject, body, variables); - - let params = { - mailProvider: doc?.ExtUserPtr?.active_mail_adapter, - extUserId: doc?.ExtUserPtr?.objectId, - recipient: signer.Email, - subject: mail.subject, - from: doc?.ExtUserPtr?.Email, - html: mail.body, - }; - try { - // The axios request is used to send a signing reminder email. - const res = await axios.post(url, params, { headers: headers }); - // console.log('res ', res.data.result); - if (res.data.result.status === 'success') { - return { status: 'success' }; - } - } catch (err) { - console.log('err in mail of sendreminder api', err); - return { status: 'error' }; - } -} -export default async function autoReminder(request, response) { - // The query below is used to find documents where the reminder date is less than or equal to the current date, and which have existing signers and a signed URL. - try { - const docQuery = new Parse.Query('contracts_Document'); - docQuery.limit(2000); - docQuery.lessThanOrEqualTo('NextReminderDate', new Date()); - docQuery.equalTo('AutomaticReminders', true); - docQuery.exists('NextReminderDate'); - docQuery.exists('Signers'); - docQuery.exists('SignedUrl'); - docQuery.descending('createdAt'); - docQuery.include('Signers,AuditTrail.UserPtr,ExtUserPtr,ExtUserPtr.TenantId'); - docQuery.notEqualTo('IsCompleted', true); - docQuery.notEqualTo('IsDeclined', true); - docQuery.notEqualTo('IsArchive', true); - docQuery.greaterThanOrEqualTo('ExpiryDate', new Date()); - - const docsArr = await docQuery.find({ useMasterKey: true }); - - if (docsArr && docsArr.length > 0) { - const _docsArr = JSON.parse(JSON.stringify(docsArr)); - let mailCount = 0; - let docCount = 0; - for (const doc of _docsArr) { - // The reminderDate variable is used to calculate the next reminder date. - const RemindOnceInEvery = doc?.RemindOnceInEvery || 5; - const ReminderDate = new Date(); - ReminderDate.setDate(ReminderDate.getDate() + RemindOnceInEvery); - // The sendInOrder variable is used to determine whether to send emails in order or not. - const SendInOrder = doc?.SendinOrder || false; - if (SendInOrder) { - // The auditTrail variable is used to get the count of how many users have already signed the document. - const auditTrail = doc?.AuditTrail?.filter(x => x.Activity === 'Signed'); - const count = auditTrail?.length || 0; - const signer = doc?.Signers?.[count]; - if (signer) { - docCount += 1; - const mailRes = await sendMail(doc, signer); - if (mailRes && mailRes.status === 'success') { - mailCount += 1; - } - try { - // The code below is used to update the next reminder date of the document based on the "remind once every X days" setting. - const updateDoc = new Parse.Object('contracts_Document'); - updateDoc.id = doc.objectId; - updateDoc.set('NextReminderDate', ReminderDate); - const updateRes = await updateDoc.save(null, { useMasterKey: true }); - // console.log('updateRes ', updateRes); - } catch (err) { - console.log('err in update document', err); - } - } - } else { - // The AuditTrail variable is used to check if there is any user who has already signed the document. - const auditTrail = doc?.AuditTrail?.filter(x => x.Activity === 'Signed'); - if (auditTrail?.length > 0) { - // The signers variable is used to get the signers who haven't signed the document. - const signers = doc?.Signers.filter(signer => { - const signedUser = auditTrail?.find(y => y.UserPtr.objectId === signer.objectId); - if (!signedUser) { - return signer; - } - }); - if (signers?.length > 0) { - docCount += 1; - // The for...of loop below is used to send a signing reminder to every signer who hasn't signed the document yet. - for (const signer of signers) { - const mailRes = await sendMail(doc, signer); - if (mailRes && mailRes.status === 'success') { - mailCount += 1; - } - } - } - } else { - // The for...of loop below is used to send a signing reminder to every signer who hasn't signed the document yet. - const signers = doc?.Signers; - if (signers?.length > 0) { - docCount += 1; - for (const signer of signers) { - const mailRes = await sendMail(doc, signer); - if (mailRes && mailRes.status === 'success') { - mailCount += 1; - } - } - } - } - // The code below is used to update the next reminder date of the document based on the "remind once every X days" setting. - try { - const updateDoc = new Parse.Object('contracts_Document'); - updateDoc.id = doc.objectId; - updateDoc.set('NextReminderDate', ReminderDate); - const updateRes = await updateDoc.save(null, { useMasterKey: true }); - // console.log('updateRes ', updateRes); - } catch (err) { - console.log('err in sendmail', err); - } - } - } - if (docCount > 0) { - response.json({ status: 'success', document_count: docCount, mail_count: mailCount }); - } else { - response.json({ status: 'no record found' }); - } - } else { - response.json({ status: 'no record found' }); - } - } catch (err) { - console.log('err ', err); - const code = err?.code || 400; - const message = err?.message || 'Somehting went wrong!'; - response.status(code).json({ error: message }); - } -} diff --git a/apps/OpenSignServer/cloud/customRoute/customApp.js b/apps/OpenSignServer/cloud/customRoute/customApp.js index a6ebc3de3..98ae7cb11 100644 --- a/apps/OpenSignServer/cloud/customRoute/customApp.js +++ b/apps/OpenSignServer/cloud/customRoute/customApp.js @@ -1,14 +1,8 @@ -//--npm modules import express from 'express'; import cors from 'cors'; import dotenv from 'dotenv'; import uploadFile from './uploadFile.js'; -import saveSubscription from './saveSubscription.js'; -import saveInvoice from './saveInvoice.js'; -import savePayments from './savePayments.js'; -import gooogleauth from './googleauth.js'; -import autoReminder from './autoReminder.js'; -import validateSmtp from './validateSmtp.js'; + export const app = express(); dotenv.config(); @@ -18,9 +12,3 @@ app.use(express.urlencoded({ limit: '50mb', extended: true })); app.post('/file_upload', uploadFile); -app.post('/savesubscription', saveSubscription); -app.post('/saveinvoice', saveInvoice); -app.post('/savepayment', savePayments); -app.post('/googleauth', gooogleauth); -app.post('/sendreminder', autoReminder); -app.post('/validatesmtp', validateSmtp); diff --git a/apps/OpenSignServer/cloud/customRoute/googleauth.js b/apps/OpenSignServer/cloud/customRoute/googleauth.js deleted file mode 100644 index 595bf8436..000000000 --- a/apps/OpenSignServer/cloud/customRoute/googleauth.js +++ /dev/null @@ -1,60 +0,0 @@ -import axios from 'axios'; -import { cloudServerUrl } from '../../Utils.js'; -const appId = process.env.APP_ID; -const serverUrl = cloudServerUrl; //process.env.SERVER_URL; -export default async function gooogleauth(request, response) { - const code = request.body.code; - const baseUrl = new URL(process.env.SERVER_URL); - - try { - const userRes = await axios.get(serverUrl + '/users/me', { - headers: { - 'X-Parse-Application-Id': appId, - 'X-Parse-Session-Token': request.headers['sessiontoken'], - }, - }); - const userId = userRes.data && userRes.data.objectId; - if (userId) { - const clientId = process.env.GOOGLE_CLIENT_ID; - const clientSecret = process.env.GOOGLE_CLIENT_SECRET; - const redirectUri = - baseUrl?.hostname === 'localhost' - ? 'http://localhost:3000' - : 'https://console.opensignlabs.com'; // Should match the redirect URI used in the authorization request - const tokenEndpoint = 'https://oauth2.googleapis.com/token'; - - const params = new URLSearchParams(); - params.append('code', code); - params.append('client_id', clientId); - params.append('client_secret', clientSecret); - params.append('redirect_uri', redirectUri); - params.append('grant_type', 'authorization_code'); - - const res = await axios.post(tokenEndpoint, params); - // console.log('oauthres ', res.data); - const refresh_token = res.data.refresh_token; - const extUserCls = new Parse.Query('contracts_Users'); - extUserCls.equalTo('UserId', { __type: 'Pointer', className: '_User', objectId: userId }); - const extUser = await extUserCls.first({ useMasterKey: true }); - - if (extUser) { - const extUserCls = new Parse.Object('contracts_Users'); - extUserCls.id = extUser.id; - extUserCls.set('google_refresh_token', refresh_token); - extUserCls.set('active_mail_adapter', 'google'); - const updateExtUser = await extUserCls.save(null, { useMasterKey: true }); - // console.log('updateExtUser ', updateExtUser); - } - return response.status(200).json({ status: 'success' }); - } else { - return response.status(404).json({ message: 'user not found!' }); - } - } catch (err) { - console.log('err in google auth', err); - if (err?.response?.data?.error) { - return response.status(404).json({ message: err.response.data.error }); - } else { - return response.status(404).json({ message: err.message }); - } - } -} diff --git a/apps/OpenSignServer/cloud/customRoute/saveInvoice.js b/apps/OpenSignServer/cloud/customRoute/saveInvoice.js deleted file mode 100644 index 63e914c5f..000000000 --- a/apps/OpenSignServer/cloud/customRoute/saveInvoice.js +++ /dev/null @@ -1,51 +0,0 @@ -export default async function saveInvoice(request, response) { - const InvoiceId = request.body.data.invoice.invoice_id; - const body = request.body; - const Email = request.body.data.invoice.email; - - try { - const extUserCls = new Parse.Query('contracts_Users'); - extUserCls.equalTo('Email', Email); - const extUser = await extUserCls.first({ useMasterKey: true }); - if (extUser) { - const invoiceCls = new Parse.Query('contracts_Invoices'); - invoiceCls.equalTo('InvoiceId', InvoiceId); - const invoice = await invoiceCls.first({ useMasterKey: true }); - if (invoice) { - const updateInvoice = new Parse.Object('contracts_Invoices'); - updateInvoice.id = invoice.id; - updateInvoice.set('InvoiceDetails', body); - await updateInvoice.save(null, { useMasterKey: true }); - return response.status(200).json({ status: 'update invoice!' }); - } else { - const createInvoice = new Parse.Object('contracts_Invoices'); - createInvoice.set('InvoiceId', InvoiceId); - createInvoice.set('InvoiceDetails', body); - createInvoice.set('ExtUserPtr', { - __type: 'Pointer', - className: 'contracts_Users', - objectId: extUser.id, - }); - createInvoice.set('CreatedBy', { - __type: 'Pointer', - className: '_User', - objectId: extUser.get('UserId').id, - }); - if (extUser?.get('TenantId')?.id) { - createInvoice.set('TenantId', { - __type: 'Pointer', - className: 'partners_Tenant', - objectId: extUser.get('TenantId').id, - }); - } - await createInvoice.save(null, { useMasterKey: true }); - return response.status(200).json({ status: 'create invoice!' }); - } - } else { - return response.status(404).json({ status: 'user not found!' }); - } - } catch (err) { - console.log('Err in save invoice', err); - return response.status(400).json({ status: 'error:' + err.message }); - } -} diff --git a/apps/OpenSignServer/cloud/customRoute/savePayments.js b/apps/OpenSignServer/cloud/customRoute/savePayments.js deleted file mode 100644 index 30ac4eee4..000000000 --- a/apps/OpenSignServer/cloud/customRoute/savePayments.js +++ /dev/null @@ -1,50 +0,0 @@ -export default async function savePayments(request, response) { - const PaymentId = request.body.data.payment.payment_id; - const body = request.body; - const Email = request.body.data.payment.email; - try { - const extUserCls = new Parse.Query('contracts_Users'); - extUserCls.equalTo('Email', Email); - const extUser = await extUserCls.first({ useMasterKey: true }); - if (extUser) { - const paymentCls = new Parse.Query('contracts_Payments'); - paymentCls.equalTo('PaymentId', PaymentId); - const payment = await paymentCls.first({ useMasterKey: true }); - if (payment) { - const updatePayment = new Parse.Object('contracts_Payments'); - updatePayment.id = payment.id; - updatePayment.set('PaymentDetails', body); - await updatePayment.save(null, { useMasterKey: true }); - return response.status(200).json({ status: 'update Payment!' }); - } else { - const createPayment = new Parse.Object('contracts_Payments'); - createPayment.set('PaymentId', PaymentId); - createPayment.set('PaymentDetails', body); - createPayment.set('ExtUserPtr', { - __type: 'Pointer', - className: 'contracts_Users', - objectId: extUser.id, - }); - createPayment.set('CreatedBy', { - __type: 'Pointer', - className: '_User', - objectId: extUser.get('UserId').id, - }); - if (extUser?.get('TenantId')?.id) { - createPayment.set('TenantId', { - __type: 'Pointer', - className: 'partners_Tenant', - objectId: extUser.get('TenantId').id, - }); - } - await createPayment.save(null, { useMasterKey: true }); - return response.status(200).json({ status: 'create payments!' }); - } - } else { - return response.status(404).json({ status: 'user not found!' }); - } - } catch (err) { - console.log('Err in save payment', err); - return response.status(400).json({ status: 'error:' + err.message }); - } -} diff --git a/apps/OpenSignServer/cloud/customRoute/saveSubscription.js b/apps/OpenSignServer/cloud/customRoute/saveSubscription.js deleted file mode 100644 index d6db217fd..000000000 --- a/apps/OpenSignServer/cloud/customRoute/saveSubscription.js +++ /dev/null @@ -1,183 +0,0 @@ -import { planCredits } from '../../Utils.js'; - -export default async function saveSubscription(request, response) { - const SubscriptionId = request.body?.data?.subscription?.subscription_id; - const body = request.body; - const Email = request.body.data?.subscription?.customer?.email; - const Next_billing_date = request.body?.data?.subscription?.next_billing_at; - const planCode = request.body?.data?.subscription?.plan?.plan_code; - const addons = request.body?.data?.subscription?.addons || []; - const event = request.body?.data?.event_type || ''; - const credits = planCredits?.[planCode] || 0; - const isTeamPlan = planCode?.includes('team'); - let newAddons = 0; - if (addons?.length > 0) { - let allowedUsersMonthly = 0; - let allowedUsersYearly = 0; - addons?.forEach(item => { - if (item.addon_code === 'extra-teams-users-monthly') { - allowedUsersMonthly += item.quantity; - } else if (item.addon_code === 'extra-teams-users-yearly') { - allowedUsersYearly += item.quantity; - } else if (item.addon_code === 'extra-users') { - allowedUsersMonthly += item.quantity; - } - }); - if (allowedUsersMonthly > 0 || allowedUsersYearly > 0) { - newAddons = allowedUsersMonthly + allowedUsersYearly + 1; - } - } else { - if (planCode === 'teams-yearly' || planCode === 'teams-monthly' || planCode === 'team-weekly') { - newAddons = 1; - } - } - try { - const extUserCls = new Parse.Query('contracts_Users'); - extUserCls.equalTo('Email', Email); - const extUser = await extUserCls.first({ useMasterKey: true }); - if (extUser) { - const subcriptionCls = new Parse.Query('contracts_Subscriptions'); - subcriptionCls.equalTo('TenantId', { - __type: 'Pointer', - className: 'partners_Tenant', - objectId: extUser.get('TenantId').id, - }); - const subscription = await subcriptionCls.first({ useMasterKey: true }); - if (subscription) { - const _resSub = JSON.parse(JSON.stringify(subscription)); - const updateSubscription = new Parse.Object('contracts_Subscriptions'); - updateSubscription.id = subscription.id; - updateSubscription.set('SubscriptionId', SubscriptionId); - updateSubscription.set('SubscriptionDetails', body); - if (Next_billing_date) { - updateSubscription.set('Next_billing_date', new Date(Next_billing_date)); - } else { - updateSubscription.unset('Next_billing_date'); - } - updateSubscription.set('PlanCode', planCode); - if (newAddons > 0) { - updateSubscription.set('AllowedUsers', parseInt(newAddons)); - } - let existAddon = 0; - let allowedUsersMonthly = 0; - let allowedUsersYearly = 0; - _resSub.SubscriptionDetails?.data?.subscription?.addons?.forEach(item => { - if (item.addon_code === 'extra-teams-users-monthly') { - allowedUsersMonthly += item.quantity; - } else if (item.addon_code === 'extra-teams-users-yearly') { - allowedUsersYearly += item.quantity; - } else if (item.addon_code === 'extra-users') { - allowedUsersMonthly += item.quantity; - } - }); - if (allowedUsersMonthly > 0 || allowedUsersYearly > 0) { - existAddon = allowedUsersMonthly + allowedUsersYearly + 1; // + 1 is Admin user - } else { - if ( - planCode === 'teams-yearly' || - planCode === 'teams-monthly' || - planCode === 'team-weekly' - ) { - existAddon = 1; // 1 is Admin user - } - } - const isSameAsPrevPlan = subscription?.get('PlanCode') === planCode; - if (isSameAsPrevPlan) { - const planCredits = subscription?.get('PlanCredits'); - const existAllowedCredits = subscription?.get('AllowedCredits') || 0; - if (planCredits) { - const oldAddons = existAddon; - const substractedAddon = newAddons - oldAddons; - if (isTeamPlan && substractedAddon > 0) { - const newCredits = existAllowedCredits + substractedAddon * planCredits; - updateSubscription.set('AllowedCredits', newCredits); - if (event === 'subscription_created') { - updateSubscription.set('PlanCredits', credits); - } - } else if (isTeamPlan) { - const existCredits = existAddon * planCredits; - updateSubscription.set('AllowedCredits', existCredits); - if (event === 'subscription_created') { - updateSubscription.set('PlanCredits', credits); - } - } else { - updateSubscription.set('AllowedCredits', planCredits); - if (event === 'subscription_created') { - updateSubscription.set('PlanCredits', credits); - } - } - } else { - if (credits > 0) { - if (isTeamPlan) { - const newCredits = newAddons * credits; - updateSubscription.set('AllowedCredits', newCredits); - updateSubscription.set('PlanCredits', credits); - } else { - updateSubscription.set('AllowedCredits', credits); - updateSubscription.set('PlanCredits', credits); - } - } - } - } else { - if (credits > 0) { - if (isTeamPlan) { - const newCredits = newAddons * credits; - updateSubscription.set('AllowedCredits', newCredits); - updateSubscription.set('PlanCredits', credits); - } else { - updateSubscription.set('AllowedCredits', credits); - updateSubscription.set('PlanCredits', credits); - } - } - } - await updateSubscription.save(null, { useMasterKey: true }); - return response.status(200).json({ status: 'update subscription!' }); - } else { - const createSubscription = new Parse.Object('contracts_Subscriptions'); - createSubscription.set('SubscriptionId', SubscriptionId); - createSubscription.set('SubscriptionDetails', body); - createSubscription.set('ExtUserPtr', { - __type: 'Pointer', - className: 'contracts_Users', - objectId: extUser.id, - }); - createSubscription.set('CreatedBy', { - __type: 'Pointer', - className: '_User', - objectId: extUser.get('UserId').id, - }); - createSubscription.set('TenantId', { - __type: 'Pointer', - className: 'partners_Tenant', - objectId: extUser.get('TenantId').id, - }); - if (Next_billing_date) { - createSubscription.set('Next_billing_date', new Date(Next_billing_date)); - } else { - createSubscription.unset('Next_billing_date'); - } - createSubscription.set('PlanCode', planCode); - if (newAddons > 0) { - createSubscription.set('AllowedUsers', parseInt(newAddons)); - } - if (credits > 0) { - if (isTeamPlan) { - const totalCredits = parseInt(newAddons) * credits; - createSubscription.set('AllowedCredits', totalCredits); - createSubscription.set('PlanCredits', credits); - } else { - createSubscription.set('AllowedCredits', credits); - createSubscription.set('PlanCredits', credits); - } - } - await createSubscription.save(null, { useMasterKey: true }); - return response.status(200).json({ status: 'create subscription!' }); - } - } else { - return response.status(404).json({ status: 'user not found!' }); - } - } catch (err) { - console.log('Err in save subscription', err); - return response.status(400).json({ status: 'error:' + err.message }); - } -} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js deleted file mode 100644 index 16a14decb..000000000 --- a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js +++ /dev/null @@ -1,119 +0,0 @@ -//--npm modules -import express from 'express'; -import cors from 'cors'; -export const app = express(); -import dotenv from 'dotenv'; -import getUser from './routes/getUser.js'; -import getDocumentList from './routes/getDocumentList.js'; -import getDocument from './routes/getDocument.js'; -import getContact from './routes/getContact.js'; -import deleteContact from './routes/deleteContact.js'; -import getContactList from './routes/getContactList.js'; -import getTemplate from './routes/getTemplate.js'; -import deletedTemplate from './routes/deleteTemplate.js'; -import getTemplatetList from './routes/getTemplateList.js'; -import updateTemplate from './routes/updateTemplate.js'; -import createContact from './routes/createContact.js'; -import multer from 'multer'; -import updateDocument from './routes/updateDocument.js'; -import deleteDocument from './routes/deleteDocument.js'; -import createDocumentWithTemplate from './routes/CreateDocumentWithTemplate.js'; -import saveWebhook from './routes/saveWebhook.js'; -import deleteWebhook from './routes/deleteWebhook.js'; -import getWebhook from './routes/getWebhook.js'; -import createDocumentwithCoordinate from './routes/createDocumentwithCoordinate.js'; -import createTemplatewithCoordinate from './routes/createTemplatewithCoordinate.js'; -import resendMail from './routes/resendMail.js'; -import getFolder from './routes/getFolder.js'; -import createFolder from './routes/createFolder.js'; -import updateFolder from './routes/updateFolder.js'; -import getFolderList from './routes/getFolderList.js'; -import deleteFolder from './routes/deleteFolder.js'; -dotenv.config(); -const storage = multer.memoryStorage(); -const upload = multer({ storage: storage }); - -app.use(cors()); -app.use(express.json({ limit: '50mb' })); -app.use(express.urlencoded({ limit: '50mb', extended: true })); - -// get user details whose api token used -app.get('/getuser', getUser); - -// get contact on the basis of id -app.post('/createcontact', createContact); - -// get contact on the basis of id -app.get('/contact/:contact_id', getContact); - -// soft delete contact -app.delete('/contact/:contact_id', deleteContact); - -// get list of contacts -app.get('/contactlist', getContactList); - -// create Document -app.post('/createdocumentwithbinary', upload.array('file', 1), createDocumentwithCoordinate); - -// create Document with co-ordinate -app.post('/createdocument', createDocumentwithCoordinate); - -// create Document with templateId -app.post('/createdocument/:template_id', createDocumentWithTemplate); - -// get Document on the basis of id -app.get('/document/:document_id', getDocument); - -// get document on the basis of id -app.put('/document/:document_id', updateDocument); - -// get document on the basis of id -app.delete('/document/:document_id', deleteDocument); - -// get all types of documents on the basis of doctype -app.get('/documentlist/:doctype', getDocumentList); - -// create Template with co-ordinate -app.post('/createtemplate', createTemplatewithCoordinate); - -// create Template with binary -app.post('/createtemplatewithbinary', upload.array('file', 1), createTemplatewithCoordinate); - -// get template on the basis of id -app.get('/template/:template_id', getTemplate); - -// get template on the basis of id -app.put('/template/:template_id', updateTemplate); - -// get template on the basis of id -app.delete('/template/:template_id', deletedTemplate); - -// get all types of documents on the basis of doctype -app.get('/templatelist', getTemplatetList); - -// set and update webhook -app.get('/webhook', getWebhook); - -// set and update webhook -app.post('/webhook', saveWebhook); - -// set and update webhook -app.delete('/webhook', deleteWebhook); - -// resend mail -app.post('/resendmail', resendMail); - -// create folder -app.post('/createfolder', createFolder); - -// update folder -app.put('/folder/:folder_id', updateFolder); - -// get folder list -app.delete('/folder/:folder_id', deleteFolder); - -// get folder -app.get('/folder/:folder_id', getFolder); - -// get folder list -app.get('/folderlist', getFolderList); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js deleted file mode 100644 index 72e119ff1..000000000 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js +++ /dev/null @@ -1,435 +0,0 @@ -import axios from 'axios'; -import { cloudServerUrl, customAPIurl, replaceMailVaribles } from '../../../../Utils.js'; - -// `sendDoctoWebhook` is used to send res data of document on webhook -async function sendDoctoWebhook(doc, WebhookUrl, userId) { - if (WebhookUrl) { - const params = { event: 'created', ...doc }; - await axios - .post(WebhookUrl, params, { headers: { 'Content-Type': 'application/json' } }) - .then(res => { - try { - // console.log('res ', res); - const webhook = new Parse.Object('contracts_Webhook'); - webhook.set('Log', res?.status); - webhook.set('UserId', { - __type: 'Pointer', - className: '_User', - objectId: userId, - }); - webhook.save(null, { useMasterKey: true }); - } catch (err) { - console.log('err save in contracts_Webhook', err); - } - }) - .catch(err => { - console.log('Err send data to webhook', err); - try { - const webhook = new Parse.Object('contracts_Webhook'); - webhook.set('Log', err?.status); - webhook.set('UserId', { - __type: 'Pointer', - className: '_User', - objectId: userId, - }); - webhook.save(null, { useMasterKey: true }); - } catch (err) { - console.log('err save in contracts_Webhook', err); - } - }); - // console.log('res ', res.data); - } -} -export default async function createDocumentWithTemplate(request, response) { - const signers = request.body.signers; - const folderId = request.body.folderId; - const templateId = request.params.template_id; - const protocol = customAPIurl(); - const baseUrl = new URL(process.env.PUBLIC_URL); - const send_email = request.body.send_email; - const email_subject = request.body.email_subject; - const email_body = request.body.email_body; - const sendInOrder = request.body.sendInOrder || true; - const TimeToCompleteDays = request.body.timeToCompleteDays || 15; - - try { - const reqToken = request.headers['x-api-token']; - if (!reqToken) { - return response.status(400).json({ error: 'Please Provide API Token' }); - } - - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('token', reqToken); - tokenQuery.include('userId'); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // Valid Token then proceed request - const parseUser = JSON.parse(JSON.stringify(token)); - const userPtr = { - __type: 'Pointer', - className: '_User', - objectId: parseUser.userId.objectId, - }; - const extUsers = new Parse.Query('contracts_Users'); - extUsers.equalTo('UserId', userPtr); - const extUser = await extUsers.first({ useMasterKey: true }); - - const subscription = new Parse.Query('contracts_Subscriptions'); - subscription.equalTo('TenantId', { - __type: 'Pointer', - className: 'partners_Tenant', - objectId: extUser.get('TenantId').id, - }); - subscription.include('ExtUserPtr'); - subscription.greaterThanOrEqualTo('Next_billing_date', new Date()); - const resSub = await subscription.first({ useMasterKey: true }); - if (resSub) { - const _resSub = JSON.parse(JSON.stringify(resSub)); - const allowedCredits = _resSub?.AllowedCredits || 0; - const addonCredits = _resSub?.AddonCredits || 0; - const totalcredits = allowedCredits + addonCredits; - if (totalcredits > 0) { - const templateQuery = new Parse.Query('contracts_Template'); - templateQuery.include('ExtUserPtr'); - templateQuery.include('ExtUserPtr.TenantId'); - const templateRes = await templateQuery.get(templateId, { useMasterKey: true }); - if (templateRes) { - const template = JSON.parse(JSON.stringify(templateRes)); - if (template?.Placeholders?.length > 0) { - const emptyplaceholder = template?.Placeholders.filter(x => !x.signerObjId); - const isValid = - signers.length >= emptyplaceholder.length && - signers.length <= template?.Placeholders?.length; - const placeholder = - signers.length > emptyplaceholder.length ? template.Placeholders : emptyplaceholder; - const updateSigners = placeholder.every(y => signers?.some(x => x.role === y.Role)); - // console.log('isValid ', isValid); - if (isValid && updateSigners) { - //Check if every item's placeholders contain at least one placeholder with type 'signature'. - let isSignature = template?.Placeholders?.every(item => - item?.placeHolder.some(x => x?.pos.some(data => data?.type === 'signature')) - ); - if (!isSignature) { - return response - .status(400) - .json({ error: 'Please add at least one signature widget for all signers' }); - } - const folderPtr = { - __type: 'Pointer', - className: 'contracts_Document', - objectId: folderId, - }; - const object = new Parse.Object('contracts_Document'); - object.set('Name', template.Name); - if (template?.Note) { - object.set('Note', template.Note); - } - if (template?.Description) { - object.set('Description', template.Description); - } - object.set('IsSendMail', send_email); - if (sendInOrder) { - object.set('SendinOrder', sendInOrder); - } else if (template?.SendinOrder && template?.SendinOrder) { - object.set('SendinOrder', template?.SendinOrder); - } - let templateSigner = template?.Signers ? template?.Signers : []; - let contact = []; - if (signers && signers.length > 0) { - let parseSigners = [...signers]; - let createContactUrl = protocol + '/v1/createcontact'; - - for (const obj of parseSigners) { - const body = { - name: obj?.name || '', - email: obj?.email || '', - phone: obj?.phone || '', - }; - try { - const res = await axios.post(createContactUrl, body, { - headers: { 'Content-Type': 'application/json', 'x-api-token': reqToken }, - }); - const contactPtr = { - __type: 'Pointer', - className: 'contracts_Contactbook', - objectId: res.data?.objectId, - }; - const newObj = { ...obj, contactPtr: contactPtr }; - contact.push(newObj); - } catch (err) { - // console.log('err ', err); - if (err?.response?.data?.objectId) { - const contactPtr = { - __type: 'Pointer', - className: 'contracts_Contactbook', - objectId: err.response.data?.objectId, - }; - const newObj = { ...obj, contactPtr: contactPtr }; - contact.push(newObj); - } else { - console.log('err ', err); - } - } - } - const contactPtrs = contact.map(x => x.contactPtr); - object.set('Signers', [...templateSigner, ...contactPtrs]); - - let updatedPlaceholder = template?.Placeholders?.map(x => { - let matchingSigner = contact.find(y => x.Role && x.Role === y.role); - - if (matchingSigner) { - return { - ...x, - signerObjId: matchingSigner?.contactPtr?.objectId, - signerPtr: matchingSigner?.contactPtr, - }; - } else { - return { ...x }; - } - }); - object.set('Placeholders', updatedPlaceholder); - } else { - object.set('Signers', templateSigner); - } - object.set('URL', template.URL); - object.set('SignedUrl', template.URL); - object.set('SentToOthers', true); - if (TimeToCompleteDays) { - object.set('TimeToCompleteDays', TimeToCompleteDays); - } - const enableOTP = request.body?.enableOTP; - const IsEnableOTP = - enableOTP !== undefined ? enableOTP : template?.IsEnableOTP || false; - const enableTour = request.body?.enableTour; - const isTourEnabled = - enableTour !== undefined ? enableTour : template?.IsTourEnabled || false; - object.set('IsTourEnabled', isTourEnabled); - object.set('IsEnableOTP', IsEnableOTP); - object.set('CreatedBy', template.CreatedBy); - object.set('ExtUserPtr', { - __type: 'Pointer', - className: 'contracts_Users', - objectId: template.ExtUserPtr.objectId, - }); - if (folderId) { - object.set('Folder', folderPtr); - } - if (template?.FileAdapterId) { - object.set('FileAdapterId', template?.FileAdapterId); - } - const newACL = new Parse.ACL(); - newACL.setPublicReadAccess(false); - newACL.setPublicWriteAccess(false); - newACL.setReadAccess(userPtr.objectId, true); - newACL.setWriteAccess(userPtr.objectId, true); - object.setACL(newACL); - const res = await object.save(null, { useMasterKey: true }); - - const newDate = new Date(); - newDate.setDate(newDate.getDate() + 15); - const localExpireDate = newDate.toLocaleDateString('en-US', { - day: 'numeric', - month: 'long', - year: 'numeric', - }); - let sender = template.ExtUserPtr.Email; - let sendMail; - if (send_email === false) { - console.log("don't send mail"); - } else { - let contactMail = contact; - if (sendInOrder) { - contactMail = contact.slice(); - contactMail.splice(1); - } - for (let i = 0; i < contactMail.length; i++) { - try { - const imgPng = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png'; - let url = `${cloudServerUrl}/functions/sendmailv3/`; - const headers = { - 'Content-Type': 'application/json', - 'X-Parse-Application-Id': process.env.APP_ID, - 'X-Parse-Master-Key': process.env.MASTER_KEY, - }; - - const objectId = contactMail[i].contactPtr.objectId; - const hostUrl = baseUrl.origin; - //encode this url value `${res.id}/${contactMail[i].email}/${objectId}` to base64 using `btoa` function - const encodeBase64 = btoa(`${res.id}/${contactMail[i].email}/${objectId}`); - let signPdf = `${hostUrl}/login/${encodeBase64}`; - const openSignUrl = 'https://www.opensignlabs.com/contact-us'; - const orgName = template.ExtUserPtr.Company - ? template.ExtUserPtr.Company - : ''; - const themeBGcolor = '#47a3ad'; - const email_html = - "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /> </head> <body> <div style='background-color: #f5f5f5; padding: 20px'> <div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background: white;padding-bottom: 20px;'> <div style='padding:10px 10px 0 10px'><img src='" + - imgPng + - "' height='50' style='padding:20px; width:170px; height:40px;' /></div><div style='padding: 2px;font-family: system-ui;background-color:" + - themeBGcolor + - ";'><p style='font-size: 20px;font-weight: 400;color: white;padding-left: 20px;' > Digital Signature Request</p></div><div><p style='padding: 20px;font-family: system-ui;font-size: 14px; margin-bottom: 10px;'> " + - template.ExtUserPtr.Name + - ' has requested you to review and sign <strong> ' + - template.Name + - "</strong>.</p><div style='padding: 5px 0px 5px 25px;display: flex;flex-direction: row;justify-content: space-around;'><table> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Sender</td> <td> </td> <td style='color:#626363;font-weight:bold'>" + - sender + - "</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Organization</td> <td> </td><td style='color:#626363;font-weight:bold'> " + - orgName + - "</td></tr> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Expires on</td><td> </td> <td style='color:#626363;font-weight:bold'>" + - localExpireDate + - "</td></tr><tr> <td></td> <td> </td></tr></table> </div> <div style='margin-left:70px'><a target=_blank href=" + - signPdf + - "> <button style='padding: 12px 12px 12px 12px;background-color: #d46b0f;color: white; border: 0px;box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px,rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;font-weight:bold;margin-top:30px;'>Sign here</button></a> </div> <div style='display: flex; justify-content: center;margin-top: 10px;'> </div></div></div><div><p> This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender " + - sender + - ' directly.If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href=' + - openSignUrl + - ' target=_blank>here</a>.</p> </div></div></body> </html>'; - - let replaceVar; - const variables = { - document_title: template.Name, - sender_name: template.ExtUserPtr.Name, - sender_mail: template.ExtUserPtr.Email, - sender_phone: template.ExtUserPtr?.Phone || '', - receiver_name: contactMail[i].name, - receiver_email: contactMail[i].email, - receiver_phone: contactMail[i]?.phone || '', - expiry_date: localExpireDate, - company_name: orgName, - signing_url: signPdf, - }; - if (email_subject && email_body) { - replaceVar = replaceMailVaribles(email_subject, email_body, variables); - } else if (email_subject) { - replaceVar = replaceMailVaribles(email_subject, '', variables); - replaceVar = { subject: replaceVar.subject, body: email_html }; - } else if (email_body) { - replaceVar = replaceMailVaribles( - `${template.ExtUserPtr.Name} has requested you to sign "${template.Name}"`, - email_body, - variables - ); - } else { - replaceVar = { - subject: `${template.ExtUserPtr.Name} has requested you to sign "${template.Name}"`, - body: email_html, - }; - } - - const subject = replaceVar.subject; - const html = replaceVar.body; - let params = { - recipient: contactMail[i].email, - subject: subject, - from: sender, - html: html, - extUserId: template.ExtUserPtr.objectId, - mailProvider: template?.ExtUserPtr?.active_mail_adapter || '', - }; - sendMail = await axios.post(url, params, { headers: headers }); - } catch (error) { - console.log('error', error); - } - } - } - // if (sendMail.data.result.status === 'success') { - try { - const doc = { - objectId: res.id, - file: template?.URL, - name: template?.Name, - note: template?.Note || '', - description: template?.Description || '', - signers: contact?.map(x => ({ - name: x.name, - email: x.email, - phone: x?.phone || '', - })), - createdAt: res.createdAt, - }; - if (template.ExtUserPtr && template.ExtUserPtr?.Webhook) { - sendDoctoWebhook(doc, template.ExtUserPtr?.Webhook, userPtr?.objectId); - } - } catch (err) { - console.log('Err', err); - } - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_create_document_with_templateid', - properties: { response_code: 200 }, - }); - } - - const subscriptionCls = new Parse.Object('contracts_Subscriptions'); - subscriptionCls.id = resSub.id; - if (allowedCredits > 0) { - const updateAllowedcredits = allowedCredits - 1 || 0; - subscriptionCls.set('AllowedCredits', updateAllowedcredits); - } else { - const updateAddonCredits = addonCredits > 0 ? addonCredits - 1 : 0; - subscriptionCls.set('AddonCredits', updateAddonCredits); - } - const resSubcription = await subscriptionCls.save(null, { useMasterKey: true }); - // console.log("resSubcription ", resSubcription) - return response.json({ - objectId: res.id, - signurl: contact.map(x => ({ - email: x.email, - url: `${baseUrl.origin}/login/${btoa( - `${res.id}/${x.email}/${x.contactPtr.objectId}` - )}`, - })), - message: 'Document sent successfully!', - }); - } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_create_document_with_templateid', - properties: { response_code: 400 }, - }); - } - return response.status(400).json({ error: 'Please provide signers properly!' }); - } - } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_create_document_with_templateid', - properties: { response_code: 400 }, - }); - } - return response.status(400).json({ error: 'Please setup template properly!' }); - } - } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_create_document_with_templateid', - properties: { response_code: 404 }, - }); - } - return response.status(404).json({ error: 'Invalid template id!' }); - } - } else { - return response - .status(429) - .json({ error: 'Quota reached, Please buy credits and try again later.' }); - } - } else { - return response.status(400).json({ - error: 'Please purchase or renew your subscription.', - }); - } - } else { - return response.status(405).json({ error: 'Invalid API Token!' }); - } - } catch (err) { - console.log('err ', err); - if (err.code === 101) { - return response.status(404).json({ error: 'Invalid template id!' }); - } - return response.status(400).json({ error: 'Something went wrong, please try again later!' }); - } -} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js deleted file mode 100644 index 2f762334d..000000000 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js +++ /dev/null @@ -1,193 +0,0 @@ -export default async function createContact(request, response) { - const name = request.body.name; - const phone = request.body?.phone; - const email = request.body.email; - const reqToken = request.headers['x-api-token']; - if (!reqToken) { - return response.status(400).json({ error: 'Please Provide API Token' }); - } - try { - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('token', reqToken); - tokenQuery.include('userId'); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // Valid Token then proceed request - const parseUser = JSON.parse(JSON.stringify(token)); - const userPtr = { - __type: 'Pointer', - className: '_User', - objectId: parseUser.userId.objectId, - }; - - try { - const contactbook = new Parse.Query('contracts_Contactbook'); - contactbook.equalTo('Email', email); - contactbook.equalTo('CreatedBy', userPtr); - contactbook.notEqualTo('IsDeleted', true); - const userExists = await contactbook.first({ useMasterKey: true }); - - if (userExists) { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_create_contact', - properties: { response_code: 401 }, - }); - } - return response - .status(401) - .json({ error: 'Contact already exists!', objectId: userExists.id }); - } else { - try { - const Tenant = new Parse.Query('partners_Tenant'); - Tenant.equalTo('UserId', userPtr); - const tenantRes = await Tenant.first({ useMasterKey: true }); - - const contactQuery = new Parse.Object('contracts_Contactbook'); - contactQuery.set('Name', name); - if (phone) { - contactQuery.set('Phone', phone); - } - contactQuery.set('Email', email); - contactQuery.set('UserRole', 'contracts_Guest'); - if (tenantRes && tenantRes.id) { - contactQuery.set('TenantId', { - __type: 'Pointer', - className: 'partners_Tenant', - objectId: tenantRes.id, - }); - } - try { - const _users = Parse.Object.extend('User'); - const _user = new _users(); - _user.set('name', name); - _user.set('username', email); - _user.set('email', email); - _user.set('password', email); - if (phone) { - _user.set('phone', phone); - } - - const user = await _user.save(); - if (user) { - const currentUser = userPtr; - contactQuery.set('CreatedBy', currentUser); - contactQuery.set('UserId', user); - - const acl = new Parse.ACL(); - acl.setReadAccess(userPtr.objectId, true); - acl.setWriteAccess(userPtr.objectId, true); - acl.setReadAccess(user.id, true); - acl.setWriteAccess(user.id, true); - contactQuery.setACL(acl); - - const contactRes = await contactQuery.save(); - const parseRes = JSON.parse(JSON.stringify(contactRes)); - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_create_contact', - properties: { response_code: 200 }, - }); - } - return response.json({ - objectId: parseRes.objectId, - name: parseRes.Name, - email: parseRes.Email, - phone: parseRes?.Phone || '', - createdAt: parseRes.createdAt, - updatedAt: parseRes.updatedAt, - }); - } - } catch (err) { - console.log('err in', err); - if (err.code === 202) { - const params = { email: email }; - const userRes = await Parse.Cloud.run('getUserId', params); - contactQuery.set('CreatedBy', userPtr); - contactQuery.set('UserId', { - __type: 'Pointer', - className: '_User', - objectId: userRes.id, - }); - const acl = new Parse.ACL(); - acl.setReadAccess(userPtr.objectId, true); - acl.setWriteAccess(userPtr.objectId, true); - acl.setReadAccess(userRes.id, true); - acl.setWriteAccess(userRes.id, true); - - contactQuery.setACL(acl); - const contactRes = await contactQuery.save(); - if (contactRes) { - const parseRes = JSON.parse(JSON.stringify(contactRes)); - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_create_contact', - properties: { response_code: 200 }, - }); - } - return response.json({ - objectId: parseRes.objectId, - name: parseRes.Name, - email: parseRes.Email, - phone: parseRes?.Phone || '', - createdAt: parseRes.createdAt, - updatedAt: parseRes.updatedAt, - }); - } - } else { - if (err.code === 137) { - return response.status(401).json({ error: 'Contact already exists!' }); - } - return response - .status(400) - .json({ error: 'Something went wrong, please try again later!' }); - } - } - } catch (err) { - console.log('err ', err); - if (err.code === 137) { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_create_contact', - properties: { response_code: 401 }, - }); - } - return response.status(401).json({ error: 'Contact already exists!' }); - } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_create_contact', - properties: { response_code: 400 }, - }); - } - return response - .status(400) - .json({ error: 'Something went wrong, please try again later!' }); - } - } - } - } catch (err) { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_create_contact', - properties: { response_code: 400 }, - }); - } - return response - .status(400) - .json({ error: 'Something went wrong, please try again later!' }); - } - } else { - return response.status(405).json({ error: 'Invalid API Token!' }); - } - } catch (err) { - console.log('Err ', err); - return response.status(400).json({ error: 'Something went wrong, please try again later!' }); - } -} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js deleted file mode 100644 index 3ed23217d..000000000 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js +++ /dev/null @@ -1,454 +0,0 @@ -import axios from 'axios'; -import { - color, - customAPIurl, - replaceMailVaribles, - saveFileUsage, - formatWidgetOptions, - sanitizeFileName, - cloudServerUrl, -} from '../../../../Utils.js'; -import uploadFileToS3 from '../../../parsefunction/uploadFiletoS3.js'; - -// `sendDoctoWebhook` is used to send res data of document on webhook -async function sendDoctoWebhook(doc, WebhookUrl, userId) { - if (WebhookUrl) { - const params = { event: 'created', ...doc }; - - await axios - .post(WebhookUrl, params, { headers: { 'Content-Type': 'application/json' } }) - .then(res => { - try { - // console.log('res ', res); - const webhook = new Parse.Object('contracts_Webhook'); - webhook.set('Log', res?.status); - webhook.set('UserId', { - __type: 'Pointer', - className: '_User', - objectId: userId, - }); - webhook.save(null, { useMasterKey: true }); - } catch (err) { - console.log('err save in contracts_Webhook', err); - } - }) - .catch(err => { - console.log('Err send data to webhook', err?.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); - } - }); - // console.log('res ', res.data); - } -} -const randomId = () => Math.floor(1000 + Math.random() * 9000); -export default async function createDocumentwithCoordinate(request, response) { - const name = request.body.title; - const note = request.body.note; - const description = request.body.description; - const send_email = request.body.send_email; - const signers = request.body.signers; - const folderId = request.body.folderId; - const base64File = request.body.file; - const fileData = request.files?.[0] ? request.files[0].buffer : null; - const email_subject = request.body.email_subject; - const email_body = request.body.email_body; - const sendInOrder = request.body.sendInOrder || true; - const TimeToCompleteDays = request.body.timeToCompleteDays || 15; - const IsEnableOTP = request.body?.enableOTP === true ? true : false; - const isTourEnabled = request.body?.enableTour || false; - // console.log('fileData ', fileData); - const protocol = customAPIurl(); - const baseUrl = new URL(process.env.PUBLIC_URL); - const reqToken = request.headers['x-api-token']; - if (!reqToken) { - return response.status(400).json({ error: 'Please Provide API Token' }); - } - - try { - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('token', reqToken); - tokenQuery.include('userId'); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // Valid Token then proceed request - const parseUser = JSON.parse(JSON.stringify(token)); - const userPtr = { - __type: 'Pointer', - className: '_User', - objectId: parseUser.userId.objectId, - }; - const extUsers = new Parse.Query('contracts_Users'); - extUsers.equalTo('UserId', userPtr); - extUsers.include('TenantId'); - const extUser = await extUsers.first({ useMasterKey: true }); - - const subscription = new Parse.Query('contracts_Subscriptions'); - subscription.equalTo('TenantId', { - __type: 'Pointer', - className: 'partners_Tenant', - objectId: extUser.get('TenantId').id, - }); - subscription.include('ExtUserPtr'); - subscription.greaterThanOrEqualTo('Next_billing_date', new Date()); - const resSub = await subscription.first({ useMasterKey: true }); - if (resSub) { - const _resSub = JSON.parse(JSON.stringify(resSub)); - const allowedCredits = _resSub?.AllowedCredits || 0; - const addonCredits = _resSub?.AddonCredits || 0; - const totalcredits = allowedCredits + addonCredits; - if (totalcredits > 0) { - if (signers && signers.length > 0) { - // Check if at least one signature exists among all items in the signers array - let isSignExist = signers.every(item => - item.widgets.some(data => data?.type === 'signature') - ); - if (!isSignExist) { - return response - .status(400) - .json({ error: 'Please add at least one signature widget for all signers' }); - } - const parseExtUser = JSON.parse(JSON.stringify(extUser)); - let fileUrl; - if (request.files?.[0]) { - const base64 = fileData?.toString('base64'); - const file = new Parse.File(request.files?.[0]?.originalname, { - base64: base64, - }); - await file.save({ useMasterKey: true }); - fileUrl = file.url(); - const buffer = Buffer.from(base64, 'base64'); - saveFileUsage(buffer.length, fileUrl, parseUser.userId.objectId); - } else { - const filename = sanitizeFileName(`${name}.pdf`); - let adapter = {}; - const ActiveFileAdapter = parseExtUser?.TenantId?.ActiveFileAdapter || ''; - if (ActiveFileAdapter) { - adapter = - parseExtUser?.TenantId?.FileAdapters?.find(x => (x.id = ActiveFileAdapter)) || {}; - } - if (adapter?.id) { - const filedata = Buffer.from(base64File, 'base64'); - // `uploadFileToS3` is used to save document in user's file storage - fileUrl = await uploadFileToS3(filedata, filename, 'application/pdf', adapter); - } else { - const file = new Parse.File(filename, { base64: base64File }, 'application/pdf'); - await file.save({ useMasterKey: true }); - fileUrl = file.url(); - } - const buffer = Buffer.from(base64File, 'base64'); - saveFileUsage(buffer.length, fileUrl, parseUser.userId.objectId); - } - const extUserPtr = { - __type: 'Pointer', - className: 'contracts_Users', - objectId: extUser.id, - }; - const object = new Parse.Object('contracts_Document'); - object.set('Name', name); - - if (note) { - object.set('Note', note); - } - if (description) { - object.set('Description', description); - } - if (sendInOrder) { - object.set('SendinOrder', sendInOrder); - } - object.set('URL', fileUrl); - object.set('SignedUrl', fileUrl); - object.set('SentToOthers', true); - object.set('CreatedBy', userPtr); - object.set('ExtUserPtr', extUserPtr); - if (TimeToCompleteDays) { - object.set('TimeToCompleteDays', TimeToCompleteDays); - } - object.set('IsEnableOTP', IsEnableOTP); - object.set('IsTourEnabled', isTourEnabled); - object.set('IsSendMail', send_email); - if (parseExtUser?.TenantId?.ActiveFileAdapter) { - object.set('FileAdapterId', parseExtUser?.TenantId?.ActiveFileAdapter); - } - let contact = []; - if (signers && signers.length > 0) { - let parseSigners; - if (base64File) { - parseSigners = signers; - } else { - parseSigners = JSON.parse(signers); - } - let createContactUrl = protocol + '/v1/createcontact'; - - for (const [index, element] of parseSigners.entries()) { - const body = { - name: element?.name || '', - email: element?.email || '', - phone: element?.phone || '', - }; - try { - const res = await axios.post(createContactUrl, body, { - headers: { 'Content-Type': 'application/json', 'x-api-token': reqToken }, - }); - // console.log('res ', res.data); - const contactPtr = { - __type: 'Pointer', - className: 'contracts_Contactbook', - objectId: res.data?.objectId, - }; - const newObj = { ...element, contactPtr: contactPtr, index: index }; - contact.push(newObj); - } catch (err) { - // console.log('err ', err.response); - if (err?.response?.data?.objectId) { - const contactPtr = { - __type: 'Pointer', - className: 'contracts_Contactbook', - objectId: err.response.data?.objectId, - }; - const newObj = { ...element, contactPtr: contactPtr, index: index }; - contact.push(newObj); - } - } - } - object.set( - 'Signers', - contact?.map(x => x.contactPtr) - ); - let updatePlaceholders = contact.map(signer => { - const placeHolder = []; - - for (const widget of signer.widgets) { - const pageNumber = widget.page; - const options = formatWidgetOptions(widget.type, widget.options); - const page = placeHolder.find(page => page.pageNumber === pageNumber); - const widgetData = { - isStamp: widget.type === 'stamp' || widget.type === 'image', - key: randomId(), - isDrag: false, - scale: 1, - isMobile: false, - zIndex: 1, - type: widget.type === 'textbox' ? 'text input' : widget.type, - options: options, - Width: widget.w, - Height: widget.h, - xPosition: widget.x, - yPosition: widget.y, - }; - - if (page) { - page.pos.push(widgetData); - } else { - placeHolder.push({ pageNumber, pos: [widgetData] }); - } - } - - return { - signerObjId: signer?.contactPtr?.objectId, - signerPtr: signer?.contactPtr, - Role: signer.role, - Id: randomId(), - blockColor: color[signer?.index], - placeHolder, - }; - }); - object.set('Placeholders', updatePlaceholders); - } - if (folderId) { - object.set('Folder', { - __type: 'Pointer', - className: 'contracts_Document', - objectId: folderId, - }); - } - const newACL = new Parse.ACL(); - newACL.setPublicReadAccess(false); - newACL.setPublicWriteAccess(false); - newACL.setReadAccess(userPtr.objectId, true); - newACL.setWriteAccess(userPtr.objectId, true); - object.setACL(newACL); - const res = await object.save(null, { useMasterKey: true }); - const doc = { - objectId: res.id, - file: fileUrl, - name: name, - note: note || '', - description: description || '', - signers: contact?.map(x => ({ name: x.name, email: x.email, phone: x?.phone || '' })), - createdAt: res.createdAt, - }; - if (parseExtUser && parseExtUser.Webhook) { - sendDoctoWebhook(doc, parseExtUser?.Webhook, userPtr?.objectId); - } - const newDate = new Date(); - newDate.setDate(newDate.getDate() + 15); - const localExpireDate = newDate.toLocaleDateString('en-US', { - day: 'numeric', - month: 'long', - year: 'numeric', - }); - let sender = parseExtUser.Email; - if (send_email === false) { - console.log("don't send mail"); - } else { - let contactMail = contact; - if (sendInOrder) { - contactMail = contact.slice(); - contactMail.splice(1); - } - for (let i = 0; i < contactMail.length; i++) { - try { - const imgPng = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png'; - let url = `${cloudServerUrl}/functions/sendmailv3/`; - const headers = { - 'Content-Type': 'application/json', - 'X-Parse-Application-Id': process.env.APP_ID, - 'X-Parse-Master-Key': process.env.MASTER_KEY, - }; - - const objectId = contactMail[i].contactPtr.objectId; - const hostUrl = baseUrl.origin; - //encode this url value `${response.id}/${contactMail[i].email}/${objectId}` to base64 using `btoa` function - const encodeBase64 = btoa(`${res.id}/${contactMail[i].email}/${objectId}`); - let signPdf = `${hostUrl}/login/${encodeBase64}`; - const openSignUrl = 'https://www.opensignlabs.com/contact-us'; - const orgName = parseExtUser.Company ? parseExtUser.Company : ''; - const themeBGcolor = '#47a3ad'; - const email_html = - "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /> </head> <body> <div style='background-color: #f5f5f5; padding: 20px'> <div style=' box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background: white;padding-bottom: 20px;'> <div style='padding:10px 10px 0 10px'><img src=" + - imgPng + - " height='50' style='padding:20px; width:170px; height:40px;' /></div> <div style='padding:2px; font-family: system-ui;background-color:" + - themeBGcolor + - ";'><p style='font-size: 20px;font-weight: 400;color: white;padding-left: 20px;' > Digital Signature Request</p></div><div><p style='padding: 20px;font-family: system-ui;font-size: 14px; margin-bottom: 10px;'> " + - parseExtUser.Name + - ' has requested you to review and sign <strong> ' + - name + - "</strong>.</p><div style='padding: 5px 0px 5px 25px;display: flex;flex-direction: row;justify-content: space-around;'><table> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Sender</td> <td> </td> <td style='color:#626363;font-weight:bold'>" + - sender + - "</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Organization</td> <td> </td><td style='color:#626363;font-weight:bold'> " + - orgName + - "</td></tr> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Expires on</td><td> </td> <td style='color:#626363;font-weight:bold'>" + - localExpireDate + - "</td></tr><tr> <td></td> <td> </td></tr></table> </div> <div style='margin-left:70px'><a target=_blank href=" + - signPdf + - "> <button style='padding: 12px 12px 12px 12px;background-color: #d46b0f;color: white; border: 0px;box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px,rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;font-weight:bold;margin-top:30px'>Sign here</button></a> </div> <div style='display: flex; justify-content: center;margin-top: 10px;'> </div></div></div><div><p> This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender " + - sender + - ' directly.If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href=' + - openSignUrl + - ' target=_blank>here</a>.</p> </div></div></body> </html>'; - let replaceVar; - const variables = { - document_title: name, - sender_name: parseExtUser.Name, - sender_mail: parseExtUser.Email, - sender_phone: parseExtUser?.Phone || '', - receiver_name: contactMail[i].name, - receiver_email: contactMail[i].email, - receiver_phone: contactMail[i]?.phone || '', - expiry_date: localExpireDate, - company_name: orgName, - signing_url: signPdf, - }; - if (email_subject && email_body) { - replaceVar = replaceMailVaribles(email_subject, email_body, variables); - } else if (email_subject) { - replaceVar = replaceMailVaribles(email_subject, '', variables); - replaceVar = { subject: replaceVar.subject, body: email_html }; - } else if (email_body) { - replaceVar = replaceMailVaribles( - `${parseExtUser.Name} has requested you to sign "${name}"`, - email_body, - variables - ); - } else { - replaceVar = { - subject: `${parseExtUser.Name} has requested you to sign "${name}"`, - body: email_html, - }; - } - const subject = replaceVar.subject; - const html = replaceVar.body; - - let params = { - recipient: contactMail[i].email, - subject: subject, - from: sender, - html: html, - extUserId: extUser.id, - mailProvider: parseExtUser?.active_mail_adapter || '', - }; - - await axios.post(url, params, { headers: headers }); - } catch (error) { - console.log('error', error); - } - } - } - // if (sendMail.data.result.status === 'success') { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_create_document', - properties: { response_code: 200 }, - }); - } - - const subscriptionCls = new Parse.Object('contracts_Subscriptions'); - subscriptionCls.id = resSub.id; - if (allowedCredits > 0) { - const updateAllowedcredits = allowedCredits - 1 || 0; - subscriptionCls.set('AllowedCredits', updateAllowedcredits); - } else { - const updateAddonCredits = addonCredits > 0 ? addonCredits - 1 : 0; - subscriptionCls.set('AddonCredits', updateAddonCredits); - } - const resSubcription = await subscriptionCls.save(null, { useMasterKey: true }); - // console.log('resSubcription ', resSubcription); - return response.json({ - objectId: res.id, - signurl: contact.map(x => ({ - email: x.email, - url: `${baseUrl.origin}/login/${btoa( - `${res.id}/${x.email}/${x.contactPtr.objectId}` - )}`, - })), - message: 'Document sent successfully!', - }); - } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_create_document', - properties: { response_code: 400 }, - }); - } - return response.status(400).json({ error: 'Please provide signers!' }); - } - } else { - return response - .status(429) - .json({ error: 'Quota reached, Please buy credits and try again later.' }); - } - } else { - return response.status(400).json({ - error: 'Please purchase or renew your subscription.', - }); - } - } else { - return response.status(405).json({ error: 'Invalid API Token!' }); - } - } catch (err) { - console.log('err ', err); - return response.status(400).json({ error: 'Something went wrong, please try again later!' }); - } -} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createFolder.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createFolder.js deleted file mode 100644 index e72f71c2a..000000000 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createFolder.js +++ /dev/null @@ -1,73 +0,0 @@ -export default async function createFolder(request, response) { - const apiToken = request.headers['x-api-token']; - const folderName = request.body.folderName; - const parentFolderId = request.body.parentFolderId; - if (!apiToken) { - return response.status(400).json({ error: 'Please Provide API Token' }); - } - try { - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('token', apiToken); - tokenQuery.include('userId'); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // Valid Token then proceed request - const parseUser = JSON.parse(JSON.stringify(token)); - const userPtr = { - __type: 'Pointer', - className: '_User', - objectId: parseUser.userId.objectId, - }; - const userQuery = new Parse.Query('contracts_Users'); - userQuery.equalTo('UserId', userPtr); - const extUser = await userQuery.first({ useMasterKey: true }); - - const folderCls = new Parse.Object('contracts_Document'); - folderCls.set('Name', folderName); - folderCls.set('CreatedBy', userPtr); - folderCls.set('Type', 'Folder'); - folderCls.set('ExtUserPtr', { - __type: 'Pointer', - className: 'contracts_Users', - objectId: extUser.id, - }); - if (parentFolderId) { - folderCls.set('Folder', { - __type: 'Pointer', - className: 'contracts_Document', - objectId: parentFolderId, - }); - } - const acl = new Parse.ACL(); - acl.setReadAccess(parseUser.userId.objectId, true); // Allow read access to the userPtr - acl.setWriteAccess(parseUser.userId.objectId, true); // Allow write access to the userPtr - - // Set the ACL to the document - folderCls.setACL(acl); - - const _resFolder = await folderCls.save(null, { useMasterKey: true }); - if (_resFolder) { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_create_folder', - properties: { response_code: 200 }, - }); - } - const parseRes = JSON.parse(JSON.stringify(_resFolder)); - return response.json({ - objectId: parseRes.objectId, - folderName: parseRes.Name, - parentFolderId: parseRes?.Folder?.objectId || '', - createdAt: parseRes.createdAt, - updatedAt: parseRes.updatedAt, - }); - } - } else { - return response.status(405).json({ error: 'Invalid API Token!' }); - } - } catch (err) { - console.log('err ', err); - return response.status(400).json({ error: 'Something went wrong, please try again later!' }); - } -} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js deleted file mode 100644 index d93c1dce0..000000000 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js +++ /dev/null @@ -1,242 +0,0 @@ -import axios from 'axios'; -import { - color, - customAPIurl, - saveFileUsage, - formatWidgetOptions, - sanitizeFileName, -} from '../../../../Utils.js'; -import uploadFileToS3 from '../../../parsefunction/uploadFiletoS3.js'; - -const randomId = () => Math.floor(1000 + Math.random() * 9000); -export default async function createTemplatewithCoordinate(request, response) { - const name = request.body.title; - const note = request.body.note; - const description = request.body.description; - const signers = request.body.signers; - const folderId = request.body.folderId; - const base64File = request.body.file; - const fileData = request.files?.[0] ? request.files[0].buffer : null; - const SendinOrder = request.body.sendInOrder || true; - const isEnableOTP = request.body?.enableOTP === true ? true : false; - const isTourEnabled = request.body?.enableTour || false; - - // console.log('fileData ', fileData); - const protocol = customAPIurl(); - - try { - const reqToken = request.headers['x-api-token']; - if (!reqToken) { - return response.status(400).json({ error: 'Please Provide API Token' }); - } - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('token', reqToken); - tokenQuery.include('userId'); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // Valid Token then proceed request - const parseUser = JSON.parse(JSON.stringify(token)); - const userPtr = { - __type: 'Pointer', - className: '_User', - objectId: parseUser.userId.objectId, - }; - if (signers && signers.length > 0) { - const contractsUser = new Parse.Query('contracts_Users'); - contractsUser.equalTo('UserId', userPtr); - contractsUser.include('TenantId'); - const extUser = await contractsUser.first({ useMasterKey: true }); - const parseExtUser = JSON.parse(JSON.stringify(extUser)); - let fileUrl; - if (request.files?.[0]) { - const base64 = fileData?.toString('base64'); - const file = new Parse.File(request.files?.[0]?.originalname, { - base64: base64, - }); - await file.save({ useMasterKey: true }); - fileUrl = file.url(); - const buffer = Buffer.from(base64, 'base64'); - saveFileUsage(buffer.length, fileUrl, parseUser.userId.objectId); - } else { - const filename = sanitizeFileName(`${name}.pdf`); - let adapter = {}; - const ActiveFileAdapter = parseExtUser?.TenantId?.ActiveFileAdapter || ''; - if (ActiveFileAdapter) { - adapter = - parseExtUser?.TenantId?.FileAdapters?.find(x => (x.id = ActiveFileAdapter)) || {}; - } - if (adapter?.id) { - const filedata = Buffer.from(base64File, 'base64'); - // `uploadFileToS3` is used to save document in user's file storage - fileUrl = await uploadFileToS3(filedata, filename, 'application/pdf', adapter); - } else { - const file = new Parse.File(filename, { base64: base64File }, 'application/pdf'); - await file.save({ useMasterKey: true }); - fileUrl = file.url(); - } - const buffer = Buffer.from(base64File, 'base64'); - saveFileUsage(buffer.length, fileUrl, parseUser.userId.objectId); - } - const extUserPtr = { - __type: 'Pointer', - className: 'contracts_Users', - objectId: extUser.id, - }; - const object = new Parse.Object('contracts_Template'); - object.set('Name', name); - if (note) { - object.set('Note', note); - } - if (description) { - object.set('Description', description); - } - if (SendinOrder) { - object.set('SendinOrder', SendinOrder); - } - object.set('URL', fileUrl); - object.set('CreatedBy', userPtr); - object.set('ExtUserPtr', extUserPtr); - object.set('IsEnableOTP', isEnableOTP); - object.set('IsTourEnabled', isTourEnabled); - let contact = []; - if (signers && signers.length > 0) { - let parseSigners; - if (base64File) { - parseSigners = signers; - } else { - parseSigners = JSON.parse(signers); - } - let createContactUrl = protocol + '/v1/createcontact'; - - for (const [index, element] of parseSigners.entries()) { - if (element?.name && element?.email) { - const body = { - name: element?.name || '', - email: element?.email || '', - phone: element?.phone || '', - }; - try { - const res = await axios.post(createContactUrl, body, { - headers: { 'Content-Type': 'application/json', 'x-api-token': reqToken }, - }); - // console.log('res ', res.data); - const contactPtr = { - __type: 'Pointer', - className: 'contracts_Contactbook', - objectId: res.data?.objectId, - }; - const newObj = { ...element, contactPtr: contactPtr, index: index }; - contact.push(newObj); - } catch (err) { - // console.log('err ', err.response); - if (err?.response?.data?.objectId) { - const contactPtr = { - __type: 'Pointer', - className: 'contracts_Contactbook', - objectId: err.response.data?.objectId, - }; - const newObj = { ...element, contactPtr: contactPtr, index: index }; - contact.push(newObj); - } - } - } else { - const newObj = { ...element, contactPtr: {}, index: index }; - contact.push(newObj); - } - } - const updatedSigners = contact?.filter(x => x.contactPtr && x.contactPtr.objectId); - if (updatedSigners && updatedSigners.length > 0) { - object.set( - 'Signers', - updatedSigners?.map(x => x.contactPtr) - ); - } - let updatePlaceholders = contact.map((signer, index) => { - const placeHolder = []; - - for (const widget of signer.widgets) { - const pageNumber = widget.page; - const page = placeHolder.find(page => page.pageNumber === pageNumber); - const options = formatWidgetOptions(widget.type, widget.options); - const widgetData = { - isStamp: widget.type === 'stamp' || widget.type === 'image', - key: randomId(), - isDrag: false, - scale: 1, - isMobile: false, - zIndex: 1, - type: widget.type === 'textbox' ? 'text input' : widget.type, - options: options, - Width: widget.w, - Height: widget.h, - xPosition: widget.x, - yPosition: widget.y, - }; - - if (page) { - page.pos.push(widgetData); - } else { - placeHolder.push({ - pageNumber, - pos: [widgetData], - }); - } - } - - return { - signerObjId: signer?.contactPtr?.objectId, - signerPtr: signer?.contactPtr, - Role: signer.role, - Id: randomId(), - blockColor: color[signer?.index], - placeHolder, - }; - }); - object.set('Placeholders', updatePlaceholders); - } - if (folderId) { - object.set('Folder', { - __type: 'Pointer', - className: 'contracts_Template', - objectId: folderId, - }); - } - if (parseExtUser?.TenantId?.ActiveFileAdapter) { - object.set('FileAdapterId', parseExtUser?.TenantId?.ActiveFileAdapter); - } - const newACL = new Parse.ACL(); - newACL.setPublicReadAccess(false); - newACL.setPublicWriteAccess(false); - newACL.setReadAccess(userPtr.objectId, true); - newACL.setWriteAccess(userPtr.objectId, true); - object.setACL(newACL); - const res = await object.save(null, { useMasterKey: true }); - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_create_template', - properties: { response_code: 200 }, - }); - } - return response.json({ - objectId: res.id, - message: 'Template created successfully!', - }); - } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_create_template', - properties: { response_code: 400 }, - }); - } - return response.status(400).json({ error: 'Please provide signers!' }); - } - } else { - return response.status(405).json({ error: 'Invalid API Token!' }); - } - } catch (err) { - console.log('err ', err); - return response.status(400).json({ error: 'Something went wrong, please try again later!' }); - } -} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js deleted file mode 100644 index 4926eceba..000000000 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js +++ /dev/null @@ -1,65 +0,0 @@ -export default async function deleteContact(request, response) { - try { - const reqToken = request.headers['x-api-token']; - if (!reqToken) { - return response.status(400).json({ error: 'Please Provide API Token' }); - } - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('token', reqToken); - tokenQuery.include('userId'); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // Valid Token then proceed request - const parseUser = JSON.parse(JSON.stringify(token)); - const userPtr = { - __type: 'Pointer', - className: '_User', - objectId: parseUser.userId.objectId, - }; - - const Contactbook = new Parse.Query('contracts_Contactbook'); - Contactbook.equalTo('objectId', request.params.contact_id); - Contactbook.equalTo('CreatedBy', userPtr); - const res = await Contactbook.first({ useMasterKey: true }); - if (res) { - const isDeleted = res.get('IsDeleted'); - if (isDeleted && isDeleted) { - return response.status(404).json({ error: 'Contact not found!' }); - } else { - const Contactbook = Parse.Object.extend('contracts_Contactbook'); - const deleteQuery = new Contactbook(); - deleteQuery.id = request.params.contact_id; - deleteQuery.set('IsDeleted', true); - const deleteRes = await deleteQuery.save(null, { useMasterKey: true }); - if (deleteRes) { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_delete_contact', - properties: { response_code: 200 }, - }); - } - return response.json({ - objectId: request.params.contact_id, - deletedAt: deleteRes.get('updatedAt'), - }); - } - } - } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_delete_contact', - properties: { response_code: 404 }, - }); - } - return response.status(404).json({ error: 'Contact not found!' }); - } - } else { - return response.status(405).json({ error: 'Invalid API Token!' }); - } - } catch (err) { - console.log('err ', err); - return response.status(400).json({ error: 'Something went wrong, please try again later!' }); - } -} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteDocument.js deleted file mode 100644 index 4f9829f46..000000000 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteDocument.js +++ /dev/null @@ -1,66 +0,0 @@ -export default async function deleteDocument(request, response) { - try { - const reqToken = request.headers['x-api-token']; - if (!reqToken) { - return response.status(400).json({ error: 'Please Provide API Token' }); - } - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('token', reqToken); - tokenQuery.include('userId'); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // Valid Token then proceed request - const parseUser = JSON.parse(JSON.stringify(token)); - const userPtr = { - __type: 'Pointer', - className: '_User', - objectId: parseUser.userId.objectId, - }; - - const Document = new Parse.Query('contracts_Document'); - Document.equalTo('objectId', request.params.document_id); - Document.equalTo('CreatedBy', userPtr); - Document.include('ExtUserPtr.TenantId'); - const res = await Document.first({ useMasterKey: true }); - if (res) { - const isArchive = res.get('IsArchive'); - if (isArchive && isArchive) { - return response.status(404).json({ error: 'Document not found!' }); - } else { - const Document = Parse.Object.extend('contracts_Document'); - const deleteQuery = new Document(); - deleteQuery.id = request.params.document_id; - deleteQuery.set('IsArchive', true); - const deleteRes = await deleteQuery.save(null, { useMasterKey: true }); - if (deleteRes) { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_delete_document', - properties: { response_code: 200 }, - }); - } - return response.json({ - objectId: request.params.document_id, - deletedAt: deleteRes.get('updatedAt'), - }); - } - } - } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_delete_document', - properties: { response_code: 404 }, - }); - } - return response.status(404).json({ error: 'Document not found!' }); - } - } else { - return response.status(405).json({ error: 'Invalid API Token!' }); - } - } catch (err) { - console.log('err ', err); - return response.status(400).json({ error: 'Something went wrong, please try again later!' }); - } -} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteFolder.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteFolder.js deleted file mode 100644 index b578eb8b3..000000000 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteFolder.js +++ /dev/null @@ -1,76 +0,0 @@ -export default async function deleteFolder(request, response) { - const apiToken = request.headers['x-api-token']; - const folderId = request.params.folder_id; - if (!apiToken) { - return response.status(400).json({ error: 'Please Provide API Token' }); - } - try { - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('token', apiToken); - tokenQuery.include('userId'); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // Valid Token then proceed request - const parseUser = JSON.parse(JSON.stringify(token)); - const userPtr = { - __type: 'Pointer', - className: '_User', - objectId: parseUser.userId.objectId, - }; - - const obj = new Parse.Query('contracts_Document'); - obj.equalTo('objectId', folderId); - obj.equalTo('IsArchive', true); - obj.equalTo('CreatedBy', userPtr); - obj.include('ExtUserPtr.TenantId'); - const isFolderDeleted = await obj.first({ useMasterKey: true }); - if (!isFolderDeleted) { - const folder = new Parse.Query('contracts_Document'); - folder.equalTo('Folder', { - __type: 'Pointer', - className: 'contracts_Document', - objectId: folderId, - }); - - folder.notEqualTo('IsArchive', true); - folder.equalTo('CreatedBy', userPtr); - folder.equalTo('Type', 'Folder'); - folder.include('ExtUserPtr.TenantId'); - const isSubItems = await folder.first({ useMasterKey: true }); - // console.log('isSubItems ', isSubItems); - if (isSubItems) { - return response - .status(400) - .json({ error: 'folder is not empty, contains document or folder.' }); - } else { - const deleteFolder = new Parse.Object('contracts_Document'); - deleteFolder.id = folderId; - deleteFolder.set('IsArchive', true); - const deleteRes = await deleteFolder.save(null, { useMasterKey: true }); - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_delete_folder', - properties: { response_code: 200 }, - }); - } - return response.json({ objectId: deleteRes.id, deletedAt: deleteRes.updatedAt }); - } - } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_delete_folder', - properties: { response_code: 404 }, - }); - } - return response.status(404).json({ error: 'folder not found.' }); - } - } else { - return response.status(405).json({ error: 'Invalid API Token!' }); - } - } catch (err) { - console.log('err is delete folder API', err); - return response.status(400).json({ error: 'Something went wrong, please try again later!' }); - } -} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js deleted file mode 100644 index a998ff04c..000000000 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js +++ /dev/null @@ -1,72 +0,0 @@ -export default async function deletedTemplate(request, response) { - const reqToken = request.headers['x-api-token']; - if (!reqToken) { - return response.status(400).json({ error: 'Please Provide API Token' }); - } - try { - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('token', reqToken); - tokenQuery.include('userId'); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // Valid Token then proceed request - const parseUser = JSON.parse(JSON.stringify(token)); - const userPtr = { - __type: 'Pointer', - className: '_User', - objectId: parseUser.userId.objectId, - }; - const template = new Parse.Query('contracts_Template'); - template.equalTo('objectId', request.params.template_id); - template.equalTo('CreatedBy', userPtr); - template.include('ExtUserPtr.TenantId'); - const res = await template.first({ useMasterKey: true }); - if (res) { - const isArchive = res.get('IsArchive'); - if (isArchive && isArchive) { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_delete_template', - properties: { response_code: 404 }, - }); - } - return response.status(404).json({ error: 'Template not found!' }); - } else { - const template = Parse.Object.extend('contracts_Template'); - const deleteQuery = new template(); - deleteQuery.id = request.params.template_id; - deleteQuery.set('IsArchive', true); - const deleteRes = await deleteQuery.save(null, { useMasterKey: true }); - if (deleteRes) { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_delete_template', - properties: { response_code: 200 }, - }); - } - return response.json({ - objectId: request.params.template_id, - deletedAt: deleteRes.get('updatedAt'), - }); - } - } - } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_delete_template', - properties: { response_code: 404 }, - }); - } - return response.status(404).json({ error: 'Template not found!' }); - } - } else { - return response.status(405).json({ error: 'Invalid API Token!' }); - } - } catch (err) { - console.log('err ', err); - return response.status(400).json({ error: 'Something went wrong, please try again later!' }); - } -} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteWebhook.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteWebhook.js deleted file mode 100644 index ac82b521f..000000000 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteWebhook.js +++ /dev/null @@ -1,57 +0,0 @@ -export default async function deleteWebhook(request, response) { - const reqToken = request.headers['x-api-token']; - if (!reqToken) { - return response.status(400).json({ error: 'Please Provide API Token' }); - } - try { - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('token', reqToken); - tokenQuery.include('userId'); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // Valid Token then proceed request - const parseUser = JSON.parse(JSON.stringify(token)); - const userPtr = { - __type: 'Pointer', - className: '_User', - objectId: parseUser.userId.objectId, - }; - - const query = new Parse.Query('contracts_Users'); - query.equalTo('UserId', userPtr); - const user = await query.first({ useMasterKey: true }); - if (user) { - const updateQuery = new Parse.Object('contracts_Users'); - updateQuery.id = user.id; - updateQuery.unset('Webhook'); - const res = await updateQuery.save(null, { useMasterKey: true }); - if (res) { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_delete_webhook', - properties: { response_code: 200 }, - }); - } - return response.json({ - result: 'Webhook deleted successfully!', - }); - } - } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_delete_webhook', - properties: { response_code: 404 }, - }); - } - return response.status(404).json({ error: 'User not found!' }); - } - } else { - return response.status(405).json({ error: 'Invalid API Token!' }); - } - } catch (err) { - console.log('err ', err); - return response.status(400).json({ error: 'Something went wrong, please try again later!' }); - } -} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js deleted file mode 100644 index 81e15f767..000000000 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js +++ /dev/null @@ -1,61 +0,0 @@ -export default async function getContact(request, response) { - try { - const reqToken = request.headers['x-api-token']; - if (!reqToken) { - return response.status(400).json({ error: 'Please Provide API Token' }); - } - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('token', reqToken); - tokenQuery.include('userId'); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // Valid Token then proceed request - const parseUser = JSON.parse(JSON.stringify(token)); - const userPtr = { - __type: 'Pointer', - className: '_User', - objectId: parseUser.userId.objectId, - }; - - const Contactbook = new Parse.Query('contracts_Contactbook'); - Contactbook.equalTo('objectId', request.params.contact_id); - Contactbook.equalTo('CreatedBy', userPtr); - Contactbook.notEqualTo('IsDeleted', true); - Contactbook.select('Name,Email,Phone'); - - const res = await Contactbook.first({ useMasterKey: true }); - if (res) { - const parseRes = JSON.parse(JSON.stringify(res)); - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_get_contact', - properties: { response_code: 200 }, - }); - } - return response.json({ - objectId: parseRes.objectId, - name: parseRes.Name, - email: parseRes.Email, - phone: parseRes?.Phone || '', - createdAt: parseRes.createdAt, - updatedAt: parseRes.updatedAt, - }); - } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_get_contact', - properties: { response_code: 404 }, - }); - } - return response.status(404).json({ error: 'Contact not found!' }); - } - } else { - return response.status(405).json({ error: 'Invalid API Token!' }); - } - } catch (err) { - console.log('err ', err); - return response.status(400).json({ error: 'Something went wrong, please try again later!' }); - } -} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js deleted file mode 100644 index bed33476c..000000000 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js +++ /dev/null @@ -1,63 +0,0 @@ -export default async function getContactList(request, response) { - try { - const reqToken = request.headers['x-api-token']; - if (!reqToken) { - return response.status(400).json({ error: 'Please Provide API Token' }); - } - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('token', reqToken); - tokenQuery.include('userId'); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // Valid Token then proceed request - const parseUser = JSON.parse(JSON.stringify(token)); - const userPtr = { - __type: 'Pointer', - className: '_User', - objectId: parseUser.userId.objectId, - }; - const limit = request?.query?.limit ? parseInt(request.query.limit) : 100; - const skip = request?.query?.skip ? parseInt(request.query.skip) : 0; - const Contactbook = new Parse.Query('contracts_Contactbook'); - Contactbook.equalTo('CreatedBy', userPtr); - Contactbook.notEqualTo('IsDeleted', true); - Contactbook.limit(limit); - Contactbook.skip(skip); - Contactbook.descending('createdAt'); - const res = await Contactbook.find({ useMasterKey: true }); - if (res && res.length > 0) { - const parseRes = JSON.parse(JSON.stringify(res)); - const contactlist = parseRes.map(x => ({ - objectId: x.objectId, - name: x.Name, - email: x.Email, - phone: x?.Phone || '', - createdAt: x.createdAt, - updatedAt: x.updatedAt, - })); - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_get_contact_list', - properties: { response_code: 200 }, - }); - } - return response.json({ result: contactlist }); - } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_get_contact_list', - properties: { response_code: 200 }, - }); - } - return response.json({ result: [] }); - } - } else { - return response.status(405).json({ error: 'Invalid API Token!' }); - } - } catch (err) { - console.log('err ', err); - return response.status(400).json({ error: 'Something went wrong, please try again later!' }); - } -} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js deleted file mode 100644 index 123aa7b60..000000000 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js +++ /dev/null @@ -1,88 +0,0 @@ -export default async function getDocument(request, response) { - try { - const reqToken = request.headers['x-api-token']; - if (!reqToken) { - return response.status(400).json({ error: 'Please Provide API Token' }); - } - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('token', reqToken); - tokenQuery.include('userId'); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // Valid Token then proceed request - const parseUser = JSON.parse(JSON.stringify(token)); - const userPtr = { - __type: 'Pointer', - className: '_User', - objectId: parseUser.userId.objectId, - }; - const Document = new Parse.Query('contracts_Document'); - Document.equalTo('objectId', request.params.document_id); - Document.equalTo('CreatedBy', userPtr); - Document.notEqualTo('IsArchive', true); - Document.include('Signers'); - Document.include('Folder'); - Document.include('ExtUserPtr'); - Document.include('Placeholders.signerPtr'); - Document.include('ExtUserPtr.TenantId'); - const res = await Document.first({ useMasterKey: true }); - if (res) { - const document = JSON.parse(JSON.stringify(res)); - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_get_document', - properties: { response_code: 200 }, - }); - } - return response.json({ - objectId: document.objectId, - title: document.Name, - note: document.Note || '', - folder: { objectId: document?.Folder?.objectId, name: document?.Folder?.Name } || '', - file: document?.SignedUrl || document.URL, - certificate: document?.CertificateUrl || '', - owner: document?.ExtUserPtr?.Name, - signers: - document?.Placeholders?.map(y => ({ - role: y.Role, - name: y?.signerPtr?.Name || '', - email: y?.signerPtr?.Email || '', - phone: y?.signerPtr?.Phone || '', - widgets: y.placeHolder?.flatMap(x => - x?.pos.map(w => ({ - type: w?.type ? w.type : w.isStamp ? 'stamp' : 'signature', - x: w.xPosition, - y: w.yPosition, - w: w?.Width || 150, - h: w?.Height || 60, - page: x?.pageNumber, - })) - ), - })) || - document?.Signers?.map(y => ({ name: y?.Name, email: y?.Email, phone: y?.Phone })) || - [], - sendInOrder: document?.SendinOrder || false, - enableOTP: document?.IsEnableOTP || false, - createdAt: document.createdAt, - updatedAt: document.updatedAt, - enableTour: document?.IsTourEnabled || false, - }); - } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_get_document', - properties: { response_code: 404 }, - }); - } - return response.status(404).json({ error: 'Document not found!' }); - } - } else { - return response.status(405).json({ error: 'Invalid API Token!' }); - } - } catch (err) { - console.log('err ', err); - return response.status(400).json({ error: 'Something went wrong, please try again later!' }); - } -} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js deleted file mode 100644 index 3a163472f..000000000 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js +++ /dev/null @@ -1,141 +0,0 @@ -import axios from 'axios'; -import reportJson from '../../../parsefunction/reportsJson.js'; -import dotenv from 'dotenv'; -import { cloudServerUrl } from '../../../../Utils.js'; -dotenv.config(); - -export default async function getDocumentList(request, response) { - const reqToken = request.headers['x-api-token']; - const appId = process.env.APP_ID; - const serverUrl = cloudServerUrl; //process.env.SERVER_URL; - if (!reqToken) { - return response.status(400).json({ error: 'Please Provide API Token' }); - } - try { - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('token', reqToken); - tokenQuery.include('userId'); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // Valid Token then proceed request - const parseUser = JSON.parse(JSON.stringify(token)); - const userPtr = { - __type: 'Pointer', - className: '_User', - objectId: parseUser.userId.objectId, - }; - const docType = request.params.doctype; - const limit = request?.query?.limit ? request.query.limit : 100; - const skip = request?.query?.skip ? request.query.skip : 0; - let reportId; - switch (docType) { - case 'draft': - reportId = 'ByHuevtCFY'; - break; - case 'signaturerequest': - reportId = '4Hhwbp482K'; - break; - case 'inprogress': - reportId = '1MwEuxLEkF'; - break; - case 'completed': - reportId = 'kQUoW4hUXz'; - break; - case 'expired': - reportId = 'zNqBHXHsYH'; - break; - case 'declined': - reportId = 'UPr2Fm5WY3'; - break; - default: - reportId = ''; - } - const json = reportId && reportJson(reportId, userPtr.objectId); - const clsName = 'contracts_Document'; - if (reportId && json) { - const { params, keys } = json; - const orderBy = '-updatedAt'; - const strParams = JSON.stringify(params); - const strKeys = keys.join(); - const headers = { - 'Content-Type': 'application/json', - 'X-Parse-Application-Id': appId, - 'X-Parse-Master-Key': process.env.MASTER_KEY, - }; - const url = `${serverUrl}/classes/${clsName}?where=${strParams}&keys=${strKeys},Placeholders&order=${orderBy}&skip=${skip}&limit=${limit}&include=AuditTrail.UserPtr,Placeholders.signerPtr,ExtUserPtr.TenantId`; - try { - const res = await axios.get(url, { headers: headers }); - if (res.data && res.data.results.length > 0) { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: `api_get_document_list_${docType}`, - properties: { response_code: 200, doc_type: docType }, - }); - } - const updateRes = res.data.results.map(x => ({ - objectId: x.objectId, - title: x.Name, - note: x.Note || '', - folder: { objectId: x?.Folder?.objectId, name: x?.Folder?.Name } || '', - // file: x?.SignedUrl || x.URL, - owner: x?.ExtUserPtr?.Name, - signers: - x?.Placeholders?.map(y => ({ - role: y.Role, - name: y?.signerPtr?.Name || '', - email: y?.signerPtr?.Email || '', - phone: y?.signerPtr?.Phone || '', - widgets: y.placeHolder?.flatMap(x => - x?.pos.map(w => ({ - type: w?.type ? w.type : w.isStamp ? 'stamp' : 'signature', - x: w.xPosition, - y: w.yPosition, - w: w?.Width || 150, - h: w?.Height || 60, - page: x?.pageNumber, - })) - ), - })) || - x?.Signers?.map(y => ({ name: y?.Name, email: y?.Email, phone: y?.Phone })) || - [], - sendInOrder: x?.SendinOrder || false, - enableOTP: x?.IsEnableOTP || false, - createdAt: x.createdAt, - updatedAt: x.updatedAt, - enableTour: x?.IsTourEnabled || false, - })); - return response.json({ result: updateRes }); - } else { - return response.json({ result: [] }); - } - } catch (err) { - console.log('err in getdocument list', err); - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: `api_get_document_list_${docType}`, - properties: { response_code: 400, doc_type: docType }, - }); - } - return response - .status(400) - .json({ error: 'Something went wrong, please try again later!' }); - } - } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: `api_get_document_list_${docType}`, - properties: { response_code: 404, doc_type: docType }, - }); - } - return response.status(404).json({ error: 'Report not available!' }); - } - } - return response.status(405).json({ error: 'Invalid API Token!' }); - } catch (err) { - console.log('Err', err); - return response.status(400).json({ error: 'Something went wrong, please try again later!' }); - } -} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getFolder.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getFolder.js deleted file mode 100644 index 2479811c9..000000000 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getFolder.js +++ /dev/null @@ -1,64 +0,0 @@ -export default async function getFolder(request, response) { - const apiToken = request.headers['x-api-token']; - const folder_id = request.params.folder_id; - if (!apiToken) { - return response.status(400).json({ error: 'Please Provide API Token' }); - } - try { - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('token', apiToken); - tokenQuery.include('userId'); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // Valid Token then proceed request - const parseUser = JSON.parse(JSON.stringify(token)); - const userPtr = { - __type: 'Pointer', - className: '_User', - objectId: parseUser.userId.objectId, - }; - - const folderCls = new Parse.Query('contracts_Document'); - folderCls.equalTo('CreatedBy', userPtr); - folderCls.equalTo('objectId', folder_id); - folderCls.equalTo('Type', 'Folder'); - folderCls.notEqualTo('IsArchive', true); - folderCls.descending('createdAt'); - folderCls.include('Folder'); - folderCls.include('ExtUserPtr.TenantId'); - const res = await folderCls.first({ useMasterKey: true }); - if (res) { - const parseRes = JSON.parse(JSON.stringify(res)); - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_get_folder', - properties: { response_code: 200 }, - }); - } - return response.json({ - objectId: parseRes.objectId, - folderName: parseRes.Name, - parentFolderId: parseRes?.Folder?.objectId || '', - parentFolderName: parseRes?.Folder?.Name || '', - createdAt: parseRes.createdAt, - updatedAt: parseRes.updatedAt, - }); - } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_get_folder', - properties: { response_code: 404 }, - }); - } - return response.status(404).json({ error: 'folder not found.' }); - } - } else { - return response.status(405).json({ error: 'Invalid API Token!' }); - } - } catch (err) { - console.log('err ', err); - return response.status(400).json({ error: 'Something went wrong, please try again later!' }); - } -} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getFolderList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getFolderList.js deleted file mode 100644 index 78a9298c2..000000000 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getFolderList.js +++ /dev/null @@ -1,77 +0,0 @@ -export default async function getFolderList(request, response) { - const apiToken = request.headers['x-api-token']; - const parentFolderId = request.query?.parentFolderId || ''; - if (!apiToken) { - return response.status(400).json({ error: 'Please Provide API Token' }); - } - try { - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('token', apiToken); - tokenQuery.include('userId'); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // Valid Token then proceed request - const parseUser = JSON.parse(JSON.stringify(token)); - const userPtr = { - __type: 'Pointer', - className: '_User', - objectId: parseUser.userId.objectId, - }; - const limit = request?.query?.limit ? parseInt(request.query.limit) : 100; - const skip = request?.query?.skip ? parseInt(request.query.skip) : 0; - const folderCls = new Parse.Query('contracts_Document'); - folderCls.equalTo('CreatedBy', userPtr); - folderCls.equalTo('Type', 'Folder'); - folderCls.notEqualTo('IsArchive', true); - folderCls.descending('createdAt'); - folderCls.include('Folder'); - if (parentFolderId) { - folderCls.equalTo('Folder', { - __type: 'Pointer', - className: 'contracts_Document', - objectId: parentFolderId, - }); - } else { - folderCls.doesNotExist('Folder'); - } - folderCls.descending('createdAt'); - folderCls.include('ExtUserPtr.TenantId'); - folderCls.limit(limit); - folderCls.skip(skip); - const res = await folderCls.find({ useMasterKey: true }); - if (res && res.length > 0) { - const parseRes = JSON.parse(JSON.stringify(res)); - const folderlist = parseRes.map(x => ({ - objectId: x.objectId, - folderName: x.Name, - parentFolderId: x?.Folder?.objectId || '', - parentFolderName: x?.Folder?.Name || '', - createdAt: x.createdAt, - updatedAt: x.updatedAt, - })); - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_get_Folder_list', - properties: { response_code: 200 }, - }); - } - return response.json({ result: folderlist }); - } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_get_Folder_list', - properties: { response_code: 200 }, - }); - } - return response.json({ result: [] }); - } - } else { - return response.status(405).json({ error: 'Invalid API Token!' }); - } - } catch (err) { - console.log('err ', err); - return response.status(400).json({ error: 'Something went wrong, please try again later!' }); - } -} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js deleted file mode 100644 index 249fb262a..000000000 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js +++ /dev/null @@ -1,87 +0,0 @@ -export default async function getTemplate(request, response) { - try { - const reqToken = request.headers['x-api-token']; - if (!reqToken) { - return response.status(400).json({ error: 'Please Provide API Token' }); - } - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('token', reqToken); - tokenQuery.include('userId'); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // Valid Token then proceed request - const parseUser = JSON.parse(JSON.stringify(token)); - const userPtr = { - __type: 'Pointer', - className: '_User', - objectId: parseUser.userId.objectId, - }; - - const Template = new Parse.Query('contracts_Template'); - Template.equalTo('objectId', request.params.template_id); - Template.equalTo('CreatedBy', userPtr); - Template.notEqualTo('IsArchive', true); - Template.include('Signers'); - Template.include('Folder'); - Template.include('ExtUserPtr'); - Template.include('Placeholders.signerPtr'); - Template.include('ExtUserPtr.TenantId'); - const res = await Template.first({ useMasterKey: true }); - if (res) { - const template = JSON.parse(JSON.stringify(res)); - - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_get_template', - properties: { response_code: 200 }, - }); - } - return response.json({ - objectId: template.objectId, - title: template.Name, - note: template.Note || '', - folder: { objectId: template?.Folder?.objectId, name: template?.Folder?.Name } || '', - file: template?.SignedUrl || template?.URL, - owner: template?.ExtUserPtr?.Name, - signers: - template?.Placeholders?.map(y => ({ - role: y.Role, - name: y?.signerPtr?.Name || '', - email: y?.signerPtr?.Email || '', - phone: y?.signerPtr?.Phone || '', - widgets: y.placeHolder?.flatMap(x => - x?.pos.map(w => ({ - type: w?.type ? w.type : w.isStamp ? 'stamp' : 'signature', - x: w.xPosition, - y: w.yPosition, - w: w?.Width || 150, - h: w?.Height || 60, - page: x?.pageNumber, - })) - ), - })) || [], - sendInOrder: template?.SendinOrder || false, - enableOTP: template?.IsEnableOTP || false, - createdAt: template.createdAt, - updatedAt: template.updatedAt, - enableTour: template?.IsTourEnabled || false, - }); - } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_get_template', - properties: { response_code: 404 }, - }); - } - return response.status(404).json({ error: 'Template not found!' }); - } - } else { - return response.status(405).json({ error: 'Invalid API Token!' }); - } - } catch (err) { - console.log('err ', err); - return response.status(400).json({ error: 'Something went wrong, please try again later!' }); - } -} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js deleted file mode 100644 index d247eb81e..000000000 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js +++ /dev/null @@ -1,114 +0,0 @@ -import axios from 'axios'; -import dotenv from 'dotenv'; -import { cloudServerUrl } from '../../../../Utils.js'; -dotenv.config(); -export default async function getTemplatetList(request, response) { - const reqToken = request.headers['x-api-token']; - const appId = process.env.APP_ID; - const serverUrl = cloudServerUrl; //process.env.SERVER_URL; - if (!reqToken) { - return response.status(400).json({ error: 'Please Provide API Token' }); - } - try { - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('token', reqToken); - tokenQuery.include('userId'); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // Valid Token then proceed request - const parseUser = JSON.parse(JSON.stringify(token)); - const userPtr = { - __type: 'Pointer', - className: '_User', - objectId: parseUser.userId.objectId, - }; - - const limit = request?.query?.limit ? request.query.limit : 100; - const skip = request?.query?.skip ? request.query.skip : 0; - - const clsName = 'contracts_Template'; - const params = { - Type: { $ne: 'Folder' }, - CreatedBy: userPtr, - IsArchive: { $ne: true }, - }; - const keys = [ - 'Name', - 'Note', - 'Description', - 'Folder.Name', - 'URL', - 'SignedUrl', - 'ExtUserPtr.Name', - 'Signers.Name', - 'Signers.Email', - 'Signers.Phone', - 'Placeholders', - ]; - const orderBy = '-updatedAt'; - const strParams = JSON.stringify(params); - const strKeys = keys.join(); - const headers = { - 'Content-Type': 'application/json', - 'X-Parse-Application-Id': appId, - 'X-Parse-Master-Key': process.env.MASTER_KEY, - }; - const url = `${serverUrl}/classes/${clsName}?where=${strParams}&keys=${strKeys}&order=${orderBy}&skip=${skip}&limit=${limit}&include=AuditTrail.UserPtr,Placeholders.signerPtr,ExtUserPtr.TenantId`; - const res = await axios.get(url, { headers: headers }); - if (res.data && res.data.results.length > 0) { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_get_template_list', - properties: { response_code: 200 }, - }); - } - const updateRes = res.data.results.map(template => ({ - objectId: template.objectId, - title: template.Name, - note: template.Note || '', - folder: { objectId: template?.Folder?.objectId, name: template?.Folder?.Name } || '', - file: template?.SignedUrl || template.URL, - owner: template?.ExtUserPtr?.Name, - signers: - template?.Placeholders?.map(y => ({ - role: y.Role, - name: y?.signerPtr?.Name || '', - email: y?.signerPtr?.Email || '', - phone: y?.signerPtr?.Phone || '', - widgets: y.placeHolder?.flatMap(x => - x?.pos.map(w => ({ - type: w?.type ? w.type : w.isStamp ? 'stamp' : 'signature', - x: w.xPosition, - y: w.yPosition, - w: w?.Width || 150, - h: w?.Height || 60, - page: x?.pageNumber, - })) - ), - })) || [], - sendInOrder: template?.SendinOrder || false, - enableOTP: template?.IsEnableOTP || false, - createdAt: template.createdAt, - updatedAt: template.updatedAt, - enableTour: template?.IsTourEnabled || false, - })); - - return response.json({ result: updateRes }); - } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_get_template_list', - properties: { response_code: 200 }, - }); - } - return response.json({ result: [] }); - } - } - return response.status(405).json({ error: 'Invalid API Token!' }); - } catch (err) { - console.log('err', err); - return response.status(400).json({ error: 'Something went wrong, please try again later!' }); - } -} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js deleted file mode 100644 index 20224a63a..000000000 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js +++ /dev/null @@ -1,62 +0,0 @@ -import dotenv from 'dotenv'; -dotenv.config(); - -export default async function getUser(request, response) { - const reqToken = request.headers['x-api-token']; - if (!reqToken) { - return response.status(400).json({ error: 'Please Provide API Token' }); - } - try { - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('token', reqToken); - tokenQuery.include('userId'); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // Valid Token then proceed request - const parseUser = JSON.parse(JSON.stringify(token)); - const userPtr = { - __type: 'Pointer', - className: '_User', - objectId: parseUser.userId.objectId, - }; - - const query = new Parse.Query('contracts_Users'); - query.equalTo('UserId', userPtr); - query.exclude('IsContactEntry,TourStatus,UserRole,TenantId,UserId,CreatedBy,Plan'); - const user = await query.first({ useMasterKey: true }); - if (user) { - const parseRes = JSON.parse(JSON.stringify(user)); - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_get_your_account_details', - properties: { response_code: 200 }, - }); - } - return response.json({ - objectId: parseRes.objectId, - name: parseRes.Name, - email: parseRes.Email, - phone: parseRes?.Phone || '', - jobTitle: parseRes.JobTitle, - company: parseRes.Company, - createdAt: parseRes.createdAt, - updatedAt: parseRes.updatedAt, - }); - } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_get_your_account_details', - properties: { response_code: 404 }, - }); - } - return response.status(404).json({ error: 'User not found!' }); - } - } - return response.status(405).json({ error: 'Invalid API Token!' }); - } catch (err) { - console.log('Err', err); - return response.status(400).json({ error: 'Something went wrong, please try again later!' }); - } -} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getWebhook.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getWebhook.js deleted file mode 100644 index 1dc692942..000000000 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getWebhook.js +++ /dev/null @@ -1,55 +0,0 @@ -export default async function getWebhook(request, response) { - const reqToken = request.headers['x-api-token']; - if (!reqToken) { - return response.status(400).json({ error: 'Please Provide API Token' }); - } - try { - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('token', reqToken); - tokenQuery.include('userId'); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // Valid Token then proceed request - const parseUser = JSON.parse(JSON.stringify(token)); - const userPtr = { - __type: 'Pointer', - className: '_User', - objectId: parseUser.userId.objectId, - }; - const query = new Parse.Query('contracts_Users'); - query.equalTo('UserId', userPtr); - const user = await query.first({ useMasterKey: true }); - if (user) { - const extUser = JSON.parse(JSON.stringify(user)); - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_get_webhook', - properties: { response_code: 200 }, - }); - } - if (extUser && extUser.Webhook) { - return response.json({ - webhook: extUser.Webhook, - }); - } else { - return response.json({}); - } - } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_get_webhook', - properties: { response_code: 404 }, - }); - } - return response.status(404).json({ error: 'User not found!' }); - } - } else { - return response.status(405).json({ error: 'Invalid API Token!' }); - } - } catch (err) { - console.log('Err ', err); - return response.status(400).json({ error: 'Something went wrong, please try again later!' }); - } -} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/resendMail.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/resendMail.js deleted file mode 100644 index 5257b39e9..000000000 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/resendMail.js +++ /dev/null @@ -1,159 +0,0 @@ -import axios from 'axios'; -import { cloudServerUrl, replaceMailVaribles } from '../../../../Utils.js'; - -export default async function resendMail(request, response) { - try { - const reqToken = request.headers['x-api-token']; - const docId = request.body.document_id; - const userMail = request.body.email; - const email_subject = request.body.email_subject; - const email_body = request.body.email_body; - const baseUrl = new URL(process.env.SERVER_URL); - - if (!reqToken) { - return response.status(400).json({ error: 'Please Provide API Token' }); - } - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('token', reqToken); - tokenQuery.include('userId'); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // Valid Token then proceed request - const parseUser = JSON.parse(JSON.stringify(token)); - const userPtr = { - __type: 'Pointer', - className: '_User', - objectId: parseUser.userId.objectId, - }; - - const docQuery = new Parse.Query('contracts_Document'); - docQuery.equalTo('objectId', docId); - docQuery.equalTo('CreatedBy', userPtr); - docQuery.include('Signers,ExtUserPtr'); - docQuery.notEqualTo('IsCompleted', true); - docQuery.notEqualTo('IsDeclined', true); - docQuery.notEqualTo('IsArchive', true); - docQuery.greaterThanOrEqualTo('ExpiryDate', new Date()); - docQuery.exists('SignedUrl'); - docQuery.include('ExtUserPtr.TenantId'); - const resDoc = await docQuery.first({ useMasterKey: true }); - // console.log("resDoc ",resDoc) - if (resDoc) { - const _resDoc = resDoc.toJSON(); - const contact = _resDoc.Signers.find(x => x.Email === userMail); - const activeMailAdapter = _resDoc?.ExtUserPtr?.active_mail_adapter || ''; - if (contact) { - try { - const imgPng = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png'; - let url = `${cloudServerUrl}/functions/sendmailv3/`; - const headers = { - 'Content-Type': 'application/json', - 'X-Parse-Application-Id': process.env.APP_ID, - 'X-Parse-Master-Key': process.env.MASTER_KEY, - }; - - const objectId = contact.objectId; - const hostUrl = baseUrl.origin; - const title = _resDoc.Name; - const receiverMail = contact.Email; - //encode this url value `${response.id}/${receiverMail}/${objectId}` to base64 using `btoa` function - const encodeBase64 = btoa(`${_resDoc.objectId}/${receiverMail}/${objectId}`); - let signPdf = `${hostUrl}/login/${encodeBase64}`; - const openSignUrl = 'https://www.opensignlabs.com/contact-us'; - const orgName = _resDoc.ExtUserPtr.Company ? _resDoc.ExtUserPtr.Company : ''; - const newDate = new Date(_resDoc.ExpiryDate.iso); - newDate.setDate(newDate.getDate() + 15); - const sender = _resDoc.ExtUserPtr.Email; - const localExpireDate = newDate.toLocaleDateString('en-US', { - day: 'numeric', - month: 'long', - year: 'numeric', - }); - - const themeBGcolor = '#47a3ad'; - const email_html = - "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /> </head> <body> <div style='background-color: #f5f5f5; padding: 20px'> <div style=' box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background: white;padding-bottom: 20px;'> <div style='padding:10px 10px 0 10px'><img src=" + - imgPng + - " height='50' style='padding:20px; width:170px; height:40px;' /></div> <div style='padding:2px; font-family: system-ui;background-color:" + - themeBGcolor + - ";'><p style='font-size: 20px;font-weight: 400;color: white;padding-left: 20px;' > Digital Signature Request</p></div><div><p style='padding: 20px;font-family: system-ui;font-size: 14px; margin-bottom: 10px;'> " + - _resDoc.ExtUserPtr.Name + - ' has requested you to review and sign <strong> ' + - title + - "</strong>.</p><div style='padding: 5px 0px 5px 25px;display: flex;flex-direction: row;justify-content: space-around;'><table> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Sender</td> <td> </td> <td style='color:#626363;font-weight:bold'>" + - sender + - "</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Organization</td> <td> </td><td style='color:#626363;font-weight:bold'> " + - orgName + - "</td></tr> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Expires on</td><td> </td> <td style='color:#626363;font-weight:bold'>" + - localExpireDate + - "</td></tr><tr> <td></td> <td> </td></tr></table> </div> <div style='margin-left:70px'><a target=_blank href=" + - signPdf + - "> <button style='padding: 12px 12px 12px 12px;background-color: #d46b0f;color: white; border: 0px;box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px,rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;font-weight:bold;margin-top:30px'>Sign here</button></a> </div> <div style='display: flex; justify-content: center;margin-top: 10px;'> </div></div></div><div><p> This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender " + - sender + - ' directly.If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href=' + - openSignUrl + - ' target=_blank>here</a>.</p> </div></div></body> </html>'; - let replaceVar; - const variables = { - document_title: title, - sender_name: _resDoc.ExtUserPtr.Name, - sender_mail: _resDoc.ExtUserPtr.Email, - sender_phone: _resDoc.ExtUserPtr?.Phone || '', - receiver_name: contact.Name, - receiver_email: contact.Email, - receiver_phone: contact?.Phone || '', - expiry_date: localExpireDate, - company_name: orgName, - signing_url: signPdf, - }; - if (email_subject && email_body) { - replaceVar = replaceMailVaribles(email_subject, email_body, variables); - } else if (email_subject) { - replaceVar = replaceMailVaribles(email_subject, '', variables); - replaceVar = { subject: replaceVar.subject, body: email_html }; - } else if (email_body) { - replaceVar = replaceMailVaribles( - `${_resDoc.ExtUserPtr.Name} has requested you to sign "${title}"`, - email_body, - variables - ); - } else { - replaceVar = { - subject: `${_resDoc.ExtUserPtr.Name} has requested you to sign "${title}"`, - body: email_html, - }; - } - const subject = replaceVar.subject; - const html = replaceVar.body; - - let params = { - recipient: contact.Email, - subject: subject, - from: sender, - html: html, - extUserId: _resDoc.ExtUserPtr.objectId, - mailProvider: activeMailAdapter, - }; - - const res = await axios.post(url, params, { headers: headers }); - if (res.data.result && res.data.result.status === 'success') { - return response.json({ result: 'mail sent successfully.' }); - } - } catch (error) { - console.log('error', error); - return response.status(400).json({ error: error.message }); - } - } else { - return response.status(404).json({ error: 'user not found.' }); - } - } else { - return response.status(404).json({ error: 'document not found.' }); - } - } else { - return response.status(405).json({ error: 'Invalid API Token.' }); - } - } catch (err) { - console.log('err in resendmail', err); - return response.status(400).json({ error: err.message || 'Something went wrong.' }); - } -} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/saveWebhook.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/saveWebhook.js deleted file mode 100644 index 9c6b4b9ba..000000000 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/saveWebhook.js +++ /dev/null @@ -1,85 +0,0 @@ -export default async function saveWebhook(request, response) { - const Url = request.body.url; - const reqToken = request.headers['x-api-token']; - if (!reqToken) { - return response.status(400).json({ error: 'Please Provide API Token' }); - } - try { - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('token', reqToken); - tokenQuery.include('userId'); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // Valid Token then proceed request - const parseUser = JSON.parse(JSON.stringify(token)); - const userPtr = { - __type: 'Pointer', - className: '_User', - objectId: parseUser.userId.objectId, - }; - const query = new Parse.Query('contracts_Users'); - query.equalTo('UserId', userPtr); - const user = await query.first({ useMasterKey: true }); - if (user) { - const extUser = JSON.parse(JSON.stringify(user)); - const isUrlExist = extUser?.Webhook && extUser?.Webhook === Url; - - if (!isUrlExist) { - try { - const updateQuery = new Parse.Object('contracts_Users'); - updateQuery.id = user.id; - updateQuery.set('Webhook', Url); - const res = await updateQuery.save(null, { useMasterKey: true }); - if (res) { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_save_webhook', - properties: { response_code: 200 }, - }); - } - return response.json({ - result: 'Webhook updated successfully!', - }); - } - } catch (err) { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_save_webhook', - properties: { response_code: 400 }, - }); - } - console.log('Err ', err); - return response - .status(400) - .json({ error: 'Something went wrong, please try again later!' }); - } - } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_save_webhook', - properties: { response_code: 401 }, - }); - } - return response.status(401).json({ error: 'Webhook url already exists!' }); - } - } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_save_webhook', - properties: { response_code: 404 }, - }); - } - return response.status(404).json({ error: 'User not found!' }); - } - } else { - return response.status(405).json({ error: 'Invalid API Token!' }); - } - } catch (err) { - console.log('Err ', err); - return response.status(400).json({ error: 'Something went wrong, please try again later!' }); - } -} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js deleted file mode 100644 index e0b8f28f0..000000000 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js +++ /dev/null @@ -1,100 +0,0 @@ -export default async function updateDocument(request, response) { - try { - const reqToken = request.headers['x-api-token']; - if (!reqToken) { - return response.status(400).json({ error: 'Please Provide API Token' }); - } - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('token', reqToken); - tokenQuery.include('userId'); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // Valid Token then proceed request - const allowedKeys = ['name', 'note', 'description', 'folderId', 'enableOTP', 'enableTour']; - const objectKeys = Object.keys(request.body); - const isValid = objectKeys.every(key => allowedKeys.includes(key)) && objectKeys.length > 0; - const parseUser = JSON.parse(JSON.stringify(token)); - const userPtr = { - __type: 'Pointer', - className: '_User', - objectId: parseUser.userId.objectId, - }; - if (isValid) { - const document = new Parse.Query('contracts_Document'); - document.equalTo('objectId', request.params.document_id); - document.equalTo('CreatedBy', userPtr); - document.include('ExtUserPtr.TenantId'); - const res = await document.first({ useMasterKey: true }); - if (res) { - const isArchive = res.get('IsArchive'); - if (isArchive && isArchive) { - return response.status(404).json({ message: 'Document not found!' }); - } else { - const document = Parse.Object.extend('contracts_Document'); - const updateQuery = new document(); - updateQuery.id = request.params.document_id; - if (request?.body?.name) { - updateQuery.set('Name', request?.body?.name); - } - if (request?.body?.note) { - updateQuery.set('Note', request?.body?.note); - } - if (request?.body?.description) { - updateQuery.set('Description', request?.body?.description); - } - if (request?.body?.folderId) { - updateQuery.set('Folder', { - __type: 'Pointer', - className: 'contracts_Document', - objectId: request?.body?.folderId, - }); - } - if (request.body?.enableOTP !== undefined) { - updateQuery.set('IsEnableOTP', request.body?.enableOTP); - } - if (request.body?.enableTour !== undefined) { - updateQuery.set('IsTourEnabled', request.body?.enableTour); - } - const updatedRes = await updateQuery.save(null, { useMasterKey: true }); - if (updatedRes) { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_update_document', - properties: { response_code: 200 }, - }); - } - return response.json({ - objectId: updatedRes.id, - updatedAt: updatedRes.get('updatedAt'), - }); - } - } - } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_update_document', - properties: { response_code: 404 }, - }); - } - return response.status(404).json({ error: 'Document not found!' }); - } - } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_update_document', - properties: { response_code: 400 }, - }); - } - return response.status(400).json({ error: 'Please provide valid field names!' }); - } - } else { - return response.status(405).json({ error: 'Invalid API Token!' }); - } - } catch (err) { - console.log('err ', err); - return response.status(400).json({ error: 'Something went wrong, please try again later!' }); - } -} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateFolder.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateFolder.js deleted file mode 100644 index 6038fe130..000000000 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateFolder.js +++ /dev/null @@ -1,67 +0,0 @@ -export default async function updateFolder(request, response) { - const apiToken = request.headers['x-api-token']; - const folderId = request.params.folder_id; - const name = request.body.folderName; - const parentFolderId = request.body.parentFolderId; - if (!apiToken) { - return response.status(400).json({ error: 'Please Provide API Token' }); - } - try { - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('token', apiToken); - tokenQuery.include('userId'); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // Valid Token then proceed request - const parseUser = JSON.parse(JSON.stringify(token)); - const userPtr = { - __type: 'Pointer', - className: '_User', - objectId: parseUser.userId.objectId, - }; - - const folderCls = new Parse.Query('contracts_Document'); - folderCls.equalTo('CreatedBy', userPtr); - folderCls.equalTo('objectId', folderId); - folderCls.equalTo('Type', 'Folder'); - folderCls.notEqualTo('IsArchive', true); - folderCls.include('ExtUserPtr.TenantId'); - const res = await folderCls.first({ useMasterKey: true }); - if (res) { - const updateFolder = new Parse.Object('contracts_Document'); - updateFolder.id = res.id; - updateFolder.set('Name', name); - if (parentFolderId) { - updateFolder.set('Folder', { - __type: 'Pointer', - className: 'contracts_Document', - objectId: parentFolderId, - }); - } - const updateRes = await updateFolder.save(null, { useMasterKey: true }); - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_update_folder', - properties: { response_code: 200 }, - }); - } - return response.json({ objectId: updateRes.id, updatedAt: updateRes.updatedAt }); - } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_update_folder', - properties: { response_code: 404 }, - }); - } - return response.status(404).json({ error: 'folder not found.' }); - } - } else { - return response.status(405).json({ error: 'Invalid API Token!' }); - } - } catch (err) { - console.log('err ', err); - return response.status(400).json({ error: 'Something went wrong, please try again later!' }); - } -} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js deleted file mode 100644 index 24df204a3..000000000 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js +++ /dev/null @@ -1,100 +0,0 @@ -export default async function updateTemplate(request, response) { - try { - const reqToken = request.headers['x-api-token']; - if (!reqToken) { - return response.status(400).json({ error: 'Please Provide API Token' }); - } - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('token', reqToken); - tokenQuery.include('userId'); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // Valid Token then proceed request - const allowedKeys = ['name', 'note', 'description', 'folderId', 'enableOTP', 'enableTour']; - const objectKeys = Object.keys(request.body); - const isValid = objectKeys.every(key => allowedKeys.includes(key)) && objectKeys.length > 0; - const parseUser = JSON.parse(JSON.stringify(token)); - const userPtr = { - __type: 'Pointer', - className: '_User', - objectId: parseUser.userId.objectId, - }; - if (isValid) { - const template = new Parse.Query('contracts_Template'); - template.equalTo('objectId', request.params.template_id); - template.equalTo('CreatedBy', userPtr); - template.include('ExtUserPtr.TenantId'); - const res = await template.first({ useMasterKey: true }); - if (res) { - const isArchive = res.get('IsArchive'); - if (isArchive && isArchive) { - return response.status(404).json({ message: 'Template not found!' }); - } else { - const template = Parse.Object.extend('contracts_Template'); - const updateQuery = new template(); - updateQuery.id = request.params.template_id; - if (request?.body?.name) { - updateQuery.set('Name', request?.body?.name); - } - if (request?.body?.note) { - updateQuery.set('Note', request?.body?.note); - } - if (request?.body?.description) { - updateQuery.set('Description', request?.body?.description); - } - if (request?.body?.folderId) { - updateQuery.set('Folder', { - __type: 'Pointer', - className: 'contracts_Template', - objectId: request?.body?.folderId, - }); - } - if (request.body?.enableOTP !== undefined) { - updateQuery.set('IsEnableOTP', request.body?.enableOTP); - } - if (request.body?.enableTour !== undefined) { - updateQuery.set('IsTourEnabled', request.body?.enableTour); - } - const updatedRes = await updateQuery.save(null, { useMasterKey: true }); - if (updatedRes) { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_update_template', - properties: { response_code: 200 }, - }); - } - return response.json({ - objectId: updatedRes.id, - updatedAt: updatedRes.get('updatedAt'), - }); - } - } - } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_update_template', - properties: { response_code: 404 }, - }); - } - return response.status(404).json({ error: 'Template not found!' }); - } - } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'api_update_template', - properties: { response_code: 400 }, - }); - } - return response.status(400).json({ error: 'Please provide valid field names!' }); - } - } else { - return response.status(405).json({ error: 'Invalid API Token!' }); - } - } catch (err) { - console.log('err ', err); - return response.status(400).json({ error: 'Something went wrong, please try again later!' }); - } -} diff --git a/apps/OpenSignServer/cloud/customRoute/validateSmtp.js b/apps/OpenSignServer/cloud/customRoute/validateSmtp.js deleted file mode 100644 index 220637b29..000000000 --- a/apps/OpenSignServer/cloud/customRoute/validateSmtp.js +++ /dev/null @@ -1,72 +0,0 @@ -import { createTransport } from 'nodemailer'; -import { appName } from '../../Utils.js'; -// Online Javascript Editor for free -// Write, Edit and Run your Javascript code using JS Online Compiler - -function generateOtpWithSum10() { - let otp = []; - let sum = 0; - - // First, generate 3 random digits (0-9) and add them to the sum - for (let i = 0; i < 3; i++) { - let digit = Math.floor(Math.random() * 10); - otp.push(digit); - sum += digit; - } - - // Calculate the last digit to ensure the sum equals 10 - let lastDigit = 10 - sum; - - // If the last digit is not valid (e.g., greater than 9), regenerate - if (lastDigit >= 0 && lastDigit <= 9) { - otp.push(lastDigit); - } else { - return generateOtpWithSum10(); // Recursively generate again - } - - return otp.join(''); -} - -export default async function validateSmtp(request, response) { - const host = request.body.host; - const port = request.body?.port?.toString(); - const username = request.body.username; - const password = request.body.password; - const secure = request.body?.secure; - const email = request.body?.email; - const otp = generateOtpWithSum10(); - // console.log('Generated OTP:', otp); - - try { - const smtpsecure = secure || port !== '465' ? false : true; - const transporterSMTP = createTransport({ - host: host, - port: port, - secure: smtpsecure, - auth: { user: username, pass: password }, - }); - const from = appName; - const mailsender = username; - const messageParams = { - from: from + ' <' + mailsender + '>', - to: email, - subject: `Your ${appName} SMTP credentials verification code`, - text: 'mail', - 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',>SMTP Verification Code</p></div><div style='padding:20px'><p style='font-family:system-ui;font-size:14px'>Your verification code is:</p><p style=' text-decoration: none; font-weight: bolder; color:blue;font-size:45px;margin:20px'>` + - otp + - '</p></div> </div> </div></body></html>', - }; - - const res = await transporterSMTP.sendMail(messageParams); - console.log('custom smtp transporter res: ', res?.response); - if (!res.err) { - response.status(200).json({ message: 'success' }); - } - } catch (err) { - console.log('err ', err); - const code = err?.responseCode || 400; - const message = err?.response || 'failed!'; - response.status(code).json({ error: message }); - } -} diff --git a/apps/OpenSignServer/cloud/main.js b/apps/OpenSignServer/cloud/main.js index 39b4cfacc..c8e1bce53 100644 --- a/apps/OpenSignServer/cloud/main.js +++ b/apps/OpenSignServer/cloud/main.js @@ -1,9 +1,7 @@ + import PDF from './parsefunction/pdf/PDF.js'; import sendmailv3 from './parsefunction/sendMailv3.js'; -import GoogleSign from './parsefunction/GoogleSign.js'; -import ZohoDetails from './parsefunction/ZohoDetails.js'; import usersignup from './parsefunction/usersignup.js'; -import FacebookSign from './parsefunction/FacebookSign.js'; import DocumentAftersave from './parsefunction/DocumentAftersave.js'; import ContactbookAftersave from './parsefunction/ContactBookAftersave.js'; import sendMailOTPv1 from './parsefunction/SendMailOTPv1.js'; @@ -13,86 +11,53 @@ import getUserDetails from './parsefunction/getUserDetails.js'; import getDocument from './parsefunction/getDocument.js'; import getDrive from './parsefunction/getDrive.js'; import getReport from './parsefunction/getReport.js'; -import generateApiToken from './parsefunction/generateApiToken.js'; -import getapitoken from './parsefunction/getapitoken.js'; import TemplateAfterSave from './parsefunction/TemplateAfterSave.js'; import GetTemplate from './parsefunction/GetTemplate.js'; -import savewebhook from './parsefunction/saveWebhook.js'; import callWebhook from './parsefunction/callWebhook.js'; -import SubscribeFree from './parsefunction/SubscribeFree.js'; import DocumentBeforesave from './parsefunction/DocumentBeforesave.js'; import TemplateBeforeSave from './parsefunction/TemplateBeforesave.js'; import DocumentBeforeFind from './parsefunction/DocumentAfterFind.js'; import TemplateAfterFind from './parsefunction/TemplateAfterFind.js'; import UserAfterFind from './parsefunction/UserAfterFInd.js'; import SignatureAfterFind from './parsefunction/SignatureAfterFind.js'; -import getInvoices from './parsefunction/getInvoices.js'; -import getPayments from './parsefunction/getPayments.js'; -import getSubscriptions from './parsefunction/getSubscriptions.js'; import TenantAterFind from './parsefunction/TenantAfterFind.js'; -import saveSubscription from './parsefunction/saveSubscription.js'; import VerifyEmail from './parsefunction/VerifyEmail.js'; import encryptedpdf from './parsefunction/encryptedPdf.js'; import { getSignedUrl } from './parsefunction/getSignedUrl.js'; import createBatchDocs from './parsefunction/createBatchDocs.js'; import linkContactToDoc from './parsefunction/linkContactToDoc.js'; -import CreatePublicTemplate from './parsefunction/CreatePublicTemplate.js'; -import GetPublicUserName from './parsefunction/GetPublicUserName.js'; -import GetPublicTemplate from './parsefunction/GetPublicTemplate.js'; -import ssoSignin from './parsefunction/ssoSignin.js'; import isextenduser from './parsefunction/isextenduser.js'; -import getUserByOrg from './parsefunction/getUserByOrg.js'; -import getUserListByOrg from './parsefunction/getUserListByOrg.js'; import TeamsAftersave from './parsefunction/TeamsAftersave.js'; -import SubscriptionAftersave from './parsefunction/SubscriptionAftersave.js'; -import PublicUserLinkContactToDoc from './parsefunction/PublicUserLinkContactToDoc.js'; -import GetLogoByDomain from './parsefunction/GetLogobyDomain.js'; +import GetLogoByDomain from './parsefunction/GetLogoByDomain.js'; import AddAdmin from './parsefunction/AddAdmin.js'; import CheckAdminExist from './parsefunction/CheckAdminExist.js'; import UpdateExistUserAsAdmin from './parsefunction/UpdateExistUserAsAdmin.js'; import Newsletter from './parsefunction/Newsletter.js'; -import getOrganizations from './parsefunction/getOrganizations.js'; -import addOrganization from './parsefunction/addOrganization.js'; -import updateOrganization from './parsefunction/updateOrganization.js'; import getTeams from './parsefunction/getTeams.js'; -import addTeam from './parsefunction/addTeam.js'; -import updateTeam from './parsefunction/updateTeam.js'; -import getOrgAdmins from './parsefunction/getOrgAdmins.js'; -import getAllUserTeamByOrg from './parsefunction/getAllUserTeamByOrg.js'; -import AllowedUsers from './parsefunction/AlllowedUsers.js'; -import BuyAddonUsers from './parsefunction/BuyAddonUsers.js'; -import ExtUserAftersave from './parsefunction/ExtUserAftersave.js'; -import ExtUserAfterdelete from './parsefunction/ExtUserAfterdelete.js'; -import AllowedCredits from './parsefunction/AllowedCredits.js'; -import BuyCredits from './parsefunction/BuyCredits.js'; import getContact from './parsefunction/getContact.js'; import updateContactTour from './parsefunction/updateContactTour.js'; import declinedocument from './parsefunction/declinedocument.js'; -import addcustomsmtp from './parsefunction/addcustomsmtp.js'; -import deactivateMailAdapter from './parsefunction/deactivateMailAdapter.js'; -import addFileAdapter from './parsefunction/addFileAdapter.js'; -import saveToFileAdapter from './parsefunction/saveToFileAdapter.js'; -import getFileAdapter from './parsefunction/getFileAdapter.js'; -import addPfxFile from './parsefunction/addPfxFile.js'; -import getPfxFile from './parsefunction/getPfxFile.js'; import getTenant from './parsefunction/getTenant.js'; import getSigners from './parsefunction/getSigners.js'; import saveFile from './parsefunction/saveFile.js'; import savecontact from './parsefunction/savecontact.js'; import isUserInContactBook from './parsefunction/isUserInContactBook.js'; import updateTourStatus from './parsefunction/updateTourStatus.js'; -import saveTemplate from './parsefunction/saveTemplate.js'; -import updateToPublicTemplate from './parsefunction/updateToPublicTemplate.js'; import updateSignatureType from './parsefunction/updatesignaturetype.js'; import updatePreferences from './parsefunction/updatePreferences.js'; +import createDuplicate from './parsefunction/createDuplicate.js'; +import createBatchContact from './parsefunction/createBatchContact.js'; +import generateCertificatebydocId from './parsefunction/generateCertificatebydocId.js'; +import fileUpload from './parsefunction/fileUpload.js'; +import getUserListByOrg from './parsefunction/getUserListByOrg.js'; +import editContact from './parsefunction/editContact.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); Parse.Cloud.afterSave('contracts_Contactbook', ContactbookAftersave); Parse.Cloud.afterSave('contracts_Template', TemplateAfterSave); Parse.Cloud.afterSave('contracts_Teams', TeamsAftersave); -Parse.Cloud.afterSave('contracts_Subscriptions', SubscriptionAftersave); -Parse.Cloud.afterSave('contracts_Users', ExtUserAftersave); // This beforeSave function triggers before an object is added or updated in the specified class, allowing for validation or modification. Parse.Cloud.beforeSave('contracts_Document', DocumentBeforesave); @@ -105,16 +70,10 @@ Parse.Cloud.afterFind('contracts_Template', TemplateAfterFind); Parse.Cloud.afterFind('contracts_Signature', SignatureAfterFind); Parse.Cloud.afterFind('partners_Tenant', TenantAterFind); -// This afterDelete function triggers after an object get deleted. -Parse.Cloud.afterDelete('contracts_Users', ExtUserAfterdelete); - // This define function creates a custom Cloud Function that can be called from the client-side, enabling custom business logic on the server. Parse.Cloud.define('signPdf', PDF); Parse.Cloud.define('sendmailv3', sendmailv3); -Parse.Cloud.define('googlesign', GoogleSign); -Parse.Cloud.define('zohodetails', ZohoDetails); Parse.Cloud.define('usersignup', usersignup); -Parse.Cloud.define('facebooksign', FacebookSign); Parse.Cloud.define('SendOTPMailV1', sendMailOTPv1); Parse.Cloud.define('AuthLoginAsMail', AuthLoginAsMail); Parse.Cloud.define('getUserId', getUserId); @@ -122,63 +81,34 @@ Parse.Cloud.define('getUserDetails', getUserDetails); Parse.Cloud.define('getDocument', getDocument); Parse.Cloud.define('getDrive', getDrive); Parse.Cloud.define('getReport', getReport); -Parse.Cloud.define('generateapitoken', generateApiToken); -Parse.Cloud.define('getapitoken', getapitoken); Parse.Cloud.define('getTemplate', GetTemplate); -Parse.Cloud.define('savewebhook', savewebhook); Parse.Cloud.define('callwebhook', callWebhook); -Parse.Cloud.define('freesubscription', SubscribeFree); -Parse.Cloud.define('getinvoices', getInvoices); -Parse.Cloud.define('getpayments', getPayments); -Parse.Cloud.define('getsubscriptions', getSubscriptions); -Parse.Cloud.define('savesubscription', saveSubscription); Parse.Cloud.define('verifyemail', VerifyEmail); Parse.Cloud.define('encryptedpdf', encryptedpdf); Parse.Cloud.define('getsignedurl', getSignedUrl); Parse.Cloud.define('batchdocuments', createBatchDocs); Parse.Cloud.define('linkcontacttodoc', linkContactToDoc); -Parse.Cloud.define('createpublictemplate', CreatePublicTemplate); -Parse.Cloud.define('getpublicusername', GetPublicUserName); -Parse.Cloud.define('getpublictemplate', GetPublicTemplate); -Parse.Cloud.define('ssosign', ssoSignin); Parse.Cloud.define('isextenduser', isextenduser); -Parse.Cloud.define('getuserbyorg', getUserByOrg); -Parse.Cloud.define('getuserlistbyorg', getUserListByOrg); -Parse.Cloud.define('publicuserlinkcontacttodoc', PublicUserLinkContactToDoc); Parse.Cloud.define('getlogobydomain', GetLogoByDomain); Parse.Cloud.define('addadmin', AddAdmin); Parse.Cloud.define('checkadminexist', CheckAdminExist); Parse.Cloud.define('updateuserasadmin', UpdateExistUserAsAdmin); Parse.Cloud.define('newsletter', Newsletter); -Parse.Cloud.define('getorganizations', getOrganizations); -Parse.Cloud.define('addorganization', addOrganization); -Parse.Cloud.define('updateorganization', updateOrganization); Parse.Cloud.define('getteams', getTeams); -Parse.Cloud.define('addteam', addTeam); -Parse.Cloud.define('updateteam', updateTeam); -Parse.Cloud.define('getorgadmins', getOrgAdmins); -Parse.Cloud.define('getalluserteambyorg', getAllUserTeamByOrg); -Parse.Cloud.define('allowedusers', AllowedUsers); -Parse.Cloud.define('buyaddonusers', BuyAddonUsers); -Parse.Cloud.define('allowedcredits', AllowedCredits); -Parse.Cloud.define('buycredits', BuyCredits); Parse.Cloud.define('getcontact', getContact); Parse.Cloud.define('updatecontacttour', updateContactTour); Parse.Cloud.define('declinedoc', declinedocument); -Parse.Cloud.define('addsmtp', addcustomsmtp); -Parse.Cloud.define('deactivatemailadapter', deactivateMailAdapter); -Parse.Cloud.define('savetofileadapter', saveToFileAdapter); -Parse.Cloud.define('addfileadapter', addFileAdapter); -Parse.Cloud.define('getfileadapter', getFileAdapter); -Parse.Cloud.define('addpfx', addPfxFile); -Parse.Cloud.define('getpfx', getPfxFile); Parse.Cloud.define('gettenant', getTenant); Parse.Cloud.define('getsigners', getSigners); -Parse.Cloud.define('savetemplate', saveTemplate); Parse.Cloud.define('savefile', saveFile); Parse.Cloud.define('savecontact', savecontact); Parse.Cloud.define('isuserincontactbook', isUserInContactBook); Parse.Cloud.define('updatetourstatus', updateTourStatus); -Parse.Cloud.define('updatetopublictemplate', updateToPublicTemplate); Parse.Cloud.define('updatesignaturetype', updateSignatureType); Parse.Cloud.define('updatepreferences', updatePreferences); +Parse.Cloud.define('createduplicate', createDuplicate); +Parse.Cloud.define('createbatchcontact', createBatchContact); +Parse.Cloud.define('generatecertificate', generateCertificatebydocId); +Parse.Cloud.define('fileupload', fileUpload); +Parse.Cloud.define('getuserlistbyorg', getUserListByOrg); +Parse.Cloud.define('editcontact', editContact); diff --git a/apps/OpenSignServer/cloud/parsefunction/AddAdmin.js b/apps/OpenSignServer/cloud/parsefunction/AddAdmin.js index e24cdcd3c..8e239fa9d 100644 --- a/apps/OpenSignServer/cloud/parsefunction/AddAdmin.js +++ b/apps/OpenSignServer/cloud/parsefunction/AddAdmin.js @@ -5,51 +5,55 @@ const APPID = process.env.APP_ID; const masterKEY = process.env.MASTER_KEY; async function addTeamAndOrg(extUser) { try { - const orgCls = new Parse.Object('contracts_Organizations'); - orgCls.set('Name', extUser.Company); - orgCls.set('IsActive', true); - orgCls.set('ExtUserId', { - __type: 'Pointer', - className: 'contracts_Users', - objectId: extUser?.objectId, - }); - orgCls.set('CreatedBy', { - __type: 'Pointer', - className: '_User', - objectId: extUser?.UserId?.objectId, - }); - orgCls.set('TenantId', { - __type: 'Pointer', - className: 'partners_Tenant', - objectId: extUser?.TenantId?.objectId, - }); - - const orgRes = await orgCls.save(null, { useMasterKey: true }); - const teamCls = new Parse.Object('contracts_Teams'); - teamCls.set('Name', 'All Users'); - teamCls.set('OrganizationId', { - __type: 'Pointer', - className: 'contracts_Organizations', - objectId: orgRes.id, - }); - teamCls.set('IsActive', true); - const teamRes = await teamCls.save(null, { useMasterKey: true }); - const updateUser = new Parse.Object('contracts_Users'); - updateUser.id = extUser.objectId; - updateUser.set('UserRole', 'contracts_Admin'); - updateUser.set('OrganizationId', { - __type: 'Pointer', - className: 'contracts_Organizations', - objectId: orgRes.id, - }); - updateUser.set('TeamIds', [ - { + const extUserCls = new Parse.Query('contracts_Users'); + const updateUser = await extUserCls.get(extUser.objectId, { useMasterKey: true }); + if (updateUser && !updateUser?.get('OrganizationId')) { + const orgCls = new Parse.Object('contracts_Organizations'); + orgCls.set('Name', extUser.Company); + orgCls.set('IsActive', true); + orgCls.set('ExtUserId', { __type: 'Pointer', - className: 'contracts_Teams', - objectId: teamRes.id, - }, - ]); - const extUserRes = await updateUser.save(null, { useMasterKey: true }); + className: 'contracts_Users', + objectId: extUser?.objectId, + }); + orgCls.set('CreatedBy', { + __type: 'Pointer', + className: '_User', + objectId: extUser?.UserId?.objectId, + }); + orgCls.set('TenantId', { + __type: 'Pointer', + className: 'partners_Tenant', + objectId: extUser?.TenantId?.objectId, + }); + + const orgRes = await orgCls.save(null, { useMasterKey: true }); + const teamCls = new Parse.Object('contracts_Teams'); + teamCls.set('Name', 'All Users'); + teamCls.set('OrganizationId', { + __type: 'Pointer', + className: 'contracts_Organizations', + objectId: orgRes.id, + }); + teamCls.set('IsActive', true); + const teamRes = await teamCls.save(null, { useMasterKey: true }); + // const updateUser = new Parse.Object('contracts_Users'); + // updateUser.id = extUser.objectId; + updateUser.set('UserRole', 'contracts_Admin'); + updateUser.set('OrganizationId', { + __type: 'Pointer', + className: 'contracts_Organizations', + objectId: orgRes.id, + }); + updateUser.set('TeamIds', [ + { + __type: 'Pointer', + className: 'contracts_Teams', + objectId: teamRes.id, + }, + ]); + const extUserRes = await updateUser.save(null, { useMasterKey: true }); + } } catch (err) { console.log('err in add team, role, org', err); } @@ -94,7 +98,6 @@ async function saveUser(userDetails) { } export default async function AddAdmin(request) { const userDetails = request.params.userDetails; - // const subscription = request.params.subscription; const user = await saveUser(userDetails); try { @@ -167,8 +170,10 @@ export default async function AddAdmin(request) { if (userDetails && userDetails.jobTitle) { newObj.set('JobTitle', userDetails.jobTitle); } + if (userDetails?.timezone) { + newObj.set('Timezone', userDetails?.timezone); + } const extRes = await newObj.save(null, { useMasterKey: true }); - // if (subscription) { const extUser = { objectId: extRes.id, Name: userDetails.name, @@ -181,8 +186,6 @@ export default async function AddAdmin(request) { JobTitle: userDetails.jobTitle, }; await addTeamAndOrg(extUser); - // await saveSubscription(extRes.id, user.id, tenantRes.id, subscription); - // } return { message: 'User sign up', sessionToken: user.sessionToken }; } } catch (err) { diff --git a/apps/OpenSignServer/cloud/parsefunction/AlllowedUsers.js b/apps/OpenSignServer/cloud/parsefunction/AlllowedUsers.js deleted file mode 100644 index bcca9951b..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/AlllowedUsers.js +++ /dev/null @@ -1,48 +0,0 @@ -export default async function AllowedUsers(request) { - if (!request?.user) { - throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.'); - } - try { - const extUser = new Parse.Query('contracts_Users'); - extUser.equalTo('UserId', { - __type: 'Pointer', - className: '_User', - objectId: request.user.id, - }); - const resExtUser = await extUser.first({ useMasterKey: true }); - if (resExtUser) { - const _resExtUser = JSON.parse(JSON.stringify(resExtUser)); - const subscription = new Parse.Query('contracts_Subscriptions'); - subscription.equalTo('TenantId', { - __type: 'Pointer', - className: 'partners_Tenant', - objectId: _resExtUser.TenantId.objectId, - }); - subscription.include('ExtUserPtr'); - const resSub = await subscription.first({ useMasterKey: true }); - if (resSub) { - const _resSub = JSON.parse(JSON.stringify(resSub)); - const count = _resSub?.UsersCount || 0; - if (count > 0) { - const allowedUser = resSub.get('AllowedUsers') || 0; - const remainUsers = allowedUser - count; - if (remainUsers > 0) { - return remainUsers; - } else { - return 0; - } - } else { - const alloweduser = resSub.get('AllowedUsers') || 0; - return alloweduser; - } - } - } else { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.'); - } - } catch (err) { - console.log('err in allowedusers', err); - const code = err?.code || 400; - const msg = err?.message || 'Something went wrong.'; - throw new Parse.Error(code, msg); - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/AllowedCredits.js b/apps/OpenSignServer/cloud/parsefunction/AllowedCredits.js deleted file mode 100644 index dc9dfe1cc..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/AllowedCredits.js +++ /dev/null @@ -1,69 +0,0 @@ -import { parseJwt } from '../../Utils.js'; -import jwt from 'jsonwebtoken'; -async function checkCredits(userId) { - const extUser = new Parse.Query('contracts_Users'); - extUser.equalTo('UserId', { - __type: 'Pointer', - className: '_User', - objectId: userId, - }); - const resExtUser = await extUser.first({ useMasterKey: true }); - if (resExtUser) { - const _resExtUser = JSON.parse(JSON.stringify(resExtUser)); - const subscription = new Parse.Query('contracts_Subscriptions'); - subscription.equalTo('TenantId', { - __type: 'Pointer', - className: 'partners_Tenant', - objectId: _resExtUser.TenantId.objectId, - }); - subscription.include('ExtUserPtr'); - const resSub = await subscription.first({ useMasterKey: true }); - if (resSub) { - const _resSub = JSON.parse(JSON.stringify(resSub)); - const AllowedCredits = _resSub?.AllowedCredits || 0; - const AddonCredits = _resSub?.AddonCredits || 0; - return { allowedcredits: AllowedCredits, addoncredits: AddonCredits }; - } - } else { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.'); - } -} -export default async function AllowedCredits(request) { - const jwttoken = request?.headers?.jwttoken || ''; - - try { - if (request?.user) { - return await checkCredits(request.user.id); - } else if (jwttoken) { - const jwtDecode = parseJwt(jwttoken); - if (jwtDecode?.user_email) { - const userCls = new Parse.Query(Parse.User); - userCls.equalTo('email', jwtDecode?.user_email); - const userRes = await userCls.first({ useMasterKey: true }); - const userId = userRes?.id; - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('userId', { - __type: 'Pointer', - className: '_User', - objectId: userId, - }); - const appRes = await tokenQuery.first({ useMasterKey: true }); - const decoded = jwt.verify(jwttoken, appRes?.get('token')); - if (decoded?.user_email) { - return await checkCredits(userId); - } else { - throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Invalid token.'); - } - } else { - throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Invalid token.'); - } - } else { - throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.'); - } - } catch (err) { - console.log('err in allowedCredits', err); - const code = err?.code || 400; - const msg = err?.message || 'Something went wrong.'; - throw new Parse.Error(code, msg); - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/BuyAddonUsers.js b/apps/OpenSignServer/cloud/parsefunction/BuyAddonUsers.js deleted file mode 100644 index 4281ab9d4..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/BuyAddonUsers.js +++ /dev/null @@ -1,121 +0,0 @@ -import axios from 'axios'; -import { planCredits } from '../../Utils.js'; -export default async function BuyAddonUsers(request) { - const users = request.params.users; - if (!request?.user) { - throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.'); - } - if (users) { - try { - const extUser = new Parse.Query('contracts_Users'); - extUser.equalTo('UserId', { - __type: 'Pointer', - className: '_User', - objectId: request.user.id, - }); - const resExtUser = await extUser.first({ useMasterKey: true }); - if (resExtUser) { - const _resExtUser = JSON.parse(JSON.stringify(resExtUser)); - const subscription = new Parse.Query('contracts_Subscriptions'); - subscription.equalTo('TenantId', { - __type: 'Pointer', - className: 'partners_Tenant', - objectId: _resExtUser.TenantId.objectId, - }); - subscription.include('ExtUserPtr'); - const resSub = await subscription.first({ useMasterKey: true }); - if (resSub) { - const _resSub = JSON.parse(JSON.stringify(resSub)); - // Define the URL - const url = 'https://accounts.zoho.in/oauth/v2/token'; - - // Convert the data to x-www-form-urlencoded format - const formData = new URLSearchParams(); - formData.append('refresh_token', process.env.ZOHO_REFRESH_TOKEN); - formData.append('client_id', process.env.ZOHO_CLIENT_ID); - formData.append('client_secret', process.env.ZOHO_CLIENT_SECRET); - formData.append('redirect_uri', process.env.ZOHO_REDIRECT_URI); - formData.append('grant_type', 'refresh_token'); - - const headers = { 'Content-Type': 'application/x-www-form-urlencoded' }; - // Make the POST request using Axios - const res = await axios.post(url, formData, { headers }); - if (res.data.access_token) { - const subscriptionId = _resSub.SubscriptionId; - const price = _resSub?.SubscriptionDetails?.data?.subscription?.plan?.price; - const plan_code = _resSub?.SubscriptionDetails?.data?.subscription?.plan?.plan_code; - const addonsArr = _resSub?.SubscriptionDetails?.data?.subscription?.addons || []; - let addon = 0; - if (addonsArr?.length > 0) { - let allowedUsersMonthly = 0; - let allowedUsersYearly = 0; - addonsArr?.forEach(item => { - if (item.addon_code === 'extra-teams-users-monthly') { - allowedUsersMonthly += item.quantity; - } else if (item.addon_code === 'extra-teams-users-yearly') { - allowedUsersYearly += item.quantity; - } else if (item.addon_code === 'extra-users') { - allowedUsersMonthly += item.quantity; - } - }); - if (allowedUsersMonthly > 0 || allowedUsersYearly > 0) { - addon = allowedUsersMonthly + allowedUsersYearly; - } - } - const quantity = parseInt(users) + parseInt(addon); - const addoncode = plan_code.includes('yearly') - ? 'extra-teams-users-yearly' - : 'extra-teams-users-monthly'; - const data = JSON.stringify({ - plan: { plan_code: plan_code }, - addons: [ - { - addon_code: addoncode, - addon_description: 'Extra users', - price: price, - quantity: quantity, - }, - ], - }); - const updatedSubscription = await axios.put( - 'https://www.zohoapis.in/billing/v1/subscriptions/' + subscriptionId, - data, - { - headers: { - Authorization: 'Zoho-oauthtoken ' + res.data.access_token, - 'X-com-zoho-subscriptions-organizationid': process.env.ZOHO_BILLING_ORG_ID, - }, - } - ); - const subscriptionInfo = { data: updatedSubscription.data }; - const allowedUsers = quantity + 1; - const existAllowedCredits = _resSub?.AllowedCredits || 0; - const credits = resSub?.PlanCredits || planCredits[plan_code]; - const newAllowedCredits = users * credits; - const totalCredits = existAllowedCredits + newAllowedCredits; - const updateSub = new Parse.Object('contracts_Subscriptions'); - updateSub.id = resSub.id; - updateSub.set('SubscriptionDetails', subscriptionInfo); - updateSub.set('AllowedUsers', allowedUsers); - updateSub.set('AllowedCredits', totalCredits); - const resupdateSub = await updateSub.save(null, { useMasterKey: true }); - return { status: 'success', addon: allowedUsers }; - } else { - throw new Parse.Error('400', 'Invalid access token.'); - } - } - } else { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.'); - } - } catch (err) { - const code = err?.response?.data?.code || err?.response?.status || err?.code || 400; - const msg = - err?.response?.data?.error || - err?.response?.data || - err?.message || - 'Something went wrong.'; - console.log('err in buyaddon', code, msg); - throw new Parse.Error(code, msg); - } - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/BuyCredits.js b/apps/OpenSignServer/cloud/parsefunction/BuyCredits.js deleted file mode 100644 index c33134cc2..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/BuyCredits.js +++ /dev/null @@ -1,92 +0,0 @@ -import axios from 'axios'; -export default async function BuyCredits(request) { - const credits = request.params.credits; - if (!request?.user) { - throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.'); - } - if (credits) { - try { - const extUser = new Parse.Query('contracts_Users'); - extUser.equalTo('UserId', { - __type: 'Pointer', - className: '_User', - objectId: request.user.id, - }); - const resExtUser = await extUser.first({ useMasterKey: true }); - if (resExtUser) { - const _resExtUser = JSON.parse(JSON.stringify(resExtUser)); - const subscription = new Parse.Query('contracts_Subscriptions'); - subscription.equalTo('TenantId', { - __type: 'Pointer', - className: 'partners_Tenant', - objectId: _resExtUser.TenantId.objectId, - }); - subscription.include('ExtUserPtr'); - const resSub = await subscription.first({ useMasterKey: true }); - if (resSub) { - const _resSub = JSON.parse(JSON.stringify(resSub)); - // Define the URL - const url = 'https://accounts.zoho.in/oauth/v2/token'; - - // Convert the data to x-www-form-urlencoded format - const formData = new URLSearchParams(); - formData.append('refresh_token', process.env.ZOHO_REFRESH_TOKEN); - formData.append('client_id', process.env.ZOHO_CLIENT_ID); - formData.append('client_secret', process.env.ZOHO_CLIENT_SECRET); - formData.append('redirect_uri', process.env.ZOHO_REDIRECT_URI); - formData.append('grant_type', 'refresh_token'); - - const headers = { 'Content-Type': 'application/x-www-form-urlencoded' }; - - // Make the POST request using Axios - const res = await axios.post(url, formData, { headers }); - if (res.data.access_token) { - const subscriptionId = _resSub.SubscriptionId; - const plan_code = _resSub?.SubscriptionDetails?.data?.subscription?.plan?.plan_code; - const quantity = parseInt(credits); - const addoncode = 'addon-credits'; - const data = JSON.stringify({ - plan: { plan_code: plan_code }, - addons: [ - { addon_code: addoncode, addon_description: 'addon credits', quantity: quantity }, - ], - }); - const creditsUrl = `https://www.zohoapis.in/billing/v1/subscriptions/${subscriptionId}/buyonetimeaddon`; - const resCredits = await axios.post(creditsUrl, data, { - headers: { - Authorization: 'Zoho-oauthtoken ' + res.data.access_token, - 'X-com-zoho-subscriptions-organizationid': process.env.ZOHO_BILLING_ORG_ID, - }, - }); - // console.log('resCredits ', resCredits.data); - if (resCredits.data) { - const existAddonCredits = _resSub?.AddonCredits ? _resSub.AddonCredits : 0; - const addonCredits = existAddonCredits + quantity; - const updateSub = new Parse.Object('contracts_Subscriptions'); - updateSub.id = resSub.id; - updateSub.set('AddonCredits', addonCredits); - const resupdateSub = await updateSub.save(null, { useMasterKey: true }); - // console.log('resupdateSub ', resupdateSub); - return { status: 'success', addon: quantity }; - } - } else { - throw new Parse.Error('400', 'Invalid access token.'); - } - } - } else { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.'); - } - } catch (err) { - const code = err?.response?.data?.code || err?.response?.status || err?.code || 400; - const msg = - err?.response?.data?.error || - err?.response?.data || - err?.message || - 'Something went wrong.'; - console.log('err in Buyaddonusers', code, msg); - throw new Parse.Error(code, msg); - } - } else { - throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide parameters.'); - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/ContactBookAftersave.js b/apps/OpenSignServer/cloud/parsefunction/ContactBookAftersave.js index fa476e60f..d86dc344b 100644 --- a/apps/OpenSignServer/cloud/parsefunction/ContactBookAftersave.js +++ b/apps/OpenSignServer/cloud/parsefunction/ContactBookAftersave.js @@ -3,22 +3,66 @@ async function ContactbookAftersave(request) { you can check as follows */ if (!request.original) { const user = request.user; - - // Retrieve the current ACL - const acl = new Parse.ACL(); - - // Ensure the current user has read access - if (acl && request?.user) { - const object = request.object; - acl.setReadAccess(user, true); - acl.setWriteAccess(user, true); - acl.setReadAccess(object.get('UserId'), true); - acl.setWriteAccess(object.get('UserId'), true); + const object = request.object; + if (object.get('UserId')) { + // Retrieve the current ACL + const acl = new Parse.ACL(); + // Ensure the current user has read access + if (acl && request?.user) { + const object = request.object; + acl.setReadAccess(user, true); + acl.setWriteAccess(user, true); + acl.setReadAccess(object.get('UserId'), true); + acl.setWriteAccess(object.get('UserId'), true); - object.setACL(acl); - object.set('IsDeleted', false) - // Continue saving the object - return object.save(null, { useMasterKey: true }); + object.setACL(acl); + object.set('IsDeleted', false); + // Continue saving the object + return object.save(null, { useMasterKey: true }); + } + } else { + const Name = object.get('Name'); + const Email = object.get('Email'); + const Phone = object.get('Phone'); + try { + const _users = Parse.Object.extend('User'); + const _user = new _users(); + _user.set('name', Name); + _user.set('username', Email); + _user.set('email', Email); + _user.set('password', Email); + if (Email) { + _user.set('phone', Phone); + } + const user = await _user.save(); + if (user) { + object.set('UserId', user); + const acl = object.getACL() || new Parse.ACL(); + acl.setReadAccess(user.id, true); + acl.setWriteAccess(user.id, true); + object.setACL(acl); + await object.save(null, { useMasterKey: true }); + // console.log('res update new user with contac', res); + } + } catch (err) { + // console.log('err ', err); + if (err.code === 202) { + const userQuery = new Parse.Query(Parse.User); + userQuery.equalTo('email', Email); + const userRes = await userQuery.first({ useMasterKey: true }); + object.set('UserId', { + __type: 'Pointer', + className: '_User', + objectId: userRes.id, + }); + const acl = object.getACL() || new Parse.ACL(); + acl.setReadAccess(userRes.id, true); + acl.setWriteAccess(userRes.id, true); + object.setACL(acl); + await object.save(null, { useMasterKey: true }); + // console.log('res update existing user with contact', res); + } + } } } else { console.log('Object being update'); diff --git a/apps/OpenSignServer/cloud/parsefunction/CreatePublicTemplate.js b/apps/OpenSignServer/cloud/parsefunction/CreatePublicTemplate.js deleted file mode 100644 index 1831b9f47..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/CreatePublicTemplate.js +++ /dev/null @@ -1,41 +0,0 @@ -export default async function CreatePublicTemplate(request) { - const templateid = request.params.templateid; - const ispublic = request.params.ispublic; - const publicrole = request.params.publicrole; - try { - if (!request?.user) { - throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.'); - } else { - const userId = request?.user && request?.user?.id; - if (templateid) { - const updateTemplate = new Parse.Object('contracts_Template'); - updateTemplate.id = templateid; - if (ispublic) { - updateTemplate.set('PublicRole', publicrole); - } - updateTemplate.set('IsPublic', ispublic); - const Acl = new Parse.ACL(); - if (ispublic) { - Acl.setPublicReadAccess(true); - } - Acl.setReadAccess(userId, true); - Acl.setWriteAccess(userId, true); - updateTemplate.setACL(Acl); - const savedObject = await updateTemplate.save(null, { useMasterKey: true }); - const res = savedObject.toJSON(); - if (res) { - return { - status: 'success', - }; - } - } else { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Please provide required parameters!'); - } - } - } catch (err) { - const code = err.code || 400; - const msg = err.message; - const error = new Parse.Error(code, msg); - throw error; - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/DocumentAfterFind.js b/apps/OpenSignServer/cloud/parsefunction/DocumentAfterFind.js index 0a4bcac31..16f7bf2af 100644 --- a/apps/OpenSignServer/cloud/parsefunction/DocumentAfterFind.js +++ b/apps/OpenSignServer/cloud/parsefunction/DocumentAfterFind.js @@ -1,31 +1,53 @@ import { useLocal } from '../../Utils.js'; -import getPresignedUrl from './getSignedUrl.js'; +import getPresignedUrl, { presignedlocalUrl } from './getSignedUrl.js'; async function DocumentAfterFind(request) { if (request.objects.length === 1) { if (request.objects) { const obj = request.objects[0]; - const FileAdapterId = obj?.get('FileAdapterId') || ''; - if (FileAdapterId || useLocal !== 'true') { + if ( + useLocal !== 'true' + ) { const SignedUrl = obj?.get('SignedUrl') && obj?.get('SignedUrl'); const Url = obj?.get('URL') && obj?.get('URL'); const certificateUrl = obj.get('CertificateUrl') && obj.get('CertificateUrl'); - let fileAdapter = {}; - if (FileAdapterId) { - const tenantId = obj?.get('ExtUserPtr')?.get('TenantId'); - if (tenantId) { - const _tenantId = JSON.parse(JSON.stringify(obj?.get('ExtUserPtr')?.get('TenantId'))); - fileAdapter = _tenantId?.FileAdapters?.find(x => x.id === FileAdapterId) || {}; - } - } if (SignedUrl) { - obj.set('SignedUrl', getPresignedUrl(SignedUrl, fileAdapter)); + obj.set( + 'SignedUrl', + getPresignedUrl( + SignedUrl, + ) + ); } if (Url) { - obj.set('URL', getPresignedUrl(Url, fileAdapter)); + obj.set( + 'URL', + getPresignedUrl( + Url, + ) + ); } if (certificateUrl) { - obj.set('CertificateUrl', getPresignedUrl(certificateUrl, fileAdapter)); + obj.set( + 'CertificateUrl', + getPresignedUrl( + certificateUrl, + ) + ); + } + return [obj]; + } else if (useLocal == 'true') { + const SignedUrl = obj?.get('SignedUrl') && obj?.get('SignedUrl'); + const Url = obj?.get('URL') && obj?.get('URL'); + const certificateUrl = obj.get('CertificateUrl') && obj.get('CertificateUrl'); + if (SignedUrl) { + obj.set('SignedUrl', presignedlocalUrl(SignedUrl)); + } + if (Url) { + obj.set('URL', presignedlocalUrl(Url)); + } + if (certificateUrl) { + obj.set('CertificateUrl', presignedlocalUrl(certificateUrl)); } return [obj]; } diff --git a/apps/OpenSignServer/cloud/parsefunction/ExtUserAfterdelete.js b/apps/OpenSignServer/cloud/parsefunction/ExtUserAfterdelete.js deleted file mode 100644 index 3a7fc4bbd..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/ExtUserAfterdelete.js +++ /dev/null @@ -1,31 +0,0 @@ -async function ExtUserAfterdelete(request) { - try { - const extUser = request.object; - const tenantId = extUser.get('TenantId')?.id; - const subscription = new Parse.Query('contracts_Subscriptions'); - subscription.equalTo('TenantId', { - __type: 'Pointer', - className: 'partners_Tenant', - objectId: tenantId, - }); - const resSub = await subscription.first({ useMasterKey: true }); - if (resSub) { - const updateSub = new Parse.Object('contracts_Subscriptions'); - updateSub.id = resSub.id; - if (resSub?.get('UsersCount') > 0) { - updateSub.decrement('UsersCount', 1); - } else { - updateSub.decrement('UsersCount', 0); - } - updateSub.save(null, { useMasterKey: true }); - } else { - const addSub = new Parse.Object('contracts_Subscriptions'); - addSub.set('UsersCount', 0); - addSub.save(null, { useMasterKey: true }); - } - } catch (err) { - console.log('err in extuser afterdelete', err); - } -} - -export default ExtUserAfterdelete; diff --git a/apps/OpenSignServer/cloud/parsefunction/ExtUserAftersave.js b/apps/OpenSignServer/cloud/parsefunction/ExtUserAftersave.js deleted file mode 100644 index cde28c232..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/ExtUserAftersave.js +++ /dev/null @@ -1,44 +0,0 @@ -async function ExtUserAftersave(request) { - try { - if (!request.original) { - const extUser = request.object; - const tenantId = extUser.get('TenantId')?.id; - const subscription = new Parse.Query('contracts_Subscriptions'); - subscription.equalTo('TenantId', { - __type: 'Pointer', - className: 'partners_Tenant', - objectId: tenantId, - }); - const resSub = await subscription.first({ useMasterKey: true }); - if (resSub) { - const updateSub = new Parse.Object('contracts_Subscriptions'); - updateSub.id = resSub.id; - updateSub.increment('UsersCount', 1); - await updateSub.save(null, { useMasterKey: true }); - } else { - const addSub = new Parse.Object('contracts_Subscriptions'); - addSub.set('UsersCount', 1); - addSub.set('ExtUserPtr', { - __type: 'Pointer', - className: 'contracts_Users', - objectId: extUser.id, - }); - addSub.set('CreatedBy', { - __type: 'Pointer', - className: '_User', - objectId: extUser.get('UserId').id, - }); - addSub.set('TenantId', { - __type: 'Pointer', - className: 'partners_Tenant', - objectId: extUser.get('TenantId').id, - }); - await addSub.save(null, { useMasterKey: true }); - } - } - } catch (err) { - console.log('err in extuser aftersave', err); - } -} - -export default ExtUserAftersave; diff --git a/apps/OpenSignServer/cloud/parsefunction/FacebookSign.js b/apps/OpenSignServer/cloud/parsefunction/FacebookSign.js deleted file mode 100644 index fbe520806..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/FacebookSign.js +++ /dev/null @@ -1,93 +0,0 @@ -import axios from 'axios'; -import { cloudServerUrl } from '../../Utils.js'; - -const serverUrl = cloudServerUrl; //process.env.SERVER_URL; -const APPID = process.env.APP_ID; -const masterKEY = process.env.MASTER_KEY; - -/** - * FacebookSign is function which is used to sign up/sign in with google - * @param Id It is google Id - * @param AccessToken It is facebook Access Token - * @param Email It is user's email with user sign in/sign up - * @param Phone It is user's Phone number - * @param Name It is user's Name - * @returns if success {email, message, sessiontoken} else on reject {message} - */ - -export default async function FacebookSign(request) { - const userGoogleId = request.params.Id; - const userAccessToken = request.params.AccessToken; - const userEmail = request.params.Email; - const phone = request.params?.Phone || ''; - const name = request.params.Name; - const authData = { - facebook: { id: userGoogleId, access_token: userAccessToken }, - }; - const userQuery = new Parse.Query(Parse.User); - userQuery.equalTo('email', userEmail); - const res = await userQuery.first({ useMasterKey: true }); - if (res) { - try { - const SignIn = await axios.put( - serverUrl + '/users/' + res.id, - { authData: authData }, - { - headers: { - 'X-Parse-Application-Id': APPID, - 'X-Parse-Master-key': masterKEY, - }, - } - ); - - if (SignIn.data) { - // console.log("google Sign in", SignIn); - const sessiontoken = SignIn.data.sessionToken; - console.log('Google sessiontoken', sessiontoken); - return { - email: userEmail, - message: 'User Sign In', - sessiontoken: sessiontoken, - }; - } - } catch (err) { - console.log('err in user google sign in', err); - return { message: 'Internal server error' }; - } - } else { - // console.log("in sign up condition"); - try { - const SignUp = await axios.post( - serverUrl + '/users', - { - authData: authData, - username: userEmail, - email: userEmail, - phone: phone, - name: name, - }, - { - headers: { - 'X-Parse-Application-Id': APPID, - 'X-Parse-Revocable-Session': '1', - }, - } - ); - - // console.log("SignUp", SignUp); - - if (SignUp.data) { - const sessiontoken = SignUp.data.sessionToken; - const payload = { - email: userEmail, - message: 'User Sign Up', - sessiontoken: sessiontoken, - }; - return payload; - } - } catch (err) { - console.log('err in user google sign up', err); - return { message: 'Internal server err' }; - } - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/GetLogobyDomain.js b/apps/OpenSignServer/cloud/parsefunction/GetLogoByDomain.js similarity index 100% rename from apps/OpenSignServer/cloud/parsefunction/GetLogobyDomain.js rename to apps/OpenSignServer/cloud/parsefunction/GetLogoByDomain.js diff --git a/apps/OpenSignServer/cloud/parsefunction/GetPublicTemplate.js b/apps/OpenSignServer/cloud/parsefunction/GetPublicTemplate.js deleted file mode 100644 index 51e075d6e..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/GetPublicTemplate.js +++ /dev/null @@ -1,51 +0,0 @@ -async function GetPublicTemplate(request) { - try { - const username = request.params.username; - if (username) { - const extUserQuery = new Parse.Query('contracts_Users'); - extUserQuery.equalTo('UserName', username); - const userRes = await extUserQuery.first({ useMasterKey: true }); - const userId = userRes.get('UserId').id; - - //get _user details - const userQuery = new Parse.Query(Parse.User); - const user = await userQuery.get(userId, { useMasterKey: true }); - if (userId) { - const templatQuery = new Parse.Query('contracts_Template'); - templatQuery.equalTo('CreatedBy', { - __type: 'Pointer', - className: '_User', - objectId: userId, - }); - templatQuery.descending('updatedAt'); - templatQuery.equalTo('IsPublic', true); - templatQuery.notEqualTo('IsArchive', true); - templatQuery.include('ExtUserPtr.TenantId'); - const getTemplate = await templatQuery.find({ useMasterKey: true }); - const extcls = new Parse.Query('contracts_Users'); - extcls.equalTo('Email', user.get('email')); - const res = await extcls.first({ useMasterKey: true }); - if (res) { - const _res = JSON.parse(JSON.stringify(res)); - return { - template: getTemplate, - user: user, - extend_User: { Tagline: _res?.Tagline || '', SearchIndex: _res?.SearchIndex || '' }, - }; - } else { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Template not found'); - } - } else { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User does not exist'); - } - } else { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Please provide required parameters!'); - } - } catch (err) { - const code = err.code || 400; - const msg = err.message; - const error = new Parse.Error(code, msg); - throw error; - } -} -export default GetPublicTemplate; diff --git a/apps/OpenSignServer/cloud/parsefunction/GetPublicUserName.js b/apps/OpenSignServer/cloud/parsefunction/GetPublicUserName.js deleted file mode 100644 index 94b08a330..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/GetPublicUserName.js +++ /dev/null @@ -1,23 +0,0 @@ -async function GetPublicUserName(request) { - try { - if (!request?.user) { - throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.'); - } else { - const username = request.params.username; - if (username) { - const userQuery = new Parse.Query('contracts_Users'); - userQuery.equalTo('UserName', username); - const res = await userQuery.first({ useMasterKey: true }); - return res; - } else { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Please provide required parameters!'); - } - } - } catch (err) { - const code = err.code || 400; - const msg = err.message; - const error = new Parse.Error(code, msg); - throw error; - } -} -export default GetPublicUserName; diff --git a/apps/OpenSignServer/cloud/parsefunction/GetTemplate.js b/apps/OpenSignServer/cloud/parsefunction/GetTemplate.js index 1c69b037d..648a927c9 100644 --- a/apps/OpenSignServer/cloud/parsefunction/GetTemplate.js +++ b/apps/OpenSignServer/cloud/parsefunction/GetTemplate.js @@ -1,45 +1,17 @@ import axios from 'axios'; -import { cloudServerUrl, parseJwt } from '../../Utils.js'; -import jwt from 'jsonwebtoken'; +import { + cloudServerUrl, +} from '../../Utils.js'; export default async function GetTemplate(request) { const serverUrl = cloudServerUrl; //process.env.SERVER_URL; const templateId = request.params.templateId; const ispublic = request.params.ispublic; - const jwttoken = request.headers?.jwttoken; const sessiontoken = request.headers?.sessiontoken; try { if (!ispublic) { let userEmail; - if (jwttoken) { - try { - const jwtDecode = parseJwt(jwttoken); - if (jwtDecode?.user_email) { - const userCls = new Parse.Query(Parse.User); - userCls.equalTo('email', jwtDecode?.user_email); - const userRes = await userCls.first({ useMasterKey: true }); - const userId = userRes?.id; - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('userId', { - __type: 'Pointer', - className: '_User', - objectId: userId, - }); - const appRes = await tokenQuery.first({ useMasterKey: true }); - const decoded = jwt.verify(jwttoken, appRes?.get('token')); - if (decoded?.user_email) { - userEmail = decoded?.user_email; - } else { - return { error: 'Invalid token!' }; - } - } else { - return { error: 'Invalid token!' }; - } - } catch (err) { - console.log('err in jwt', err); - return { error: "You don't have access of this document!" }; - } - } else if (sessiontoken) { + if (sessiontoken) { const userRes = await axios.get(serverUrl + '/users/me', { headers: { 'X-Parse-Application-Id': process.env.APP_ID, @@ -56,6 +28,7 @@ export default async function GetTemplate(request) { template.include('Signers'); template.include('CreatedBy'); template.include('ExtUserPtr.TenantId'); + template.include('Bcc'); const extUserQuery = new Parse.Query('contracts_Users'); extUserQuery.equalTo('Email', userEmail); extUserQuery.include('TeamIds'); @@ -83,6 +56,7 @@ export default async function GetTemplate(request) { template.include('CreatedBy'); template.include('ExtUserPtr.TenantId'); template.include('Placeholders.signerPtr'); + template.include('Bcc'); } } const res = await template.first({ useMasterKey: true }); @@ -109,6 +83,7 @@ export default async function GetTemplate(request) { template.include('Signers'); template.include('CreatedBy'); template.include('ExtUserPtr.TenantId'); + template.include('Bcc'); const res = await template.first({ useMasterKey: true }); // console.log("res ", res) if (res) { diff --git a/apps/OpenSignServer/cloud/parsefunction/GoogleSign.js b/apps/OpenSignServer/cloud/parsefunction/GoogleSign.js deleted file mode 100644 index 3af59398e..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/GoogleSign.js +++ /dev/null @@ -1,100 +0,0 @@ -import axios from 'axios'; -import { cloudServerUrl } from '../../Utils.js'; - -const serverUrl = cloudServerUrl; //process.env.SERVER_URL; -const APPID = process.env.APP_ID; -const masterKEY = process.env.MASTER_KEY; - -/** - * GoogleSign is function which is used to sign up/sign in with google - * @param Id It is google Id - * @param TokenId It is google token Id - * @param Gmail It is user's gmail with user sign in/sign up - * @param Phone It is user's Phone number - * @param Name It is user's Name - * @returns if success {email, message, sessiontoken} else on reject {message} - */ - -export default async function GoogleSign(request) { - const userGoogleId = request.params.Id; - const userTokenId = request.params.TokenId; - const userEmail = request.params.Gmail; - const phone = request.params?.Phone || ''; - const name = request.params.Name; - const extUserId = request.params?.extUserId || ''; - const authData = { google: { id: userGoogleId, id_token: userTokenId } }; - const userQuery = new Parse.Query(Parse.User); - userQuery.equalTo('email', userEmail); - const res = await userQuery.first({ useMasterKey: true }); - if (res) { - if (extUserId) { - const userQuery = new Parse.Query('contracts_Users'); - const resExtUser = await userQuery.get(extUserId, { useMasterKey: true }); - const _resExtUser = JSON.parse(JSON.stringify(resExtUser)); - try { - const SignIn = await axios.put( - serverUrl + '/users/' + res.id, - { authData: authData }, - { - headers: { - 'X-Parse-Application-Id': APPID, - 'X-Parse-Master-key': masterKEY, - }, - } - ); - - if (SignIn.data) { - // console.log("google Sign in", SignIn); - const sessiontoken = SignIn.data.sessionToken; - return { - email: userEmail, - phone: _resExtUser?.Phone || '', - company: _resExtUser?.Company, - message: 'User Sign In', - sessiontoken: sessiontoken, - }; - } - } catch (err) { - console.log('err in user google sign in', err); - return { message: 'Internal server error' }; - } - } else { - return { message: 'Internal server err' }; - } - } else { - // console.log("in sign up condition"); - try { - const SignUp = await axios.post( - serverUrl + '/users', - { - authData: authData, - username: userEmail, - email: userEmail, - phone: phone, - name: name, - }, - { - headers: { - 'X-Parse-Application-Id': APPID, - 'X-Parse-Revocable-Session': '1', - }, - } - ); - - // console.log("SignUp", SignUp); - - if (SignUp.data) { - const sessiontoken = SignUp.data.sessionToken; - const payload = { - email: userEmail, - message: 'User Sign Up', - sessiontoken: sessiontoken, - }; - return payload; - } - } catch (err) { - console.log('err in user google sign up', err); - return { message: 'Internal server err' }; - } - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/Newsletter.js b/apps/OpenSignServer/cloud/parsefunction/Newsletter.js index 2250e8f9d..9f6dd1422 100644 --- a/apps/OpenSignServer/cloud/parsefunction/Newsletter.js +++ b/apps/OpenSignServer/cloud/parsefunction/Newsletter.js @@ -4,12 +4,11 @@ export default async function Newsletter(request) { const email = request.params.email; const domain = request.params.domain; try { - const headers = { - 'Content-Type': 'application/json', - 'X-Parse-Application-Id': 'legadranaxn', - }; + const envAppId = process.env.REACT_APP_APPID || 'legadranaxn'; + const headers = { 'Content-Type': 'application/json', 'X-Parse-Application-Id': envAppId }; + const envProdServer = process.env.REACT_APP_SERVERURL || 'https://app.opensignlabs.com/api/app'; const newsletter = await axios.post( - 'https://app.opensignlabs.com/api/app/classes/Newsletter', + `${envProdServer}/classes/Newsletter`, { Name: name, Email: email, Domain: domain }, { headers: headers } ); diff --git a/apps/OpenSignServer/cloud/parsefunction/PublicUserLinkContactToDoc.js b/apps/OpenSignServer/cloud/parsefunction/PublicUserLinkContactToDoc.js deleted file mode 100644 index 20fa843aa..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/PublicUserLinkContactToDoc.js +++ /dev/null @@ -1,456 +0,0 @@ -import { replaceMailVaribles } from '../../Utils.js'; - -// `saveRoleContact` is used to save user in contracts_Guest role and create contact -const saveRoleContact = async contact => { - try { - const Role = new Parse.Query(Parse.Role); - const guestRole = await Role.equalTo('name', 'contracts_Guest').first(); - if (guestRole) { - // Check if the user is already in the role - const relation = guestRole.relation('users'); - const usersInRoleQuery = relation.query(); - usersInRoleQuery.equalTo('objectId', contact.UserId.objectId); - const usersInRole = await usersInRoleQuery.find(); - if (usersInRole.length > 0) { - console.log('User already added to Guest role.'); - } else { - relation.add({ __type: 'Pointer', className: '_User', id: contact.UserId.objectId }); - await guestRole.save(null, { useMasterKey: true }); - // console.log('User added to Guest role successfully.'); - } - } - } catch (err) { - console.log('err in role save', err); - } - const contactQuery = new Parse.Object('contracts_Contactbook'); - contactQuery.set('Name', contact.Name); - contactQuery.set('Email', contact.Email); - if (contact?.Phone) { - contactQuery.set('Phone', contact.Phone); - } - contactQuery.set('CreatedBy', contact.CreatedBy); - contactQuery.set('UserId', contact.UserId); - contactQuery.set('UserRole', 'contracts_Guest'); - if (contact?.TenantId) { - contactQuery.set('TenantId', { - __type: 'Pointer', - className: 'partners_Tenant', - objectId: contact.TenantId, - }); - } - contactQuery.set('IsDeleted', false); - const acl = new Parse.ACL(); - acl.setReadAccess(contact.CreatedBy.objectId, true); - acl.setWriteAccess(contact.CreatedBy.objectId, true); - acl.setReadAccess(contact.UserId.objectId, true); - acl.setWriteAccess(contact.UserId.objectId, true); - contactQuery.setACL(acl); - const contactRes = await contactQuery.save(); - if (contactRes) { - return contactRes; - } -}; - -// `createDocumentFromTemplate` is used to create document from template -const createDocumentFromTemplate = async (template, existContact, index) => { - try { - if (template) { - //update contact in placeholder, signers and update ACl in provide document - const object = new Parse.Object('contracts_Document'); - object.set('Name', template?.Name); - object.set('Description', template?.Description); - object.set('Note', template?.Note); - object.set('TimeToCompleteDays', template?.TimeToCompleteDays || 15); - object.set('SendinOrder', template?.SendinOrder || false); - object.set('AutomaticReminders', template?.AutomaticReminders || false); - object.set('RemindOnceInEvery', template?.RemindOnceInEvery || 5); - object.set('URL', template?.URL); - object.set('CreatedBy', template?.CreatedBy); - object.set('ExtUserPtr', template?.ExtUserPtr); - object.set('OriginIp', template?.OriginIp || ''); - object.set('IsEnableOTP', template?.IsEnableOTP || false); - object.set('IsTourEnabled', template?.IsTourEnabled || false); - object.set('FileAdapterId', template?.FileAdapterId || ''); - if (template?.SignatureType?.length > 0) { - object.set('SignatureType', template?.SignatureType); - } - if (template?.NotifyOnSignatures) { - object.set('NotifyOnSignatures', template?.NotifyOnSignatures); - } - let signers = template?.Signers || []; - const signerobj = { - __type: 'Pointer', - className: 'contracts_Contactbook', - objectId: existContact.id, - }; - signers = [...signers.slice(0, index), signerobj, ...signers.slice(index)]; - object.set('Signers', signers); - object.set('SignedUrl', template.URL || template.SignedUrl); - const Placeholders = template?.Placeholders || []; - Placeholders[index] = { - ...Placeholders[index], - signerObjId: existContact.id, - signerPtr: { - __type: 'Pointer', - className: 'contracts_Contactbook', - objectId: existContact.id, - }, - }; - object.set('Placeholders', Placeholders); - object.set('SendMail', true); - const resDoc = await object.save(null, { useMasterKey: true }); - return resDoc; - } - } catch (err) { - console.log('err in create document from template', err); - } -}; - -//`sendMailToAllSigners` is used to send email to all signers at a time if send-in-order false -const sendMailToAllSigners = async docId => { - try { - //get document details that recenlty created from public template - const docQuery = new Parse.Query('contracts_Document'); - docQuery.include('ExtUserPtr,ExtUserPtr.TenantId'); - docQuery.include('Signers'); - const docRes = await docQuery.get(docId, { useMasterKey: true }); - const Doc = JSON.parse(JSON.stringify(docRes)); - const templateOwnerUserId = Doc?.CreatedBy?.objectId; - const tenantCreditsQuery = new Parse.Query('partners_Tenant'); - tenantCreditsQuery.equalTo('UserId', { - __type: 'Pointer', - className: '_User', - objectId: templateOwnerUserId, - }); - const res = await tenantCreditsQuery.first(); - if (res) { - const existUserId = Doc?.ExtUserPtr?.objectId; - try { - const getSubscriptionDetails = await Parse.Cloud.run('getsubscriptions', { - extUserId: existUserId, - ispublic: true, - }); - if (getSubscriptionDetails) { - const tenantRes = JSON.parse(JSON.stringify(res)); - const extUserDetails = Doc?.ExtUserPtr; - const signerMail = Doc?.Signers; - const requestBody = tenantRes?.RequestBody; - const requestSubject = tenantRes?.RequestSubject; - const subscription_json = JSON.parse(JSON.stringify(getSubscriptionDetails)); - const billingDate = - subscription_json?.result?.Next_billing_date && - subscription_json?.result?.Next_billing_date?.iso; - const isSubscribed = billingDate ? new Date(billingDate) > new Date() : false; - for (let i = 0; i < signerMail.length; i++) { - try { - const senderEmail = Doc?.ExtUserPtr?.Email; - const senderPhone = Doc?.ExtUserPtr?.Phone; - const expireDate = Doc?.ExpiryDate?.iso || 15; - const newDate = new Date(expireDate); - const localExpireDate = newDate.toLocaleDateString('en-US', { - day: 'numeric', - month: 'long', - year: 'numeric', - }); - const imgPng = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png'; - const objectId = signerMail[i].objectId; - const hostPublicUrl = 'https://app.opensignlabs.com'; - - //encode this url value `${Doc.objectId}/${signerMail[i].Email}/${objectId}` to base64 using `btoa` function - const encodeBase64 = btoa(`${Doc?.objectId}/${signerMail[i].Email}/${objectId}`); - let signPdf = `${hostPublicUrl}/login/${encodeBase64}`; - const openSignUrl = 'https://www.opensignlabs.com/'; - const orgName = Doc?.ExtUserPtr?.Company || ''; - const themeBGcolor = '#47a3ad'; - const senderName = `${Doc?.ExtUserPtr.Name}`; - const documentName = `${Doc?.Name}`; - let replaceVar; - if (isSubscribed && requestBody && requestSubject) { - const replacedRequestBody = requestBody.replace(/"/g, "'"); - htmlReqBody = - "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body>" + - replacedRequestBody + - '</body> </html>'; - - const variables = { - document_title: documentName, - sender_name: senderName, - sender_mail: senderEmail, - sender_phone: senderPhone || '', - receiver_name: signerMail[i].Name, - receiver_email: signerMail[i].Email, - receiver_phone: signerMail[i]?.Phone || '', - expiry_date: localExpireDate, - company_name: orgName, - signing_url: `<a href=${signPdf} target=_blank>Sign here</a>`, - }; - replaceVar = replaceMailVaribles(requestSubject, htmlReqBody, variables); - } - let params = { - mailProvider: extUserDetails?.activeMailAdapter, - extUserId: existUserId, - recipient: signerMail[i].Email, - subject: - replaceVar?.subject || - `${senderName} has requested you to sign "${documentName}"`, - from: senderEmail, - html: - replaceVar?.body || - "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /> </head> <body> <div style='background-color: #f5f5f5; padding: 20px'=> <div style=' box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background: white;padding-bottom: 20px;'> <div style='padding:10px 10px 0 10px'><img src=" + - imgPng + - " height='50' style='padding: 20px,width:170px,height:40px' /></div> <div style=' padding: 2px;font-family: system-ui;background-color:" + - themeBGcolor + - ";'><p style='font-size: 20px;font-weight: 400;color: white;padding-left: 20px;' > Digital Signature Request</p></div><div><p style='padding: 20px;font-family: system-ui;font-size: 14px; margin-bottom: 10px;'> " + - Doc?.ExtUserPtr.Name + - ' has requested you to review and sign <strong> ' + - Doc?.Name + - "</strong>.</p><div style='padding: 5px 0px 5px 25px;display: flex;flex-direction: row;justify-content: space-around;'><table> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Sender</td> <td> </td> <td style='color:#626363;font-weight:bold'>" + - senderEmail + - "</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Organization</td> <td> </td><td style='color:#626363;font-weight:bold'> " + - orgName + - "</td></tr> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Expire on</td><td> </td> <td style='color:#626363;font-weight:bold'>" + - localExpireDate + - "</td></tr><tr> <td></td> <td> </td></tr></table> </div> <div style='margin-left:70px'><a href=" + - signPdf + - "> <button style='padding: 12px 12px 12px 12px;background-color: #d46b0f;color: white; border: 0px;box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px,rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;font-weight:bold;margin-top:30px'>Sign here</button></a> </div> <div style='display: flex; justify-content: center;margin-top: 10px;'> </div></div></div><div><p> This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender " + - senderEmail + - ' directly.If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href= ' + - openSignUrl + - ' target=_blank>here</a>.</p> </div></div></body> </html>', - }; - - await Parse.Cloud.run('sendmailv3', params); - } catch (error) { - console.log('error', error); - } - } - } else { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.'); - } - } catch (e) { - console.log('error in get partners_Tenant class details', err); - } - } - } catch (e) { - console.log('error in sendMailToAllSigners function', err); - } -}; - -const deductcount = async _resSub => { - try { - const subscriptionCls = new Parse.Object('contracts_Subscriptions'); - subscriptionCls.id = _resSub.objectId; - const allowedCredits = _resSub?.AllowedCredits || 0; - const addonCredits = _resSub?.AddonCredits || 0; - if (allowedCredits > 0) { - const updateAllowedcredits = allowedCredits - 1 || 0; - subscriptionCls.set('AllowedCredits', updateAllowedcredits); - } else { - const updateAddonCredits = addonCredits > 0 ? addonCredits - 1 : 0; - subscriptionCls.set('AddonCredits', updateAddonCredits); - } - await subscriptionCls.save(null, { useMasterKey: true }); - } catch (err) { - console.log('Err in deductcount in PublicUserLinkContacttoDoc cloud function', err); - } -}; - -// `PublicUserLinkContactToDoc` cloud function is used to create contact, add this contact in contracts_Guest role and -// create new document from template and save contact pointer in placeholder, signers and ACL of Document -export default async function PublicUserLinkContactToDoc(req) { - const email = req.params.email; - const templateid = req.params.templateid; - const signatureType = req.params.signatureType; - const name = req.params.name; - const phone = req.params.phone; - const role = req.params.role; - try { - if (templateid) { - // Execute the query to get the template with the specified 'templateid' - const docQuery = new Parse.Query('contracts_Template'); - docQuery.include('ExtUserPtr'); - docQuery.include('ExtUserPtr.TenantId'); - const tempRes = await docQuery.get(templateid, { useMasterKey: true }); - // Check if the template was found; if not, throw an error indicating the template was not found - if (!tempRes) { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Template not found.'); - } - const _tempRes = JSON.parse(JSON.stringify(tempRes)); - const subscription = new Parse.Query('contracts_Subscriptions'); - subscription.equalTo('TenantId', { - __type: 'Pointer', - className: 'partners_Tenant', - objectId: _tempRes?.ExtUserPtr?.TenantId?.objectId, - }); - subscription.include('ExtUserPtr'); - const date = new Date(); - subscription.greaterThanOrEqualTo('Next_billing_date', date); - const resSub = await subscription.first({ useMasterKey: true }); - if (resSub) { - const _resSub = JSON.parse(JSON.stringify(resSub)); - const allowedCredits = _resSub?.AllowedCredits || 0; - const addonCredits = _resSub?.AddonCredits || 0; - const totalcredits = allowedCredits + addonCredits; - if (totalcredits > 0) { - const Placeholders = _tempRes?.Placeholders || []; - let index; - if (role) { - index = Placeholders?.findIndex(x => x.Role && x.Role === role); - } else { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, ''); - } - if (index !== -1) { - // Execute the query to check if a contact already exists in the 'contracts_Contactbook' class - const contactCls = new Parse.Query('contracts_Contactbook'); - contactCls.equalTo('Email', email); - contactCls.equalTo('CreatedBy', _tempRes.CreatedBy); - contactCls.notEqualTo('IsDeleted', true); - const existContact = await contactCls.first({ useMasterKey: true }); - if (existContact) { - const template_json = JSON.parse(JSON.stringify(tempRes)); - const _template_json = template_json; - _template_json.SignatureType = - signatureType?.length > 0 ? signatureType : _template_json?.SignatureType; - //update contact in placeholder, signers and update ACl in provide document - const docRes = await createDocumentFromTemplate(_template_json, existContact, index); - if (docRes) { - await deductcount(_resSub); - //condition will execute only if sendInOrder will be false for send email to all signers at a time. - if (!template_json?.SendinOrder) { - await sendMailToAllSigners(docRes.id); - } - return { contactId: existContact.id, docId: docRes.id }; - } - } else { - // Execute the query to check if a user already exists in the 'contracts_Users' class - const extUserQuery = new Parse.Query('contracts_Users'); - extUserQuery.equalTo('Email', email); - const extUser = await extUserQuery.first({ useMasterKey: true }); - if (extUser) { - const _extUser = JSON.parse(JSON.stringify(extUser)); - const contact = { - UserId: _extUser.UserId, - Name: _extUser.Name, - Email: email, - Phone: _extUser?.Phone ? _extUser.Phone : '', - CreatedBy: _tempRes.CreatedBy, - TenantId: _tempRes.ExtUserPtr?.TenantId?.objectId, - }; - const template_json = JSON.parse(JSON.stringify(tempRes)); - const _template_json = template_json; - _template_json.SignatureType = - signatureType?.length > 0 ? signatureType : _template_json?.SignatureType; - // if user present on platform create contact on the basis of extended user details - const contactRes = await saveRoleContact(contact); - const docRes = await createDocumentFromTemplate(_template_json, contactRes, index); - if (docRes) { - await deductcount(_resSub); - //condition will execute only if sendInOrder will be false for send email to all signers at a time. - if (!template_json?.SendinOrder) { - await sendMailToAllSigners(docRes.id); - } - return { contactId: contactRes.id, docId: docRes.id }; - } - } else if (name) { - try { - // Execute the query to check if a user already exists in the '_User' class - const userQuery = new Parse.Query(Parse.User); - userQuery.equalTo('email', email); - const userRes = await userQuery.first({ useMasterKey: true }); - if (userRes) { - const contact = { - UserId: { __type: 'Pointer', className: '_User', objectId: userRes.id }, - Name: name, - Email: email, - Phone: phone, - CreatedBy: _tempRes.CreatedBy, - TenantId: _tempRes.ExtUserPtr?.TenantId?.objectId, - }; - const template_json = JSON.parse(JSON.stringify(tempRes)); - const _template_json = template_json; - _template_json.SignatureType = - signatureType?.length > 0 ? signatureType : _template_json?.SignatureType; - // Create new contract on the basis provided contact details by user and userId from _User class - const contactRes = await saveRoleContact(contact); - //update contact in placeholder, signers and update ACl in provide document - const docRes = await createDocumentFromTemplate( - _template_json, - contactRes, - index - ); - if (docRes) { - await deductcount(_resSub); - //condition will execute only if sendInOrder will be false for send email to all signers at a time. - if (!template_json?.SendinOrder) { - await sendMailToAllSigners(docRes.id); - } - return { contactId: contactRes.id, docId: docRes.id }; - } - } else { - // create new user in _User class on the basis of details provide by user - const _users = Parse.Object.extend('User'); - const _user = new _users(); - _user.set('name', name); - _user.set('username', email); - _user.set('email', email); - _user.set('password', email); - if (phone) { - _user.set('phone', phone); - } - const newUserRes = await _user.save(); - const contact = { - UserId: { __type: 'Pointer', className: '_User', objectId: newUserRes.id }, - Name: name, - Email: email, - Phone: phone, - CreatedBy: _tempRes.CreatedBy, - TenantId: _tempRes.ExtUserPtr?.TenantId?.objectId, - }; - const template_json = JSON.parse(JSON.stringify(tempRes)); - const _template_json = template_json; - _template_json.SignatureType = - signatureType?.length > 0 ? signatureType : _template_json?.SignatureType; - // Create new contract on the basis provided contact details by user and userId from _User class - const contactRes = await saveRoleContact(contact); - //update contact in placeholder, signers and update ACl in provide document - const docRes = await createDocumentFromTemplate( - _template_json, - contactRes, - index - ); - if (docRes) { - await deductcount(_resSub); - //condition will execute only if sendInOrder will be false for send email to all signers at a time. - if (!template_json?.SendinOrder) { - await sendMailToAllSigners(docRes.id); - } - return { contactId: contactRes.id, docId: docRes.id }; - } - } - } catch (err) { - console.log('Err', err); - } - } else { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.'); - } - } - } else { - throw new Parse.Error( - Parse.Error.OBJECT_NOT_FOUND, - 'Please provide required parameters!' - ); - } - } else { - throw new Parse.Error(Parse.Error.REQUEST_LIMIT_EXCEEDED, 'Insufficient Credit'); - } - } else { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Plan expired'); - } - } else { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Template not found.'); - } - } catch (err) { - console.log('err in publicuserlinkcontacttodoc', err); - throw err; - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/SignatureAfterFind.js b/apps/OpenSignServer/cloud/parsefunction/SignatureAfterFind.js index 1d1174324..ffb6851a6 100644 --- a/apps/OpenSignServer/cloud/parsefunction/SignatureAfterFind.js +++ b/apps/OpenSignServer/cloud/parsefunction/SignatureAfterFind.js @@ -1,5 +1,5 @@ import { useLocal } from '../../Utils.js'; -import getPresignedUrl from './getSignedUrl.js'; +import getPresignedUrl, { presignedlocalUrl } from './getSignedUrl.js'; async function SignatureAfterFind(request) { if (useLocal !== 'true') { @@ -17,6 +17,21 @@ async function SignatureAfterFind(request) { return [obj]; } } + } else if (useLocal == 'true') { + if (request.objects.length === 1) { + if (request.objects) { + const obj = request.objects[0]; + const ImageURL = obj?.get('ImageURL') && obj?.get('ImageURL'); + const Initials = obj?.get('Initials') && obj?.get('Initials'); + if (ImageURL) { + obj.set('ImageURL', presignedlocalUrl(ImageURL)); + } + if (Initials) { + obj.set('Initials', presignedlocalUrl(Initials)); + } + return [obj]; + } + } } } export default SignatureAfterFind; diff --git a/apps/OpenSignServer/cloud/parsefunction/SubscribeFree.js b/apps/OpenSignServer/cloud/parsefunction/SubscribeFree.js deleted file mode 100644 index 31ed14adf..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/SubscribeFree.js +++ /dev/null @@ -1,86 +0,0 @@ -export default async function SubscribeFree(request) { - const userId = request.params.userId; - const userPtr = { __type: 'Pointer', className: '_User', objectId: userId }; - try { - const extQuery = new Parse.Query('contracts_Users'); - extQuery.equalTo('UserId', userPtr); - const extUser = await extQuery.first({ useMasterKey: true }); - if (extUser) { - const subscriptionCls = new Parse.Query('contracts_Subscriptions'); - subscriptionCls.equalTo('TenantId', { - __type: 'Pointer', - className: 'partners_Tenant', - objectId: extUser.get('TenantId').id, - }); - subscriptionCls.descending('createdAt'); - const subcripitions = await subscriptionCls.first({ useMasterKey: true }); - if (subcripitions) { - if (subcripitions?.get('PlanCode') === 'freeplan') { - return { status: 'success', result: 'already subscribed!' }; - } else if (subcripitions?.get('Next_billing_date') < new Date()) { - try { - const updateSubscription = new Parse.Object('contracts_Subscriptions'); - updateSubscription.id = subcripitions.id; - updateSubscription.set('PlanCode', 'freeplan'); - updateSubscription.set('AllowedCredits', 0); - updateSubscription.set('PlanCredits', 0); - await updateSubscription.save(null, { useMasterKey: true }); - return { status: 'success', result: 'subscribed!' }; - } catch (err) { - console.log('err ', err); - return { status: 'error', result: err.message }; - } - } else if (subcripitions?.get('Next_billing_date') > new Date()) { - return { status: 'success', result: 'already subscribed!' }; - } else { - try { - const updateSubscription = new Parse.Object('contracts_Subscriptions'); - updateSubscription.id = subcripitions.id; - updateSubscription.set('PlanCode', 'freeplan'); - updateSubscription.set('AllowedCredits', 0); - updateSubscription.set('PlanCredits', 0); - await updateSubscription.save(null, { useMasterKey: true }); - return { status: 'success', result: 'subscribed!' }; - } catch (err) { - console.log('err ', err); - return { status: 'error', result: err.message }; - } - } - } else { - try { - const createSubscription = new Parse.Object('contracts_Subscriptions'); - createSubscription.set('PlanCode', 'freeplan'); - createSubscription.set('ExtUserPtr', { - __type: 'Pointer', - className: 'contracts_Users', - objectId: extUser.id, - }); - createSubscription.set('CreatedBy', { - __type: 'Pointer', - className: '_User', - objectId: extUser.get('UserId').id, - }); - if (extUser?.get('TenantId')) { - createSubscription.set('TenantId', { - __type: 'Pointer', - className: 'partners_Tenant', - objectId: extUser.get('TenantId').id, - }); - } - createSubscription.set('AllowedCredits', 0); - createSubscription.set('PlanCredits', 0); - await createSubscription.save(null, { useMasterKey: true }); - return { status: 'success', result: 'subscribed!' }; - } catch (err) { - console.log('err ', err); - return { status: 'error', result: err.message }; - } - } - } else { - return { status: 'error', result: 'User not found!' }; - } - } catch (err) { - console.log('err ', err); - return { status: 'error', result: err.message }; - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/SubscriptionAftersave.js b/apps/OpenSignServer/cloud/parsefunction/SubscriptionAftersave.js deleted file mode 100644 index 9c8ae81bd..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/SubscriptionAftersave.js +++ /dev/null @@ -1,98 +0,0 @@ -async function addTeamAndOrg(extUser) { - try { - const orgCls = new Parse.Object('contracts_Organizations'); - orgCls.set('Name', extUser.Company); - orgCls.set('IsActive', true); - orgCls.set('ExtUserId', { - __type: 'Pointer', - className: 'contracts_Users', - objectId: extUser?.objectId, - }); - orgCls.set('CreatedBy', { - __type: 'Pointer', - className: '_User', - objectId: extUser?.UserId?.objectId, - }); - orgCls.set('TenantId', { - __type: 'Pointer', - className: 'partners_Tenant', - objectId: extUser?.TenantId?.objectId, - }); - - const orgRes = await orgCls.save(null, { useMasterKey: true }); - const teamCls = new Parse.Object('contracts_Teams'); - teamCls.set('Name', 'All Users'); - teamCls.set('OrganizationId', { - __type: 'Pointer', - className: 'contracts_Organizations', - objectId: orgRes.id, - }); - teamCls.set('IsActive', true); - const teamRes = await teamCls.save(null, { useMasterKey: true }); - const updateUser = new Parse.Object('contracts_Users'); - updateUser.id = extUser.objectId; - updateUser.set('UserRole', 'contracts_Admin'); - updateUser.set('OrganizationId', { - __type: 'Pointer', - className: 'contracts_Organizations', - objectId: orgRes.id, - }); - updateUser.set('TeamIds', [ - { - __type: 'Pointer', - className: 'contracts_Teams', - objectId: teamRes.id, - }, - ]); - const extUserRes = await updateUser.save(null, { useMasterKey: true }); - } catch (err) { - console.log('err in add team, role, org', err); - } -} - -export default async function SubscriptionAftersave(request) { - const oldObj = request.original; - if (!oldObj) { - try { - const subscription = new Parse.Query('contracts_Subscriptions'); - subscription.include('CreatedBy'); - const res = await subscription.get(request.object.id, { useMasterKey: true }); - const _res = JSON.parse(JSON.stringify(res)); - const user = _res.CreatedBy?.email; - if (user) { - const extUserQuery = new Parse.Query('contracts_Users'); - extUserQuery.equalTo('Email', user); - const extUserRes = await extUserQuery.first({ useMasterKey: true }); - if (extUserRes) { - const extUser = JSON.parse(JSON.stringify(extUserRes)); - if (!extUser?.OrganizationId) { - await addTeamAndOrg(extUser); - } - } - } - } catch (err) { - console.log('Err in subscriptionaftersave', err); - } - } else { - try { - const subscription = new Parse.Query('contracts_Subscriptions'); - subscription.include('CreatedBy'); - const res = await subscription.get(request.object.id, { useMasterKey: true }); - const _res = JSON.parse(JSON.stringify(res)); - const user = _res.CreatedBy?.email; - if (user) { - const extUserQuery = new Parse.Query('contracts_Users'); - extUserQuery.equalTo('Email', user); - const extUserRes = await extUserQuery.first({ useMasterKey: true }); - if (extUserRes) { - const extUser = JSON.parse(JSON.stringify(extUserRes)); - if (!extUser?.OrganizationId) { - await addTeamAndOrg(extUser); - } - } - } - } catch (err) { - console.log('Err in subscriptionaftersave', err); - } - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/TemplateAfterFind.js b/apps/OpenSignServer/cloud/parsefunction/TemplateAfterFind.js index c10a80e47..32c8084c9 100644 --- a/apps/OpenSignServer/cloud/parsefunction/TemplateAfterFind.js +++ b/apps/OpenSignServer/cloud/parsefunction/TemplateAfterFind.js @@ -1,31 +1,53 @@ import { useLocal } from '../../Utils.js'; -import getPresignedUrl from './getSignedUrl.js'; +import getPresignedUrl, { presignedlocalUrl } from './getSignedUrl.js'; async function TemplateAfterFind(request) { if (request.objects.length === 1) { if (request.objects) { const obj = request.objects[0]; - const FileAdapterId = obj?.get('FileAdapterId') || ''; - if (FileAdapterId || useLocal !== 'true') { + if ( + useLocal !== 'true' + ) { const SignedUrl = obj?.get('SignedUrl') && obj?.get('SignedUrl'); const Url = obj?.get('URL') && obj?.get('URL'); const certificateUrl = obj.get('CertificateUrl') && obj.get('CertificateUrl'); - let fileAdapter = {}; - if (FileAdapterId) { - const tenantId = obj?.get('ExtUserPtr')?.get('TenantId'); - if (tenantId) { - const _tenantId = JSON.parse(JSON.stringify(obj?.get('ExtUserPtr')?.get('TenantId'))); - fileAdapter = _tenantId?.FileAdapters?.find(x => x.id === FileAdapterId) || {}; - } - } if (SignedUrl) { - obj.set('SignedUrl', getPresignedUrl(SignedUrl, fileAdapter)); + obj.set( + 'SignedUrl', + getPresignedUrl( + SignedUrl, + ) + ); } if (Url) { - obj.set('URL', getPresignedUrl(Url, fileAdapter)); + obj.set( + 'URL', + getPresignedUrl( + Url, + ) + ); } if (certificateUrl) { - obj.set('CertificateUrl', getPresignedUrl(certificateUrl, fileAdapter)); + obj.set( + 'CertificateUrl', + getPresignedUrl( + certificateUrl, + ) + ); + } + return [obj]; + } else if (useLocal == 'true') { + const SignedUrl = obj?.get('SignedUrl') && obj?.get('SignedUrl'); + const Url = obj?.get('URL') && obj?.get('URL'); + const certificateUrl = obj.get('CertificateUrl') && obj.get('CertificateUrl'); + if (SignedUrl) { + obj.set('SignedUrl', presignedlocalUrl(SignedUrl)); + } + if (Url) { + obj.set('URL', presignedlocalUrl(Url)); + } + if (certificateUrl) { + obj.set('CertificateUrl', presignedlocalUrl(certificateUrl)); } return [obj]; } diff --git a/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js b/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js index 610130e22..e5ccc41b2 100644 --- a/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js +++ b/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js @@ -6,13 +6,16 @@ export default async function TemplateAfterSave(request) { const signers = request.object.get('Signers'); const AutoReminder = request?.object?.get('AutomaticReminders') || false; const ip = request?.headers?.['x-real-ip'] || ''; + const originIp = request?.object?.get('OriginIp') || ''; if (AutoReminder) { const RemindOnceInEvery = request?.object?.get('RemindOnceInEvery') || 5; const ReminderDate = new Date(request?.object?.get('createdAt')); ReminderDate.setDate(ReminderDate.getDate() + RemindOnceInEvery); request.object.set('NextReminderDate', ReminderDate); } - request.object.set('OriginIp', ip); + if (!originIp) { + request.object.set('OriginIp', ip); + } await request.object.save(null, { useMasterKey: true }); if (signers && signers.length > 0) { await updateAclDoc(request.object.id); diff --git a/apps/OpenSignServer/cloud/parsefunction/TenantAfterFind.js b/apps/OpenSignServer/cloud/parsefunction/TenantAfterFind.js index bb520928f..e09d5fadc 100644 --- a/apps/OpenSignServer/cloud/parsefunction/TenantAfterFind.js +++ b/apps/OpenSignServer/cloud/parsefunction/TenantAfterFind.js @@ -1,5 +1,5 @@ import { useLocal } from '../../Utils.js'; -import getPresignedUrl from './getSignedUrl.js'; +import getPresignedUrl, { presignedlocalUrl } from './getSignedUrl.js'; async function TenantAterFind(request) { if (useLocal !== 'true') { @@ -13,6 +13,17 @@ async function TenantAterFind(request) { return [obj]; } } + } else if (useLocal == 'true') { + if (request.objects.length === 1) { + if (request.objects) { + const obj = request.objects[0]; + const Logo = obj?.get('Logo') && obj?.get('Logo'); + if (Logo) { + obj.set('Logo', presignedlocalUrl(Logo)); + } + return [obj]; + } + } } } export default TenantAterFind; diff --git a/apps/OpenSignServer/cloud/parsefunction/UserAfterFInd.js b/apps/OpenSignServer/cloud/parsefunction/UserAfterFInd.js index 5a414e1ac..4abc7ee66 100644 --- a/apps/OpenSignServer/cloud/parsefunction/UserAfterFInd.js +++ b/apps/OpenSignServer/cloud/parsefunction/UserAfterFInd.js @@ -1,5 +1,5 @@ import { useLocal } from '../../Utils.js'; -import getPresignedUrl from './getSignedUrl.js'; +import getPresignedUrl, { presignedlocalUrl } from './getSignedUrl.js'; async function UserAfterFind(request) { if (useLocal !== 'true') { @@ -13,6 +13,17 @@ async function UserAfterFind(request) { return [obj]; } } + } else if (useLocal == 'true') { + if (request.objects.length === 1) { + if (request.objects) { + const obj = request.objects[0]; + const ProfilePic = obj?.get('ProfilePic') && obj?.get('ProfilePic'); + if (ProfilePic) { + obj.set('ProfilePic', presignedlocalUrl(ProfilePic)); + } + return [obj]; + } + } } } export default UserAfterFind; diff --git a/apps/OpenSignServer/cloud/parsefunction/ZohoDetails.js b/apps/OpenSignServer/cloud/parsefunction/ZohoDetails.js deleted file mode 100644 index 677e8725f..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/ZohoDetails.js +++ /dev/null @@ -1,61 +0,0 @@ -import axios from 'axios'; - -/** - * ZohoDetails function - * @param hostedpagesId Id must be in String - * @returns response {phone, name, email, nextBillingDate, company, plan, customer_id, subscription_id} - */ - -export default async function ZohoDetails(request) { - // Define the URL - const url = 'https://accounts.zoho.in/oauth/v2/token'; - - // Convert the data to x-www-form-urlencoded format - const formData = new URLSearchParams(); - formData.append('refresh_token', process.env.ZOHO_REFRESH_TOKEN); - formData.append('client_id', process.env.ZOHO_CLIENT_ID); - formData.append('client_secret', process.env.ZOHO_CLIENT_SECRET); - formData.append('redirect_uri', process.env.ZOHO_REDIRECT_URI); - formData.append('grant_type', 'refresh_token'); - - const headers = { 'Content-Type': 'application/x-www-form-urlencoded' }; - // Make the POST request using Axios - const res = await axios.post(url, formData, { headers }); - // console.log("Access Token:", res.data); - if (res.data.access_token) { - const hostedpages = request.params.hostedpagesId; - const userData = await axios.get( - 'https://www.zohoapis.in/billing/v1/hostedpages/' + hostedpages, - { - headers: { - Authorization: 'Zoho-oauthtoken ' + res.data.access_token, - 'X-com-zoho-subscriptions-organizationid': process.env.ZOHO_BILLING_ORG_ID, - }, - } - ); - - const first_name = userData.data.data.subscription.contactpersons[0].first_name || ''; - const last_name = userData.data.data.subscription.contactpersons[0].last_name || ''; - const company_name = - (userData.data.data.subscription.customer && - userData.data.data.subscription.customer.company_name) || - ''; - const jobTitle = - (userData.data.data.subscription.customer && - userData.data.data.subscription.customer.cd_job_title) || - ''; - const resData = { - phone: userData.data.data.subscription.contactpersons[0]?.mobile || '', - name: first_name + ' ' + last_name, - email: userData.data.data.subscription.contactpersons[0].email, - nextBillingDate: userData.data.data.subscription.next_billing_at, - company: company_name, - plan: userData.data.data.subscription.plan, - customer_id: userData.data.data.subscription.customer_id, - subscription_id: userData.data.data.subscription.subscription_id, - jobTitle: jobTitle, - subscription: userData.data, - }; - return resData; - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/addFileAdapter.js b/apps/OpenSignServer/cloud/parsefunction/addFileAdapter.js deleted file mode 100644 index 7fc5f3de8..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/addFileAdapter.js +++ /dev/null @@ -1,142 +0,0 @@ -// `generateId` is used to unique Id for fileAdapter -function generateId(length) { - const characters = 'abcdefghijklmnopqrstuvwxyz0123456789'; - let result = ''; - const charactersLength = characters.length; - for (let i = 0; i < length; i++) { - result += characters.charAt(Math.floor(Math.random() * charactersLength)); - } - return result; -} - -// `getExtUser` get ext user details -async function getExtUser(request) { - const extUserCls = new Parse.Query('contracts_Users'); - extUserCls.equalTo('UserId', request.user); - extUserCls.include('TenantId'); - return await extUserCls.first({ useMasterKey: true }); -} - -// `saveTenant` save file adapter details in tenant class -async function saveTenant(tenantId, fileAdapters, activeAdapter) { - const tenantCls = new Parse.Object('partners_Tenant'); - tenantCls.id = tenantId; - if (fileAdapters?.length > 0) { - tenantCls.set('FileAdapters', fileAdapters); - } - if (activeAdapter) { - tenantCls.set('ActiveFileAdapter', activeAdapter); - } else { - tenantCls.unset('ActiveFileAdapter'); - } - return await tenantCls.save(null, { useMasterKey: true }); -} - -// `updateTenantSchema` is used add FileAdapter in protected fields -async function updateTenantSchema() { - const tenantSchema = new Parse.Schema('partners_Tenant'); - const currentSchema = await tenantSchema.get(); - let clp = currentSchema.classLevelPermissions; - // Public permission ("*") - const role = '*'; - if (!clp.protectedFields || Object.keys(clp.protectedFields).length === 0) { - // Initialize protectedFields if it doesn't exist - clp.protectedFields = { [role]: [] }; - } - // save FileAdapters field is in protectedFields if not exists - if (!clp.protectedFields[role]?.includes('FileAdapters')) { - clp.protectedFields[role].push('FileAdapters'); - // Update the class schema with the modified CLP - tenantSchema.setCLP(clp); - await tenantSchema.update(); - } -} - -export default async function addFileAdapter(request) { - if (!request?.user) { - throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.'); - } - const fileAdapterName = request.params.fileAdapterName; - const bucketName = request.params.bucketName; - const region = request.params.region; - const endpoint = request.params.endpoint; - const baseUrl = request.params.baseUrl; - const accessKeyId = request.params.accessKeyId; - const secretAccessKey = request.params.secretAccessKey; - const adapter = request.params.fileAdapter; - - if (fileAdapterName && accessKeyId && secretAccessKey && adapter) { - try { - const extUser = await getExtUser(request); - if (extUser) { - const _extUser = JSON.parse(JSON.stringify(extUser)); - const tenantId = extUser?.get('TenantId')?.id; - // assign existing file adapters or empty array - let fileAdapters = _extUser?.TenantId?.FileAdapters || []; - const uniqueId = generateId(10); - let id = extUser?.get('TenantId')?.id + '_' + uniqueId; - const index = fileAdapters?.findIndex(x => x.fileAdapterName === fileAdapterName); - if (index !== -1) { - // If an object with the same fileAdapterName exists, update it - if (bucketName || region || endpoint || baseUrl) { - throw new Parse.Error( - Parse.Error.INVALID_QUERY, - 'Cannot update bucketName, region, endpoint, baseUrl.' - ); - } else { - const adapterConfig = { accessKeyId: accessKeyId, secretAccessKey: secretAccessKey }; - fileAdapters[index] = { ...fileAdapters[index], ...adapterConfig }; - id = fileAdapters[index].id; - } - } else { - if (bucketName && region && endpoint && baseUrl) { - // If the object with the given fileAdapterName doesn't exist, add a new one - fileAdapters.push({ - id: id, - fileAdapterName: fileAdapterName, - fileAdapter: adapter, - bucketName: bucketName, - region: region, - endpoint: endpoint, - baseUrl: baseUrl, - accessKeyId: accessKeyId, - secretAccessKey: secretAccessKey, - }); - } else { - throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide all parameters.'); - } - } - const updateTenant = await saveTenant(tenantId, fileAdapters, id); - await updateTenantSchema(); - const ActiveFileAdapter = adapter === 'opensign' ? 'opensign' : id; - return { ActiveFileAdapter: ActiveFileAdapter, updateAt: updateTenant.updatedAt }; - } else { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.'); - } - } catch (err) { - console.log('Err in add custom file adapter', err); - const code = err.code || 400; - const msg = err.message || 'Something went wrong.'; - throw new Parse.Error(code, msg); - } - } else if (adapter === 'opensign') { - try { - const extUser = await getExtUser(request); - if (extUser) { - const tenantId = extUser?.get('TenantId')?.id; - const updateTenant = await saveTenant(tenantId); - await updateTenantSchema(); - return { ActiveFileAdapter: 'opensign', updateAt: updateTenant.updatedAt }; - } else { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.'); - } - } catch (err) { - console.log('Err in add custom file adapter', err); - const code = err.code || 400; - const msg = err.message || 'Something went wrong.'; - throw new Parse.Error(code, msg); - } - } else { - throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide all parameters.'); - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/addOrganization.js b/apps/OpenSignServer/cloud/parsefunction/addOrganization.js deleted file mode 100644 index 0b589bf91..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/addOrganization.js +++ /dev/null @@ -1,70 +0,0 @@ -export default async function addOrganization(request) { - const name = request.params.name; - - if (!request?.user) { - throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.'); - } - try { - const extUserQuery = new Parse.Query('contracts_Users'); - extUserQuery.equalTo('UserId', { - __type: 'Pointer', - className: '_User', - objectId: request.user.id, - }); - extUserQuery.notEqualTo('IsDisabled', true); - const resExt = await extUserQuery.first({ useMasterKey: true }); - if (!resExt) { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.'); - } - const _resExt = JSON.parse(JSON.stringify(resExt)); - - const orgQuery = new Parse.Query('contracts_Organizations'); - orgQuery.equalTo('Name', name); - orgQuery.equalTo('CreatedBy', { - __type: 'Pointer', - className: '_User', - objectId: request.user.id, - }); - const resOrg = await orgQuery.first({ useMasterKey: true }); - if (resOrg) { - throw new Parse.Error(Parse.Error.DUPLICATE_VALUE, 'Organization already exists.'); - } else { - const newOrg = new Parse.Object('contracts_Organizations'); - newOrg.set('Name', name); - newOrg.set('IsActive', true); - newOrg.set('CreatedBy', { - __type: 'Pointer', - className: '_User', - objectId: request.user.id, - }); - newOrg.set('TenantId', { - __type: 'Pointer', - className: 'partners_Tenant', - objectId: _resExt.TenantId.objectId, - }); - newOrg.set('ExtUserId', { - __type: 'Pointer', - className: 'contracts_Users', - objectId: resExt.id, - }); - const newResOrg = await newOrg.save(null, { useMasterKey: true }); - const teamCls = new Parse.Object('contracts_Teams'); - teamCls.set('Name', 'All Users'); - teamCls.set('OrganizationId', { - __type: 'Pointer', - className: 'contracts_Organizations', - objectId: newResOrg.id, - }); - teamCls.set('IsActive', true); - await teamCls.save(null, { useMasterKey: true }); - if (newResOrg) { - return newResOrg; - } - } - } catch (err) { - console.log('err in addorganization', err); - const code = err?.code || 400; - const msg = err?.message || 'Something went wrong.'; - throw new Parse.Error(code, msg); - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/addPfxFile.js b/apps/OpenSignServer/cloud/parsefunction/addPfxFile.js deleted file mode 100644 index 4503d436d..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/addPfxFile.js +++ /dev/null @@ -1,58 +0,0 @@ -// `updateTenantSchema` is used add FileAdapter in protected fields -async function updateTenantSchema() { - const tenantSchema = new Parse.Schema('partners_Tenant'); - const currentSchema = await tenantSchema.get(); - let clp = currentSchema.classLevelPermissions; - // Public permission ("*") - const role = '*'; - if (!clp.protectedFields || Object.keys(clp.protectedFields).length === 0) { - // Initialize protectedFields if it doesn't exist - clp.protectedFields = { [role]: [] }; - } - // save PfxFile field is in protectedFields if not exists - if (!clp.protectedFields[role]?.includes('PfxFile')) { - clp.protectedFields[role].push('PfxFile'); - // Update the class schema with the modified CLP - tenantSchema.setCLP(clp); - await tenantSchema.update(); - } -} - -export default async function addPfxFile(request) { - if (!request?.user) { - throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.'); - } - const pfxBase64 = request.params.pfxBase64; - const title = request.params.title; - const password = request.params.password; - const provider = request.params.provider; - if (provider === 'opensign' || (pfxBase64 && password)) { - try { - const extUserCls = new Parse.Query('contracts_Users'); - extUserCls.equalTo('UserId', request.user); - extUserCls.include('TenantId'); - const extUser = await extUserCls.first({ useMasterKey: true }); - if (extUser) { - const tenantCls = new Parse.Object('partners_Tenant'); - tenantCls.id = extUser?.get('TenantId')?.id; - if (provider === 'opensign') { - tenantCls.unset('PfxFile'); - } else { - tenantCls.set('PfxFile', { title: title, password: password, base64: pfxBase64 }); - } - const updateTenant = await tenantCls.save(null, { useMasterKey: true }); - await updateTenantSchema(); - return { updateAt: updateTenant.updatedAt }; - } else { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.'); - } - } catch (err) { - console.log('Err in add custom file adapter', err); - const code = err.code || 400; - const msg = err.message || 'Something went wrong.'; - throw new Parse.Error(code, msg); - } - } else { - throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide all parameters.'); - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/addTeam.js b/apps/OpenSignServer/cloud/parsefunction/addTeam.js deleted file mode 100644 index 1c7ef5e17..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/addTeam.js +++ /dev/null @@ -1,63 +0,0 @@ -export default async function addTeam(request) { - const Name = request.params.Name; - const ParentId = request.params.ParentId; - const Ancestors = request.params.Ancestors; - const ParentPtr = { __type: 'Pointer', className: 'contracts_Teams', objectId: ParentId }; - if (Name) { - if (!request?.user) { - throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.'); - } - try { - const extUserQuery = new Parse.Query('contracts_Users'); - extUserQuery.equalTo('UserId', { - __type: 'Pointer', - className: '_User', - objectId: request.user.id, - }); - extUserQuery.notEqualTo('IsDisabled', true); - const resExt = await extUserQuery.first({ useMasterKey: true }); - const extUser = JSON.parse(JSON.stringify(resExt)); - if (!extUser) { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.'); - } - const teamCls = new Parse.Query('contracts_Teams'); - teamCls.equalTo('Name', Name); - teamCls.equalTo('OrganizationId', { - __type: 'Pointer', - className: 'contracts_Organizations', - objectId: extUser.OrganizationId.objectId, - }); - if (ParentId) { - teamCls.equalTo('ParentId', ParentPtr); - } - const teamRes = await teamCls.first({ useMasterKey: true }); - if (teamRes) { - throw new Parse.Error(Parse.Error.DUPLICATE_VALUE, 'Team already exists.'); - } else { - const newteam = new Parse.Object('contracts_Teams'); - newteam.set('Name', Name); - newteam.set('OrganizationId', { - __type: 'Pointer', - className: 'contracts_Organizations', - objectId: extUser.OrganizationId.objectId, - }); - if (ParentId) { - newteam.set('ParentId', ParentPtr); - } - if (Ancestors && Ancestors.length > 0) { - newteam.set('Ancestors', Ancestors); - } - newteam.set('IsActive', true); - const newTeamRes = await newteam.save(null, { useMasterKey: true }); - return newTeamRes; - } - } catch (err) { - console.log('err in getOrganizations', err); - const code = err?.code || 400; - const msg = err?.message || 'Something went wrong.'; - throw new Parse.Error(code, msg); - } - } else { - throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide parameters'); - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/addcustomsmtp.js b/apps/OpenSignServer/cloud/parsefunction/addcustomsmtp.js deleted file mode 100644 index 40e0986d5..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/addcustomsmtp.js +++ /dev/null @@ -1,33 +0,0 @@ -export default async function addcustomsmtp(request) { - if (!request?.user) { - throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.'); - } - const host = request.params.host; - const port = request.params.port; - const username = request.params.username; - const password = request.params.password; - if (host && port && username && password) { - try { - const extUserCls = new Parse.Query('contracts_Users'); - extUserCls.equalTo('UserId', request.user); - const extUser = await extUserCls.first({ useMasterKey: true }); - if (extUser) { - const extUserCls = new Parse.Object('contracts_Users'); - extUserCls.id = extUser.id; - extUserCls.set('SmtpConfig', { host, port, username, password }); - extUserCls.set('active_mail_adapter', 'smtp'); - const updateExtUser = await extUserCls.save(null, { useMasterKey: true }); - // console.log('updateExtUser ', updateExtUser); - return updateExtUser.updatedAt; - } - return extUser; - } catch (err) { - console.log('Err in add custom smtp', err); - const code = err.code || 400; - const msg = err.message || 'Something went wrong.'; - throw new Parse.Error(code, msg); - } - } else { - throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide all parameters.'); - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/createBatchContact.js b/apps/OpenSignServer/cloud/parsefunction/createBatchContact.js new file mode 100644 index 000000000..b364c97ce --- /dev/null +++ b/apps/OpenSignServer/cloud/parsefunction/createBatchContact.js @@ -0,0 +1,56 @@ +import axios from 'axios'; +import { cloudServerUrl } from '../../Utils.js'; +const appId = process.env.APP_ID; +const masterkey = process.env.MASTER_KEY; +export default async function createBatchContact(req) { + if (!req?.user) { + throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.'); + } + if (!req.params?.contacts) { + throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide parameter.'); + } + const contactData = JSON.parse(req.params.contacts); + if (contactData?.length > 0) { + try { + const requests = contactData.map(x => { + return { + method: 'POST', + path: '/app/classes/contracts_Contactbook', + body: { + UserRole: 'contracts_Guest', + TenantId: { __type: 'Pointer', className: 'partners_Tenant', objectId: x.TenantId }, + CreatedBy: { __type: 'Pointer', className: '_User', objectId: req.user.id }, + Name: x.Name, + Email: x.Email, + IsDeleted: false, + IsImported: true, + ...(x?.Phone ? { Phone: `${x?.Phone}` } : {}), + ACL: { [req.user.id]: { read: true, write: true } }, + }, + }; + }); + const parseConfig = { + baseURL: cloudServerUrl, + headers: { + 'X-Parse-Application-Id': appId, + 'X-Parse-Master-Key': masterkey, + 'Content-Type': 'application/json', + }, + }; + const response = await axios.post('batch', { requests: requests }, parseConfig); + // Handle the batch query response + // console.info('createbatchcontact ', response.data); + const successCount = response?.data?.filter(item => item.success).length; + const failedCount = requests.length - successCount; + console.log( + `createbatchcontact query response: success: ${successCount}, failed: ${failedCount}` + ); + return { success: successCount, failed: failedCount }; + } catch (err) { + console.log('err while create batch contact', err); + throw new Parse.Error(400, 'Something went wrong, please try again later'); + } + } else { + throw new Parse.Error(Parse.Error.INVALID_CONTENT_LENGTH, 'Please provide parameter'); + } +} diff --git a/apps/OpenSignServer/cloud/parsefunction/createBatchDocs.js b/apps/OpenSignServer/cloud/parsefunction/createBatchDocs.js index 36dd5c19f..4e464d734 100644 --- a/apps/OpenSignServer/cloud/parsefunction/createBatchDocs.js +++ b/apps/OpenSignServer/cloud/parsefunction/createBatchDocs.js @@ -1,27 +1,15 @@ import axios from 'axios'; -import { cloudServerUrl, parseJwt } from '../../Utils.js'; -import jwt from 'jsonwebtoken'; +import { + cloudServerUrl, + replaceMailVaribles, +} from '../../Utils.js'; const serverUrl = cloudServerUrl; //process.env.SERVER_URL; const appId = process.env.APP_ID; -const licenseKey = process.env.LICENSE_KEY; -async function deductcount(docsCount, extUserId, subscription) { +async function deductcount( + docsCount, + extUserId, +) { try { - if (licenseKey) { - const allowedCredits = subscription?.AllowedCredits || 0; - const addonCredits = subscription?.AddonCredits || 0; - const subscriptionCls = new Parse.Object('contracts_Subscriptions'); - subscriptionCls.id = subscription.objectId; - if (docsCount <= allowedCredits) { - const updateAllowedcredits = allowedCredits - docsCount; - subscriptionCls.set('AllowedCredits', updateAllowedcredits); - } else { - const remaingCount = docsCount - allowedCredits; - const updateAddonCredits = addonCredits - remaingCount; - subscriptionCls.set('AllowedCredits', 0); - subscriptionCls.set('AddonCredits', updateAddonCredits); - } - await subscriptionCls.save(null, { useMasterKey: true }); - } const extCls = new Parse.Object('contracts_Users'); extCls.id = extUserId; extCls.increment('DocumentCount', docsCount); @@ -55,11 +43,7 @@ async function sendMail(document) { try { const imgPng = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png'; let url = `${serverUrl}/functions/sendmailv3`; - const headers = { - 'Content-Type': 'application/json', - 'X-Parse-Application-Id': appId, - // sessionToken: sessionToken, - }; + const headers = { 'Content-Type': 'application/json', 'X-Parse-Application-Id': appId }; const objectId = signerMail[i]?.signerObjId; const hostUrl = baseUrl.origin; let encodeBase64; @@ -74,35 +58,67 @@ async function sendMail(document) { const openSignUrl = 'https://www.opensignlabs.com/'; const orgName = document.ExtUserPtr.Company ? document.ExtUserPtr.Company : ''; const themeBGcolor = '#47a3ad'; + const senderObj = document?.ExtUserPtr; + const mailBody = document?.ExtUserPtr?.TenantId?.RequestBody || ''; + const mailSubject = document?.ExtUserPtr?.TenantId?.RequestSubject || ''; + let replaceVar; + if (mailBody && mailSubject) { + const replacedRequestBody = mailBody.replace(/"/g, "'"); + const htmlReqBody = + "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body>" + + replacedRequestBody + + '</body></html>'; + const variables = { + document_title: document?.Name, + sender_name: + senderObj?.Name, + sender_mail: + senderObj?.Email, + sender_phone: senderObj?.Phone || '', + receiver_name: existSigner?.Name || '', + receiver_email: existSigner?.Email || signerMail[i].email, + receiver_phone: existSigner?.Phone || '', + expiry_date: localExpireDate, + company_name: orgName, + signing_url: `<a href=${signPdf} target=_blank>Sign here</a>`, + }; + replaceVar = replaceMailVaribles(mailSubject, htmlReqBody, variables); + } + let params = { - mailProvider: document?.ExtUserPtr?.active_mail_adapter || '', extUserId: document.ExtUserPtr.objectId, recipient: objectId ? existSigner?.Email : signerMail[i].email, - subject: `${document.ExtUserPtr.Name} has requested you to sign "${document.Name}"`, - mailProvider: document?.ExtUserPtr?.active_mail_adapter || '', - from: sender, - html: - "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /> </head> <body> <div style='background-color: #f5f5f5; padding: 20px'> <div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background: white;padding-bottom: 20px;'> <div style='padding:10px 10px 0 10px'><img src='" + - imgPng + - "' height='50' style='padding:20px; width:170px; height:40px;' /></div><div style='padding: 2px;font-family: system-ui;background-color:" + - themeBGcolor + - ";'><p style='font-size: 20px;font-weight: 400;color: white;padding-left: 20px;' > Digital Signature Request</p></div><div><p style='padding: 20px;font-family: system-ui;font-size: 14px; margin-bottom: 10px;'> " + - document.ExtUserPtr.Name + - ' has requested you to review and sign <strong> ' + - document.Name + - "</strong>.</p><div style='padding: 5px 0px 5px 25px;display: flex;flex-direction: row;justify-content: space-around;'><table> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Sender</td> <td> </td> <td style='color:#626363;font-weight:bold'>" + - sender + - "</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Organization</td> <td> </td><td style='color:#626363;font-weight:bold'> " + - orgName + - "</td></tr> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Expires on</td><td> </td> <td style='color:#626363;font-weight:bold'>" + - localExpireDate + - "</td></tr><tr> <td></td> <td> </td></tr></table> </div> <div style='margin-left:70px'><a target=_blank href=" + - signPdf + - "> <button style='padding: 12px 12px 12px 12px;background-color: #d46b0f;color: white; border: 0px;box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px,rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;font-weight:bold;margin-top:30px;'>Sign here</button></a> </div> <div style='display: flex; justify-content: center;margin-top: 10px;'> </div></div></div><div><p> This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender " + - sender + - ' directly.If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href=' + - openSignUrl + - ' target=_blank>here</a>.</p> </div></div></body> </html>', + subject: replaceVar?.subject + ? replaceVar?.subject + : `${document.ExtUserPtr.Name} has requested you to sign "${document.Name}"`, + from: + sender, + replyto: + sender || + '', + html: replaceVar?.body + ? replaceVar?.body + : "<html><head><meta http-equiv='Content-Type' content='text/html;charset=UTF-8' /></head><body><div style='background-color:#f5f5f5;padding:20px;'><div style='box-shadow:rgba(0, 0, 0, 0.1) 0px 4px 12px;background:white;padding-bottom:20px;'><div style='padding:10px 10px 0 10px'><img src=" + + imgPng + + " height='50' style='padding:20px;width:170px;height:40px;' /></div><div style='padding:2px;font-family:system-ui;background-color:" + + themeBGcolor + + ";'><p style='font-size:20px;font-weight:400;color:white;padding-left:20px;' > Digital Signature Request</p></div><div><p style='padding:20px;font-family:system-ui;font-size:14px;margin-bottom:10px;'> " + + document.ExtUserPtr.Name + + ' has requested you to review and sign <strong> ' + + document.Name + + "</strong>.</p><div style='padding: 5px 0px 5px 25px;display:flex;flex-direction:row;justify-content:space-around;'><table><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Sender</td><td></td><td style='color:#626363;font-weight:bold'>" + + sender + + "</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Organization</td><td></td><td style='color:#626363;font-weight:bold'> " + + orgName + + "</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Expires on</td><td></td><td style='color:#626363;font-weight:bold'>" + + localExpireDate + + "</td></tr><tr><td></td><td></td></tr></table></div><div style='margin-left:70px;'><a target=_blank href=" + + signPdf + + "><button style='padding:12px 12px 12px 12px;background-color:#d46b0f;color:white;border:0px;box-shadow:rgba(0, 0, 0, 0.05) 0px 6px 24px 0px,rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;font-weight:bold;margin-top:30px;'>Sign here</button></a></div><div style='display:flex;justify-content:center;margin-top:10px;'></div></div></div><div><p> This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender " + + sender + + ' directly.If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href=' + + openSignUrl + + ' target=_blank>here</a>.</p></div></div></body></html>', }; const sendMail = await axios.post(url, params, { headers: headers }); // if (sendMail.data.result.status === 'success') { @@ -113,75 +129,13 @@ async function sendMail(document) { } } } -async function callwebhookevent(document) { - const Signers = document.Signers; - const allSigner = document?.Placeholders?.map(item => { - if (item.signerObjId) { - const signer = Signers?.find(e => item?.signerPtr?.objectId === e?.objectId); - if (signer) { - return { - role: item?.Role || '', - name: signer?.Name || '', - email: signer?.Email || '', - phone: signer?.Phone || '', - }; - } - } else { - return { role: item?.Role || '', name: '', email: item?.email || '', phone: '' }; - } - }); - const params = { - event: 'created', - body: { - objectId: document?.objectId, - file: document?.SignedUrl || document?.URL, - name: document?.Name, - note: document?.Note || '', - description: document?.Description || '', - signers: allSigner, - createdBy: document?.ExtUserPtr.Email, - createdAt: document?.createdAt, - }, - }; - try { - await axios - .post(document?.ExtUserPtr?.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: document.CreatedBy.objectId, - }); - webhook.save(null, { useMasterKey: true }); - } catch (err) { - console.log('err save in contracts_Webhook', err); - } - }) - .catch(err => { - console.log('Err send data to webhook', err?.message); - try { - const webhook = new Parse.Object('contracts_Webhook'); - webhook.set('Log', err?.status); - webhook.set('UserId', { - __type: 'Pointer', - className: '_User', - objectId: document.CreatedBy.objectId, - }); - webhook.save(null, { useMasterKey: true }); - } catch (err) { - console.log('err save in contracts_Webhook', err?.message); - } - }); - } catch (err) { - console.log('Err ', err?.message); - } -} -async function batchQuery(userId, Documents, Ip, parseConfig) { +async function batchQuery( + userId, + Documents, + Ip, + parseConfig, + type +) { const extCls = new Parse.Query('contracts_Users'); extCls.equalTo('UserId', { __type: 'Pointer', @@ -202,10 +156,14 @@ async function batchQuery(userId, Documents, Ip, parseConfig) { let Acl = { [x.CreatedBy.objectId]: { read: true, write: true } }; if (allSigner && allSigner.length > 0) { allSigner.forEach(x => { - const obj = { [x.CreatedBy.objectId]: { read: true, write: true } }; - Acl = { ...Acl, ...obj }; + if (x?.CreatedBy?.objectId) { + const obj = { [x.CreatedBy.objectId]: { read: true, write: true } }; + Acl = { ...Acl, ...obj }; + } }); } + const mailBody = x?.ExtUserPtr?.TenantId?.RequestBody || ''; + const mailSubject = x?.ExtUserPtr?.TenantId?.RequestSubject || ''; return { method: 'POST', path: '/app/classes/contracts_Document', @@ -231,8 +189,9 @@ async function batchQuery(userId, Documents, Ip, parseConfig) { objectId: y.signerPtr.objectId, }, signerObjId: y.signerObjId, + email: y?.signerPtr?.Email || y?.email || '', } - : { ...y, signerPtr: {}, signerObjId: '' } + : { ...y, signerPtr: {}, signerObjId: '', email: y.email || '' } ), SignedUrl: x.URL || x.SignedUrl, SentToOthers: true, @@ -250,55 +209,17 @@ async function batchQuery(userId, Documents, Ip, parseConfig) { DocSentAt: { __type: 'Date', iso: isoDate }, IsEnableOTP: x?.IsEnableOTP || false, IsTourEnabled: x?.IsTourEnabled || false, - FileAdapterId: x?.FileAdapterId || '', + AllowModifications: x?.AllowModifications || false, ...(x?.SignatureType ? { SignatureType: x?.SignatureType } : {}), ...(x?.NotifyOnSignatures ? { NotifyOnSignatures: x?.NotifyOnSignatures } : {}), + ...(x?.Bcc?.length > 0 ? { Bcc: x?.Bcc } : {}), + ...(x?.RedirectUrl ? { RedirectUrl: x?.RedirectUrl } : {}), + ...(mailBody ? { RequestBody: mailBody } : {}), + ...(mailSubject ? { RequestSubject: mailSubject } : {}), }, }; }); // console.log('requests ', requests); - if (licenseKey) { - const subscription = new Parse.Query('contracts_Subscriptions'); - subscription.equalTo('TenantId', { - __type: 'Pointer', - className: 'partners_Tenant', - objectId: _resExt.TenantId.objectId, - }); - subscription.include('ExtUserPtr'); - subscription.greaterThanOrEqualTo('Next_billing_date', new Date()); - const resSub = await subscription.first({ useMasterKey: true }); - if (resSub) { - const _resSub = JSON.parse(JSON.stringify(resSub)); - const allowedCredits = _resSub?.AllowedCredits || 0; - const addonCredits = _resSub?.AddonCredits || 0; - const totalcredits = allowedCredits + addonCredits; - if (requests?.length <= totalcredits) { - const response = await axios.post('batch', { requests: requests }, parseConfig); - // Handle the batch query response - // console.log('Batch query response:', response.data); - if (response.data && response.data.length > 0) { - const updateDocuments = Documents.map((x, i) => ({ - ...x, - objectId: response.data[i]?.success?.objectId, - createdAt: response.data[i]?.success?.createdAt, - })); - deductcount(response.data.length, resExt.id, _resSub); - for (let i = 0; i < updateDocuments.length; i++) { - sendMail(updateDocuments[i], ''); //sessionToken - } - callwebhookevent(Documents[0]); - return 'success'; - } - } else { - throw new Parse.Error(429, 'Quota reached, Please buy credits and try again later.'); - } - } else { - throw new Parse.Error( - Parse.Error.INVALID_QUERY, - 'Please purchase or renew your subscription.' - ); - } - } else { if (requests?.length > 0) { const newrequests = [requests?.[0]]; const response = await axios.post('batch', { requests: newrequests }, parseConfig); @@ -313,10 +234,8 @@ async function batchQuery(userId, Documents, Ip, parseConfig) { }; deductcount(response.data.length, resExt.id); sendMail(updateDocuments); //sessionToken - callwebhookevent(Documents[0]); return 'success'; } - } } } catch (error) { const code = error?.response?.data?.code || error?.response?.status || error?.code || 400; @@ -335,7 +254,7 @@ async function batchQuery(userId, Documents, Ip, parseConfig) { export default async function createBatchDocs(request) { const strDocuments = request.params.Documents; const sessionToken = request.headers?.sessiontoken; - const jwttoken = request.headers?.jwttoken; + const type = request.headers?.type || 'quicksend'; const Documents = JSON.parse(strDocuments); const Ip = request?.headers?.['x-real-ip'] || ''; const parseConfig = { @@ -348,31 +267,9 @@ export default async function createBatchDocs(request) { }; try { if (request?.user) { - return await batchQuery(request.user.id, Documents, Ip, parseConfig); - } else if (jwttoken) { - const jwtDecode = parseJwt(jwttoken); - if (jwtDecode?.user_email) { - const userCls = new Parse.Query(Parse.User); - userCls.equalTo('email', jwtDecode?.user_email); - const userRes = await userCls.first({ useMasterKey: true }); - const userId = userRes?.id; - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('userId', { - __type: 'Pointer', - className: '_User', - objectId: userId, - }); - const appRes = await tokenQuery.first({ useMasterKey: true }); - const decoded = jwt.verify(jwttoken, appRes?.get('token')); - if (decoded?.user_email) { - return await batchQuery(userId, Documents, Ip, parseConfig); - } else { - throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Invalid token.'); - } - } else { - throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Invalid token.'); - } - } else { + return await batchQuery(request.user.id, Documents, Ip, parseConfig, '', type); + } + else { throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.'); } } catch (err) { diff --git a/apps/OpenSignServer/cloud/parsefunction/createDuplicate.js b/apps/OpenSignServer/cloud/parsefunction/createDuplicate.js new file mode 100644 index 000000000..887703411 --- /dev/null +++ b/apps/OpenSignServer/cloud/parsefunction/createDuplicate.js @@ -0,0 +1,112 @@ +export default async function createDuplicate(request) { + const templateId = request.params.templateId; + + if (!request.user) { + throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.'); + } + + if (templateId) { + try { + const templateQuery = new Parse.Query('contracts_Template'); + templateQuery.equalTo('objectId', templateId); + templateQuery.equalTo('CreatedBy', { + __type: 'Pointer', + className: '_User', + objectId: request.user.id, + }); + templateQuery.notEqualTo('IsArchive', true); + const templateRes = await templateQuery.first({ useMasterKey: true }); + if (templateRes?.id) { + const _templateRes = JSON.parse(JSON.stringify(templateRes)); + const newTemplate = new Parse.Object('contracts_Template'); + + let signers = []; + if (_templateRes.Signers?.length > 0) { + _templateRes.Signers?.forEach(x => { + if (x.objectId) { + const obj = { + __type: 'Pointer', + className: 'contracts_Contactbook', + objectId: x.objectId, + }; + signers.push(obj); + } + }); + } + newTemplate.set('Name', _templateRes.Name); + newTemplate.set('URL', _templateRes.URL); + newTemplate.set('SignedUrl', _templateRes.SignedUrl); + newTemplate.set('SentToOthers', _templateRes?.SentToOthers || false); + newTemplate.set('SendinOrder', _templateRes?.SendinOrder || false); + newTemplate.set('AutomaticReminders', _templateRes?.AutomaticReminders || false); + newTemplate.set('RemindOnceInEvery', _templateRes?.RemindOnceInEvery || 5); + newTemplate.set('IsEnableOTP', _templateRes?.IsEnableOTP || false); + newTemplate.set('AllowModifications', _templateRes?.AllowModifications || false); + newTemplate.set('Signers', signers); + newTemplate.set('ExtUserPtr', { + __type: 'Pointer', + className: 'contracts_Users', + objectId: _templateRes.ExtUserPtr.objectId, + }); + newTemplate.set('CreatedBy', { + __type: 'Pointer', + className: '_User', + objectId: _templateRes.CreatedBy.objectId, + }); + if (_templateRes?.Note) { + newTemplate.set('Note', _templateRes?.Note); + } + if (_templateRes?.Description) { + newTemplate.set('Description', _templateRes?.Description); + } + if (_templateRes?.Placeholders?.length > 0) { + newTemplate.set('Placeholders', _templateRes.Placeholders); + } + if (_templateRes?.SignatureType?.length > 0) { + newTemplate.set('SignatureType', _templateRes?.SignatureType); + } + if (_templateRes?.NotifyOnSignatures !== undefined) { + newTemplate.set('NotifyOnSignatures', _templateRes.NotifyOnSignatures); + } + if (_templateRes?.SharedWith?.length > 0) { + newTemplate.set('SharedWith', _templateRes.SharedWith); + } + if (_templateRes?.IsPublic) { + newTemplate.set('IsPublic', _templateRes?.IsPublic); + } + if (_templateRes?.PublicRole?.length > 0) { + newTemplate.set('PublicRole', _templateRes?.PublicRole); + } + if (_templateRes?.IsTourEnabled) { + newTemplate.set('IsTourEnabled', _templateRes?.IsTourEnabled); + } + if (_templateRes?.Bcc?.length) { + newTemplate.set('Bcc', _templateRes?.Bcc); + } + const OriginIp = _templateRes?.OriginIp || request?.headers?.['x-real-ip'] || ''; + + if (OriginIp) { + newTemplate.set('OriginIp', OriginIp); + } + if (_templateRes?.RedirectUrl) { + newTemplate.set('RedirectUrl', _templateRes?.RedirectUrl); + } + const acl = templateRes.getACL(); + if (acl) { + newTemplate.setACL(acl); + } + const newTemplateRes = await newTemplate.save(null, { useMasterKey: true }); + const _newTemplateRes = JSON.parse(JSON.stringify(newTemplateRes)); + return _newTemplateRes; + } else { + throw new Parse.Error( + Parse.Error.INVALID_QUERY, + 'You cannot create duplicate of this template.' + ); + } + } catch (err) { + console.log('err while creating duplicate', err); + throw err; + } + } +} diff --git a/apps/OpenSignServer/cloud/parsefunction/deactivateMailAdapter.js b/apps/OpenSignServer/cloud/parsefunction/deactivateMailAdapter.js deleted file mode 100644 index a84087613..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/deactivateMailAdapter.js +++ /dev/null @@ -1,24 +0,0 @@ -export default async function deactivateMailAdapter(request) { - if (!request?.user) { - throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.'); - } - try { - const extUserCls = new Parse.Query('contracts_Users'); - extUserCls.equalTo('UserId', request.user); - const extUser = await extUserCls.first({ useMasterKey: true }); - if (extUser) { - const extUserCls = new Parse.Object('contracts_Users'); - extUserCls.id = extUser.id; - extUserCls.unset('active_mail_adapter'); - const updateExtUser = await extUserCls.save(null, { useMasterKey: true }); - // console.log('updateExtUser ', updateExtUser); - return updateExtUser.updatedAt; - } - return extUser; - } catch (err) { - console.log('Err in add custom smtp', err); - const code = err.code || 400; - const msg = err.message || 'Something went wrong.'; - throw new Parse.Error(code, msg); - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/editContact.js b/apps/OpenSignServer/cloud/parsefunction/editContact.js new file mode 100644 index 000000000..dbe3b3374 --- /dev/null +++ b/apps/OpenSignServer/cloud/parsefunction/editContact.js @@ -0,0 +1,90 @@ +export default async function editContact(request) { + const { contactId, name, email, phone, tenantId } = request.params; + if (!request?.user) { + throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.'); + } + const createdBy = { __type: 'Pointer', className: '_User', objectId: request.user.id }; + try { + const contact = new Parse.Object('contracts_Contactbook'); + contact.id = contactId; + contact.set('IsDeleted', true); + const contactRes = await contact.save(null, { + sessionToken: request?.user.getSessionToken(), + }); + if (contactRes) { + const query = new Parse.Query('contracts_Contactbook'); + query.equalTo('CreatedBy', createdBy); + query.notEqualTo('IsDeleted', true); + query.equalTo('Email', email); + const isContactExist = await query.first({ useMasterKey: true }); + if (isContactExist) { + throw new Parse.Error(Parse.Error.DUPLICATE_VALUE, 'Contact already exists.'); + } + const contactQuery = new Parse.Object('contracts_Contactbook'); + contactQuery.set('Name', name); + if (phone) { + contactQuery.set('Phone', phone); + } + contactQuery.set('Email', email); + contactQuery.set('UserRole', 'contracts_Guest'); + contactQuery.set('IsDeleted', false); + contactQuery.set('TenantId', { + __type: 'Pointer', + className: 'partners_Tenant', + objectId: tenantId, + }); + try { + const _users = Parse.Object.extend('User'); + const _user = new _users(); + _user.set('name', name); + _user.set('username', email); + _user.set('email', email); + _user.set('password', email); + if (phone) { + _user.set('phone', phone); + } + + const user = await _user.save(); + if (user) { + contactQuery.set('CreatedBy', createdBy); + contactQuery.set('UserId', user); + const acl = new Parse.ACL(); + acl.setReadAccess(user.id, true); + acl.setWriteAccess(user.id, true); + acl.setReadAccess(createdBy.objectId, true); + acl.setWriteAccess(createdBy.objectId, true); + contactQuery.setACL(acl); + + const res = await contactQuery.save(); + const parseData = JSON.parse(JSON.stringify(res)); + return parseData; + } + } catch (err) { + console.log('err ', err); + if (err.code === 202) { + const params = { email: email }; + const userRes = await Parse.Cloud.run('getUserId', params); + contactQuery.set('CreatedBy', createdBy); + contactQuery.set('UserId', { + __type: 'Pointer', + className: '_User', + objectId: userRes.id, + }); + const acl = new Parse.ACL(); + acl.setReadAccess(userRes.id, true); + acl.setWriteAccess(userRes.id, true); + acl.setReadAccess(createdBy.objectId, true); + acl.setWriteAccess(createdBy.objectId, true); + contactQuery.setACL(acl); + const res = await contactQuery.save(); + const parseData = JSON.parse(JSON.stringify(res)); + return parseData; + } + } + } else { + throw new Parse.Error(400, 'Something went wrong.'); + } + } catch (err) { + throw err; + } +} diff --git a/apps/OpenSignServer/cloud/parsefunction/fileUpload.js b/apps/OpenSignServer/cloud/parsefunction/fileUpload.js new file mode 100644 index 000000000..cbf5e32ed --- /dev/null +++ b/apps/OpenSignServer/cloud/parsefunction/fileUpload.js @@ -0,0 +1,13 @@ +import { getSignedLocalUrl } from './getSignedUrl.js'; + +export default async function fileUpload(request) { + const url = request.params.url; + + try { + const urlwithjwt = getSignedLocalUrl(url, 200); + return { url: urlwithjwt }; + } catch (err) { + console.log('Err ', err); + throw err; + } +} diff --git a/apps/OpenSignServer/cloud/parsefunction/generateApiToken.js b/apps/OpenSignServer/cloud/parsefunction/generateApiToken.js deleted file mode 100644 index a7ac42524..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/generateApiToken.js +++ /dev/null @@ -1,45 +0,0 @@ -import { generateApiKey } from 'generate-api-key'; -import axios from 'axios'; -import { cloudServerUrl } from '../../Utils.js'; -export default async function generateApiToken(request) { - const serverUrl = cloudServerUrl; //process.env.SERVER_URL; - try { - const userRes = await axios.get(serverUrl + '/users/me', { - headers: { - 'X-Parse-Application-Id': process.env.APP_ID, - 'X-Parse-Session-Token': request.headers['sessiontoken'], - }, - }); - const userId = userRes.data && userRes.data.objectId; - if (userId) { - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('userId', { __type: 'Pointer', className: '_User', objectId: userId }); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // return exsiting Token - console.log('Regenerate API Token'); - const AppToken = Parse.Object.extend('appToken'); - const updateToken = new AppToken(); - updateToken.id = token.id; - const newToken = generateApiKey({ method: 'base62', prefix: 'opensign' }); - updateToken.set('token', newToken); - const updatedRes = await updateToken.save(null, { useMasterKey: true }); - return updatedRes; - } else { - // Create New Token - console.log('New API Token Generation'); - const appToken = Parse.Object.extend('appToken'); - const appTokenQuery = new appToken(); - const token = generateApiKey({ method: 'base62', prefix: 'opensign' }); - appTokenQuery.set('token', token); - appTokenQuery.set('userId', { __type: 'Pointer', className: '_User', objectId: userId }); - const newRes = await appTokenQuery.save(null, { useMasterKey: true }); - return newRes; - } - } else { - return 'User not found!'; - } - } catch (err) { - console.log('err ', err); - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/generateCertificatebydocId.js b/apps/OpenSignServer/cloud/parsefunction/generateCertificatebydocId.js new file mode 100644 index 000000000..f17ffc38f --- /dev/null +++ b/apps/OpenSignServer/cloud/parsefunction/generateCertificatebydocId.js @@ -0,0 +1,109 @@ +import { SignPdf } from '@signpdf/signpdf'; +import { P12Signer } from '@signpdf/signer-p12'; +import { pdflibAddPlaceholder } from '@signpdf/placeholder-pdf-lib'; +import { PDFDocument } from 'pdf-lib'; +import Parse from 'parse/node.js'; +import fs from 'node:fs'; +import dotenv from 'dotenv'; +import GenerateCertificate from './pdf/GenerateCertificate.js'; +import { getSecureUrl } from '../../Utils.js'; +dotenv.config(); +const eSignName = 'opensign'; +const eSigncontact = 'hello@opensignlabs.com'; + +// `uploadFile` is used to create url in from pdfFile +async function uploadFile( + pdfName, + filepath, +) { + try { + const filedata = fs.readFileSync(filepath); + let fileUrl; + const file = new Parse.File(pdfName, [...filedata], 'application/pdf'); + await file.save({ useMasterKey: true }); + const fileRes = getSecureUrl(file.url()); + fileUrl = fileRes.url; + return { imageUrl: fileUrl }; + } catch (err) { + console.log('Err ', err); + // `unlinkCertificate` is used to remove exported signed pdf file from exports folder + unlinkCertificate(filepath); + } +} + +async function unlinkCertificate(path) { + if (fs.existsSync(path)) { + try { + fs.unlinkSync(path); + } catch (err) { + console.log('Err in unlink certificate generatecertificatebydocid', err); + } + } +} + +export default async function generateCertificatebydocId(req) { + const docId = req.params.docId; + // const userId = req.headers.userid; + + if (!docId) { + throw new Parse.Error(Parse.Error.INVALID_QUERY, 'please provide parameter.'); + } + // `P12Buffer` used to create buffer from p12 certificate + const pfxFile = process.env.PFX_BASE64; + // const P12Buffer = fs.readFileSync(); + const P12Buffer = Buffer.from(pfxFile, 'base64'); + const certificatePath = `./exports/certificate_${docId}.pdf`; + try { + const getDocument = new Parse.Query('contracts_Document'); + getDocument.include('ExtUserPtr,Signers,AuditTrail.UserPtr,Placeholders,ExtUserPtr.TenantId'); + const docRes = await getDocument.get(docId, { useMasterKey: true }); + + if (docRes && docRes?.get('IsCompleted') && !docRes?.get('CertificateUrl')) { + const _docRes = JSON.parse(JSON.stringify(docRes)); + const filteredaudit = _docRes?.AuditTrail?.filter(x => x?.UserPtr?.objectId); + // Create a reversed copy of the array and find the last object with 'signedOn' + const lastObj = [...filteredaudit].reverse().find(obj => obj.hasOwnProperty('SignedOn')); + const completedAt = lastObj.SignedOn; + const doc = { ..._docRes, completedAt: completedAt }; + const certificate = await GenerateCertificate(doc); + const certificatePdf = await PDFDocument.load(certificate); + const p12 = new P12Signer(P12Buffer, { passphrase: process.env.PASS_PHRASE || null }); + // `pdflibAddPlaceholder` is used to add code of only digitial sign in certificate + pdflibAddPlaceholder({ + pdfDoc: certificatePdf, + reason: 'Digitally signed by OpenSign.', + location: 'n/a', + name: eSignName, + contactInfo: eSigncontact, + signatureLength: 15000, + }); + const pdfWithPlaceholderBytes = await certificatePdf.save(); + const CertificateBuffer = Buffer.from(pdfWithPlaceholderBytes); + //`new signPDF` create new instance of CertificateBuffer and p12Buffer + const certificateOBJ = new SignPdf(); + // `signedCertificate` is used to sign certificate digitally + const signedCertificate = await certificateOBJ.sign(CertificateBuffer, p12); + + //below is used to save signed certificate in exports folder + fs.writeFileSync(certificatePath, signedCertificate); + const file = await uploadFile( + 'certificate.pdf', + certificatePath, + ); + const updateDoc = new Parse.Object('contracts_Document'); + updateDoc.id = doc.objectId; + updateDoc.set('CertificateUrl', file.imageUrl); + const updateDocRes = await updateDoc.save(null, { useMasterKey: true }); + unlinkCertificate(certificatePath); + return { CertificateUrl: file.imageUrl }; + } else { + return { CertificateUrl: '' }; + } + } catch (error) { + console.error('Error fetching or processing document:', error); + const code = error?.code || 400; + const message = error?.message || 'Something went wrong.'; + unlinkCertificate(certificatePath); + throw new Parse.Error(code, message); + } +} diff --git a/apps/OpenSignServer/cloud/parsefunction/getAllUserTeamByOrg.js b/apps/OpenSignServer/cloud/parsefunction/getAllUserTeamByOrg.js deleted file mode 100644 index 0e6ee03f4..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/getAllUserTeamByOrg.js +++ /dev/null @@ -1,26 +0,0 @@ -export default async function getAllUserTeamByOrg(request) { - const OrgId = request.params.orgId; - if (!request?.user) { - throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.'); - } - try { - const teamCls = new Parse.Query('contracts_Teams'); - teamCls.equalTo('OrganizationId', { - __type: 'Pointer', - className: 'contracts_Organizations', - objectId: OrgId, - }); - teamCls.equalTo('IsActive', true); - const teamRes = await teamCls.first({ useMasterKey: true }); - if (teamRes) { - return teamRes; - } else { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Team not found.'); - } - } catch (err) { - console.log('err in getOrganizations', err); - const code = err?.code || 400; - const msg = err?.message || 'Something went wrong.'; - throw new Parse.Error(code, msg); - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/getDocument.js b/apps/OpenSignServer/cloud/parsefunction/getDocument.js index 112374e46..ab0513d4a 100644 --- a/apps/OpenSignServer/cloud/parsefunction/getDocument.js +++ b/apps/OpenSignServer/cloud/parsefunction/getDocument.js @@ -1,11 +1,10 @@ import axios from 'axios'; -import { cloudServerUrl, parseJwt } from '../../Utils.js'; -import jwt from 'jsonwebtoken'; - +import { + cloudServerUrl, +} from '../../Utils.js'; export default async function getDocument(request) { const serverUrl = cloudServerUrl; //process.env.SERVER_URL; const docId = request.params.docId; - const jwttoken = request?.headers?.jwttoken || ''; const sessiontoken = request?.headers?.sessiontoken || ''; try { if (docId) { @@ -48,38 +47,8 @@ export default async function getDocument(request) { console.log('err user in not authenticated', err); return { error: "You don't have access of this document!" }; } - } else if (jwttoken) { - try { - const jwtDecode = parseJwt(jwttoken); - if (jwtDecode?.user_email) { - const userCls = new Parse.Query(Parse.User); - userCls.equalTo('email', jwtDecode?.user_email); - const userRes = await userCls.first({ useMasterKey: true }); - const userId = userRes?.id; - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('userId', { - __type: 'Pointer', - className: '_User', - objectId: userId, - }); - const appRes = await tokenQuery.first({ useMasterKey: true }); - const decoded = jwt.verify(jwttoken, appRes?.get('token')); - if (decoded?.user_email) { - const acl = res.getACL(); - if (userId && acl && acl.getReadAccess(userId)) { - return document; - } else { - return { error: "You don't have access of this document!" }; - } - } else { - return { status: 'error', result: 'Invalid token!' }; - } - } - } catch (err) { - console.log('err in jwt', err); - return { error: "You don't have access of this document!" }; - } - } else { + } + else { return { error: "You don't have access of this document!" }; } } diff --git a/apps/OpenSignServer/cloud/parsefunction/getDrive.js b/apps/OpenSignServer/cloud/parsefunction/getDrive.js index 6d2760dfa..9899e3e86 100644 --- a/apps/OpenSignServer/cloud/parsefunction/getDrive.js +++ b/apps/OpenSignServer/cloud/parsefunction/getDrive.js @@ -16,25 +16,29 @@ export default async function getDrive(request) { }); const userId = userRes.data && userRes.data.objectId; if (userId) { - let url; - if (docId) { - url = `${classUrl}?where={"Folder":{"__type":"Pointer","className":"contracts_Document","objectId":"${docId}"},"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"${userId}"},"IsArchive":{"$ne":true}}&include=ExtUserPtr,ExtUserPtr.TenantId,Signers,Folder&order=-updatedAt&skip=${skip}&limit=${limit}`; - } else { - url = `${classUrl}?where={"Folder":{"$exists":false},"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"${userId}"},"IsArchive":{"$ne":true}}&include=ExtUserPtr,ExtUserPtr.TenantId,Signers&order=-updatedAt&skip=${skip}&limit=${limit}`; - } try { - const res = await axios.get(url, { - headers: { - 'X-Parse-Application-Id': appId, - 'X-Parse-Master-key': process.env.MASTER_KEY, - }, - }); - // console.log('res.data.results ', res.data.results); - if (res.data && res.data.results) { - return res.data.results; + const query = new Parse.Query('contracts_Document'); + if (docId) { + query.equalTo('Folder', { + __type: 'Pointer', + className: 'contracts_Document', + objectId: docId, + }); + query.include('Folder'); } else { - return []; + query.doesNotExist('Folder', true); } + query.equalTo('CreatedBy', { __type: 'Pointer', className: '_User', objectId: userId }); + query.include('ExtUserPtr'); + query.include('ExtUserPtr.TenantId'); + query.include('Signers'); + query.notEqualTo('IsArchive', true); + query.descending('updatedAt'); + query.skip(skip); + query.limit(limit); + query.exclude('AuditTrail'); + const res = await query.find({ useMasterKey: true }); + return res; } catch (err) { console.log('err', err); return { error: "You don't have access to drive" }; diff --git a/apps/OpenSignServer/cloud/parsefunction/getFileAdapter.js b/apps/OpenSignServer/cloud/parsefunction/getFileAdapter.js deleted file mode 100644 index 1aec6ffd3..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/getFileAdapter.js +++ /dev/null @@ -1,25 +0,0 @@ -export default async function getFileAdapter(request) { - if (!request?.user) { - throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.'); - } - try { - const extUserCls = new Parse.Query('contracts_Users'); - extUserCls.equalTo('UserId', request.user); - extUserCls.include('TenantId'); - const extUser = await extUserCls.first({ useMasterKey: true }); - if (extUser) { - const _extUser = JSON.parse(JSON.stringify(extUser)); - const FileAdapters = - _extUser?.TenantId?.FileAdapters?.length > 0 ? _extUser?.TenantId?.FileAdapters : []; - const ActiveFileAdapter = _extUser?.TenantId?.ActiveFileAdapter || 'opensign'; - return { ActiveFileAdapter: ActiveFileAdapter, FileAdapters: FileAdapters }; - } else { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.'); - } - } catch (err) { - console.log('Err in add custom file adapter', err); - const code = err.code || 400; - const msg = err.message || 'Something went wrong.'; - throw new Parse.Error(code, msg); - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/getInvoices.js b/apps/OpenSignServer/cloud/parsefunction/getInvoices.js deleted file mode 100644 index 283abe66d..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/getInvoices.js +++ /dev/null @@ -1,44 +0,0 @@ -import axios from 'axios'; -import { cloudServerUrl } from '../../Utils.js'; -const serverUrl = cloudServerUrl; //process.env.SERVER_URL; -const appId = process.env.APP_ID; -export default async function getInvoices(request) { - const limit = request.params.limit || 100; - const skip = request.params.skip || 0; - const extUserId = request.params.extUserId; - try { - const userRes = await axios.get(serverUrl + '/users/me', { - headers: { - 'X-Parse-Application-Id': appId, - 'X-Parse-Session-Token': request.headers['sessiontoken'], - }, - }); - const userId = userRes.data && userRes.data.objectId; - if (userId) { - if (!extUserId) { - return { status: 'error', result: 'Please provide parameter!' }; - } - const invoiceCls = new Parse.Query('contracts_Invoices'); - invoiceCls.equalTo('ExtUserPtr', { - __type: 'Pointer', - className: 'contracts_Users', - objectId: extUserId, - }); - invoiceCls.limit(limit); - invoiceCls.skip(skip); - invoiceCls.descending('createdAt'); - const invoices = await invoiceCls.find({ useMasterKey: true }); - if (invoices?.length > 0) { - const _invoices = JSON.parse(JSON.stringify(invoices)); - return { status: 'success', result: _invoices }; - } else { - return { status: 'success', result: [] }; - } - } else { - return { status: 'error', result: 'Invalid session token!' }; - } - } catch (err) { - console.log('Err in get invoices', err.message); - return { status: 'error', result: err.message }; - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/getOrgAdmins.js b/apps/OpenSignServer/cloud/parsefunction/getOrgAdmins.js deleted file mode 100644 index 07c37c888..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/getOrgAdmins.js +++ /dev/null @@ -1,24 +0,0 @@ -export default async function getOrgAdmins(req) { - if (!req?.user) { - throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.'); - } else { - try { - const extUser = new Parse.Query('contracts_Users'); - extUser.equalTo('UserRole', 'contracts_OrgAdmin'); - extUser.equalTo('CreatedBy', req?.user); - extUser.notEqualTo('UserId', req?.user); - extUser.include('TeamIds,OrganizationId'); - extUser.descending('createdAt'); - const userRes = await extUser.find({ useMasterKey: true }); - if (userRes.length > 0) { - const _userRes = JSON.parse(JSON.stringify(userRes)); - return _userRes; - } else { - return []; - } - } catch (err) { - console.log('err in getOrgAdmins', err); - throw err; - } - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/getOrganizations.js b/apps/OpenSignServer/cloud/parsefunction/getOrganizations.js deleted file mode 100644 index b8d9909c1..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/getOrganizations.js +++ /dev/null @@ -1,39 +0,0 @@ -export default async function getOrganizations(request) { - const limit = request.params.limit || 200; - const skip = request.params.skip || 0; - const extUserId = request.params.extUserId; - const activeOrgs = request.params.active; - if (!request?.user) { - throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.'); - } - try { - const orgQuery = new Parse.Query('contracts_Organizations'); - orgQuery.equalTo('CreatedBy', { - __type: 'Pointer', - className: '_User', - objectId: request.user.id, - }); - orgQuery.equalTo('ExtUserId', { - __type: 'Pointer', - className: 'contracts_Users', - objectId: extUserId, - }); - if (activeOrgs) { - orgQuery.equalTo('IsActive', true); - } - orgQuery.exclude('ExtUserId'); - orgQuery.limit(limit); - orgQuery.skip(skip); - const resOrg = await orgQuery.find({ useMasterKey: true }); - if (resOrg && resOrg.length > 0) { - return resOrg; - } else { - return []; - } - } catch (err) { - console.log('err in getOrganizations', err); - const code = err?.code || 400; - const msg = err?.message || 'Something went wrong.'; - throw new Parse.Error(code, msg); - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/getPayments.js b/apps/OpenSignServer/cloud/parsefunction/getPayments.js deleted file mode 100644 index 2c52178b4..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/getPayments.js +++ /dev/null @@ -1,41 +0,0 @@ -import axios from 'axios'; -import { cloudServerUrl } from '../../Utils.js'; -const serverUrl = cloudServerUrl; //process.env.SERVER_URL; -const appId = process.env.APP_ID; -export default async function getPayments(request) { - const limit = request.params.limit || 100; - const skip = request.params.skip || 0; - const extUserId = request.params.extUserId; - try { - const userRes = await axios.get(serverUrl + '/users/me', { - headers: { - 'X-Parse-Application-Id': appId, - 'X-Parse-Session-Token': request.headers['sessiontoken'], - }, - }); - const userId = userRes.data && userRes.data.objectId; - if (userId) { - const paymentsCls = new Parse.Query('contracts_Payments'); - paymentsCls.equalTo('ExtUserPtr', { - __type: 'Pointer', - className: 'contracts_User', - objectId: extUserId, - }); - paymentsCls.limit(limit); - paymentsCls.skip(skip); - paymentsCls.descending('createdAt'); - const payments = await paymentsCls.find({ useMasterKey: true }); - if (payments?.length > 0) { - const _payments = JSON.parse(JSON.stringify(payments)); - return { status: 'success', result: _payments }; - } else { - return { status: 'success', result: [] }; - } - } else { - return { status: 'error', result: 'Invalid session token!' }; - } - } catch (err) { - console.log('Err in get Payments', err.message); - return { status: 'error', result: err.message }; - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/getPfxFile.js b/apps/OpenSignServer/cloud/parsefunction/getPfxFile.js deleted file mode 100644 index 9a2c9da01..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/getPfxFile.js +++ /dev/null @@ -1,25 +0,0 @@ -export default async function getPfxFile(request) { - if (!request?.user) { - throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.'); - } - try { - const extUserCls = new Parse.Query('contracts_Users'); - extUserCls.equalTo('UserId', request.user); - extUserCls.include('TenantId'); - const extUser = await extUserCls.first({ useMasterKey: true }); - if (extUser) { - const _extUser = JSON.parse(JSON.stringify(extUser)); - const title = _extUser?.TenantId?.PfxFile?.title || ''; - const pfxBase64 = _extUser?.TenantId?.PfxFile?.base64 || ''; - const password = _extUser?.TenantId?.PfxFile?.password || ''; - return { title: title, password: password, base64: pfxBase64 }; - } else { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.'); - } - } catch (err) { - console.log('Err in add custom file adapter', err); - const code = err.code || 400; - const msg = err.message || 'Something went wrong.'; - throw new Parse.Error(code, msg); - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/getSignedUrl.js b/apps/OpenSignServer/cloud/parsefunction/getSignedUrl.js index 24b15de21..1a595f2d1 100644 --- a/apps/OpenSignServer/cloud/parsefunction/getSignedUrl.js +++ b/apps/OpenSignServer/cloud/parsefunction/getSignedUrl.js @@ -1,29 +1,47 @@ import AWS from 'aws-sdk'; import { useLocal } from '../../Utils.js'; -export default function getPresignedUrl(url, adapter) { - const credentials = { - accessKeyId: adapter?.accessKeyId || process.env.DO_ACCESS_KEY_ID, - secretAccessKey: adapter?.secretAccessKey || process.env.DO_SECRET_ACCESS_KEY, - }; - AWS.config.update({ credentials: credentials, region: adapter?.region || process.env.DO_REGION }); - const spacesEndpoint = adapter?.endpoint || new AWS.Endpoint(process.env.DO_ENDPOINT); +import jwt from 'jsonwebtoken'; +import dotenv from 'dotenv'; +dotenv.config(); - const s3 = new AWS.S3({ endpoint: spacesEndpoint, signatureVersion: "v4" }); +export default function getPresignedUrl( + url, +) { + if (url?.includes('files')) { + return presignedlocalUrl(url); + } else { + const credentials = { + accessKeyId: + process.env.DO_ACCESS_KEY_ID, + secretAccessKey: + process.env.DO_SECRET_ACCESS_KEY, + }; + AWS.config.update({ + credentials: credentials, + region: + process.env.DO_REGION, + }); + const spacesEndpoint = + new AWS.Endpoint(process.env.DO_ENDPOINT); - // Create a new URL object - const parsedUrl = new URL(url); - // Get the pathname of the URL - const pathname = parsedUrl.pathname; - // Extract the filename from the pathname - const filename = pathname.substring(pathname.lastIndexOf('/') + 1); + const s3 = new AWS.S3({ endpoint: spacesEndpoint, signatureVersion: 'v4' }); - // presignedGETURL return presignedUrl with expires time - const presignedGETURL = s3.getSignedUrl('getObject', { - Bucket: adapter?.bucketName || process.env.DO_SPACE, - Key: filename, //filename - Expires: 160, //time to expire in seconds - }); - return presignedGETURL; + // Create a new URL object + const parsedUrl = new URL(url); + // Get the pathname of the URL + const pathname = parsedUrl.pathname; + // Extract the filename from the pathname + const filename = pathname.substring(pathname.lastIndexOf('/') + 1); + + // presignedGETURL return presignedUrl with expires time + const presignedGETURL = s3.getSignedUrl('getObject', { + Bucket: + process.env.DO_SPACE, + Key: filename, //filename + Expires: 160, //time to expire in seconds + }); + return presignedGETURL; + } } export async function getSignedUrl(request) { @@ -31,10 +49,13 @@ export async function getSignedUrl(request) { const docId = request.params.docId || ''; const templateId = request.params.templateId || ''; const url = request.params.url; - const fileAdapterId = request.params.fileAdapterId || ''; if (docId || templateId) { try { - if (fileAdapterId || useLocal !== 'true') { + if (url?.includes('files')) { + return presignedlocalUrl(url); + } else if ( + useLocal !== 'true' + ) { const query = new Parse.Query(docId ? 'contracts_Document' : 'contracts_Template'); query.equalTo('objectId', docId ? docId : templateId); query.include('ExtUserPtr.TenantId'); @@ -49,26 +70,15 @@ export async function getSignedUrl(request) { 'User is not authenticated.' ); } else { - let adapterConfig = {}; - if (fileAdapterId) { - // `adapterConfig` is used to get file in user's fileAdapter - adapterConfig = - _resDoc?.ExtUserPtr?.TenantId?.FileAdapters?.find( - x => x.id === fileAdapterId - ) || {}; - } - const presignedUrl = getPresignedUrl(url, adapterConfig); + const presignedUrl = getPresignedUrl( + url, + ); return presignedUrl; } } else { - let adapterConfig = {}; - if (fileAdapterId) { - // `adapterConfig` is used to get file in user's fileAdapter - adapterConfig = - _resDoc?.ExtUserPtr?.TenantId?.FileAdapters?.find(x => x.id === fileAdapterId) || - {}; - } - const presignedUrl = getPresignedUrl(url, adapterConfig); + const presignedUrl = getPresignedUrl( + url, + ); return presignedUrl; } } @@ -83,7 +93,9 @@ export async function getSignedUrl(request) { if (!request?.user) { throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.'); } else { - if (useLocal !== 'true') { + if (url?.includes('files')) { + return presignedlocalUrl(url); + } else if (useLocal !== 'true') { const presignedUrl = getPresignedUrl(url); return presignedUrl; } else { @@ -99,3 +111,71 @@ export async function getSignedUrl(request) { throw error; } } + +// Function to generate a signed URL with JWT +export function getSignedLocalUrl(fileUrl, expirationTimeInSeconds) { + const secretKey = process.env.MASTER_KEY; + const exp = expirationTimeInSeconds || 200; + try { + // Create the payload with the file URL and expiration time + const payload = { + fileUrl, + exp: Math.floor(Date.now() / 1000) + exp, // Expiry time in seconds + }; + + // Generate the JWT token + const token = jwt.sign(payload, secretKey); + // Return the signed URL containing the token + return `${fileUrl}?token=${token}`; + } catch (err) { + console.log('Err while siging local url', err); + throw new Error('Invalid or expired token.'); + } +} + +export function presignedlocalUrl(signedUrl, expirationTimeInSeconds) { + if (signedUrl?.includes('files')) { + const fileUrl = signedUrl.split('?')?.[0]; + const secretKey = process.env.MASTER_KEY; + const exp = expirationTimeInSeconds || 200; + try { + // Create the payload with the file URL and expiration time + const payload = { + fileUrl, + exp: Math.floor(Date.now() / 1000) + exp, // Expiry time in seconds + }; + // Generate the JWT token + const token = jwt.sign(payload, secretKey); + // Return the signed URL containing the token + return `${fileUrl}?token=${token}`; + } catch (err) { + throw new Error('Invalid or expired token.'); + } + } else { + return signedUrl; + } +} + +// Function to validate the signed URL +export async function validateSignedLocalUrl(signedUrl) { + const urlParams = new URLSearchParams(signedUrl.split('?')[1]); + const token = urlParams.get('token'); + try { + if (!token) { + throw new Error('No token provided.'); + } + const secretKey = process.env.MASTER_KEY; + // Now verify the token (validate signature and expiration automatically) + const decoded = jwt.verify(token, secretKey); + // Check if the file URL in the JWT matches the requested file URL + const fileUrl = signedUrl.split('?')[0]; + if (decoded.fileUrl !== fileUrl) { + throw new Error('Invalid file URL in token.'); + } + // If the token is valid and not expired, return the file URL + return signedUrl; + } catch (error) { + console.log('Error validating file', error.message); + return 'Unauthorized'; + } +} diff --git a/apps/OpenSignServer/cloud/parsefunction/getSigners.js b/apps/OpenSignServer/cloud/parsefunction/getSigners.js index 15fcad4cb..7d41726e0 100644 --- a/apps/OpenSignServer/cloud/parsefunction/getSigners.js +++ b/apps/OpenSignServer/cloud/parsefunction/getSigners.js @@ -1,61 +1,42 @@ -import { parseJwt } from '../../Utils.js'; -import jwt from 'jsonwebtoken'; +// Function to escape special characters in the search string +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // Escape special characters +} +async function getContacts(searchObj, isJWT) { + try { + const escapedSearch = escapeRegExp(searchObj.search); // Escape the search input + const searchRegex = new RegExp(escapedSearch, 'i'); // Create regex once to reuse + const contactNameQuery = new Parse.Query('contracts_Contactbook'); + contactNameQuery.matches('Name', searchRegex); + + const conatctEmailQuery = new Parse.Query('contracts_Contactbook'); + conatctEmailQuery.matches('Email', searchRegex); + + // Combine the two queries with OR + const mainQuery = Parse.Query.or(contactNameQuery, conatctEmailQuery); + + // Add the common condition for 'CreatedBy' + mainQuery.equalTo('CreatedBy', searchObj.CreatedBy); + mainQuery.notEqualTo('IsDeleted', true); + const findOpt = isJWT ? { useMasterKey: true } : { sessionToken: searchObj.sessionToken }; + const contactRes = await mainQuery.find(findOpt); + const _contactRes = JSON.parse(JSON.stringify(contactRes)); + return _contactRes; + } catch (err) { + console.log('err while fetch contacts', err); + throw err; + } +} export default async function getSigners(request) { - const jwttoken = request.headers.jwttoken || ''; - const search = request.params.search || ''; - const searchEmail = request.params.searchEmail || ''; + const searchObj = { search: request.params.search || '', sessionToken: '' }; try { if (request.user) { - const contactbook = new Parse.Query('contracts_Contactbook'); - contactbook.equalTo('CreatedBy', { - __type: 'Pointer', - className: '_User', - objectId: request?.user?.id, - }); - if (search) { - contactbook.matches('Name', new RegExp(search, 'i')); - } else if (searchEmail) { - contactbook.matches('Email', new RegExp(searchEmail, 'i')); - } - contactbook.notEqualTo('IsDeleted', true); - const contactRes = await contactbook.find({ sessionToken: request.user.getSessionToken() }); - const _contactRes = JSON.parse(JSON.stringify(contactRes)); - return _contactRes; - } else if (jwttoken) { - const jwtDecode = parseJwt(jwttoken); - const userCls = new Parse.Query(Parse.User); - userCls.equalTo('email', jwtDecode?.user_email); - const userRes = await userCls.first({ useMasterKey: true }); - const userId = userRes?.id; - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('userId', { - __type: 'Pointer', - className: '_User', - objectId: userId, - }); - const appRes = await tokenQuery.first({ useMasterKey: true }); - const decoded = jwt.verify(jwttoken, appRes?.get('token')); - if (decoded?.user_email) { - const contactbook = new Parse.Query('contracts_Contactbook'); - contactbook.equalTo('CreatedBy', { - __type: 'Pointer', - className: '_User', - objectId: userId, - }); - if (search) { - contactbook.matches('Name', new RegExp(search, 'i')); - } else if (searchEmail) { - contactbook.matches('Email', new RegExp(searchEmail, 'i')); - } - contactbook.notEqualTo('IsDeleted', true); - const contactRes = await contactbook.find({ useMasterKey: true }); - const _contactRes = JSON.parse(JSON.stringify(contactRes)); - return _contactRes; - } else { - throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Invalid token'); - } - } else { + searchObj.CreatedBy = { __type: 'Pointer', className: '_User', objectId: request?.user?.id }; + searchObj.sessionToken = request.user.getSessionToken(); + return await getContacts(searchObj); + } + else { throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Invalid session token'); } } catch (err) { diff --git a/apps/OpenSignServer/cloud/parsefunction/getSubscriptions.js b/apps/OpenSignServer/cloud/parsefunction/getSubscriptions.js deleted file mode 100644 index 0538ae757..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/getSubscriptions.js +++ /dev/null @@ -1,134 +0,0 @@ -import axios from 'axios'; -import { cloudServerUrl, parseJwt } from '../../Utils.js'; -import jwt from 'jsonwebtoken'; -const serverUrl = cloudServerUrl; //process.env.SERVER_URL; -const appId = process.env.APP_ID; -export default async function getSubscription(request) { - const extUserId = request.params.extUserId || ''; - const contactId = request.params.contactId || ''; - const ispublic = request.params.ispublic || false; - const jwttoken = request.headers?.jwttoken || ''; - - if (jwttoken) { - const jwtDecode = parseJwt(jwttoken); - if (jwtDecode?.user_email) { - const verifyToken = jwttoken; - const userCls = new Parse.Query(Parse.User); - userCls.equalTo('email', jwtDecode?.user_email); - const userRes = await userCls.first({ useMasterKey: true }); - const userId = userRes?.id; - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('userId', { - __type: 'Pointer', - className: '_User', - objectId: userId, - }); - const appRes = await tokenQuery.first({ useMasterKey: true }); - const decoded = jwt.verify(verifyToken, appRes?.get('token')); - if (decoded?.user_email) { - const extCls = new Parse.Query('contracts_Users'); - extCls.equalTo('Email', decoded?.user_email); - const exUser = await extCls.first({ useMasterKey: true }); - if (exUser) { - const subscriptionCls = new Parse.Query('contracts_Subscriptions'); - subscriptionCls.equalTo('TenantId', { - __type: 'Pointer', - className: 'partners_Tenant', - objectId: exUser.get('TenantId').id, - }); - subscriptionCls.descending('createdAt'); - const subcripitions = await subscriptionCls.first({ useMasterKey: true }); - if (subcripitions) { - const _subcripitions = JSON.parse(JSON.stringify(subcripitions)); - return { status: 'success', result: _subcripitions }; - } else { - return { status: 'success', result: {} }; - } - } else { - return { status: 'error', result: 'User not found!' }; - } - } else { - return { status: 'error', result: 'Invalid token!' }; - } - } - } else if (extUserId) { - try { - let userId; - //`ispublic` is used in public profile to get subscription details - if (!ispublic) { - 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 (userId || ispublic) { - const extCls = new Parse.Query('contracts_Users'); - const exUser = await extCls.get(extUserId, { useMasterKey: true }); - if (exUser) { - const subscriptionCls = new Parse.Query('contracts_Subscriptions'); - subscriptionCls.equalTo('TenantId', { - __type: 'Pointer', - className: 'partners_Tenant', - objectId: exUser.get('TenantId').id, - }); - subscriptionCls.descending('createdAt'); - const subcripitions = await subscriptionCls.first({ useMasterKey: true }); - if (subcripitions) { - const _subcripitions = JSON.parse(JSON.stringify(subcripitions)); - return { status: 'success', result: _subcripitions }; - } else { - return { status: 'success', result: {} }; - } - } else { - return { status: 'error', result: 'User not found!' }; - } - } else { - return { status: 'error', result: 'Invalid session token!' }; - } - } catch (err) { - console.log('Err in get subscription', err.message); - return { status: 'error', result: err.message }; - } - } else if (contactId) { - try { - const contactCls = new Parse.Query('contracts_Contactbook'); - const contactUser = await contactCls.get(contactId, { useMasterKey: true }); - if (contactUser) { - const subscriptionCls = new Parse.Query('contracts_Subscriptions'); - subscriptionCls.equalTo('TenantId', { - __type: 'Pointer', - className: 'partners_Tenant', - objectId: contactUser.get('TenantId').id, - }); - subscriptionCls.descending('createdAt'); - const subcripitions = await subscriptionCls.first({ useMasterKey: true }); - if (subcripitions) { - const _subcripitions = JSON.parse(JSON.stringify(subcripitions)); - if (_subcripitions.PlanCode === 'freeplan') { - return { status: 'success', result: { isSubscribed: false, plan: 'freeplan' } }; - } else if (_subcripitions?.Next_billing_date?.iso) { - if (new Date(_subcripitions.Next_billing_date.iso) > new Date()) { - return { status: 'success', result: { isSubscribed: true } }; - } else { - return { status: 'success', result: { isSubscribed: false } }; - } - } else { - return { status: 'success', result: { isSubscribed: false } }; - } - } else { - return { status: 'success', result: { isSubscribed: false } }; - } - } else { - return { status: 'error', result: 'User not found!' }; - } - } catch (err) { - console.log('Err in get subscription2', err.message); - return { status: 'error', result: err.message }; - } - } else { - return { status: 'error', result: 'Invalid session token!' }; - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/getTeams.js b/apps/OpenSignServer/cloud/parsefunction/getTeams.js index 7021d5063..5d692965b 100644 --- a/apps/OpenSignServer/cloud/parsefunction/getTeams.js +++ b/apps/OpenSignServer/cloud/parsefunction/getTeams.js @@ -30,7 +30,7 @@ export default async function getTeams(request) { return []; } } catch (err) { - console.log('err in getOrganizations', err); + console.log('err in getTeams', err); const code = err?.code || 400; const msg = err?.message || 'Something went wrong.'; throw new Parse.Error(code, msg); diff --git a/apps/OpenSignServer/cloud/parsefunction/getTenant.js b/apps/OpenSignServer/cloud/parsefunction/getTenant.js index 4b0e328a4..1c98aa7e1 100644 --- a/apps/OpenSignServer/cloud/parsefunction/getTenant.js +++ b/apps/OpenSignServer/cloud/parsefunction/getTenant.js @@ -1,5 +1,3 @@ -import { parseJwt } from '../../Utils.js'; -import jwt from 'jsonwebtoken'; async function getTenantByUserId(userId, contactId) { try { @@ -50,34 +48,13 @@ async function getTenantByUserId(userId, contactId) { } } export default async function getTenant(request) { - const jwttoken = request.headers.jwttoken || ''; const userId = request.params.userId || ''; const contactId = request.params.contactId || ''; - if (jwttoken) { - const jwtDecode = parseJwt(jwttoken); - if (jwtDecode?.user_email) { - const verifyToken = jwttoken; - const userCls = new Parse.Query(Parse.User); - userCls.equalTo('email', jwtDecode?.user_email); - const userRes = await userCls.first({ useMasterKey: true }); - const apiUserId = userRes?.id; - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('userId', { - __type: 'Pointer', - className: '_User', - objectId: apiUserId, - }); - const appRes = await tokenQuery.first({ useMasterKey: true }); - const decoded = jwt.verify(verifyToken, appRes?.get('token')); - if (decoded?.user_email) { - return await getTenantByUserId(apiUserId, contactId); - } else { - return { status: 'error', result: 'Invalid token!' }; - } - } - } else if (userId || contactId) { + + if (userId || contactId) { return await getTenantByUserId(userId, contactId); - } else { + } + else { return {}; } } diff --git a/apps/OpenSignServer/cloud/parsefunction/getUserByOrg.js b/apps/OpenSignServer/cloud/parsefunction/getUserByOrg.js deleted file mode 100644 index 86815ac39..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/getUserByOrg.js +++ /dev/null @@ -1,27 +0,0 @@ -export default async function getUserByOrg(req) { - const OrganizationId = req.params.organizationId; - const orgPtr = { - __type: 'Pointer', - className: 'contracts_Organizations', - objectId: OrganizationId, - }; - if (!req?.user) { - throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.'); - } else { - try { - const extUser = new Parse.Query('contracts_Users'); - extUser.include('TeamIds'); - extUser.equalTo('OrganizationId', orgPtr); - const userRes = await extUser.first({ useMasterKey: true }); - if (userRes.length > 0) { - const _userRes = JSON.parse(JSON.stringify(userRes)); - return _userRes; - } else { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.'); - } - } catch (err) { - console.log('err in getuserlist', err); - throw err; - } - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/getUserDetails.js b/apps/OpenSignServer/cloud/parsefunction/getUserDetails.js index fa8228ed0..6e1127e7e 100644 --- a/apps/OpenSignServer/cloud/parsefunction/getUserDetails.js +++ b/apps/OpenSignServer/cloud/parsefunction/getUserDetails.js @@ -1,9 +1,5 @@ -import { parseJwt } from '../../Utils.js'; -import jwt from 'jsonwebtoken'; - async function getUserDetails(request) { const reqEmail = request.params.email; - const jwttoken = request?.headers?.jwttoken || ''; if (reqEmail || request.user) { try { const userId = request.params.userId; @@ -40,49 +36,8 @@ async function getUserDetails(request) { const msg = err?.message || 'Something went wrong.'; throw new Parse.Error(code, msg); } - } else if (jwttoken) { - const jwtDecode = parseJwt(jwttoken); - if (jwtDecode?.user_email) { - const userCls = new Parse.Query(Parse.User); - userCls.equalTo('email', jwtDecode?.user_email); - const userRes = await userCls.first({ useMasterKey: true }); - const userId = userRes?.id; - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('userId', { - __type: 'Pointer', - className: '_User', - objectId: userId, - }); - const appRes = await tokenQuery.first({ useMasterKey: true }); - const decoded = jwt.verify(jwttoken, appRes?.get('token')); - if (decoded?.user_email) { - try { - const userQuery = new Parse.Query('contracts_Users'); - userQuery.equalTo('Email', decoded?.user_email); - userQuery.include('TenantId'); - userQuery.include('UserId'); - userQuery.include('CreatedBy'); - userQuery.exclude('CreatedBy.authData'); - userQuery.exclude('TenantId.FileAdapters'); - userQuery.exclude('google_refresh_token'); - userQuery.exclude('TenantId.PfxFile'); - const res = await userQuery.first({ useMasterKey: true }); - if (res) { - return res; - } else { - return ''; - } - } catch (err) { - console.log('Err ', err); - const code = err?.code || 400; - const msg = err?.message || 'Something went wrong.'; - throw new Parse.Error(code, msg); - } - } else { - return { status: 'error', result: 'Invalid token!' }; - } - } - } else { + } + else { throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.'); } } diff --git a/apps/OpenSignServer/cloud/parsefunction/getapitoken.js b/apps/OpenSignServer/cloud/parsefunction/getapitoken.js deleted file mode 100644 index 0f051e011..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/getapitoken.js +++ /dev/null @@ -1,34 +0,0 @@ -import axios from 'axios'; -import { cloudServerUrl } from '../../Utils.js'; - -export default async function getapitoken(request) { - try { - const serverUrl = cloudServerUrl; //process.env.SERVER_URL; - const userRes = await axios.get(serverUrl + '/users/me', { - headers: { - 'X-Parse-Application-Id': process.env.APP_ID, - 'X-Parse-Session-Token': request.headers['sessiontoken'], - }, - }); - const userId = userRes.data && userRes.data.objectId; - if (userId) { - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('userId', { __type: 'Pointer', className: '_User', objectId: userId }); - const res = await tokenQuery.first({ useMasterKey: true }); - if (res) { - return { status: 'success', result: res.get('token') }; - } else { - return { error: 'api token found.' }; - } - } else { - return { error: 'Invalid session token.' }; - } - } catch (err) { - console.log('Err in getapitoken', err); - if (err.code == 209) { - return { error: 'Invalid session token.' }; - } else { - return { error: "You don't have access." }; - } - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/isUserInContactBook.js b/apps/OpenSignServer/cloud/parsefunction/isUserInContactBook.js index 87d6fe723..7e452dedf 100644 --- a/apps/OpenSignServer/cloud/parsefunction/isUserInContactBook.js +++ b/apps/OpenSignServer/cloud/parsefunction/isUserInContactBook.js @@ -1,36 +1,7 @@ -import { parseJwt } from '../../Utils.js'; -import jwt from 'jsonwebtoken'; export default async function isUserInContactBook(request) { try { - const jwttoken = request.headers.jwttoken; - if (jwttoken) { - const jwtDecode = parseJwt(jwttoken); - const userCls = new Parse.Query(Parse.User); - userCls.equalTo('email', jwtDecode?.user_email); - const userRes = await userCls.first({ useMasterKey: true }); - const userId = userRes?.id; - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('userId', { - __type: 'Pointer', - className: '_User', - objectId: userId, - }); - const appRes = await tokenQuery.first({ useMasterKey: true }); - const decoded = jwt.verify(jwttoken, appRes?.get('token')); - if (decoded?.user_email) { - const email = userRes?.get('email'); - const userPtr = { __type: 'Pointer', className: '_User', objectId: userId }; - const query = new Parse.Query('contracts_Contactbook'); - query.equalTo('CreatedBy', userPtr); - query.notEqualTo('IsDeleted', true); - query.equalTo('Email', email); - const res = await query.first({ useMasterKey: true }); - return res; - } else { - throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Invalid token'); - } - } else if (request.user) { + if (request.user) { const email = request.user.get('email'); const userPtr = { __type: 'Pointer', className: '_User', objectId: request.user?.id }; const query = new Parse.Query('contracts_Contactbook'); diff --git a/apps/OpenSignServer/cloud/parsefunction/pdf/GenerateCertificate.js b/apps/OpenSignServer/cloud/parsefunction/pdf/GenerateCertificate.js index 0f0e98f30..400ad7148 100644 --- a/apps/OpenSignServer/cloud/parsefunction/pdf/GenerateCertificate.js +++ b/apps/OpenSignServer/cloud/parsefunction/pdf/GenerateCertificate.js @@ -1,8 +1,10 @@ import { PDFDocument, StandardFonts, rgb } from 'pdf-lib'; import fs from 'node:fs'; import fontkit from '@pdf-lib/fontkit'; +import { formatTimeInTimezone } from '../../../Utils.js'; export default async function GenerateCertificate(docDetails) { + const timezone = docDetails?.ExtUserPtr?.Timezone || ''; const pdfDoc = await PDFDocument.create(); // `fontBytes` is used to embed custom font in pdf const fontBytes = fs.readFileSync('./font/times.ttf'); // @@ -23,19 +25,23 @@ export default async function GenerateCertificate(docDetails) { const timeText = 11; const textKeyColor = rgb(0.12, 0.12, 0.12); const textValueColor = rgb(0.3, 0.3, 0.3); - const completedAt = new Date(); - const completedUTCtime = completedAt.toUTCString(); + const completedAt = docDetails?.completedAt ? new Date(docDetails?.completedAt) : new Date(); + const completedAtperTimezone = formatTimeInTimezone(completedAt, timezone); + const completedUTCtime = completedAtperTimezone; const signersCount = docDetails?.Signers?.length || 1; - const generateAt = new Date(); - const generatedUTCTime = generateAt.toUTCString(); + const generateAt = docDetails?.completedAt ? new Date(docDetails?.completedAt) : new Date(); + const generatedAtperTimezone = formatTimeInTimezone(generateAt, timezone); + const generatedUTCTime = generatedAtperTimezone; const generatedOn = 'Generated On ' + generatedUTCTime; const OriginIp = docDetails?.OriginIp || ''; const company = docDetails?.ExtUserPtr?.Company || ''; const createdAt = docDetails?.DocSentAt?.iso || docDetails.createdAt; + const createdAtperTimezone = formatTimeInTimezone(createdAt, timezone); const IsEnableOTP = docDetails?.IsEnableOTP || false; + const filteredaudit = docDetails?.AuditTrail?.filter(x => x?.UserPtr?.objectId); const auditTrail = docDetails?.Signers?.length > 0 - ? docDetails.AuditTrail.map(x => { + ? filteredaudit?.map(x => { const data = docDetails.Signers.find(y => y.objectId === x.UserPtr.objectId); return { ...data, @@ -48,16 +54,15 @@ export default async function GenerateCertificate(docDetails) { : [ { ...docDetails.ExtUserPtr, - ipAddress: docDetails?.AuditTrail[0].ipAddress, - SignedOn: docDetails?.AuditTrail[0]?.SignedOn || generatedUTCTime, - ViewedOn: - docDetails?.AuditTrail[0]?.ViewedOn || - docDetails?.AuditTrail[0]?.SignedOn || - generatedUTCTime, - Signature: docDetails?.AuditTrail[0]?.Signature || '', + ipAddress: filteredaudit[0].ipAddress, + SignedOn: filteredaudit[0]?.SignedOn || generatedUTCTime, + ViewedOn: filteredaudit[0]?.ViewedOn || filteredaudit[0]?.SignedOn || generatedUTCTime, + Signature: filteredaudit[0]?.Signature || '', }, ]; + const ownerName = docDetails?.SenderName || docDetails.ExtUserPtr?.Name || 'n/a'; + const ownerEmail = docDetails?.SenderMail || docDetails.ExtUserPtr?.Email || 'n/a'; const half = width / 2; // Draw a border page.drawRectangle({ @@ -131,10 +136,10 @@ export default async function GenerateCertificate(docDetails) { color: textKeyColor, }); - page.drawText(docDetails.Name, { + page.drawText(docDetails?.Name, { x: 140, y: 665, - size: text, + size: docDetails?.Name?.length >= 78 ? 12 : text, font: timesRomanFont, color: textValueColor, }); @@ -162,7 +167,7 @@ export default async function GenerateCertificate(docDetails) { color: textKeyColor, }); - page.drawText(`${new Date(createdAt).toUTCString()}`, { + page.drawText(`${createdAtperTimezone}`, { x: 105, y: 625, size: text, @@ -213,7 +218,7 @@ export default async function GenerateCertificate(docDetails) { font: timesRomanFont, color: textKeyColor, }); - page.drawText(`${docDetails.ExtUserPtr.Name}`, { + page.drawText(ownerName, { x: 105, y: 545, size: text, @@ -227,7 +232,7 @@ export default async function GenerateCertificate(docDetails) { font: timesRomanFont, color: textKeyColor, }); - page.drawText(`${docDetails.ExtUserPtr.Email}`, { + page.drawText(ownerEmail, { x: 105, y: 525, size: text, @@ -287,15 +292,16 @@ export default async function GenerateCertificate(docDetails) { }); page.drawText('Viewed on :', { - x: half + 55, + x: half + 45, y: yPosition2, size: timeText, font: timesRomanFont, color: textKeyColor, }); - page.drawText(`${new Date(x.ViewedOn).toUTCString()}`, { - x: half + 112, + //new Date(x.ViewedOn).toUTCString() + page.drawText(`${formatTimeInTimezone(x.ViewedOn, timezone)}`, { + x: half + 102, y: yPosition2, size: timeText, font: timesRomanFont, @@ -319,15 +325,16 @@ export default async function GenerateCertificate(docDetails) { }); page.drawText('Signed on :', { - x: half + 55, + x: half + 45, y: yPosition3 + 5, size: timeText, font: timesRomanFont, color: textKeyColor, }); - page.drawText(`${new Date(x.SignedOn).toUTCString()}`, { - x: half + 108, + // new Date(x.SignedOn).toUTCString() + page.drawText(`${formatTimeInTimezone(x.SignedOn, timezone)}`, { + x: half + 98, y: yPosition3 + 5, size: timeText, font: timesRomanFont, @@ -351,14 +358,14 @@ export default async function GenerateCertificate(docDetails) { }); if (IsEnableOTP) { page.drawText('Security level :', { - x: half + 55, + x: half + 45, y: yPosition4 + 10, size: timeText, font: timesRomanFont, color: textKeyColor, }); page.drawText('Email, OTP Auth', { - x: half + 125, + x: half + 115, y: yPosition4 + 10, size: timeText, font: timesRomanFont, @@ -458,15 +465,16 @@ export default async function GenerateCertificate(docDetails) { }); currentPage.drawText('Viewed on :', { - x: half + 55, + x: half + 45, y: yPosition2, size: timeText, font: timesRomanFont, color: textKeyColor, }); - currentPage.drawText(`${new Date(x.ViewedOn).toUTCString()}`, { - x: half + 112, + // new Date(x.ViewedOn).toUTCString() + currentPage.drawText(`${formatTimeInTimezone(x.ViewedOn, timezone)}`, { + x: half + 102, y: yPosition2, size: timeText, font: timesRomanFont, @@ -490,15 +498,16 @@ export default async function GenerateCertificate(docDetails) { }); currentPage.drawText('Signed on :', { - x: half + 55, + x: half + 45, y: yPosition3 + 5, size: timeText, font: timesRomanFont, color: textKeyColor, }); - currentPage.drawText(`${new Date(x.SignedOn).toUTCString()}`, { - x: half + 108, + // new Date(x.SignedOn).toUTCString() + currentPage.drawText(`${formatTimeInTimezone(x.SignedOn, timezone)}`, { + x: half + 98, y: yPosition3 + 5, size: timeText, font: timesRomanFont, @@ -523,14 +532,14 @@ export default async function GenerateCertificate(docDetails) { if (IsEnableOTP) { currentPage.drawText('Security level :', { - x: half + 55, + x: half + 45, y: yPosition4 + 10, size: timeText, font: timesRomanFont, color: textKeyColor, }); currentPage.drawText(`Email, OTP Auth`, { - x: half + 125, + x: half + 115, y: yPosition4 + 10, size: timeText, font: timesRomanFont, diff --git a/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.js b/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.js index 613cbbb95..0b4aafbcb 100644 --- a/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.js +++ b/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.js @@ -4,37 +4,31 @@ import { SignPdf } from '@signpdf/signpdf'; import { P12Signer } from '@signpdf/signer-p12'; import { pdflibAddPlaceholder } from '@signpdf/placeholder-pdf-lib'; import { PDFDocument } from 'pdf-lib'; -import { cloudServerUrl, replaceMailVaribles, saveFileUsage } from '../../../Utils.js'; +import { + cloudServerUrl, + replaceMailVaribles, + saveFileUsage, + getSecureUrl, +} from '../../../Utils.js'; import GenerateCertificate from './GenerateCertificate.js'; -import uploadFileToS3 from '../uploadFiletoS3.js'; +import { Placeholder } from './Placeholder.js'; const serverUrl = cloudServerUrl; // process.env.SERVER_URL; const APPID = process.env.APP_ID; const masterKEY = process.env.MASTER_KEY; const eSignName = 'opensign'; const eSigncontact = 'hello@opensignlabs.com'; // `updateDoc` is used to create url in from pdfFile -async function uploadFile(pdfName, filepath, adapter) { +async function uploadFile( + pdfName, + filepath, +) { try { const filedata = fs.readFileSync(filepath); let fileUrl; - if (adapter?.bucketName) { - const adapterConfig = { - id: adapter?.id, - fileAdapter: adapter?.fileAdapter, - bucketName: adapter?.bucketName, - region: adapter?.region, - endpoint: adapter?.endpoint, - accessKeyId: adapter?.accessKeyId, - secretAccessKey: adapter?.secretAccessKey, - baseUrl: adapter?.baseUrl, - }; - // `uploadFileToS3` is used to save document in user's file storage - fileUrl = await uploadFileToS3(filedata, pdfName, 'application/pdf', adapterConfig); - } else { const file = new Parse.File(pdfName, [...filedata], 'application/pdf'); await file.save({ useMasterKey: true }); - fileUrl = file.url(); - } + const fileRes = getSecureUrl(file.url()); + fileUrl = fileRes.url; return { imageUrl: fileUrl }; } catch (err) { @@ -161,67 +155,80 @@ async function sendCompletedMail(obj) { const recipient = signersMail; let subject = `Document "${pdfName}" has been signed by all parties`; let body = - "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body> <div style='background-color:#f5f5f5;padding:20px'> <div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background-color:white;'> <div><img src=" + - mailLogo + - " height='50' style='padding:20px'/> </div><div style='padding:2px;font-family:system-ui; background-color: #47a3ad;'> <p style='font-size:20px;font-weight:400;color:white;padding-left:20px',> Document signed 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 OpenSign™. 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 OpenSign™ <a href=www.opensignlabs.com target=_blank>here</a>.</p></div></div></body></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='background-color:white;'>" + + `<div><img src=${mailLogo} height='50' style='padding:20px'/></div><div style='padding:2px;font-family:system-ui; background-color: #47a3ad;'>` + + `<p style='font-size:20px;font-weight:400;color:white;padding-left:20px;'>Document signed 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 OpenSign™. 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 OpenSign™ <a href=www.opensignlabs.com target=_blank>here</a>.</p></div></div></body></html>'; if (obj?.isCustomMail) { - try { - const tenantCreditsQuery = new Parse.Query('partners_Tenant'); - tenantCreditsQuery.equalTo('UserId', { - __type: 'Pointer', - className: '_User', - objectId: sender.UserId.objectId, - }); - const res = await tenantCreditsQuery.first(); - if (res) { - const _res = JSON.parse(JSON.stringify(res)); - if (_res?.CompletionSubject) { - subject = _res?.CompletionSubject; + const tenant = sender?.TenantId; + if (tenant) { + subject = tenant?.CompletionSubject || ''; + body = tenant?.CompletionBody || ''; + } else { + const userId = sender?.CreatedBy?.objectId || sender?.UserId?.objectId; + if (userId) { + try { + const tenantQuery = new Parse.Query('partners_Tenant'); + tenantQuery.equalTo('UserId', { + __type: 'Pointer', + className: '_User', + objectId: userId, + }); + const tenantRes = await tenantQuery.first(); + if (tenantRes) { + const _tenantRes = JSON.parse(JSON.stringify(tenantRes)); + subject = _tenantRes?.CompletionSubject || ''; + body = _tenantRes?.CompletionBody || ''; + } + } catch (err) { + console.log('error in fetch tenant in signpdf', err.message); } - if (_res?.CompletionBody) { - body = _res?.CompletionBody; - } - const expireDate = doc.ExpiryDate.iso; - const newDate = new Date(expireDate); - const localExpireDate = newDate.toLocaleDateString('en-US', { - day: 'numeric', - month: 'long', - year: 'numeric', - }); - - const variables = { - document_title: pdfName, - sender_name: sender.Name, - sender_mail: sender.Email, - sender_phone: sender?.Phone || '', - receiver_name: sender.Name, - receiver_email: sender.Email, - receiver_phone: sender?.Phone || '', - expiry_date: localExpireDate, - company_name: sender.Company, - }; - const replaceVar = replaceMailVaribles(subject, body, variables); - subject = replaceVar.subject; - body = replaceVar.body; } - } catch (err) { - console.log('error in fetch tenant in signpdf', err.message); } + const expireDate = doc.ExpiryDate.iso; + const newDate = new Date(expireDate); + const localExpireDate = newDate.toLocaleDateString('en-US', { + day: 'numeric', + month: 'long', + year: 'numeric', + }); + + const variables = { + document_title: pdfName, + sender_name: + sender.Name, + sender_mail: doc?.SenderMail || sender.Email, + sender_phone: sender?.Phone || '', + receiver_name: sender.Name, + receiver_email: sender.Email, + receiver_phone: sender?.Phone || '', + expiry_date: localExpireDate, + company_name: sender.Company, + }; + const replaceVar = replaceMailVaribles(subject, body, variables); + subject = replaceVar.subject; + body = replaceVar.body; } + const Bcc = doc?.Bcc?.length > 0 ? doc.Bcc.map(x => x.Email) : ''; const params = { extUserId: sender.objectId, url: url, - from: 'OpenSign™', + from: + 'OpenSign™', + replyto: + doc?.ExtUserPtr?.Email || + '', recipient: recipient, subject: subject, pdfName: pdfName, html: body, mailProvider: obj.mailProvider, + bcc: Bcc, + certificatePath: `./exports/certificate_${doc.objectId}.pdf`, + filename: obj?.filename, }; const res = await axios.post(serverUrl + '/functions/sendmailv3', params, { headers: { @@ -232,72 +239,15 @@ async function sendCompletedMail(obj) { }); } -// `sendDoctoWebhook` is used to send res data of document on webhook -async function sendDoctoWebhook(doc, Url, event, signUser, certificateUrl) { - let signers = []; - if (signUser) { - signers = { name: signUser?.Name, email: signUser?.Email, phone: signUser?.Phone }; - } else { - signers = doc?.Signers?.map(x => ({ name: x.Name, email: x.Email, phone: x.Phone })) || [ - { name: doc?.ExtUserPtr?.Name, email: doc?.ExtUserPtr?.Email, phone: doc?.ExtUserPtr?.Phone }, - ]; - } - - if (doc.ExtUserPtr?.Webhook) { - const time = - event === 'signed' - ? { signer: signers, signedAt: new Date() } - : { signers: signers, completedAt: new Date() }; - const certificate = certificateUrl ? { certificate: certificateUrl } : {}; - const params = { - event: event, - objectId: doc?.objectId, - file: Url || '', - ...certificate, - name: doc?.Name, - note: doc?.Note || '', - description: doc?.Description || '', - ...time, - createdAt: doc?.createdAt, - }; - axios - .post(doc?.ExtUserPtr?.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: doc.ExtUserPtr.UserId.objectId, - }); - 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: doc.ExtUserPtr.UserId.objectId, - }); - webhook.save(null, { useMasterKey: true }); - } catch (err) { - console.log('err save in contracts_Webhook', err.message); - } - }); - } -} // `sendMailsaveCertifcate` is used send completion mail and update complete status of document -async function sendMailsaveCertifcate(doc, P12Buffer, isCustomMail, mailProvider, adapterConfig) { +async function sendMailsaveCertifcate( + doc, + P12Buffer, + isCustomMail, + mailProvider, + filename +) { const certificate = await GenerateCertificate(doc); const certificatePdf = await PDFDocument.load(certificate); let passphrase = process.env.PASS_PHRASE; @@ -320,10 +270,13 @@ async function sendMailsaveCertifcate(doc, P12Buffer, isCustomMail, mailProvider const certificateOBJ = new SignPdf(); // `signedCertificate` is used to sign certificate digitally const signedCertificate = await certificateOBJ.sign(CertificateBuffer, p12); - + const certificatePath = `./exports/certificate_${doc.objectId}.pdf`; //below is used to save signed certificate in exports folder - fs.writeFileSync('./exports/certificate.pdf', signedCertificate); - const file = await uploadFile('certificate.pdf', './exports/certificate.pdf', adapterConfig); + fs.writeFileSync(certificatePath, signedCertificate); + const file = await uploadFile( + 'certificate.pdf', + certificatePath, + ); const body = { CertificateUrl: file.imageUrl }; await axios.put(serverUrl + '/classes/contracts_Document/' + doc.objectId, body, { headers: { @@ -336,10 +289,9 @@ async function sendMailsaveCertifcate(doc, P12Buffer, isCustomMail, mailProvider if (doc.IsSendMail === false) { console.log("don't send mail"); } else { - sendCompletedMail({ isCustomMail, doc, mailProvider }); + sendCompletedMail({ isCustomMail, doc, mailProvider, filename }); } saveFileUsage(CertificateBuffer.length, file.imageUrl, doc?.CreatedBy?.objectId); - sendDoctoWebhook(doc, doc?.SignedUrl, 'completed', '', file.imageUrl); } /** * @@ -357,7 +309,7 @@ async function PDF(req) { const sign = req.params.signature || ''; // below bode is used to get info of docId const docQuery = new Parse.Query('contracts_Document'); - docQuery.include('ExtUserPtr,Signers,ExtUserPtr.TenantId'); + docQuery.include('ExtUserPtr,Signers,ExtUserPtr.TenantId,Bcc'); docQuery.equalTo('objectId', docId); const resDoc = await docQuery.first({ useMasterKey: true }); if (!resDoc) { @@ -371,17 +323,6 @@ async function PDF(req) { } } const _resDoc = resDoc?.toJSON(); - // `fileAdapterId` is used check document uploaded in custom file adapter and get customFileAdapter id - const fileAdapterId = _resDoc?.FileAdapterId || ''; - let adapterConfig = {}; - if (fileAdapterId) { - // `FileAdapter` is used to credintials of file adapter - const FileAdapter = - _resDoc?.ExtUserPtr?.TenantId?.FileAdapters?.find(x => x.id === fileAdapterId) || {}; - if (FileAdapter) { - adapterConfig = FileAdapter; - } - } let signUser; let className; // `reqUserId` is send throught pdfrequest signing flow @@ -433,38 +374,32 @@ async function PDF(req) { const randomNumber = Math.floor(Math.random() * 5000); // below regex is used to replace all word with "_" except A to Z, a to z, numbers const docName = _resDoc?.Name?.replace(/[^a-zA-Z0-9._-]/g, '_')?.toLowerCase(); - const name = `signed_${docName}_${randomNumber}.pdf`; + const filename = docName?.length > 100 ? docName?.slice(0, 100) : docName; + const name = `signed_${filename}_${randomNumber}.pdf`; const filePath = `./exports/${name}`; let pdfSize = PdfBuffer.length; if (isCompleted) { const signersName = _resDoc.Signers?.map(x => x.Name + ' <' + x.Email + '>'); - if (signersName && signersName.length > 0) { - // `pdflibAddPlaceholder` is used to add code of only digitial sign without widget - const pdfDoc = await PDFDocument.load(PdfBuffer); - pdflibAddPlaceholder({ - pdfDoc: pdfDoc, - reason: 'Digitally signed by OpenSign for ' + signersName?.join(', '), - location: 'n/a', - name: eSignName, - contactInfo: eSigncontact, - signatureLength: 15000, - }); - const pdfWithPlaceholderBytes = await pdfDoc.save(); - PdfBuffer = Buffer.from(pdfWithPlaceholderBytes); - } else { - // `pdflibAddPlaceholder` is used to add code of only digitial sign without widget (signyourself) - const pdfDoc = await PDFDocument.load(PdfBuffer); - pdflibAddPlaceholder({ - pdfDoc: pdfDoc, - reason: 'Digitally signed by OpenSign for ' + username + ' <' + userEmail + '>', - location: 'n/a', - name: eSignName, - contactInfo: eSigncontact, - signatureLength: 15000, - }); - const pdfWithPlaceholderBytes = await pdfDoc.save(); - PdfBuffer = Buffer.from(pdfWithPlaceholderBytes); - } + const reason = + signersName && signersName.length > 0 + ? signersName?.join(', ') + : username + ' <' + userEmail + '>'; + const pdfDoc = await PDFDocument.load(PdfBuffer); + const form = pdfDoc.getForm(); + // Updates the field appearances to ensure visual changes are reflected. + form.updateFieldAppearances(); + // Flattens the form, converting all form fields into non-editable, static content + form.flatten(); + Placeholder({ + pdfDoc: pdfDoc, + reason: 'Digitally signed by OpenSign for ' + reason, + location: 'n/a', + name: eSignName, + contactInfo: eSigncontact, + signatureLength: 15000, + }); + const pdfWithPlaceholderBytes = await pdfDoc.save(); + PdfBuffer = Buffer.from(pdfWithPlaceholderBytes); //`new signPDF` create new instance of pdfBuffer and p12Buffer const OBJ = new SignPdf(); // `signedDocs` is used to signpdf digitally @@ -480,7 +415,10 @@ async function PDF(req) { } // `uploadFile` is used to upload pdf to aws s3 and get it's url - const data = await uploadFile(name, filePath, adapterConfig); + const data = await uploadFile( + name, + filePath, + ); if (data && data.imageUrl) { // `axios` is used to update signed pdf url in contracts_Document classes for given DocId @@ -493,12 +431,17 @@ async function PDF(req) { className, // className based on flow sign // sign base64 ); - sendDoctoWebhook(_resDoc, data.imageUrl, 'signed', signUser); sendNotifyMail(_resDoc, signUser, mailProvider); saveFileUsage(pdfSize, data.imageUrl, _resDoc?.CreatedBy?.objectId); if (updatedDoc && updatedDoc.isCompleted) { const doc = { ..._resDoc, AuditTrail: updatedDoc.AuditTrail, SignedUrl: data.imageUrl }; - sendMailsaveCertifcate(doc, P12Buffer, isCustomMail, mailProvider, adapterConfig); + sendMailsaveCertifcate( + doc, + P12Buffer, + isCustomMail, + mailProvider, + name + ); } // `fs.unlinkSync` is used to remove exported signed pdf file from exports folder fs.unlinkSync(filePath); diff --git a/apps/OpenSignServer/cloud/parsefunction/pdf/PDFArrayCustom.js b/apps/OpenSignServer/cloud/parsefunction/pdf/PDFArrayCustom.js new file mode 100644 index 000000000..44596a616 --- /dev/null +++ b/apps/OpenSignServer/cloud/parsefunction/pdf/PDFArrayCustom.js @@ -0,0 +1,53 @@ +import { PDFArray, CharCodes } from 'pdf-lib'; + +/** + * Extends PDFArray class in order to make ByteRange look like this: + * /ByteRange [0 /********** /********** /**********] + * Not this: + * /ByteRange [ 0 /********** /********** /********** ] + */ +export default class PDFArrayCustom extends PDFArray { + static withContext(context) { + return new PDFArrayCustom(context); + } + + clone(context) { + const clone = PDFArrayCustom.withContext(context || this.context); + for (let idx = 0, len = this.size(); idx < len; idx++) { + clone.push(this.array[idx]); + } + return clone; + } + + toString() { + let arrayString = '['; + for (let idx = 0, len = this.size(); idx < len; idx++) { + arrayString += this.get(idx).toString(); + if (idx < len - 1) arrayString += ' '; + } + arrayString += ']'; + return arrayString; + } + + sizeInBytes() { + let size = 2; + for (let idx = 0, len = this.size(); idx < len; idx++) { + size += this.get(idx).sizeInBytes(); + if (idx < len - 1) size += 1; + } + return size; + } + + copyBytesInto(buffer, offset) { + const initialOffset = offset; + + buffer[offset++] = CharCodes.LeftSquareBracket; + for (let idx = 0, len = this.size(); idx < len; idx++) { + offset += this.get(idx).copyBytesInto(buffer, offset); + if (idx < len - 1) buffer[offset++] = CharCodes.Space; + } + buffer[offset++] = CharCodes.RightSquareBracket; + + return offset - initialOffset; + } +} diff --git a/apps/OpenSignServer/cloud/parsefunction/pdf/Placeholder.js b/apps/OpenSignServer/cloud/parsefunction/pdf/Placeholder.js new file mode 100644 index 000000000..c45f17ace --- /dev/null +++ b/apps/OpenSignServer/cloud/parsefunction/pdf/Placeholder.js @@ -0,0 +1,130 @@ +import { + DEFAULT_SIGNATURE_LENGTH, + DEFAULT_BYTE_RANGE_PLACEHOLDER, + SUBFILTER_ADOBE_PKCS7_DETACHED, + ANNOTATION_FLAGS, + SIG_FLAGS, + SignPdfError, +} from '@signpdf/utils'; +import { + PDFArray, + PDFNumber, + PDFName, + PDFHexString, + PDFString, + PDFInvalidObject, + PDFDict, +} from 'pdf-lib'; + +export const Placeholder = ({ + pdfDoc, + pdfPage, + reason, + contactInfo, + name, + location, + signingTime = new Date(), + signatureLength = DEFAULT_SIGNATURE_LENGTH, + byteRangePlaceholder = DEFAULT_BYTE_RANGE_PLACEHOLDER, + subFilter = SUBFILTER_ADOBE_PKCS7_DETACHED, + widgetRect = [0, 0, 0, 0], + appName, +}) => { + if (!pdfDoc && !pdfPage) { + throw new SignPdfError('PDFDoc or PDFPage must be set.', SignPdfError.TYPE_INPUT); + } + + const doc = pdfDoc || pdfPage.doc; + const page = pdfPage || doc.getPages()[0]; + + const byteRange = PDFArray.withContext(doc.context); + byteRange.push(PDFNumber.of(0)); + byteRange.push(PDFName.of(byteRangePlaceholder)); + byteRange.push(PDFName.of(byteRangePlaceholder)); + byteRange.push(PDFName.of(byteRangePlaceholder)); + + const placeholder = PDFHexString.of(String.fromCharCode(0).repeat(signatureLength)); + + const appBuild = appName ? { App: { Name: appName } } : {}; + const signatureDict = doc.context.obj({ + Type: 'Sig', + Filter: 'Adobe.PPKLite', + SubFilter: subFilter, + ByteRange: byteRange, + Contents: placeholder, + Reason: PDFString.of(reason), + M: PDFString.fromDate(signingTime), + ContactInfo: PDFString.of(contactInfo), + Name: PDFString.of(name), + Location: PDFString.of(location), + Prop_Build: { + Filter: { Name: 'Adobe.PPKLite' }, + ...appBuild, + }, + }); + + const signatureBuffer = new Uint8Array(signatureDict.sizeInBytes()); + signatureDict.copyBytesInto(signatureBuffer, 0); + const signatureObj = PDFInvalidObject.of(signatureBuffer); + const signatureDictRef = doc.context.register(signatureObj); + + const rect = PDFArray.withContext(doc.context); + widgetRect.forEach(c => rect.push(PDFNumber.of(c))); + const apStream = doc.context.formXObject([], { + BBox: widgetRect, + Resources: {}, + }); + + const widgetDict = doc.context.obj({ + Type: 'Annot', + Subtype: 'Widget', + FT: 'Sig', + Rect: rect, + V: signatureDictRef, + T: PDFString.of('Signature1'), + F: ANNOTATION_FLAGS.PRINT, + P: page.ref, + AP: { N: doc.context.register(apStream) }, + }); + + const widgetDictRef = doc.context.register(widgetDict); + + let annotations = page.node.lookupMaybe(PDFName.of('Annots'), PDFArray); + if (!annotations) { + annotations = doc.context.obj([]); + } + annotations.push(widgetDictRef); + page.node.set(PDFName.of('Annots'), annotations); + + let acroForm = doc.catalog.lookupMaybe(PDFName.of('AcroForm'), PDFDict); + if (!acroForm) { + acroForm = doc.context.obj({ Fields: [] }); + const acroFormRef = doc.context.register(acroForm); + doc.catalog.set(PDFName.of('AcroForm'), acroFormRef); + } + + let sigFlags = acroForm.has(PDFName.of('SigFlags')) + ? acroForm.get(PDFName.of('SigFlags')) + : PDFNumber.of(0); + + const updatedFlags = PDFNumber.of( + sigFlags.asNumber() | SIG_FLAGS.SIGNATURES_EXIST | SIG_FLAGS.APPEND_ONLY + ); + acroForm.set(PDFName.of('SigFlags'), updatedFlags); + + let fields = acroForm.get(PDFName.of('Fields')); + if (fields instanceof PDFArray) { + fields.push(widgetDictRef); + } + // else if (fields) { + // const newFields = PDFArray.withContext(doc.context); + // fields.asArray().forEach(field => newFields.push(field)); + // newFields.push(widgetDictRef); + // acroForm.set(PDFName.of('Fields'), newFields); + // } + else { + const newFields = PDFArray.withContext(doc.context); + newFields.push(widgetDictRef); + acroForm.set(PDFName.of('Fields'), newFields); + } +}; diff --git a/apps/OpenSignServer/cloud/parsefunction/reportsJson.js b/apps/OpenSignServer/cloud/parsefunction/reportsJson.js index 7e5d896ea..4a6c2d0d8 100644 --- a/apps/OpenSignServer/cloud/parsefunction/reportsJson.js +++ b/apps/OpenSignServer/cloud/parsefunction/reportsJson.js @@ -12,11 +12,7 @@ export default function reportJson(id, userId) { IsDeclined: { $ne: true }, IsArchive: { $ne: true }, SignedUrl: { $exists: false }, - CreatedBy: { - __type: 'Pointer', - className: '_User', - objectId: currentUserId, - }, + CreatedBy: { __type: 'Pointer', className: '_User', objectId: currentUserId }, }, keys: [ 'Name', @@ -29,7 +25,6 @@ export default function reportJson(id, userId) { 'Signers.Phone', 'Placeholders', 'IsSignyourself', - 'FileAdapterId', ], }; @@ -43,19 +38,11 @@ export default function reportJson(id, userId) { IsDeclined: { $ne: true }, IsArchive: { $ne: true }, SignedUrl: { $ne: null }, - ExpiryDate: { - $gt: { __type: 'Date', iso: new Date().toISOString() }, - }, + ExpiryDate: { $gt: { __type: 'Date', iso: new Date().toISOString() } }, Placeholders: { $ne: null }, Signers: { $inQuery: { - where: { - UserId: { - __type: 'Pointer', - className: '_User', - objectId: currentUserId, - }, - }, + where: { UserId: { __type: 'Pointer', className: '_User', objectId: currentUserId } }, className: 'contracts_Contactbook', }, }, @@ -67,7 +54,6 @@ export default function reportJson(id, userId) { 'URL', 'ExtUserPtr.Name', 'ExtUserPtr.Email', - 'ExtUserPtr.active_mail_adapter', 'Signers.Name', 'Signers.Email', 'Signers.Phone', @@ -75,7 +61,6 @@ export default function reportJson(id, userId) { 'AuditTrail', 'Placeholders', 'SignedUrl', - 'FileAdapterId', 'ExpiryDate', ], }; @@ -90,14 +75,8 @@ export default function reportJson(id, userId) { IsCompleted: { $ne: true }, IsDeclined: { $ne: true }, IsArchive: { $ne: true }, - CreatedBy: { - __type: 'Pointer', - className: '_User', - objectId: currentUserId, - }, - ExpiryDate: { - $gt: { __type: 'Date', iso: new Date().toISOString() }, - }, + CreatedBy: { __type: 'Pointer', className: '_User', objectId: currentUserId }, + ExpiryDate: { $gt: { __type: 'Date', iso: new Date().toISOString() } }, }, keys: [ 'Name', @@ -106,7 +85,6 @@ export default function reportJson(id, userId) { 'URL', 'ExtUserPtr.Name', 'ExtUserPtr.Email', - 'ExtUserPtr.active_mail_adapter', 'Signers.Name', 'Signers.Email', 'Signers.Phone', @@ -116,7 +94,6 @@ export default function reportJson(id, userId) { 'SendMail', 'Placeholders', 'SignedUrl', - 'FileAdapterId', ], }; // completed documents report @@ -126,13 +103,28 @@ export default function reportJson(id, userId) { params: { Type: { $ne: 'Folder' }, IsCompleted: true, - CreatedBy: { - __type: 'Pointer', - className: '_User', - objectId: currentUserId, - }, IsDeclined: { $ne: true }, IsArchive: { $ne: true }, + // CreatedBy: { + // __type: 'Pointer', + // className: '_User', + // objectId: currentUserId, + // }, + $or: [ + // Condition 1: If `CreatedBy` exists, no need for `Signers` filter + { CreatedBy: { __type: 'Pointer', className: '_User', objectId: currentUserId } }, + // Condition 2: If `CreatedBy` does not exist, apply the `Signers` filter + { + Signers: { + $inQuery: { + where: { + UserId: { __type: 'Pointer', className: '_User', objectId: currentUserId }, + }, + className: 'contracts_Contactbook', + }, + }, + }, + ], }, keys: [ 'Name', @@ -148,7 +140,6 @@ export default function reportJson(id, userId) { 'Placeholders', 'IsSignyourself', 'IsCompleted', - 'FileAdapterId', ], }; // declined documents report @@ -159,13 +150,8 @@ export default function reportJson(id, userId) { Type: null, IsArchive: { $ne: true }, IsDeclined: true, - CreatedBy: { - __type: 'Pointer', - className: '_User', - objectId: currentUserId, - }, + CreatedBy: { __type: 'Pointer', className: '_User', objectId: currentUserId }, }, - keys: [ 'Name', 'Note', @@ -178,7 +164,6 @@ export default function reportJson(id, userId) { 'Placeholders', 'DeclineReason', 'SignedUrl', - 'FileAdapterId', ], }; // Expired Documents report @@ -191,14 +176,8 @@ export default function reportJson(id, userId) { IsArchive: { $ne: true }, Type: { $ne: 'Folder' }, SignedUrl: { $ne: null }, - ExpiryDate: { - $lt: { __type: 'Date', iso: new Date().toISOString() }, - }, - CreatedBy: { - __type: 'Pointer', - className: '_User', - objectId: currentUserId, - }, + ExpiryDate: { $lt: { __type: 'Date', iso: new Date().toISOString() } }, + CreatedBy: { __type: 'Pointer', className: '_User', objectId: currentUserId }, }, keys: [ 'Name', @@ -211,7 +190,6 @@ export default function reportJson(id, userId) { 'Signers.Phone', 'Placeholders', 'SignedUrl', - 'FileAdapterId', 'ExpiryDate', ], }; @@ -226,14 +204,8 @@ export default function reportJson(id, userId) { IsCompleted: { $ne: true }, IsDeclined: { $ne: true }, IsArchive: { $ne: true }, - CreatedBy: { - __type: 'Pointer', - className: '_User', - objectId: currentUserId, - }, - ExpiryDate: { - $gt: { __type: 'Date', iso: new Date().toISOString() }, - }, + CreatedBy: { __type: 'Pointer', className: '_User', objectId: currentUserId }, + ExpiryDate: { $gt: { __type: 'Date', iso: new Date().toISOString() } }, }, keys: [ 'Name', @@ -241,7 +213,6 @@ export default function reportJson(id, userId) { 'URL', 'ExtUserPtr.Name', 'ExtUserPtr.Email', - 'ExtUserPtr.active_mail_adapter', 'Signers.Name', 'Signers.Email', 'Signers.Phone', @@ -250,7 +221,6 @@ export default function reportJson(id, userId) { 'ExpiryDate', 'Placeholders', 'SignedUrl', - 'FileAdapterId', ], }; // Recent signature requests report show on dashboard @@ -263,19 +233,11 @@ export default function reportJson(id, userId) { IsCompleted: { $ne: true }, IsDeclined: { $ne: true }, IsArchive: { $ne: true }, - ExpiryDate: { - $gt: { __type: 'Date', iso: new Date().toISOString() }, - }, + ExpiryDate: { $gt: { __type: 'Date', iso: new Date().toISOString() } }, Placeholders: { $ne: null }, Signers: { $inQuery: { - where: { - UserId: { - __type: 'Pointer', - className: '_User', - objectId: currentUserId, - }, - }, + where: { UserId: { __type: 'Pointer', className: '_User', objectId: currentUserId } }, className: 'contracts_Contactbook', }, }, @@ -285,7 +247,6 @@ export default function reportJson(id, userId) { 'URL', 'ExtUserPtr.Name', 'ExtUserPtr.Email', - 'ExtUserPtr.active_mail_adapter', 'Signers.Name', 'Signers.UserId', 'AuditTrail', @@ -293,7 +254,6 @@ export default function reportJson(id, userId) { 'Signers.Phone', 'Placeholders', 'SignedUrl', - 'FileAdapterId', 'ExpiryDate', ], }; @@ -307,11 +267,7 @@ export default function reportJson(id, userId) { IsDeclined: { $ne: true }, IsArchive: { $ne: true }, SignedUrl: { $exists: false }, - CreatedBy: { - __type: 'Pointer', - className: '_User', - objectId: currentUserId, - }, + CreatedBy: { __type: 'Pointer', className: '_User', objectId: currentUserId }, }, keys: [ 'Name', @@ -323,20 +279,15 @@ export default function reportJson(id, userId) { 'Signers.Email', 'Signers.Phone', 'Placeholders', - 'FileAdapterId', ], }; // contact book report - case '5KhaPr482K': + case 'contacts': return { reportName: 'Contactbook', reportClass: 'contracts_Contactbook', params: { - CreatedBy: { - __type: 'Pointer', - className: '_User', - objectId: currentUserId, - }, + CreatedBy: { __type: 'Pointer', className: '_User', objectId: currentUserId }, IsDeleted: { $ne: true }, }, keys: ['Name', 'Email', 'Phone'], @@ -346,17 +297,13 @@ export default function reportJson(id, userId) { return { reportName: 'Templates', reportClass: 'contracts_Template', - params: { - Type: { $ne: 'Folder' }, - IsArchive: { $ne: true }, - }, + params: { Type: { $ne: 'Folder' }, IsArchive: { $ne: true } }, keys: [ 'Name', 'Note', 'Folder.Name', 'URL', 'ExtUserPtr.Name', - 'ExtUserPtr.active_mail_adapter', 'Signers.Name', 'Signers.Email', 'Signers.Phone', @@ -364,7 +311,6 @@ export default function reportJson(id, userId) { 'IsPublic', 'SharedWith.Name', 'SendinOrder', - 'FileAdapterId', 'SignatureType', 'NotifyOnSignatures', ], diff --git a/apps/OpenSignServer/cloud/parsefunction/saveFile.js b/apps/OpenSignServer/cloud/parsefunction/saveFile.js index 6538f70ab..5b1ee71b6 100644 --- a/apps/OpenSignServer/cloud/parsefunction/saveFile.js +++ b/apps/OpenSignServer/cloud/parsefunction/saveFile.js @@ -1,9 +1,8 @@ -import uploadFileToS3 from './uploadFiletoS3.js'; -import { parseJwt } from '../../Utils.js'; -import jwt from 'jsonwebtoken'; +import { + flattenPdf, + getSecureUrl, +} from '../../Utils.js'; export default async function saveFile(request) { - const jwttoken = request.headers.jwttoken || ''; - if (!request.params.fileBase64) { throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide file.'); } @@ -17,111 +16,29 @@ export default async function saveFile(request) { const resExt = await extCls.first({ useMasterKey: true }); if (resExt) { const _resExt = JSON.parse(JSON.stringify(resExt)); - const fileAdapters = _resExt?.TenantId.FileAdapters || []; - const fileAdapter = fileAdapters?.find(x => x.id === id) || {}; - if (fileAdapter?.accessKeyId) { - const adapterConfig = { - id: id, - fileAdapter: fileAdapter?.fileAdapter, - bucketName: fileAdapter?.bucketName, - region: fileAdapter?.region, - endpoint: fileAdapter?.endpoint, - accessKeyId: fileAdapter?.accessKeyId, - secretAccessKey: fileAdapter?.secretAccessKey, - baseUrl: fileAdapter?.baseUrl, - }; - const buffer = Buffer.from(fileBase64, 'base64'); const fileName = request.params.fileName; const ext = request.params.fileName?.split('.')?.pop(); let mimeType; + let file; if (ext === 'pdf') { mimeType = 'application/pdf'; + const flatPdf = await flattenPdf(fileBase64); + file = [...flatPdf]; } else if (ext === 'png' || ext === 'jpeg' || ext === 'jpg') { mimeType = `image/${ext}`; + file = { base64: fileBase64 }; } - try { - const presignedUrl = await uploadFileToS3(buffer, fileName, mimeType, adapterConfig); - return { url: presignedUrl }; - } catch (err) { - console.error('Error generate presigned url:', err); - const msg = 'Fileadapter credentials are invalid.'; - throw new Parse.Error(400, msg); - } - } else { - const fileName = request.params.fileName; - const pdfFile = new Parse.File(fileName, { base64: fileBase64 }); + const pdfFile = new Parse.File(fileName, file, mimeType); // Save the Parse File if needed const pdfData = await pdfFile.save({ useMasterKey: true }); const presignedUrl = pdfData.url(); - return { url: presignedUrl }; - } + const fileRes = getSecureUrl(presignedUrl); + return { url: fileRes.url }; } else { throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.'); } - } else if (jwttoken) { - const jwtDecode = parseJwt(jwttoken); - const userCls = new Parse.Query(Parse.User); - userCls.equalTo('email', jwtDecode?.user_email); - const userRes = await userCls.first({ useMasterKey: true }); - const userId = userRes?.id; - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('userId', { - __type: 'Pointer', - className: '_User', - objectId: userId, - }); - const appRes = await tokenQuery.first({ useMasterKey: true }); - const decoded = jwt.verify(jwttoken, appRes?.get('token')); - if (decoded?.user_email) { - const extCls = new Parse.Query('contracts_Users'); - extCls.equalTo('Email', decoded?.user_email); - extCls.include('TenantId'); - const resExt = await extCls.first({ useMasterKey: true }); - if (resExt) { - const _resExt = JSON.parse(JSON.stringify(resExt)); - const fileAdapters = _resExt?.TenantId.FileAdapters || []; - const fileAdapter = fileAdapters?.find(x => x.id === id) || {}; - if (fileAdapter?.accessKeyId) { - const adapterConfig = { - id: id, - fileAdapter: fileAdapter?.fileAdapter, - bucketName: fileAdapter?.bucketName, - region: fileAdapter?.region, - endpoint: fileAdapter?.endpoint, - accessKeyId: fileAdapter?.accessKeyId, - secretAccessKey: fileAdapter?.secretAccessKey, - baseUrl: fileAdapter?.baseUrl, - }; - const buffer = Buffer.from(fileBase64, 'base64'); - const fileName = request.params.fileName; - const ext = request.params.fileName?.split('.')?.pop(); - let mimeType; - if (ext === 'pdf') { - mimeType = 'application/pdf'; - } else if (ext === 'png' || ext === 'jpeg' || ext === 'jpg') { - mimeType = `image/${ext}`; - } - try { - const presignedUrl = await uploadFileToS3(buffer, fileName, mimeType, adapterConfig); - return { url: presignedUrl }; - } catch (err) { - console.error('Error generate presigned url:', err); - const msg = 'Fileadapter credentials are invalid.'; - throw new Parse.Error(400, msg); - } - } else { - const fileName = request.params.fileName; - const pdfFile = new Parse.File(fileName, { base64: fileBase64 }); - // Save the Parse File if needed - const pdfData = await pdfFile.save({ useMasterKey: true }); - const presignedUrl = pdfData.url(); - return { url: presignedUrl }; - } - } else { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.'); - } - } - } else { + } + else { throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.'); } } catch (err) { diff --git a/apps/OpenSignServer/cloud/parsefunction/saveSubscription.js b/apps/OpenSignServer/cloud/parsefunction/saveSubscription.js deleted file mode 100644 index b7e8fcb3a..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/saveSubscription.js +++ /dev/null @@ -1,193 +0,0 @@ -import axios from 'axios'; -import { cloudServerUrl, planCredits } from '../../Utils.js'; -export default async function saveSubscription(request) { - const serverUrl = cloudServerUrl; //process.env.SERVER_URL; - const appId = process.env.APP_ID; - const subscription = request.params.subscription; - const SubscriptionId = subscription.data.subscription.subscription_id; - const body = subscription; - const Next_billing_date = subscription.data.subscription.next_billing_at; - const planCode = subscription.data.subscription.plan.plan_code; - const event = subscription?.data?.event_type || ''; - const credits = planCredits?.[planCode] || 0; - const isTeamPlan = planCode?.includes('team'); - let newAddons = 0; - try { - const userRes = await axios.get(serverUrl + '/users/me', { - headers: { - 'X-Parse-Application-Id': appId, - 'X-Parse-Session-Token': request.headers['sessiontoken'], - }, - }); - if (userRes.data && userRes.data.objectId) { - const extUserCls = new Parse.Query('contracts_Users'); - extUserCls.equalTo('UserId', { - __type: 'Pointer', - className: '_User', - objectId: userRes.data.objectId, - }); - const extUser = await extUserCls.first({ useMasterKey: true }); - if (extUser) { - const subcriptionCls = new Parse.Query('contracts_Subscriptions'); - subcriptionCls.equalTo('TenantId', { - __type: 'Pointer', - className: 'partners_Tenant', - objectId: extUser.get('TenantId').id, - }); - const resSubscription = await subcriptionCls.first({ useMasterKey: true }); - const addons = subscription?.data?.subscription?.addons || []; - if (addons?.length > 0) { - let allowedUsersMonthly = 0; - let allowedUsersYearly = 0; - addons?.forEach(item => { - if (item.addon_code === 'extra-teams-users-monthly') { - allowedUsersMonthly += item.quantity; - } else if (item.addon_code === 'extra-teams-users-yearly') { - allowedUsersYearly += item.quantity; - } else if (item.addon_code === 'extra-users') { - allowedUsersMonthly += item.quantity; - } - }); - if (allowedUsersMonthly > 0 || allowedUsersYearly > 0) { - newAddons = allowedUsersMonthly + allowedUsersYearly + 1; // + 1 is Admin user - } - } else { - if ( - planCode === 'teams-yearly' || - planCode === 'teams-monthly' || - planCode === 'team-weekly' - ) { - newAddons = 1; // 1 is Admin user - } - } - if (resSubscription) { - const _resSub = JSON.parse(JSON.stringify(resSubscription)); - const updateSubscription = new Parse.Object('contracts_Subscriptions'); - updateSubscription.id = resSubscription.id; - updateSubscription.set('SubscriptionId', SubscriptionId); - updateSubscription.set('SubscriptionDetails', body); - updateSubscription.set('Next_billing_date', new Date(Next_billing_date)); - updateSubscription.set('PlanCode', planCode); - if (newAddons > 0) { - updateSubscription.set('AllowedUsers', parseInt(newAddons)); - } - let existAddon = 0; - let allowedUsersMonthly = 0; - let allowedUsersYearly = 0; - _resSub.SubscriptionDetails?.data?.subscription?.addons?.forEach(item => { - if (item.addon_code === 'extra-teams-users-monthly') { - allowedUsersMonthly += item.quantity; - } else if (item.addon_code === 'extra-teams-users-yearly') { - allowedUsersYearly += item.quantity; - } else if (item.addon_code === 'extra-users') { - allowedUsersMonthly += item.quantity; - } - }); - if (allowedUsersMonthly > 0 || allowedUsersYearly > 0) { - existAddon = allowedUsersMonthly + allowedUsersYearly + 1; // + 1 is Admin user - } else { - if ( - planCode === 'teams-yearly' || - planCode === 'teams-monthly' || - planCode === 'team-weekly' - ) { - existAddon = 1; // 1 is Admin user - } - } - const isSameAsPrevPlan = resSubscription?.get('PlanCode') === planCode; - if (isSameAsPrevPlan) { - const planCredits = resSubscription?.get('PlanCredits'); - const existAllowedCredits = resSubscription?.get('AllowedCredits') || 0; - if (planCredits) { - const oldAddons = existAddon; - const substractedAddon = newAddons - oldAddons; - if (isTeamPlan && substractedAddon > 0) { - const newCredits = existAllowedCredits + substractedAddon * planCredits; - updateSubscription.set('AllowedCredits', newCredits); - if (event === 'subscription_created') { - updateSubscription.set('PlanCredits', credits); - } - } else if (isTeamPlan) { - const existCredits = existAddon * planCredits; - updateSubscription.set('AllowedCredits', existCredits); - if (event === 'subscription_created') { - updateSubscription.set('PlanCredits', credits); - } - } else { - updateSubscription.set('AllowedCredits', planCredits); - if (event === 'subscription_created') { - updateSubscription.set('PlanCredits', credits); - } - } - } else { - if (isTeamPlan) { - const newCredits = newAddons * credits; - updateSubscription.set('AllowedCredits', newCredits); - updateSubscription.set('PlanCredits', credits); - } else { - updateSubscription.set('AllowedCredits', credits); - updateSubscription.set('PlanCredits', credits); - } - } - } else { - if (credits > 0) { - if (isTeamPlan) { - const newCredits = newAddons * credits; - updateSubscription.set('AllowedCredits', newCredits); - updateSubscription.set('PlanCredits', credits); - } else { - updateSubscription.set('AllowedCredits', credits); - updateSubscription.set('PlanCredits', credits); - } - } - } - await updateSubscription.save(null, { useMasterKey: true }); - return { status: 'update subscription!' }; - } else { - const createSubscription = new Parse.Object('contracts_Subscriptions'); - createSubscription.set('SubscriptionId', SubscriptionId); - createSubscription.set('SubscriptionDetails', body); - createSubscription.set('ExtUserPtr', { - __type: 'Pointer', - className: 'contracts_Users', - objectId: extUser.id, - }); - createSubscription.set('CreatedBy', { - __type: 'Pointer', - className: '_User', - objectId: extUser.get('UserId').id, - }); - createSubscription.set('TenantId', { - __type: 'Pointer', - className: 'partners_Tenant', - objectId: extUser.get('TenantId').id, - }); - createSubscription.set('Next_billing_date', new Date(Next_billing_date)); - createSubscription.set('PlanCode', planCode); - if (newAddons > 0) { - createSubscription.set('AllowedUsers', parseInt(newAddons)); - } - if (credits > 0) { - if (isTeamPlan) { - const totalCredits = parseInt(newAddons) * credits; - createSubscription.set('AllowedCredits', totalCredits); - createSubscription.set('PlanCredits', credits); - } else { - createSubscription.set('AllowedCredits', credits); - createSubscription.set('PlanCredits', credits); - } - } - await createSubscription.save(null, { useMasterKey: true }); - return { status: 'create subscription!' }; - } - } else { - return { status: 'user not found!' }; - } - } else { - return { status: 'user not found!' }; - } - } catch (err) { - console.log('Err in save subscription', err); - throw new Error(err.message); - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/saveTemplate.js b/apps/OpenSignServer/cloud/parsefunction/saveTemplate.js deleted file mode 100644 index 9732303c3..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/saveTemplate.js +++ /dev/null @@ -1,114 +0,0 @@ -import { parseJwt } from '../../Utils.js'; -import jwt from 'jsonwebtoken'; - -async function updateTemplate(template, isJwt = false) { - try { - if (template?.Id) { - const updateTemplate = new Parse.Object('contracts_Template'); - updateTemplate.id = template.Id; - if (template?.URL) { - updateTemplate.set('URL', template.URL); - } - if (template?.Name) { - updateTemplate.set('Name', template.Name); - } - if (template?.Note) { - updateTemplate.set('Note', template.Note); - } - if (template?.Description) { - updateTemplate.set('Description', template.Description); - } - if (template?.SendinOrder) { - updateTemplate.set('SendinOrder', template.SendinOrder); - } - if (template?.AutomaticReminders) { - updateTemplate.set('AutomaticReminders', template.AutomaticReminders); - } - if (template?.RemindOnceInEvery) { - updateTemplate.set('RemindOnceInEvery', template.RemindOnceInEvery); - } - if (template?.NextReminderDate) { - updateTemplate.set('NextReminderDate', new Date(template.NextReminderDate)); - } - if (template?.IsEnableOTP) { - updateTemplate.set('IsEnableOTP', template.IsEnableOTP); - } - if (template?.IsTourEnabled) { - updateTemplate.set('IsTourEnabled', template.IsTourEnabled); - } - const isPublic = template?.IsPublic !== undefined ? template?.IsPublic : false; - if (template?.IsPublic !== undefined) { - updateTemplate.set('IsPublic', isPublic); - } - updateTemplate.set('Placeholders', template.Placeholders); - updateTemplate.set('Signers', template.Signers); - if (template?.SignatureType?.length > 0) { - updateTemplate.set('SignatureType', template.SignatureType); - } - - let updateTemplateRes; - if (isJwt) { - updateTemplateRes = await updateTemplate.save(null, { useMasterKey: true }); - } else { - updateTemplateRes = await updateTemplate.save(); - } - return updateTemplateRes; - } else { - throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide Id.'); - } - } catch (err) { - console.log('err in update template', err); - throw err; - } -} -export default async function saveTemplate(request) { - const jwttoken = request.headers.jwttoken || ''; - const template = { - Id: request.params?.templateId, - URL: request.params?.URL || '', - Name: request.params?.Name, - Note: request.params?.Note, - Description: request.params?.Description, - Placeholders: request.params?.Placeholders, - Signers: request.params?.Signers, - SendMail: request.params?.SendMail || false, - SendinOrder: request.params?.SendinOrder || true, - AutomaticReminders: request.params?.AutomaticReminders, - RemindOnceInEvery: parseInt(request.params.RemindOnceInEvery) || 15, - NextReminderDate: request.params?.NextReminderDate, - IsEnableOTP: request.params?.IsEnableOTP === true ? true : false, - IsTourEnabled: request.params?.IsTourEnabled === true ? true : false, - IsPublic: request.params?.IsPublic, - SignatureType: request.params?.SignatureType || [], - }; - - try { - if (request.user) { - return await updateTemplate(template); - } else if (jwttoken) { - const jwtDecode = parseJwt(jwttoken); - const userCls = new Parse.Query(Parse.User); - userCls.equalTo('email', jwtDecode?.user_email); - const userRes = await userCls.first({ useMasterKey: true }); - const userId = userRes?.id; - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('userId', { - __type: 'Pointer', - className: '_User', - objectId: userId, - }); - const appRes = await tokenQuery.first({ useMasterKey: true }); - const decoded = jwt.verify(jwttoken, appRes?.get('token')); - if (decoded?.user_email) { - return await updateTemplate(template, true); - } else { - throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Invalid token'); - } - } else { - throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Invalid session token'); - } - } catch (err) { - console.log('err in get signers', err); - throw err; - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/saveToFileAdapter.js b/apps/OpenSignServer/cloud/parsefunction/saveToFileAdapter.js deleted file mode 100644 index 63a843348..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/saveToFileAdapter.js +++ /dev/null @@ -1,60 +0,0 @@ -import uploadFileToS3 from './uploadFiletoS3.js'; - -export default async function saveToFileAdapter(request) { - if (!request?.user) { - throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.'); - } - - if (!request.params.fileBase64) { - throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide file.'); - } - const fileBase64 = request.params.fileBase64; - const id = request.params.id; - try { - const extCls = new Parse.Query('contracts_Users'); - extCls.equalTo('UserId', request.user); - extCls.include('TenantId'); - const resExt = await extCls.first({ useMasterKey: true }); - if (resExt) { - const _resExt = JSON.parse(JSON.stringify(resExt)); - const fileAdapters = _resExt?.TenantId.FileAdapters || []; - const fileAdapter = fileAdapters?.find(x => x.id === id) || {}; - if (fileAdapter?.accessKeyId) { - const adapterConfig = { - id: id, - fileAdapter: fileAdapter?.fileAdapter, - bucketName: fileAdapter?.bucketName, - region: fileAdapter?.region, - endpoint: fileAdapter?.endpoint, - accessKeyId: fileAdapter?.accessKeyId, - secretAccessKey: fileAdapter?.secretAccessKey, - baseUrl: fileAdapter?.baseUrl, - }; - const buffer = Buffer.from(fileBase64, 'base64'); - const fileName = request.params.fileName; - const ext = request.params.fileName?.split('.')?.pop(); - let mimeType; - if (ext === 'pdf') { - mimeType = 'application/pdf'; - } else if (ext === 'png' || ext === 'jpeg' || ext === 'jpg') { - mimeType = `image/${ext}`; - } - try { - const presignedUrl = await uploadFileToS3(buffer, fileName, mimeType, adapterConfig); - return { url: presignedUrl }; - } catch (err) { - console.error('Error generate presigned url:', err); - const msg = 'Fileadapter credentials are invalid.'; - throw new Parse.Error(400, msg); - } - } else { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'S3 credentials not found.'); - } - } else { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.'); - } - } catch (err) { - console.log('err in savetoS3', err); - throw err; - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/saveWebhook.js b/apps/OpenSignServer/cloud/parsefunction/saveWebhook.js deleted file mode 100644 index 30c99e3b0..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/saveWebhook.js +++ /dev/null @@ -1,30 +0,0 @@ -import axios from 'axios'; -import { cloudServerUrl } from '../../Utils.js'; -export default async function savewebhook(request) { - const serverUrl = cloudServerUrl; //process.env.SERVER_URL; - try { - const userRes = await axios.get(serverUrl + '/users/me', { - headers: { - 'X-Parse-Application-Id': process.env.APP_ID, - 'X-Parse-Session-Token': request.headers['sessiontoken'], - }, - }); - const userId = userRes.data && userRes.data.objectId; - const contractuser = new Parse.Query('contracts_Users'); - contractuser.equalTo('UserId', { __type: 'Pointer', className: '_User', objectId: userId }); - const user = await contractuser.first({ useMasterKey: true }); - - if (user) { - const updateUser = new Parse.Object('contracts_Users'); - updateUser.id = user.id; - updateUser.set('Webhook', request.params.url); - const updatedRes = await updateUser.save(null, { useMasterKey: true }); - if (updatedRes) { - return { code: 200, Webhook: updatedRes.get('Webhook') }; - } - } - } catch (err) { - console.log('update user', err); - return err; - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/savecontact.js b/apps/OpenSignServer/cloud/parsefunction/savecontact.js index 0c9a13903..fdd8e462f 100644 --- a/apps/OpenSignServer/cloud/parsefunction/savecontact.js +++ b/apps/OpenSignServer/cloud/parsefunction/savecontact.js @@ -1,12 +1,8 @@ -import { parseJwt } from '../../Utils.js'; -import jwt from 'jsonwebtoken'; - export default async function savecontact(request) { const name = request.params.name; const phone = request.params.phone; const email = request.params.email; const tenantId = request.params.tenantId; - const jwttoken = request.headers.jwttoken; if (request.user) { const currentUser = request?.user; @@ -84,97 +80,5 @@ export default async function savecontact(request) { } else { throw new Parse.Error(Parse.Error.DUPLICATE_VALUE, 'Contact already exists.'); } - } else if (jwttoken) { - const jwtDecode = parseJwt(jwttoken); - const userCls = new Parse.Query(Parse.User); - userCls.equalTo('email', jwtDecode?.user_email); - const userRes = await userCls.first({ useMasterKey: true }); - const userId = userRes?.id; - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('userId', { - __type: 'Pointer', - className: '_User', - objectId: userId, - }); - const appRes = await tokenQuery.first({ useMasterKey: true }); - const decoded = jwt.verify(jwttoken, appRes?.get('token')); - const currentUser = userRes; - const currentUserPtr = { __type: 'Pointer', className: '_User', objectId: userId }; - if (decoded?.user_email) { - const query = new Parse.Query('contracts_Contactbook'); - query.equalTo('CreatedBy', currentUserPtr); - query.notEqualTo('IsDeleted', true); - query.equalTo('Email', email); - const res = await query.first({ useMasterKey: true }); - if (!res) { - const contactQuery = new Parse.Object('contracts_Contactbook'); - contactQuery.set('Name', name); - if (phone) { - contactQuery.set('Phone', phone); - } - contactQuery.set('Email', email); - contactQuery.set('UserRole', 'contracts_Guest'); - contactQuery.set('IsDeleted', false); - if (tenantId) { - contactQuery.set('TenantId', { - __type: 'Pointer', - className: 'partners_Tenant', - objectId: tenantId, - }); - } - try { - const _users = Parse.Object.extend('User'); - const _user = new _users(); - _user.set('name', name); - _user.set('username', email); - _user.set('email', email); - _user.set('password', email); - if (phone) { - _user.set('phone', phone); - } - - const user = await _user.save(); - if (user) { - contactQuery.set('CreatedBy', currentUserPtr); - contactQuery.set('UserId', user); - const acl = new Parse.ACL(); - acl.setReadAccess(user.id, true); - acl.setWriteAccess(user.id, true); - acl.setReadAccess(currentUser.id, true); - acl.setWriteAccess(currentUser.id, true); - contactQuery.setACL(acl); - - const res = await contactQuery.save(); - const parseData = JSON.parse(JSON.stringify(res)); - return parseData; - } - } catch (err) { - console.log('err ', err); - if (err.code === 202) { - const params = { email: email }; - const userRes = await Parse.Cloud.run('getUserId', params); - contactQuery.set('CreatedBy', currentUserPtr); - contactQuery.set('UserId', { - __type: 'Pointer', - className: '_User', - objectId: userRes.id, - }); - const acl = new Parse.ACL(); - acl.setReadAccess(userRes.id, true); - acl.setWriteAccess(userRes.id, true); - acl.setReadAccess(currentUser.id, true); - acl.setWriteAccess(currentUser.id, true); - contactQuery.setACL(acl); - const res = await contactQuery.save(); - const parseData = JSON.parse(JSON.stringify(res)); - return parseData; - } - } - } else { - throw new Parse.Error(Parse.Error.DUPLICATE_VALUE, 'Contact already exists.'); - } - } else { - throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Invalid token.'); - } } } diff --git a/apps/OpenSignServer/cloud/parsefunction/sendMailGmailProvider.js b/apps/OpenSignServer/cloud/parsefunction/sendMailGmailProvider.js index b6321362d..c63945440 100644 --- a/apps/OpenSignServer/cloud/parsefunction/sendMailGmailProvider.js +++ b/apps/OpenSignServer/cloud/parsefunction/sendMailGmailProvider.js @@ -2,8 +2,6 @@ import axios from 'axios'; import { google } from 'googleapis'; import fs from 'node:fs'; import https from 'https'; -import http from 'http'; -import { useLocal } from '../../Utils.js'; const clientId = process.env.GOOGLE_CLIENT_ID; const clientSecret = process.env.GOOGLE_CLIENT_SECRET; // Function to create a Gmail client @@ -27,10 +25,24 @@ const refreshAccessToken = async refreshToken => { }; // Function to create a raw email message -const makeEmail = async (to, from, subject, html, url, pdfName) => { +const makeEmail = async ( + to, + from, + subject, + html, + url, + pdfName, + bcc, + filename, + certificatePath, + replyto +) => { const publicUrl = new URL(process.env.SERVER_URL); const htmlContent = html; const boundary = 'boundary_' + Date.now().toString(16); + const bccHeader = bcc && bcc.length > 0 ? `BCC: ${bcc.join(',')}\n` : ''; // Construct BCC header if provided + const replyToHeader = replyto ? `Reply-To: ${replyto}\n` : ''; // Construct Reply-To header if provided + let str; if (url) { let attachments; @@ -39,18 +51,24 @@ const makeEmail = async (to, from, subject, html, url, pdfName) => { return new Promise((resolve, reject) => { const isSecure = new URL(url)?.protocol === 'https:' && new URL(url)?.hostname !== 'localhost'; - if (useLocal !== 'true' || isSecure) { + if (isSecure) { https.get(url, async function (response) { response.pipe(Pdf); response.on('end', () => resolve('success')); }); } else { - const path = new URL(url)?.pathname; - const localurl = 'http://localhost:8080' + path; - http.get(localurl, async function (response) { - response.pipe(Pdf); - response.on('end', () => resolve('success')); - }); + const httpsAgent = new https.Agent({ rejectUnauthorized: false }); // Disable SSL validation + axios + .get(url, { responseType: 'stream', httpsAgent }) + .then(response => { + response.data.pipe(Pdf); + Pdf.on('finish', () => resolve('success')); + Pdf.on('error', () => resolve('error')); + }) + .catch(e => { + console.log('error', e.message); + resolve('error'); + }); } }); }; @@ -58,7 +76,7 @@ const makeEmail = async (to, from, subject, html, url, pdfName) => { const ress = await writeToLocalDisk(); if (ress) { const file = { - filename: `${pdfName}.pdf` || 'exported.pdf', + filename: filename || `${pdfName}.pdf` || 'exported.pdf', type: 'application/pdf', path: Pdf.path, }; @@ -68,7 +86,7 @@ const makeEmail = async (to, from, subject, html, url, pdfName) => { const certificate = { filename: 'certificate.pdf', type: 'application/pdf', - path: './exports/certificate.pdf', + path: certificatePath || './exports/certificate.pdf', }; if (fs.existsSync(certificate.path)) { attachments = [file, certificate]; @@ -99,6 +117,8 @@ const makeEmail = async (to, from, subject, html, url, pdfName) => { 'MIME-Version: 1.0\n', `To: ${to}\n`, `From: ${from}\n`, + bccHeader, + replyToHeader, `Subject: ${subject}\n\n`, '--' + boundary + '\n', 'Content-Type: text/html; charset="UTF-8"\n', @@ -114,6 +134,8 @@ const makeEmail = async (to, from, subject, html, url, pdfName) => { 'MIME-Version: 1.0\n', `To: ${to}\n`, `From: ${from}\n`, + bccHeader, + replyToHeader, `Subject: ${subject}\n\n`, '--' + boundary + '\n', 'Content-Type: text/html; charset="UTF-8"\n', @@ -127,7 +149,8 @@ const makeEmail = async (to, from, subject, html, url, pdfName) => { return encodedMail; }; export default async function sendMailGmailProvider(_extRes, template) { - const { sender, receiver, subject, html, url, pdfName } = template; + const { sender, receiver, subject, html, url, pdfName, bcc, filename, certificatePath, replyto } = + template; if (_extRes) { const refresh_token = _extRes.google_refresh_token; @@ -138,21 +161,30 @@ export default async function sendMailGmailProvider(_extRes, template) { // Construct email message const from = sender || _extRes.Email || 'me'; const to = receiver; - const email = await makeEmail(to, from, subject, html, url, pdfName); + const email = await makeEmail( + to, + from, + subject, + html, + url, + pdfName, + bcc, + filename, + certificatePath, + replyto + ); // Update Gmail client with new access token const newGmail = createGmailClient(access_token); // sending email with new client const response = await newGmail.users.messages.send({ userId: 'me', - requestBody: { - raw: email, - }, + requestBody: { raw: email }, }); console.log('gmail provider res: ', response?.status); - const certificatePath = './exports/certificate.pdf'; - if (fs.existsSync(certificatePath)) { + const certificatepath = certificatePath || './exports/certificate.pdf'; + if (fs.existsSync(certificatepath)) { try { - fs.unlinkSync(certificatePath); + fs.unlinkSync(certificatepath); } catch (err) { console.log('Err in unlink certificate sendmailgmail provider'); } diff --git a/apps/OpenSignServer/cloud/parsefunction/sendMailv3.js b/apps/OpenSignServer/cloud/parsefunction/sendMailv3.js index 2cb484f6a..bcca7d826 100644 --- a/apps/OpenSignServer/cloud/parsefunction/sendMailv3.js +++ b/apps/OpenSignServer/cloud/parsefunction/sendMailv3.js @@ -1,11 +1,10 @@ import fs from 'node:fs'; import https from 'https'; -import http from 'http'; import formData from 'form-data'; import Mailgun from 'mailgun.js'; -import { smtpenable, smtpsecure, updateMailCount, useLocal } from '../../Utils.js'; -import sendMailGmailProvider from './sendMailGmailProvider.js'; +import { smtpenable, smtpsecure, updateMailCount } from '../../Utils.js'; import { createTransport } from 'nodemailer'; +import axios from 'axios'; async function sendMailProvider(req, plan, monthchange) { const mailgunApiKey = process.env.MAILGUN_API_KEY; try { @@ -36,18 +35,29 @@ async function sendMailProvider(req, plan, monthchange) { const isSecure = new URL(req.params.url)?.protocol === 'https:' && new URL(req.params.url)?.hostname !== 'localhost'; - if (useLocal !== 'true' || isSecure) { - https.get(req.params.url, async function (response) { - response.pipe(Pdf); - response.on('end', () => resolve('success')); - }); + if (isSecure) { + https + .get(req.params.url, async function (response) { + response.pipe(Pdf); + response.on('end', () => resolve('success')); + }) + .on('error', e => { + console.error(`error: ${e.message}`); + resolve('error'); + }); } else { - const path = new URL(req.params.url)?.pathname; - const localurl = 'http://localhost:8080' + path; - http.get(localurl, async function (response) { - response.pipe(Pdf); - response.on('end', () => resolve('success')); - }); + const httpsAgent = new https.Agent({ rejectUnauthorized: false }); // Disable SSL validation + axios + .get(req.params.url, { responseType: 'stream', httpsAgent }) + .then(response => { + response.data.pipe(Pdf); + Pdf.on('finish', () => resolve('success')); + Pdf.on('error', () => resolve('error')); + }) + .catch(e => { + console.log('error', e.message); + resolve('error'); + }); } }); }; @@ -65,14 +75,15 @@ async function sendMailProvider(req, plan, monthchange) { // `PdfBuffer` used to create buffer from pdf file let PdfBuffer = await readTolocal(); const pdfName = req.params.pdfName && `${req.params.pdfName}.pdf`; + const filename = req.params.filename; const file = { - filename: pdfName || 'exported.pdf', + filename: filename || pdfName || 'exported.pdf', content: smtpenable ? PdfBuffer : undefined, data: smtpenable ? undefined : PdfBuffer, }; let attachment; - const certificatePath = './exports/certificate.pdf'; + const certificatePath = req.params.certificatePath || `./exports/certificate.pdf`; if (fs.existsSync(certificatePath)) { try { // `certificateBuffer` used to create buffer from pdf file @@ -92,7 +103,7 @@ async function sendMailProvider(req, plan, monthchange) { } const from = req.params.from || ''; const mailsender = smtpenable ? process.env.SMTP_USER_EMAIL : process.env.MAILGUN_SENDER; - + const replyto = req.params?.replyto || ''; const messageParams = { from: from + ' <' + mailsender + '>', to: req.params.recipient, @@ -101,6 +112,8 @@ async function sendMailProvider(req, plan, monthchange) { html: req.params.html || '', attachments: smtpenable ? attachment : undefined, attachment: smtpenable ? undefined : attachment, + bcc: req.params.bcc ? req.params.bcc : undefined, + replyTo: replyto ? replyto : undefined, }; if (transporterSMTP) { const res = await transporterSMTP.sendMail(messageParams); @@ -150,13 +163,15 @@ async function sendMailProvider(req, plan, monthchange) { } else { const from = req.params.from || ''; const mailsender = smtpenable ? process.env.SMTP_USER_EMAIL : process.env.MAILGUN_SENDER; - + const replyto = req.params?.replyto || ''; const messageParams = { from: from + ' <' + mailsender + '>', to: req.params.recipient, subject: req.params.subject, text: req.params.text || 'mail', html: req.params.html || '', + bcc: req.params.bcc ? req.params.bcc : undefined, + replyTo: replyto ? replyto : undefined, }; if (transporterSMTP) { @@ -190,189 +205,10 @@ async function sendMailProvider(req, plan, monthchange) { } } } -async function sendcustomsmtp(extRes, req) { - const smtpsecure = extRes.SmtpConfig.port !== '465' ? false : true; - const transporterSMTP = createTransport({ - host: extRes.SmtpConfig.host, - port: extRes.SmtpConfig.port, - secure: smtpsecure, - auth: { user: extRes.SmtpConfig.username, pass: extRes.SmtpConfig.password }, - }); - if (req.params.url) { - let Pdf = fs.createWriteStream('test.pdf'); - const writeToLocalDisk = () => { - return new Promise((resolve, reject) => { - const isSecure = - new URL(req.params.url)?.protocol === 'https:' && - new URL(req.params.url)?.hostname !== 'localhost'; - if (useLocal !== 'true' || isSecure) { - https.get(req.params.url, async function (response) { - response.pipe(Pdf); - response.on('end', () => resolve('success')); - }); - } else { - const path = new URL(req.params.url)?.pathname; - const localurl = 'http://localhost:8080' + path; - http.get(localurl, async function (response) { - response.pipe(Pdf); - response.on('end', () => resolve('success')); - }); - } - }); - }; - // `writeToLocalDisk` is used to create pdf file from doc url - const ress = await writeToLocalDisk(); - if (ress) { - function readTolocal() { - return new Promise((resolve, reject) => { - setTimeout(() => { - let PdfBuffer = fs.readFileSync(Pdf.path); - resolve(PdfBuffer); - }, 100); - }); - } - // `PdfBuffer` used to create buffer from pdf file - let PdfBuffer = await readTolocal(); - const pdfName = req.params.pdfName ? `${req.params.pdfName}.pdf` : 'exported.pdf'; - const file = { filename: pdfName, content: PdfBuffer }; - let attachment; - const certificatePath = './exports/certificate.pdf'; - if (fs.existsSync(certificatePath)) { - try { - // `certificateBuffer` used to create buffer from pdf file - const certificateBuffer = fs.readFileSync(certificatePath); - const certificate = { filename: 'certificate.pdf', content: certificateBuffer }; - attachment = [file, certificate]; - } catch (err) { - attachment = [file]; - console.log('Err in read certificate sendmailv3', err); - } - } else { - attachment = [file]; - } - const from = req.params.from || ''; - const mailsender = extRes.SmtpConfig.username; - const messageParams = { - from: from + ' <' + mailsender + '>', - to: req.params.recipient, - subject: req.params.subject, - text: req.params.text || 'mail', - html: req.params.html || '', - attachments: attachment, - }; - const res = await transporterSMTP.sendMail(messageParams); - console.log('custom smtp transporter res: ', res?.response); - if (!res.err) { - if (req.params?.extUserId) { - await updateMailCount(req.params.extUserId); //, plan, monthchange - } - if (fs.existsSync(certificatePath)) { - try { - fs.unlinkSync(certificatePath); - } catch (err) { - console.log('Err in unlink certificate sendmailv3'); - } - } - return { status: 'success', code: 200 }; - } - } - } else { - const from = req.params.from || ''; - const mailsender = extRes.SmtpConfig.username; - const messageParams = { - from: from + ' <' + mailsender + '>', - to: req.params.recipient, - subject: req.params.subject, - text: req.params.text || 'mail', - html: req.params.html || '', - }; - - const res = await transporterSMTP.sendMail(messageParams); - console.log('custom smtp transporter res: ', res?.response); - if (!res.err) { - if (req.params?.extUserId) { - await updateMailCount(req.params.extUserId); //, plan, monthchange - } - return { status: 'success', code: 200 }; - } - } -} async function sendmailv3(req) { - const mailProvider = req.params.mailProvider || 'default'; - if (mailProvider) { - try { - const Plan = req.params.plan; - const extUserId = req.params.extUserId || ''; - const pdfName = req.params.pdfName || ''; - const template = { - sender: req.params.from || '', - receiver: req.params.recipient, - subject: req.params.subject, - html: req.params.html || '', - url: req.params.url ? req.params.url : '', - pdfName: pdfName, - }; - const extUserQuery = new Parse.Query('contracts_Users'); - const extRes = await extUserQuery.get(extUserId, { useMasterKey: true }); - if (extRes) { - const _extRes = JSON.parse(JSON.stringify(extRes)); - if ( - _extRes.active_mail_adapter === 'google' && - _extRes.google_refresh_token && - mailProvider === 'google' - ) { - const res = await sendMailGmailProvider(_extRes, template); - if (res.code === 200) { - await updateMailCount(req.params.extUserId); - return { status: 'success' }; - } else { - return { status: 'error' }; - } - } else if (_extRes.active_mail_adapter === 'smtp' && mailProvider === 'smtp') { - const res = await sendcustomsmtp(_extRes, req); - if (res.code === 200) { - await updateMailCount(req.params.extUserId); - return { status: 'success' }; - } else { - return { status: 'error' }; - } - } else { - if (Plan && Plan === 'freeplan') { - let MonthlyFreeEmails = _extRes?.MonthlyFreeEmails || 0; - if (_extRes?.LastEmailCountReset?.iso) { - const lastDate = new Date(_extRes?.LastEmailCountReset?.iso); - const newDate = new Date(); - const isMonthChange = newDate.getMonth() > lastDate.getMonth(); - if (isMonthChange) { - const nonCustomMail = await sendMailProvider(req, Plan, true); - return nonCustomMail; - } else { - if (MonthlyFreeEmails >= 15) { - return { status: 'quota-reached' }; - } else { - const nonCustomMail = await sendMailProvider(req, Plan); - return nonCustomMail; - } - } - } else { - const nonCustomMail = await sendMailProvider(req, Plan); - return nonCustomMail; - } - } else { - const nonCustomMail = await sendMailProvider(req, ''); - return nonCustomMail; - } - } - } - } catch (err) { - console.log('err in send custom mail', err); - return { status: 'error' }; - } - } else { const nonCustomMail = await sendMailProvider(req); return nonCustomMail; - } } export default sendmailv3; diff --git a/apps/OpenSignServer/cloud/parsefunction/ssoSignin.js b/apps/OpenSignServer/cloud/parsefunction/ssoSignin.js deleted file mode 100644 index acbed765e..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/ssoSignin.js +++ /dev/null @@ -1,133 +0,0 @@ -import axios from 'axios'; -import { cloudServerUrl } from '../../Utils.js'; - -const serverUrl = cloudServerUrl; //process.env.SERVER_URL; -const APPID = process.env.APP_ID; -const masterKEY = process.env.MASTER_KEY; -const clientUrl = process.env.PUBLIC_URL; -const ssoApiUrl = process.env.SSO_API_URL || 'https://sso.opensignlabs.com/api'; //'https://osl-jacksonv2.vercel.app/api'; -/** - * ssoSign is function which is used to sign up/sign in with SSO - * @param code It is code return by jackson using authorize endpoint - * @param email It is user's email with user sign in/sign up - * @returns if success {email, name, phone message, sessiontoken} else on reject error {code, message} - */ - -export default async function ssoSignin(request) { - const code = request.params.code; - const userEmail = request.params.email; - try { - const headers = { 'content-type': 'application/x-www-form-urlencoded' }; - const axiosRes = await axios.post( - ssoApiUrl + '/oauth/token', - { - grant_type: 'authorization_code', - client_id: 'dummy', - tenant: 'Okta-dev-nxglabs-in', - product: 'OpenSign', - client_secret: 'dummy', - redirect_uri: clientUrl + '/sso', - code: code, - }, - { headers: headers } - ); - const ssoAccessToken = axiosRes.data && axiosRes.data.access_token; - const authData = { sso: { id: userEmail, access_token: ssoAccessToken } }; - const userQuery = new Parse.Query(Parse.User); - userQuery.equalTo('username', userEmail); - const res = await userQuery.first({ useMasterKey: true }); - if (res) { - try { - const SignIn = await axios.put( - serverUrl + '/users/' + res.id, - { authData: authData }, - { - headers: { - 'X-Parse-Application-Id': APPID, - 'X-Parse-Master-key': masterKEY, - }, - } - ); - - if (SignIn.data) { - const response = await axios.get(ssoApiUrl + '/oauth/userinfo', { - headers: { - Authorization: `Bearer ${ssoAccessToken}`, - }, - }); - const sessiontoken = SignIn.data.sessionToken; - // console.log('sso sessiontoken', sessiontoken); - const payload = { - email: userEmail, - name: response.data?.firstName + ' ' + response.data?.lastName, - phone: response?.data?.phone || '', - message: 'User Sign In', - sessiontoken: sessiontoken, - }; - return payload; - } - } catch (err) { - const errCode = err?.response?.data?.code || err?.response?.status || err?.code || 400; - const message = - err?.response?.data?.error || - err?.response?.data || - err?.message || - 'Internal server error.'; - console.log('err in user sso sign in', errCode, message); - throw new Parse.Error(errCode, message); - } - } else { - // console.log("in sign up condition"); - const response = await axios.get(ssoApiUrl + '/oauth/userinfo', { - headers: { - Authorization: `Bearer ${ssoAccessToken}`, - }, - }); - if (response.data && response.data.id) { - try { - const SignUp = await axios.post( - serverUrl + '/users', - { - authData: authData, - username: response.data.email, - email: response.data.email, - phone: response.data?.phone, - name: response.data?.firstName + ' ' + response.data?.lastName, - }, - { - headers: { - 'X-Parse-Application-Id': APPID, - 'X-Parse-Revocable-Session': '1', - }, - } - ); - if (SignUp.data) { - const sessiontoken = SignUp.data.sessionToken; - const payload = { - email: userEmail, - name: SignUp?.data?.name, - phone: SignUp?.data?.phone || '', - message: 'User Sign Up', - sessiontoken: sessiontoken, - }; - return payload; - } - } catch (err) { - const errCode = err?.response?.data?.code || err?.response?.status || err?.code || 400; - const message = - err?.response?.data?.error || - err?.response?.data || - err?.message || - 'Internal server error.'; - console.log('err in user sso sign up', errCode, message); - throw new Parse.Error(errCode, message); - } - } - } - } catch (err) { - const errCode = err?.response?.status || err?.code || 400; - const message = err?.response?.data || err?.message || 'Internal server error.'; - console.log('err in ssoSign', errCode, message); - throw new Parse.Error(errCode, message); - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/updateOrganization.js b/apps/OpenSignServer/cloud/parsefunction/updateOrganization.js deleted file mode 100644 index 493b9e0cb..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/updateOrganization.js +++ /dev/null @@ -1,33 +0,0 @@ -export default async function updateOrganization(request) { - const orgId = request.params.orgId; - const isactive = request.params.isactive; - if (!request?.user) { - throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.'); - } - try { - const orgQuery = new Parse.Query('contracts_Organizations'); - orgQuery.equalTo('objectId', orgId); - orgQuery.equalTo('CreatedBy', { - __type: 'Pointer', - className: '_User', - objectId: request.user.id, - }); - const resOrg = await orgQuery.first({ useMasterKey: true }); - if (resOrg) { - const newOrg = new Parse.Object('contracts_Organizations'); - newOrg.id = orgId; - newOrg.set('IsActive', isactive); - const newResOrg = await newOrg.save(null, { useMasterKey: true }); - if (newResOrg) { - return newResOrg; - } - } else { - throw new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, 'Premission denied.'); - } - } catch (err) { - console.log('err in addorganization', err); - const code = err?.code || 400; - const msg = err?.message || 'Something went wrong.'; - throw new Parse.Error(code, msg); - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/updatePreferences.js b/apps/OpenSignServer/cloud/parsefunction/updatePreferences.js index b8ff2f9fd..6ae55ff2b 100644 --- a/apps/OpenSignServer/cloud/parsefunction/updatePreferences.js +++ b/apps/OpenSignServer/cloud/parsefunction/updatePreferences.js @@ -4,7 +4,8 @@ export default async function updatePreferences(request) { } const SignatureType = request.params.SignatureType || []; const NotifyOnSignatures = request.params.NotifyOnSignatures; - if (SignatureType?.length > 0 || NotifyOnSignatures !== undefined) { + const Timezone = request.params.Timezone; + if (SignatureType?.length > 0 || NotifyOnSignatures !== undefined || Timezone) { try { const orgQuery = new Parse.Query('contracts_Users'); orgQuery.equalTo('UserId', { @@ -19,6 +20,9 @@ export default async function updatePreferences(request) { if (NotifyOnSignatures !== undefined) { newOrg.set('NotifyOnSignatures', NotifyOnSignatures); } + if (Timezone) { + newOrg.set('Timezone', Timezone); + } if (SignatureType.length > 0) { const enabledSignTypes = SignatureType?.filter(x => x.enabled); const isDefaultSignTypeOnly = diff --git a/apps/OpenSignServer/cloud/parsefunction/updateTeam.js b/apps/OpenSignServer/cloud/parsefunction/updateTeam.js deleted file mode 100644 index b70f6b119..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/updateTeam.js +++ /dev/null @@ -1,50 +0,0 @@ -export default async function updateTeam(request) { - const TeamId = request.params.TeamId; - const IsActive = request.params.IsActive; - const Name = request.params.Name; - if (!request?.user) { - throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.'); - } - try { - const extUserQuery = new Parse.Query('contracts_Users'); - extUserQuery.equalTo('UserId', { - __type: 'Pointer', - className: '_User', - objectId: request.user.id, - }); - extUserQuery.notEqualTo('IsDisabled', true); - const resExt = await extUserQuery.first({ useMasterKey: true }); - const extUser = JSON.parse(JSON.stringify(resExt)); - if (!extUser) { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.'); - } - const teamCls = new Parse.Query('contracts_Teams'); - teamCls.equalTo('objectId', TeamId); - teamCls.equalTo('OrganizationId', { - __type: 'Pointer', - className: 'contracts_Organizations', - objectId: extUser.OrganizationId.objectId, - }); - const teamRes = await teamCls.first({ useMasterKey: true }); - if (teamRes) { - const updateteam = new Parse.Object('contracts_Teams'); - updateteam.id = TeamId; - if (Name) { - updateteam.set('Name', Name); - } - if (IsActive) { - const active = IsActive === 'false' ? false : true; - updateteam.set('IsActive', active); - } - const updateTeamRes = await updateteam.save(null, { useMasterKey: true }); - return updateTeamRes; - } else { - throw new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, 'Premission denied.'); - } - } catch (err) { - console.log('err in getOrganizations', err); - const code = err?.code || 400; - const msg = err?.message || 'Something went wrong.'; - throw new Parse.Error(code, msg); - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/updateToPublicTemplate.js b/apps/OpenSignServer/cloud/parsefunction/updateToPublicTemplate.js deleted file mode 100644 index e44599e4e..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/updateToPublicTemplate.js +++ /dev/null @@ -1,73 +0,0 @@ -import { parseJwt } from '../../Utils.js'; -import jwt from 'jsonwebtoken'; - -async function updateTemplate(template, isJwt = false) { - try { - if (template?.Id) { - const updateTemplate = new Parse.Object('contracts_Template'); - updateTemplate.id = template.Id; - - const isPublic = template?.IsPublic !== undefined ? template?.IsPublic : false; - if (template?.IsPublic !== undefined) { - updateTemplate.set('IsPublic', isPublic); - updateTemplate.set('PublicRole', template.PublicRole); - } - - let updateTemplateRes; - if (isJwt) { - updateTemplateRes = await updateTemplate.save(null, { useMasterKey: true }); - } else { - updateTemplateRes = await updateTemplate.save(); - } - return updateTemplateRes; - } else { - throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide Id.'); - } - } catch (err) { - console.log('err in update template', err); - throw err; - } -} -export default async function updateToPublicTemplate(request) { - const jwttoken = request.headers.jwttoken || ''; - const Role = request.params.Role; - if (!Role) { - throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide public role.'); - } - const PublicRole = [Role]; - const template = { - Id: request.params.templateId, - IsPublic: request.params?.IsPublic, - PublicRole: PublicRole, - }; - - try { - if (request.user) { - return await updateTemplate(template); - } else if (jwttoken) { - const jwtDecode = parseJwt(jwttoken); - const userCls = new Parse.Query(Parse.User); - userCls.equalTo('email', jwtDecode?.user_email); - const userRes = await userCls.first({ useMasterKey: true }); - const userId = userRes?.id; - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('userId', { - __type: 'Pointer', - className: '_User', - objectId: userId, - }); - const appRes = await tokenQuery.first({ useMasterKey: true }); - const decoded = jwt.verify(jwttoken, appRes?.get('token')); - if (decoded?.user_email) { - return await updateTemplate(template, true); - } else { - throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Invalid token'); - } - } else { - throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Invalid session token'); - } - } catch (err) { - console.log('err in get signers', err); - throw err; - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/updateTourStatus.js b/apps/OpenSignServer/cloud/parsefunction/updateTourStatus.js index 1636ac278..fea5f2afb 100644 --- a/apps/OpenSignServer/cloud/parsefunction/updateTourStatus.js +++ b/apps/OpenSignServer/cloud/parsefunction/updateTourStatus.js @@ -1,10 +1,7 @@ -import { parseJwt } from '../../Utils.js'; -import jwt from 'jsonwebtoken'; - export default async function updateTourStatus(request) { const tourstatus = request.params.TourStatus; const extUserId = request.params.ExtUserId; - const jwttoken = request?.headers?.jwttoken || ''; + if (request.user) { try { const updateUser = new Parse.Object('contracts_Users'); @@ -18,41 +15,8 @@ export default async function updateTourStatus(request) { const msg = err?.message || 'Something went wrong.'; throw new Parse.Error(code, msg); } - } else if (jwttoken) { - const jwtDecode = parseJwt(jwttoken); - if (jwtDecode?.user_email) { - const userCls = new Parse.Query(Parse.User); - userCls.equalTo('email', jwtDecode?.user_email); - const userRes = await userCls.first({ useMasterKey: true }); - const userId = userRes?.id; - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('userId', { - __type: 'Pointer', - className: '_User', - objectId: userId, - }); - const appRes = await tokenQuery.first({ useMasterKey: true }); - const decoded = jwt.verify(jwttoken, appRes?.get('token')); - if (decoded?.user_email) { - try { - const updateUser = new Parse.Object('contracts_Users'); - updateUser.id = extUserId; - updateUser.set('TourStatus', tourstatus); - const res = await updateUser.save(null, { useMasterKey: true }); - return res; - } catch (err) { - console.log('Err ', err); - const code = err?.code || 400; - const msg = err?.message || 'Something went wrong.'; - throw new Parse.Error(code, msg); - } - } else { - return { status: 'error', result: 'Invalid token!' }; - } - } else { - return { status: 'error', result: 'Invalid token!' }; - } - } else { + } + else { throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.'); } } diff --git a/apps/OpenSignServer/cloud/parsefunction/uploadFiletoS3.js b/apps/OpenSignServer/cloud/parsefunction/uploadFiletoS3.js deleted file mode 100644 index 3fe0a6d2a..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/uploadFiletoS3.js +++ /dev/null @@ -1,39 +0,0 @@ -import { S3Client, PutObjectCommand, GetObjectCommand } from '@aws-sdk/client-s3'; -import { getSignedUrl } from '@aws-sdk/s3-request-presigner'; -import * as crypto from 'node:crypto'; -async function uploadFileToS3(buffer, fileName, mimeType, adapter) { - const bucketName = adapter?.bucketName; - let client; - if (adapter?.fileAdapter === 'digitalocean') { - client = new S3Client({ - endpoint: adapter?.endpoint, - region: adapter?.region, - credentials: { accessKeyId: adapter?.accessKeyId, secretAccessKey: adapter?.secretAccessKey }, - }); - } else { - client = new S3Client({ - region: adapter?.region, - credentials: { accessKeyId: adapter?.accessKeyId, secretAccessKey: adapter?.secretAccessKey }, - signatureVersion: 'v4' - }); - } - const prefixId = crypto.randomBytes(16).toString('hex'); - const fileKey = `${prefixId}_${fileName}`; - const uploadParams = { Bucket: bucketName, Key: fileKey, Body: buffer, ContentType: mimeType }; - - try { - // Upload the buffer to the Space - const command = new PutObjectCommand(uploadParams); - await client.send(command); - const getCommand = new GetObjectCommand({ Bucket: bucketName, Key: fileKey }); - - // Generate a presigned URL for the uploaded file - const presignedUrl = await getSignedUrl(client, getCommand, { expiresIn: 900 }); // URL expiration time in seconds (e.g., 15 min) - return presignedUrl; - } catch (error) { - console.error('Error uploading file to aws:', error?.message); - throw error; - } -} - -export default uploadFileToS3; diff --git a/apps/OpenSignServer/cloud/parsefunction/usersignup.js b/apps/OpenSignServer/cloud/parsefunction/usersignup.js index 44f9665b4..de561ccdf 100644 --- a/apps/OpenSignServer/cloud/parsefunction/usersignup.js +++ b/apps/OpenSignServer/cloud/parsefunction/usersignup.js @@ -1,5 +1,7 @@ import axios from 'axios'; -import { cloudServerUrl, planCredits } 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; @@ -43,7 +45,6 @@ async function saveUser(userDetails) { } export default async function usersignup(request) { const userDetails = request.params.userDetails; - const subscription = request.params.subscription; const user = await saveUser(userDetails); try { @@ -120,10 +121,10 @@ export default async function usersignup(request) { if (userDetails && userDetails.jobTitle) { newObj.set('JobTitle', userDetails.jobTitle); } - const extRes = await newObj.save(null, { useMasterKey: true }); - if (subscription) { - await saveSubscription(extRes.id, user.id, tenantRes.id, subscription); + if (userDetails && userDetails?.timezone) { + newObj.set('Timezone', userDetails.timezone); } + const extRes = await newObj.save(null, { useMasterKey: true }); return { message: 'User sign up', sessionToken: user.sessionToken }; } } catch (err) { @@ -131,39 +132,3 @@ export default async function usersignup(request) { } } -async function saveSubscription(extUserId, UserId, tenantId, subscription) { - const SubscriptionId = subscription?.data?.subscription?.subscription_id || ''; - const Next_billing_date = subscription?.data?.subscription?.next_billing_at || ''; - const planCode = subscription?.data?.subscription?.plan?.plan_code || ''; - const credits = planCredits?.[planCode] || 0; - - try { - const createSubscription = new Parse.Object('contracts_Subscriptions'); - createSubscription.set('SubscriptionId', SubscriptionId); - createSubscription.set('SubscriptionDetails', subscription); - createSubscription.set('ExtUserPtr', { - __type: 'Pointer', - className: 'contracts_Users', - objectId: extUserId, - }); - createSubscription.set('CreatedBy', { - __type: 'Pointer', - className: '_User', - objectId: UserId, - }); - createSubscription.set('TenantId', { - __type: 'Pointer', - className: 'partners_Tenant', - objectId: tenantId, - }); - createSubscription.set('Next_billing_date', new Date(Next_billing_date)); - createSubscription.set('PlanCode', planCode); - if (credits > 0) { - createSubscription.set('AllowedCredits', credits); - createSubscription.set('PlanCredits', credits); - } - await createSubscription.save(null, { useMasterKey: true }); - } catch (err) { - console.log('err in save subscription pgsignup', err); - } -} diff --git a/apps/OpenSignServer/databases/migrations/20240110100110-update_document_cls_cjs.cjs b/apps/OpenSignServer/databases/migrations/20240110100110-update_document_cls_cjs.cjs index 1a95b4f46..05a68e97a 100644 --- a/apps/OpenSignServer/databases/migrations/20240110100110-update_document_cls_cjs.cjs +++ b/apps/OpenSignServer/databases/migrations/20240110100110-update_document_cls_cjs.cjs @@ -3,7 +3,6 @@ * @param {Parse} Parse */ exports.up = async Parse => { - // TODO: set className here const className = 'contracts_Document'; const schema = new Parse.Schema(className); schema.addBoolean('IsArchive'); @@ -15,7 +14,6 @@ exports.up = async Parse => { * @param {Parse} Parse */ exports.down = async Parse => { - // TODO: set className here const className = 'contracts_Document'; const schema = new Parse.Schema(className); schema.deleteField('IsArchive'); diff --git a/apps/OpenSignServer/databases/migrations/20240306123606-add_fields_contracts_users_cjs.cjs b/apps/OpenSignServer/databases/migrations/20240306123606-add_fields_contracts_users_cjs.cjs index 2875ef34e..72a95996a 100644 --- a/apps/OpenSignServer/databases/migrations/20240306123606-add_fields_contracts_users_cjs.cjs +++ b/apps/OpenSignServer/databases/migrations/20240306123606-add_fields_contracts_users_cjs.cjs @@ -3,7 +3,6 @@ * @param {Parse} Parse */ exports.up = async Parse => { - // TODO: set className here const className = 'contracts_Users'; const schema = new Parse.Schema(className); schema.addBoolean('HeaderDocId'); @@ -16,35 +15,9 @@ exports.up = async Parse => { * @param {Parse} Parse */ exports.down = async Parse => { - // TODO: set className here const className = 'contracts_Users'; const schema = new Parse.Schema(className); - - schema.addString('Name'); - schema.addString('Phone'); - schema.addString('JobTitle'); - schema.addString('Email'); - schema.addString('Company'); - schema.addString('UserRole'); - schema.addObject('Plan'); - schema.addString('Customer_id'); - schema.addString('Subscription_id'); - schema.addDate('Next_billing_date'); - schema.addBoolean('IsContactEntry'); - schema.addBoolean('ShareWithTeam'); - schema.addPointer('TenantId', 'partners_Tenant'); - schema.addPointer('UserId', '_User'); - schema.addPointer('CreatedBy', '_User'); - schema.addArray('TourStatus'); - schema.setCLP({ - get: {}, - find: {}, - count: {}, - create: { '*': true }, - update: { '*': true }, - delete: {}, - addField: {}, - }); - + schema.deleteField('HeaderDocId'); + schema.deleteField('Webhook'); return schema.update(); }; diff --git a/apps/OpenSignServer/databases/migrations/20240408133151-update_contracts_document_cls.cjs b/apps/OpenSignServer/databases/migrations/20240408133151-update_contracts_document_cls.cjs index 3c6ec8e71..db86d0812 100644 --- a/apps/OpenSignServer/databases/migrations/20240408133151-update_contracts_document_cls.cjs +++ b/apps/OpenSignServer/databases/migrations/20240408133151-update_contracts_document_cls.cjs @@ -3,15 +3,10 @@ * @param {Parse} Parse */ exports.up = async Parse => { - // TODO: set className here const className = 'contracts_Document'; const schema = new Parse.Schema(className); schema.addString('RequestBody'); schema.addString('RequestSubject'); - // TODO: Set the schema here - // Example: - // schema.addString('name').addNumber('cash'); - return schema.update(); }; @@ -20,14 +15,9 @@ exports.up = async Parse => { * @param {Parse} Parse */ exports.down = async Parse => { - // TODO: set className here const className = 'contracts_Document'; const schema = new Parse.Schema(className); schema.deleteField('RequestBody'); schema.deleteField('RequestSubject'); - // TODO: Set the schema here - // Example: - // schema.deleteField('name').deleteField('cash'); - return schema.update(); }; diff --git a/apps/OpenSignServer/databases/migrations/20240521184801-update_contracts_document_cls_cjs.cjs b/apps/OpenSignServer/databases/migrations/20240521184801-update_contracts_document_cls_cjs.cjs index 8575d42a2..cc6d83c98 100644 --- a/apps/OpenSignServer/databases/migrations/20240521184801-update_contracts_document_cls_cjs.cjs +++ b/apps/OpenSignServer/databases/migrations/20240521184801-update_contracts_document_cls_cjs.cjs @@ -3,15 +3,10 @@ * @param {Parse} Parse */ exports.up = async Parse => { - // TODO: set className here const className = 'contracts_Document'; const schema = new Parse.Schema(className); schema.addBoolean('SendMail'); schema.addBoolean('SendCompletionMail'); - // TODO: Set the schema here - // Example: - // schema.addString('name').addNumber('cash'); - return schema.update(); }; @@ -20,15 +15,9 @@ exports.up = async Parse => { * @param {Parse} Parse */ exports.down = async Parse => { - // TODO: set className here const className = 'contracts_Document'; const schema = new Parse.Schema(className); schema.deleteField('SendMail'); schema.deleteField('SendCompletionMail'); - - // TODO: Set the schema here - // Example: - // schema.deleteField('name').deleteField('cash'); - return schema.update(); }; diff --git a/apps/OpenSignServer/databases/migrations/20240527194216-update_contracts_template_cls_cjs.cjs b/apps/OpenSignServer/databases/migrations/20240527194216-update_contracts_template_cls_cjs.cjs index 94489b287..ec3ffaa81 100644 --- a/apps/OpenSignServer/databases/migrations/20240527194216-update_contracts_template_cls_cjs.cjs +++ b/apps/OpenSignServer/databases/migrations/20240527194216-update_contracts_template_cls_cjs.cjs @@ -3,16 +3,10 @@ * @param {Parse} Parse */ exports.up = async Parse => { - // TODO: set className here const className = 'contracts_Template'; const schema = new Parse.Schema(className); schema.addArray('PublicRole'); schema.addBoolean('IsPublic'); - - // TODO: Set the schema here - // Example: - // schema.addString('name').addNumber('cash'); - return schema.update(); }; @@ -21,15 +15,9 @@ exports.up = async Parse => { * @param {Parse} Parse */ exports.down = async Parse => { - // TODO: set className here const className = 'contracts_Template'; const schema = new Parse.Schema(className); schema.deleteField('PublicRole'); schema.deleteField('IsPublic'); - - // TODO: Set the schema here - // Example: - // schema.deleteField('name').deleteField('cash'); - return schema.update(); }; diff --git a/apps/OpenSignServer/databases/migrations/20240701151539-update_contracts_users_cls_cjs.cjs b/apps/OpenSignServer/databases/migrations/20240701151539-update_contracts_users_cls_cjs.cjs index e2db7dafc..eed3f4738 100644 --- a/apps/OpenSignServer/databases/migrations/20240701151539-update_contracts_users_cls_cjs.cjs +++ b/apps/OpenSignServer/databases/migrations/20240701151539-update_contracts_users_cls_cjs.cjs @@ -3,16 +3,11 @@ * @param {Parse} Parse */ exports.up = async Parse => { - // TODO: set className here const className = 'contracts_Users'; const schema = new Parse.Schema(className); schema.addString('UserName'); schema.addString('Tagline'); schema.addBoolean('SearchIndex'); - // TODO: Set the schema here - // Example: - // schema.addString('name').addNumber('cash'); - return schema.update(); }; @@ -21,15 +16,10 @@ exports.up = async Parse => { * @param {Parse} Parse */ exports.down = async Parse => { - // TODO: set className here const className = 'contracts_Users'; const schema = new Parse.Schema(className); schema.deleteField('UserName'); schema.deleteField('Tagline'); schema.deleteField('SearchIndex'); - // TODO: Set the schema here - // Example: - // schema.deleteField('name').deleteField('cash'); - return schema.update(); }; diff --git a/apps/OpenSignServer/databases/migrations/20240726114557-update_contracts_template_cjs.cjs b/apps/OpenSignServer/databases/migrations/20240726114557-update_contracts_template_cjs.cjs index dbbf88a3b..991b9ce58 100644 --- a/apps/OpenSignServer/databases/migrations/20240726114557-update_contracts_template_cjs.cjs +++ b/apps/OpenSignServer/databases/migrations/20240726114557-update_contracts_template_cjs.cjs @@ -2,16 +2,10 @@ * * @param {Parse} Parse */ -exports.up = async (Parse) => { - // TODO: set className here +exports.up = async Parse => { const className = 'contracts_Template'; const schema = new Parse.Schema(className); schema.addString('OriginIp'); - - // TODO: Set the schema here - // Example: - // schema.addString('name').addNumber('cash'); - return schema.update(); }; @@ -19,14 +13,9 @@ exports.up = async (Parse) => { * * @param {Parse} Parse */ -exports.down = async (Parse) => { - // TODO: set className here +exports.down = async Parse => { const className = 'contracts_Template'; const schema = new Parse.Schema(className); schema.deleteField('OriginIp'); - // TODO: Set the schema here - // Example: - // schema.deleteField('name').deleteField('cash'); - return schema.update(); }; diff --git a/apps/OpenSignServer/databases/migrations/20240806141611-update_contracts_users_cjs.cjs b/apps/OpenSignServer/databases/migrations/20240806141611-update_contracts_users_cjs.cjs index e0a2b0a36..ad549ded0 100644 --- a/apps/OpenSignServer/databases/migrations/20240806141611-update_contracts_users_cjs.cjs +++ b/apps/OpenSignServer/databases/migrations/20240806141611-update_contracts_users_cjs.cjs @@ -3,14 +3,9 @@ * @param {Parse} Parse */ exports.up = async Parse => { - // TODO: set className here const className = 'contracts_Users'; const schema = new Parse.Schema(className); schema.addString('Language'); - // TODO: Set the schema here - // Example: - // schema.addString('name').addNumber('cash'); - return schema.update(); }; @@ -19,13 +14,8 @@ exports.up = async Parse => { * @param {Parse} Parse */ exports.down = async Parse => { - // TODO: set className here const className = 'contracts_Users'; const schema = new Parse.Schema(className); schema.deleteField('Language'); - // TODO: Set the schema here - // Example: - // schema.deleteField('name').deleteField('cash'); - return schema.update(); }; diff --git a/apps/OpenSignServer/databases/migrations/20240903170628-update_contracts_document_cls_cjs.cjs b/apps/OpenSignServer/databases/migrations/20240903170628-update_contracts_document_cls_cjs.cjs index 74adeda91..17c73a987 100644 --- a/apps/OpenSignServer/databases/migrations/20240903170628-update_contracts_document_cls_cjs.cjs +++ b/apps/OpenSignServer/databases/migrations/20240903170628-update_contracts_document_cls_cjs.cjs @@ -3,14 +3,9 @@ * @param {Parse} Parse */ exports.up = async Parse => { - // TODO: set className here const className = 'contracts_Document'; const schema = new Parse.Schema(className); schema.addPointer('DeclineBy', '_User'); - // TODO: Set the schema here - // Example: - // schema.addString('name').addNumber('cash'); - return schema.update(); }; @@ -19,13 +14,8 @@ exports.up = async Parse => { * @param {Parse} Parse */ exports.down = async Parse => { - // TODO: set className here const className = 'contracts_Document'; const schema = new Parse.Schema(className); schema.deleteField('DeclineBy'); - // TODO: Set the schema here - // Example: - // schema.deleteField('name').deleteField('cash'); - return schema.update(); }; diff --git a/apps/OpenSignServer/databases/migrations/20241205115937-add_bcc_field_cjs.cjs b/apps/OpenSignServer/databases/migrations/20241205115937-add_bcc_field_cjs.cjs new file mode 100644 index 000000000..226aed619 --- /dev/null +++ b/apps/OpenSignServer/databases/migrations/20241205115937-add_bcc_field_cjs.cjs @@ -0,0 +1,28 @@ +/** + * + * @param {Parse} Parse + */ +exports.up = async Parse => { + const docSchema = new Parse.Schema('contracts_Document'); + docSchema.addArray('Bcc'); + await docSchema.update(); + + const templateSchema = new Parse.Schema('contracts_Template'); + templateSchema.addArray('Bcc'); + await templateSchema.update(); + +}; + +/** + * + * @param {Parse} Parse + */ +exports.down = async Parse => { + const docSchema = new Parse.Schema('contracts_Document'); + docSchema.deleteField('Bcc'); + await docSchema.update(); + + const templateSchema = new Parse.Schema('contracts_Template'); + templateSchema.deleteField('Bcc'); + await templateSchema.update(); +}; diff --git a/apps/OpenSignServer/databases/migrations/20241205163817-add_redirecturl_field_cjs.cjs b/apps/OpenSignServer/databases/migrations/20241205163817-add_redirecturl_field_cjs.cjs new file mode 100644 index 000000000..21bc6b2d0 --- /dev/null +++ b/apps/OpenSignServer/databases/migrations/20241205163817-add_redirecturl_field_cjs.cjs @@ -0,0 +1,28 @@ +/** + * + * @param {Parse} Parse + */ +exports.up = async Parse => { + const docSchema = new Parse.Schema('contracts_Document'); + docSchema.addString('RedirectUrl'); + await docSchema.update(); + + const templateSchema = new Parse.Schema('contracts_Template'); + templateSchema.addString('RedirectUrl'); + await templateSchema.update(); + +}; + +/** + * + * @param {Parse} Parse + */ +exports.down = async Parse => { + const docSchema = new Parse.Schema('contracts_Document'); + docSchema.deleteField('RedirectUrl'); + await docSchema.update(); + + const templateSchema = new Parse.Schema('contracts_Template'); + templateSchema.deleteField('RedirectUrl'); + await templateSchema.update(); +}; diff --git a/apps/OpenSignServer/databases/migrations/20241227112339-update_contracts_document_cls_cjs.cjs b/apps/OpenSignServer/databases/migrations/20241227112339-update_contracts_document_cls_cjs.cjs new file mode 100644 index 000000000..5b176f7ef --- /dev/null +++ b/apps/OpenSignServer/databases/migrations/20241227112339-update_contracts_document_cls_cjs.cjs @@ -0,0 +1,21 @@ +/** + * + * @param {Parse} Parse + */ +exports.up = async Parse => { + const className = 'contracts_Document'; + const schema = new Parse.Schema(className); + schema.addBoolean('AllowModifications'); + return schema.update(); +}; + +/** + * + * @param {Parse} Parse + */ +exports.down = async Parse => { + const className = 'contracts_Document'; + const schema = new Parse.Schema(className); + schema.deleteField('AllowModifications'); + return schema.update(); +}; diff --git a/apps/OpenSignServer/databases/migrations/20241227125916-update_contracts_template_cls_cjs.cjs b/apps/OpenSignServer/databases/migrations/20241227125916-update_contracts_template_cls_cjs.cjs new file mode 100644 index 000000000..cc7972a14 --- /dev/null +++ b/apps/OpenSignServer/databases/migrations/20241227125916-update_contracts_template_cls_cjs.cjs @@ -0,0 +1,21 @@ +/** + * + * @param {Parse} Parse + */ +exports.up = async Parse => { + const className = 'contracts_Template'; + const schema = new Parse.Schema(className); + schema.addBoolean('AllowModifications'); + return schema.update(); +}; + +/** + * + * @param {Parse} Parse + */ +exports.down = async Parse => { + const className = 'contracts_Template'; + const schema = new Parse.Schema(className); + schema.deleteField('AllowModifications'); + return schema.update(); +}; diff --git a/apps/OpenSignServer/index.js b/apps/OpenSignServer/index.js index 9109bf9e1..ce4105cd4 100644 --- a/apps/OpenSignServer/index.js +++ b/apps/OpenSignServer/index.js @@ -15,11 +15,14 @@ import AWS from 'aws-sdk'; import { app as customRoute } from './cloud/customRoute/customApp.js'; import { exec } from 'child_process'; import { createTransport } from 'nodemailer'; -import { app as v1 } from './cloud/customRoute/v1/apiV1.js'; import { PostHog } from 'posthog-node'; import { appName, cloudServerUrl, smtpenable, smtpsecure, useLocal } from './Utils.js'; import { SSOAuth } from './auth/authadapter.js'; +import createContactIndex from './migrationdb/createContactIndex.js'; +import { validateSignedLocalUrl } from './cloud/parsefunction/getSignedUrl.js'; +import maintenance_mode_message from 'aws-sdk/lib/maintenance_mode_message.js'; let fsAdapter; +maintenance_mode_message.suppress = true; if (useLocal !== 'true') { try { const spacesEndpoint = new AWS.Endpoint(process.env.DO_ENDPOINT); @@ -33,8 +36,10 @@ if (useLocal !== 'true') { presignedUrl: true, presignedUrlExpires: 900, s3overrides: { - accessKeyId: process.env.DO_ACCESS_KEY_ID, - secretAccessKey: process.env.DO_SECRET_ACCESS_KEY, + credentials: { + accessKeyId: process.env.DO_ACCESS_KEY_ID, + secretAccessKey: process.env.DO_SECRET_ACCESS_KEY, + }, endpoint: spacesEndpoint, }, }; @@ -178,6 +183,28 @@ app.use(function (req, res, next) { } next(); }); + +app.use(async function (req, res, next) { + const isFilePath = req.path.includes('files') || false; + if (isFilePath && req.method.toLowerCase() === 'get') { + const serverUrl = new URL(process.env.SERVER_URL); + const origin = serverUrl.pathname === '/api/app' ? serverUrl.origin + '/api' : serverUrl.origin; + const fileUrl = origin + req.originalUrl; + const params = fileUrl?.split('?')?.[1]; + if (params) { + const fileRes = await validateSignedLocalUrl(fileUrl); + if (fileRes === 'Unauthorized') { + return res.status(400).json({ message: 'unauthorized' }); + } + } else { + return res.status(400).json({ message: 'unauthorized' }); + } + next(); + } else { + next(); + } +}); + // Serve static assets from the /public folder app.use('/public', express.static(path.join(__dirname, '/public'))); @@ -190,13 +217,12 @@ if (!process.env.TESTING) { app.use(mountPath, server.app); } catch (err) { console.log(err); + process.exit(); } } // Mount your custom express app app.use('/', customRoute); -// Mount v1 -app.use('/v1', v1); // Parse Server plays nicely with the rest of your web routes app.get('/', function (req, res) { @@ -227,6 +253,7 @@ if (!process.env.TESTING) { console.error(`Error: ${stderr}`); return; } + createContactIndex(); console.log(`Command output: ${stdout}`); }); }); diff --git a/apps/OpenSignServer/migrationdb/createContactIndex.js b/apps/OpenSignServer/migrationdb/createContactIndex.js new file mode 100644 index 000000000..2c199ebdb --- /dev/null +++ b/apps/OpenSignServer/migrationdb/createContactIndex.js @@ -0,0 +1,71 @@ +import dotenv from 'dotenv'; +import { MongoClient } from 'mongodb'; +import { generateId } from '../Utils.js'; +dotenv.config(); + +export default async function createContactIndex() { + // Provide the complete MongoDB connection URL with the database name + const uri = process.env.MONGODB_URI || 'mongodb://localhost:27017/dev'; // Replace with your MongoDB URI + const client = new MongoClient(uri); + try { + await client.connect(); + const database = client.db(); + + const migrationCollection = database.collection('Migrationdb'); + const migrationName = 'contactIndex_1'; + + // Check if the migration has already been executed + const migrationExists = await migrationCollection.findOne({ name: migrationName }); + + if (migrationExists) { + console.log(' INFO No migrations were executed, database schema was already up to date.'); + console.log(' SUCCESS Successfully ran indexed migrations directly on db.'); + return; + } + + const collection = database.collection('contracts_Contactbook'); + + // Create the unique index, but only on documents where IsImported is true + const query = { + IsImported: { $eq: true }, + $or: [{ IsDeleted: false }, { IsDeleted: { $eq: false } }], + }; // Include documents with IsImported: true and IsDeleted not true + await collection.createIndex( + { _p_CreatedBy: 1, Email: 1, IsImported: 1 }, + { unique: true, partialFilterExpression: query } + ); + + // Save the migration record in the migrationdb collection + await migrationCollection.insertOne({ + _id: generateId(10), + name: migrationName, + _created_at: new Date(), + _updated_at: new Date(), + executedAt: new Date(), + details: 'Created unique index on CreatedBy, IsImported, Email', + }); + + const migrationdb = database.collection('_SCHEMA'); + // create migrationdb SCHEM migrationdb + + // Document to be inserted + const schemaDocument = { + _id: 'Migrationdb', + objectId: 'string', + name: 'string', + updatedAt: 'date', + createdAt: 'date', + executedAt: 'date', + details: 'string', + }; + + // Insert the document + await migrationdb.insertOne(schemaDocument); + console.log(' Unique index created successfully.'); + console.log(' SUCCESS Successfully ran indexed migrations directly on db.'); + } catch (error) { + console.log(' ERROR running indexed migration:', error); + } finally { + await client.close(); + } +} diff --git a/apps/OpenSignServer/package-lock.json b/apps/OpenSignServer/package-lock.json index bebf20cc9..8c0672e8c 100644 --- a/apps/OpenSignServer/package-lock.json +++ b/apps/OpenSignServer/package-lock.json @@ -9,10 +9,10 @@ "version": "1.4.0", "license": "MIT", "dependencies": { - "@aws-sdk/client-s3": "^3.699.0", - "@aws-sdk/s3-request-presigner": "^3.700.0", + "@aws-sdk/client-s3": "^3.741.0", + "@aws-sdk/s3-request-presigner": "^3.741.0", "@parse/fs-files-adapter": "^3.0.0", - "@parse/s3-files-adapter": "^3.0.0", + "@parse/s3-files-adapter": "^4.1.0", "@pdf-lib/fontkit": "^1.1.1", "@signpdf/placeholder-pdf-lib": "^3.2.4", "@signpdf/signer-p12": "^3.2.4", @@ -20,33 +20,34 @@ "aws-sdk": "^2.1692.0", "axios": "^1.7.9", "cors": "^2.8.5", - "dotenv": "^16.4.5", + "date-fns-tz": "^3.2.0", + "dotenv": "^16.4.7", "express": "^4.21.1", "form-data": "^4.0.1", "generate-api-key": "^1.0.2", "googleapis": "^144.0.0", - "mailgun.js": "^10.2.3", - "mongoose": "^8.8.4", + "mailgun.js": "^11.1.0", + "mongodb": "^6.13.0", "multer": "^1.4.5-lts.1", "multer-s3": "^3.0.1", "node-forge": "^1.3.1", - "nodemailer": "^6.9.16", + "nodemailer": "^6.10.0", "parse": "^5.3.0", "parse-dbtool": "^1.2.0", - "parse-server": "^7.3.0", + "parse-server": "^7.4.0", "parse-server-api-mail-adapter": "^4.1.0", "pdf-lib": "^1.17.1", - "posthog-node": "^4.2.3", + "posthog-node": "^4.5.0", "ws": "^8.18.0" }, "devDependencies": { - "@babel/eslint-parser": "^7.25.9", - "eslint": "^9.14.0", - "jasmine": "^5.4.0", + "@babel/eslint-parser": "^7.26.5", + "eslint": "^9.20.0", + "jasmine": "^5.6.0", "mongodb-runner": "^5.7.1", - "nodemon": "^3.1.7", + "nodemon": "^3.1.9", "nyc": "^17.1.0", - "prettier": "^3.3.3" + "prettier": "^3.5.0" }, "engines": { "node": "18 || 20 || 22" @@ -97,9 +98,9 @@ } }, "node_modules/@apollo/server": { - "version": "4.10.5", - "resolved": "https://registry.npmjs.org/@apollo/server/-/server-4.10.5.tgz", - "integrity": "sha512-I+Oi1CnphXExSAAsZbclgRDN4k4CEMxyKRzYg3bir5N8OmydEhzXDlIGAOETP/TKblxR7HPXGvwn2cJKzbl46w==", + "version": "4.11.2", + "resolved": "https://registry.npmjs.org/@apollo/server/-/server-4.11.2.tgz", + "integrity": "sha512-WUTHY7DDek8xAMn4Woa9Bl8duQUDzRYQkosX/d1DtCsBWESZyApR7ndnI5d6+W4KSTtqBHhJFkusEI7CWuIJXg==", "dependencies": { "@apollo/cache-control-types": "^1.0.3", "@apollo/server-gateway-interface": "^1.1.1", @@ -117,7 +118,7 @@ "@types/node-fetch": "^2.6.1", "async-retry": "^1.2.1", "cors": "^2.8.5", - "express": "^4.17.1", + "express": "^4.21.1", "loglevel": "^1.6.8", "lru-cache": "^7.10.1", "negotiator": "^0.6.3", @@ -529,163 +530,492 @@ } }, "node_modules/@aws-sdk/client-s3": { - "version": "3.699.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.699.0.tgz", - "integrity": "sha512-x3wV9e6d0esA6Yyg3xWJucMYd/O8JVrNCJnGm/sz3lMYOQGefpVZKZZsHcnzQcTEVAQMF/T5/cdfdvPzIx/esA==", + "version": "3.741.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.741.0.tgz", + "integrity": "sha512-sZvdbRZ+E9/GcOMUOkZvYvob95N6c9LdzDneXHFASA7OIaEOQxQT1Arimz7JpEhfq/h9K2/j7wNO4jh4x80bmA==", + "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha1-browser": "5.2.0", "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.699.0", - "@aws-sdk/client-sts": "3.699.0", - "@aws-sdk/core": "3.696.0", - "@aws-sdk/credential-provider-node": "3.699.0", - "@aws-sdk/middleware-bucket-endpoint": "3.696.0", - "@aws-sdk/middleware-expect-continue": "3.696.0", - "@aws-sdk/middleware-flexible-checksums": "3.697.0", - "@aws-sdk/middleware-host-header": "3.696.0", - "@aws-sdk/middleware-location-constraint": "3.696.0", - "@aws-sdk/middleware-logger": "3.696.0", - "@aws-sdk/middleware-recursion-detection": "3.696.0", - "@aws-sdk/middleware-sdk-s3": "3.696.0", - "@aws-sdk/middleware-ssec": "3.696.0", - "@aws-sdk/middleware-user-agent": "3.696.0", - "@aws-sdk/region-config-resolver": "3.696.0", - "@aws-sdk/signature-v4-multi-region": "3.696.0", - "@aws-sdk/types": "3.696.0", - "@aws-sdk/util-endpoints": "3.696.0", - "@aws-sdk/util-user-agent-browser": "3.696.0", - "@aws-sdk/util-user-agent-node": "3.696.0", - "@aws-sdk/xml-builder": "3.696.0", - "@smithy/config-resolver": "^3.0.12", - "@smithy/core": "^2.5.3", - "@smithy/eventstream-serde-browser": "^3.0.13", - "@smithy/eventstream-serde-config-resolver": "^3.0.10", - "@smithy/eventstream-serde-node": "^3.0.12", - "@smithy/fetch-http-handler": "^4.1.1", - "@smithy/hash-blob-browser": "^3.1.9", - "@smithy/hash-node": "^3.0.10", - "@smithy/hash-stream-node": "^3.1.9", - "@smithy/invalid-dependency": "^3.0.10", - "@smithy/md5-js": "^3.0.10", - "@smithy/middleware-content-length": "^3.0.12", - "@smithy/middleware-endpoint": "^3.2.3", - "@smithy/middleware-retry": "^3.0.27", - "@smithy/middleware-serde": "^3.0.10", - "@smithy/middleware-stack": "^3.0.10", - "@smithy/node-config-provider": "^3.1.11", - "@smithy/node-http-handler": "^3.3.1", - "@smithy/protocol-http": "^4.1.7", - "@smithy/smithy-client": "^3.4.4", - "@smithy/types": "^3.7.1", - "@smithy/url-parser": "^3.0.10", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.27", - "@smithy/util-defaults-mode-node": "^3.0.27", - "@smithy/util-endpoints": "^2.1.6", - "@smithy/util-middleware": "^3.0.10", - "@smithy/util-retry": "^3.0.10", - "@smithy/util-stream": "^3.3.1", - "@smithy/util-utf8": "^3.0.0", - "@smithy/util-waiter": "^3.1.9", + "@aws-sdk/core": "3.734.0", + "@aws-sdk/credential-provider-node": "3.741.0", + "@aws-sdk/middleware-bucket-endpoint": "3.734.0", + "@aws-sdk/middleware-expect-continue": "3.734.0", + "@aws-sdk/middleware-flexible-checksums": "3.735.0", + "@aws-sdk/middleware-host-header": "3.734.0", + "@aws-sdk/middleware-location-constraint": "3.734.0", + "@aws-sdk/middleware-logger": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.734.0", + "@aws-sdk/middleware-sdk-s3": "3.740.0", + "@aws-sdk/middleware-ssec": "3.734.0", + "@aws-sdk/middleware-user-agent": "3.734.0", + "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/signature-v4-multi-region": "3.740.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.734.0", + "@aws-sdk/util-user-agent-browser": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.734.0", + "@aws-sdk/xml-builder": "3.734.0", + "@smithy/config-resolver": "^4.0.1", + "@smithy/core": "^3.1.1", + "@smithy/eventstream-serde-browser": "^4.0.1", + "@smithy/eventstream-serde-config-resolver": "^4.0.1", + "@smithy/eventstream-serde-node": "^4.0.1", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/hash-blob-browser": "^4.0.1", + "@smithy/hash-node": "^4.0.1", + "@smithy/hash-stream-node": "^4.0.1", + "@smithy/invalid-dependency": "^4.0.1", + "@smithy/md5-js": "^4.0.1", + "@smithy/middleware-content-length": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.2", + "@smithy/middleware-retry": "^4.0.3", + "@smithy/middleware-serde": "^4.0.1", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/node-http-handler": "^4.0.2", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.2", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.3", + "@smithy/util-defaults-mode-node": "^4.0.3", + "@smithy/util-endpoints": "^3.0.1", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "@smithy/util-stream": "^4.0.2", + "@smithy/util-utf8": "^4.0.0", + "@smithy/util-waiter": "^4.0.2", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@smithy/abort-controller": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.1.tgz", + "integrity": "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@smithy/core": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.1.2.tgz", + "integrity": "sha512-htwQXkbdF13uwwDevz9BEzL5ABK+1sJpVQXywwGSH973AVOvisHNfpcB8A8761G6XgHoS2kHPqc9DqHJ2gp+/Q==", + "dependencies": { + "@smithy/middleware-serde": "^4.0.2", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-stream": "^4.0.2", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@smithy/fetch-http-handler": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.0.1.tgz", + "integrity": "sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA==", + "dependencies": { + "@smithy/protocol-http": "^5.0.1", + "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-base64": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@smithy/is-array-buffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.0.0.tgz", + "integrity": "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@smithy/middleware-endpoint": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.0.3.tgz", + "integrity": "sha512-YdbmWhQF5kIxZjWqPIgboVfi8i5XgiYMM7GGKFMTvBei4XjNQfNv8sukT50ITvgnWKKKpOtp0C0h7qixLgb77Q==", + "dependencies": { + "@smithy/core": "^3.1.2", + "@smithy/middleware-serde": "^4.0.2", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-middleware": "^4.0.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@smithy/middleware-serde": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.0.2.tgz", + "integrity": "sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@smithy/middleware-stack": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.0.1.tgz", + "integrity": "sha512-dHwDmrtR/ln8UTHpaIavRSzeIk5+YZTBtLnKwDW3G2t6nAupCiQUvNzNoHBpik63fwUaJPtlnMzXbQrNFWssIA==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@smithy/node-config-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.0.1.tgz", + "integrity": "sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ==", + "dependencies": { + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@smithy/node-http-handler": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.2.tgz", + "integrity": "sha512-X66H9aah9hisLLSnGuzRYba6vckuFtGE+a5DcHLliI/YlqKrGoxhisD5XbX44KyoeRzoNlGr94eTsMVHFAzPOw==", + "dependencies": { + "@smithy/abort-controller": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@smithy/property-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.1.tgz", + "integrity": "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@smithy/protocol-http": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.0.1.tgz", + "integrity": "sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@smithy/querystring-builder": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.0.1.tgz", + "integrity": "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg==", + "dependencies": { + "@smithy/types": "^4.1.0", + "@smithy/util-uri-escape": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@smithy/querystring-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.0.1.tgz", + "integrity": "sha512-Ma2XC7VS9aV77+clSFylVUnPZRindhB7BbmYiNOdr+CHt/kZNJoPP0cd3QxCnCFyPXC4eybmyE98phEHkqZ5Jw==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@smithy/shared-ini-file-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.1.tgz", + "integrity": "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@smithy/smithy-client": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.1.3.tgz", + "integrity": "sha512-A2Hz85pu8BJJaYFdX8yb1yocqigyqBzn+OVaVgm+Kwi/DkN8vhN2kbDVEfADo6jXf5hPKquMLGA3UINA64UZ7A==", + "dependencies": { + "@smithy/core": "^3.1.2", + "@smithy/middleware-endpoint": "^4.0.3", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-stream": "^4.0.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@smithy/url-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.0.1.tgz", + "integrity": "sha512-gPXcIEUtw7VlK8f/QcruNXm7q+T5hhvGu9tl63LsJPZ27exB6dtNwvh2HIi0v7JcXJ5emBxB+CJxwaLEdJfA+g==", + "dependencies": { + "@smithy/querystring-parser": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@smithy/util-base64": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.0.0.tgz", + "integrity": "sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@smithy/util-body-length-browser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.0.0.tgz", + "integrity": "sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@smithy/util-buffer-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.0.0.tgz", + "integrity": "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==", + "dependencies": { + "@smithy/is-array-buffer": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@smithy/util-hex-encoding": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.0.0.tgz", + "integrity": "sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@smithy/util-middleware": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.0.1.tgz", + "integrity": "sha512-HiLAvlcqhbzhuiOa0Lyct5IIlyIz0PQO5dnMlmQ/ubYM46dPInB+3yQGkfxsk6Q24Y0n3/JmcA1v5iEhmOF5mA==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@smithy/util-stream": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.0.2.tgz", + "integrity": "sha512-0eZ4G5fRzIoewtHtwaYyl8g2C+osYOT4KClXgfdNEDAgkbe2TYPqcnw4GAWabqkZCax2ihRGPe9LZnsPdIUIHA==", + "dependencies": { + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/node-http-handler": "^4.0.2", + "@smithy/types": "^4.1.0", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-hex-encoding": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@smithy/util-uri-escape": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.0.0.tgz", + "integrity": "sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@smithy/util-utf8": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", + "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@aws-sdk/client-sso": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.696.0.tgz", - "integrity": "sha512-q5TTkd08JS0DOkHfUL853tuArf7NrPeqoS5UOvqJho8ibV9Ak/a/HO4kNvy9Nj3cib/toHYHsQIEtecUPSUUrQ==", + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.734.0.tgz", + "integrity": "sha512-oerepp0mut9VlgTwnG5Ds/lb0C0b2/rQ+hL/rF6q+HGKPfGsCuPvFx1GtwGKCXd49ase88/jVgrhcA9OQbz3kg==", + "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.696.0", - "@aws-sdk/middleware-host-header": "3.696.0", - "@aws-sdk/middleware-logger": "3.696.0", - "@aws-sdk/middleware-recursion-detection": "3.696.0", - "@aws-sdk/middleware-user-agent": "3.696.0", - "@aws-sdk/region-config-resolver": "3.696.0", - "@aws-sdk/types": "3.696.0", - "@aws-sdk/util-endpoints": "3.696.0", - "@aws-sdk/util-user-agent-browser": "3.696.0", - "@aws-sdk/util-user-agent-node": "3.696.0", - "@smithy/config-resolver": "^3.0.12", - "@smithy/core": "^2.5.3", - "@smithy/fetch-http-handler": "^4.1.1", - "@smithy/hash-node": "^3.0.10", - "@smithy/invalid-dependency": "^3.0.10", - "@smithy/middleware-content-length": "^3.0.12", - "@smithy/middleware-endpoint": "^3.2.3", - "@smithy/middleware-retry": "^3.0.27", - "@smithy/middleware-serde": "^3.0.10", - "@smithy/middleware-stack": "^3.0.10", - "@smithy/node-config-provider": "^3.1.11", - "@smithy/node-http-handler": "^3.3.1", - "@smithy/protocol-http": "^4.1.7", - "@smithy/smithy-client": "^3.4.4", - "@smithy/types": "^3.7.1", - "@smithy/url-parser": "^3.0.10", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.27", - "@smithy/util-defaults-mode-node": "^3.0.27", - "@smithy/util-endpoints": "^2.1.6", - "@smithy/util-middleware": "^3.0.10", - "@smithy/util-retry": "^3.0.10", - "@smithy/util-utf8": "^3.0.0", + "@aws-sdk/core": "3.734.0", + "@aws-sdk/middleware-host-header": "3.734.0", + "@aws-sdk/middleware-logger": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.734.0", + "@aws-sdk/middleware-user-agent": "3.734.0", + "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.734.0", + "@aws-sdk/util-user-agent-browser": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.734.0", + "@smithy/config-resolver": "^4.0.1", + "@smithy/core": "^3.1.1", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/hash-node": "^4.0.1", + "@smithy/invalid-dependency": "^4.0.1", + "@smithy/middleware-content-length": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.2", + "@smithy/middleware-retry": "^4.0.3", + "@smithy/middleware-serde": "^4.0.1", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/node-http-handler": "^4.0.2", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.2", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.3", + "@smithy/util-defaults-mode-node": "^4.0.3", + "@smithy/util-endpoints": "^3.0.1", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, "node_modules/@aws-sdk/client-sso-oidc": { - "version": "3.699.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.699.0.tgz", - "integrity": "sha512-u8a1GorY5D1l+4FQAf4XBUC1T10/t7neuwT21r0ymrtMFSK2a9QqVHKMoLkvavAwyhJnARSBM9/UQC797PFOFw==", + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.709.0.tgz", + "integrity": "sha512-1w6egz17QQy661lNCRmZZlqIANEbD6g2VFAQIJbVwSiu7brg+GUns+mT1eLLLHAMQc1sL0Ds8/ybSK2SrgGgIA==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.696.0", - "@aws-sdk/credential-provider-node": "3.699.0", - "@aws-sdk/middleware-host-header": "3.696.0", - "@aws-sdk/middleware-logger": "3.696.0", - "@aws-sdk/middleware-recursion-detection": "3.696.0", - "@aws-sdk/middleware-user-agent": "3.696.0", - "@aws-sdk/region-config-resolver": "3.696.0", - "@aws-sdk/types": "3.696.0", - "@aws-sdk/util-endpoints": "3.696.0", - "@aws-sdk/util-user-agent-browser": "3.696.0", - "@aws-sdk/util-user-agent-node": "3.696.0", - "@smithy/config-resolver": "^3.0.12", - "@smithy/core": "^2.5.3", - "@smithy/fetch-http-handler": "^4.1.1", - "@smithy/hash-node": "^3.0.10", - "@smithy/invalid-dependency": "^3.0.10", - "@smithy/middleware-content-length": "^3.0.12", - "@smithy/middleware-endpoint": "^3.2.3", - "@smithy/middleware-retry": "^3.0.27", - "@smithy/middleware-serde": "^3.0.10", - "@smithy/middleware-stack": "^3.0.10", - "@smithy/node-config-provider": "^3.1.11", - "@smithy/node-http-handler": "^3.3.1", - "@smithy/protocol-http": "^4.1.7", - "@smithy/smithy-client": "^3.4.4", - "@smithy/types": "^3.7.1", - "@smithy/url-parser": "^3.0.10", + "@aws-sdk/core": "3.709.0", + "@aws-sdk/credential-provider-node": "3.709.0", + "@aws-sdk/middleware-host-header": "3.709.0", + "@aws-sdk/middleware-logger": "3.709.0", + "@aws-sdk/middleware-recursion-detection": "3.709.0", + "@aws-sdk/middleware-user-agent": "3.709.0", + "@aws-sdk/region-config-resolver": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@aws-sdk/util-endpoints": "3.709.0", + "@aws-sdk/util-user-agent-browser": "3.709.0", + "@aws-sdk/util-user-agent-node": "3.709.0", + "@smithy/config-resolver": "^3.0.13", + "@smithy/core": "^2.5.5", + "@smithy/fetch-http-handler": "^4.1.2", + "@smithy/hash-node": "^3.0.11", + "@smithy/invalid-dependency": "^3.0.11", + "@smithy/middleware-content-length": "^3.0.13", + "@smithy/middleware-endpoint": "^3.2.5", + "@smithy/middleware-retry": "^3.0.30", + "@smithy/middleware-serde": "^3.0.11", + "@smithy/middleware-stack": "^3.0.11", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/node-http-handler": "^3.3.2", + "@smithy/protocol-http": "^4.1.8", + "@smithy/smithy-client": "^3.5.0", + "@smithy/types": "^3.7.2", + "@smithy/url-parser": "^3.0.11", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.27", - "@smithy/util-defaults-mode-node": "^3.0.27", - "@smithy/util-endpoints": "^2.1.6", - "@smithy/util-middleware": "^3.0.10", - "@smithy/util-retry": "^3.0.10", + "@smithy/util-defaults-mode-browser": "^3.0.30", + "@smithy/util-defaults-mode-node": "^3.0.30", + "@smithy/util-endpoints": "^2.1.7", + "@smithy/util-middleware": "^3.0.11", + "@smithy/util-retry": "^3.0.11", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, @@ -693,52 +1023,50 @@ "node": ">=16.0.0" }, "peerDependencies": { - "@aws-sdk/client-sts": "^3.699.0" + "@aws-sdk/client-sts": "^3.709.0" } }, - "node_modules/@aws-sdk/client-sts": { - "version": "3.699.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.699.0.tgz", - "integrity": "sha512-++lsn4x2YXsZPIzFVwv3fSUVM55ZT0WRFmPeNilYIhZClxHLmVAWKH4I55cY9ry60/aTKYjzOXkWwyBKGsGvQg==", + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/client-sso": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.709.0.tgz", + "integrity": "sha512-Qxeo8cN0jNy6Wnbqq4wucffAGJM6sJjofoTgNtPA6cC7sPYx7aYC6OAAAo6NaMRY+WywOKdS9Wgjx2QYRxKx7w==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.699.0", - "@aws-sdk/core": "3.696.0", - "@aws-sdk/credential-provider-node": "3.699.0", - "@aws-sdk/middleware-host-header": "3.696.0", - "@aws-sdk/middleware-logger": "3.696.0", - "@aws-sdk/middleware-recursion-detection": "3.696.0", - "@aws-sdk/middleware-user-agent": "3.696.0", - "@aws-sdk/region-config-resolver": "3.696.0", - "@aws-sdk/types": "3.696.0", - "@aws-sdk/util-endpoints": "3.696.0", - "@aws-sdk/util-user-agent-browser": "3.696.0", - "@aws-sdk/util-user-agent-node": "3.696.0", - "@smithy/config-resolver": "^3.0.12", - "@smithy/core": "^2.5.3", - "@smithy/fetch-http-handler": "^4.1.1", - "@smithy/hash-node": "^3.0.10", - "@smithy/invalid-dependency": "^3.0.10", - "@smithy/middleware-content-length": "^3.0.12", - "@smithy/middleware-endpoint": "^3.2.3", - "@smithy/middleware-retry": "^3.0.27", - "@smithy/middleware-serde": "^3.0.10", - "@smithy/middleware-stack": "^3.0.10", - "@smithy/node-config-provider": "^3.1.11", - "@smithy/node-http-handler": "^3.3.1", - "@smithy/protocol-http": "^4.1.7", - "@smithy/smithy-client": "^3.4.4", - "@smithy/types": "^3.7.1", - "@smithy/url-parser": "^3.0.10", + "@aws-sdk/core": "3.709.0", + "@aws-sdk/middleware-host-header": "3.709.0", + "@aws-sdk/middleware-logger": "3.709.0", + "@aws-sdk/middleware-recursion-detection": "3.709.0", + "@aws-sdk/middleware-user-agent": "3.709.0", + "@aws-sdk/region-config-resolver": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@aws-sdk/util-endpoints": "3.709.0", + "@aws-sdk/util-user-agent-browser": "3.709.0", + "@aws-sdk/util-user-agent-node": "3.709.0", + "@smithy/config-resolver": "^3.0.13", + "@smithy/core": "^2.5.5", + "@smithy/fetch-http-handler": "^4.1.2", + "@smithy/hash-node": "^3.0.11", + "@smithy/invalid-dependency": "^3.0.11", + "@smithy/middleware-content-length": "^3.0.13", + "@smithy/middleware-endpoint": "^3.2.5", + "@smithy/middleware-retry": "^3.0.30", + "@smithy/middleware-serde": "^3.0.11", + "@smithy/middleware-stack": "^3.0.11", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/node-http-handler": "^3.3.2", + "@smithy/protocol-http": "^4.1.8", + "@smithy/smithy-client": "^3.5.0", + "@smithy/types": "^3.7.2", + "@smithy/url-parser": "^3.0.11", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.27", - "@smithy/util-defaults-mode-node": "^3.0.27", - "@smithy/util-endpoints": "^2.1.6", - "@smithy/util-middleware": "^3.0.10", - "@smithy/util-retry": "^3.0.10", + "@smithy/util-defaults-mode-browser": "^3.0.30", + "@smithy/util-defaults-mode-node": "^3.0.30", + "@smithy/util-endpoints": "^2.1.7", + "@smithy/util-middleware": "^3.0.11", + "@smithy/util-retry": "^3.0.11", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, @@ -746,21 +1074,20 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/core": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.696.0.tgz", - "integrity": "sha512-3c9III1k03DgvRZWg8vhVmfIXPG6hAciN9MzQTzqGngzWAELZF/WONRTRQuDFixVtarQatmLHYVw/atGeA2Byw==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/core": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.709.0.tgz", + "integrity": "sha512-7kuSpzdOTAE026j85wq/fN9UDZ70n0OHw81vFqMWwlEFtm5IQ/MRCLKcC4HkXxTdfy1PqFlmoXxWqeBa15tujw==", "dependencies": { - "@aws-sdk/types": "3.696.0", - "@smithy/core": "^2.5.3", - "@smithy/node-config-provider": "^3.1.11", - "@smithy/property-provider": "^3.1.9", - "@smithy/protocol-http": "^4.1.7", - "@smithy/signature-v4": "^4.2.2", - "@smithy/smithy-client": "^3.4.4", - "@smithy/types": "^3.7.1", - "@smithy/util-middleware": "^3.0.10", + "@aws-sdk/types": "3.709.0", + "@smithy/core": "^2.5.5", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/property-provider": "^3.1.11", + "@smithy/protocol-http": "^4.1.8", + "@smithy/signature-v4": "^4.2.4", + "@smithy/smithy-client": "^3.5.0", + "@smithy/types": "^3.7.2", + "@smithy/util-middleware": "^3.0.11", "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" }, @@ -768,138 +1095,2480 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.696.0.tgz", - "integrity": "sha512-T9iMFnJL7YTlESLpVFT3fg1Lkb1lD+oiaIC8KMpepb01gDUBIpj9+Y+pA/cgRWW0yRxmkDXNazAE2qQTVFGJzA==", + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/credential-provider-env": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.709.0.tgz", + "integrity": "sha512-ZMAp9LSikvHDFVa84dKpQmow6wsg956Um20cKuioPpX2GGreJFur7oduD+tRJT6FtIOHn+64YH+0MwiXLhsaIQ==", "dependencies": { - "@aws-sdk/core": "3.696.0", - "@aws-sdk/types": "3.696.0", - "@smithy/property-provider": "^3.1.9", - "@smithy/types": "^3.7.1", + "@aws-sdk/core": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@smithy/property-provider": "^3.1.11", + "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/credential-provider-http": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.709.0.tgz", + "integrity": "sha512-lIS7XLwCOyJnLD70f+VIRr8DNV1HPQe9oN6aguYrhoczqz7vDiVZLe3lh714cJqq9rdxzFypK5DqKHmcscMEPQ==", + "dependencies": { + "@aws-sdk/core": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@smithy/fetch-http-handler": "^4.1.2", + "@smithy/node-http-handler": "^3.3.2", + "@smithy/property-provider": "^3.1.11", + "@smithy/protocol-http": "^4.1.8", + "@smithy/smithy-client": "^3.5.0", + "@smithy/types": "^3.7.2", + "@smithy/util-stream": "^3.3.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.709.0.tgz", + "integrity": "sha512-qCF8IIGcPoUp+Ib3ANhbF5gElxFd+kIrtv2/1tKdvhudMANstQbMiWV0LTH47ZZR6c3as4iSrm09NZnpEoD/pA==", + "dependencies": { + "@aws-sdk/core": "3.709.0", + "@aws-sdk/credential-provider-env": "3.709.0", + "@aws-sdk/credential-provider-http": "3.709.0", + "@aws-sdk/credential-provider-process": "3.709.0", + "@aws-sdk/credential-provider-sso": "3.709.0", + "@aws-sdk/credential-provider-web-identity": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@smithy/credential-provider-imds": "^3.2.8", + "@smithy/property-provider": "^3.1.11", + "@smithy/shared-ini-file-loader": "^3.1.12", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.709.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.709.0.tgz", + "integrity": "sha512-4HRX9KYWPSjO5O/Vg03YAsebKpvTjTvpK1n7zHYBmlLMBLxUrVsL1nNKKC5p2/7OW3RL8XR1ki3QkoV7kGRxUQ==", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.709.0", + "@aws-sdk/credential-provider-http": "3.709.0", + "@aws-sdk/credential-provider-ini": "3.709.0", + "@aws-sdk/credential-provider-process": "3.709.0", + "@aws-sdk/credential-provider-sso": "3.709.0", + "@aws-sdk/credential-provider-web-identity": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@smithy/credential-provider-imds": "^3.2.8", + "@smithy/property-provider": "^3.1.11", + "@smithy/shared-ini-file-loader": "^3.1.12", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/credential-provider-process": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.709.0.tgz", + "integrity": "sha512-IAC+jPlGQII6jhIylHOwh3RgSobqlgL59nw2qYTURr8hMCI0Z1p5y2ee646HTVt4WeCYyzUAXfxr6YI/Vitv+Q==", + "dependencies": { + "@aws-sdk/core": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@smithy/property-provider": "^3.1.11", + "@smithy/shared-ini-file-loader": "^3.1.12", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.709.0.tgz", + "integrity": "sha512-rYdTDOxazS2GdGScelsRK5CAkktRLCCdRjlwXaxrcW57j749hEqxcF5uTv9RD6WBwInfedcSywErNZB+hylQlg==", + "dependencies": { + "@aws-sdk/client-sso": "3.709.0", + "@aws-sdk/core": "3.709.0", + "@aws-sdk/token-providers": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@smithy/property-provider": "^3.1.11", + "@smithy/shared-ini-file-loader": "^3.1.12", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.709.0.tgz", + "integrity": "sha512-2lbDfE0IQ6gma/7BB2JpkjW5G0wGe4AS0x80oybYAYYviJmUtIR3Cn2pXun6bnAWElt4wYKl4su7oC36rs5rNA==", + "dependencies": { + "@aws-sdk/core": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@smithy/property-provider": "^3.1.11", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.709.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/middleware-host-header": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.709.0.tgz", + "integrity": "sha512-8gQYCYAaIw4lOCd5WYdf15Y/61MgRsAnrb2eiTl+icMlUOOzl8aOl5iDwm/Idp0oHZTflwxM4XSvGXO83PRWcw==", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/middleware-logger": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.709.0.tgz", + "integrity": "sha512-jDoGSccXv9zebnpUoisjWd5u5ZPIalrmm6TjvPzZ8UqzQt3Beiz0tnQwmxQD6KRc7ADweWP5Ntiqzbw9xpVajg==", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.709.0.tgz", + "integrity": "sha512-PObL/wLr4lkfbQ0yXUWaoCWu/jcwfwZzCjsUiXW/H6hW9b/00enZxmx7OhtJYaR6xmh/Lcx5wbhIoDCbzdv0tw==", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.709.0.tgz", + "integrity": "sha512-ooc9ZJvgkjPhi9q05XwSfNTXkEBEIfL4hleo5rQBKwHG3aTHvwOM7LLzhdX56QZVa6sorPBp6fwULuRDSqiQHw==", + "dependencies": { + "@aws-sdk/core": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@aws-sdk/util-endpoints": "3.709.0", + "@smithy/core": "^2.5.5", + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/region-config-resolver": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.709.0.tgz", + "integrity": "sha512-/NoCAMEVKAg3kBKOrNtgOfL+ECt6nrl+L7q2SyYmrcY4tVCmwuECVqewQaHc03fTnJijfKLccw0Fj+6wOCnB6w==", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/types": "^3.7.2", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.11", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/token-providers": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.709.0.tgz", + "integrity": "sha512-q5Ar6k71nci43IbULFgC8a89d/3EHpmd7HvBzqVGRcHnoPwh8eZDBfbBXKH83NGwcS1qPSRYiDbVfeWPm4/1jA==", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@smithy/property-provider": "^3.1.11", + "@smithy/shared-ini-file-loader": "^3.1.12", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sso-oidc": "^3.709.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/types": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.709.0.tgz", + "integrity": "sha512-ArtLTMxgjf13Kfu3gWH3Ez9Q5TkDdcRZUofpKH3pMGB/C6KAbeSCtIIDKfoRTUABzyGlPyCrZdnFjKyH+ypIpg==", + "dependencies": { + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/util-endpoints": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.709.0.tgz", + "integrity": "sha512-Mbc7AtL5WGCTKC16IGeUTz+sjpC3ptBda2t0CcK0kMVw3THDdcSq6ZlNKO747cNqdbwUvW34oHteUiHv4/z88Q==", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@smithy/types": "^3.7.2", + "@smithy/util-endpoints": "^2.1.7", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.709.0.tgz", + "integrity": "sha512-/rL2GasJzdTWUURCQKFldw2wqBtY4k4kCiA2tVZSKg3y4Ey7zO34SW8ebaeCE2/xoWOyLR2/etdKyphoo4Zrtg==", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@smithy/types": "^3.7.2", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.709.0.tgz", + "integrity": "sha512-trBfzSCVWy7ILgqhEXgiuM7hfRCw4F4a8IK90tjk9YL0jgoJ6eJuOp7+DfCtHJaygoBxD3cdMFkOu+lluFmGBA==", + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/config-resolver": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.13.tgz", + "integrity": "sha512-Gr/qwzyPaTL1tZcq8WQyHhTZREER5R1Wytmz4WnVGL4onA3dNk6Btll55c8Vr58pLdvWZmtG8oZxJTw3t3q7Jg==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.12", + "@smithy/types": "^3.7.2", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.11", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/credential-provider-imds": { + "version": "3.2.8", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.2.8.tgz", + "integrity": "sha512-ZCY2yD0BY+K9iMXkkbnjo+08T2h8/34oHd0Jmh6BZUSZwaaGlGCyBT/3wnS7u7Xl33/EEfN4B6nQr3Gx5bYxgw==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.12", + "@smithy/property-provider": "^3.1.11", + "@smithy/types": "^3.7.2", + "@smithy/url-parser": "^3.0.11", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/hash-node": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.11.tgz", + "integrity": "sha512-emP23rwYyZhQBvklqTtwetkQlqbNYirDiEEwXl2v0GYWMnCzxst7ZaRAnWuy28njp5kAH54lvkdG37MblZzaHA==", + "dependencies": { + "@smithy/types": "^3.7.2", + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/invalid-dependency": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.11.tgz", + "integrity": "sha512-NuQmVPEJjUX6c+UELyVz8kUx8Q539EDeNwbRyu4IIF8MeV7hUtq1FB3SHVyki2u++5XLMFqngeMKk7ccspnNyQ==", + "dependencies": { + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/middleware-content-length": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.13.tgz", + "integrity": "sha512-zfMhzojhFpIX3P5ug7jxTjfUcIPcGjcQYzB9t+rv0g1TX7B0QdwONW+ATouaLoD7h7LOw/ZlXfkq4xJ/g2TrIw==", + "dependencies": { + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/middleware-retry": { + "version": "3.0.34", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.34.tgz", + "integrity": "sha512-yVRr/AAtPZlUvwEkrq7S3x7Z8/xCd97m2hLDaqdz6ucP2RKHsBjEqaUA2ebNv2SsZoPEi+ZD0dZbOB1u37tGCA==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.12", + "@smithy/protocol-http": "^4.1.8", + "@smithy/service-error-classification": "^3.0.11", + "@smithy/smithy-client": "^3.7.0", + "@smithy/types": "^3.7.2", + "@smithy/util-middleware": "^3.0.11", + "@smithy/util-retry": "^3.0.11", + "tslib": "^2.6.2", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/service-error-classification": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.11.tgz", + "integrity": "sha512-QnYDPkyewrJzCyaeI2Rmp7pDwbUETe+hU8ADkXmgNusO1bgHBH7ovXJiYmba8t0fNfJx75fE8dlM6SEmZxheog==", + "dependencies": { + "@smithy/types": "^3.7.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/signature-v4": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-4.2.4.tgz", + "integrity": "sha512-5JWeMQYg81TgU4cG+OexAWdvDTs5JDdbEZx+Qr1iPbvo91QFGzjy0IkXAKaXUHqmKUJgSHK0ZxnCkgZpzkeNTA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", + "@smithy/util-hex-encoding": "^3.0.0", + "@smithy/util-middleware": "^3.0.11", + "@smithy/util-uri-escape": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/util-body-length-node": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-3.0.0.tgz", + "integrity": "sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/util-config-provider": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-3.0.0.tgz", + "integrity": "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/util-defaults-mode-browser": { + "version": "3.0.34", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.34.tgz", + "integrity": "sha512-FumjjF631lR521cX+svMLBj3SwSDh9VdtyynTYDAiBDEf8YPP5xORNXKQ9j0105o5+ARAGnOOP/RqSl40uXddA==", + "dependencies": { + "@smithy/property-provider": "^3.1.11", + "@smithy/smithy-client": "^3.7.0", + "@smithy/types": "^3.7.2", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/util-defaults-mode-node": { + "version": "3.0.34", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.34.tgz", + "integrity": "sha512-vN6aHfzW9dVVzkI0wcZoUXvfjkl4CSbM9nE//08lmUMyf00S75uuCpTrqF9uD4bD9eldIXlt53colrlwKAT8Gw==", + "dependencies": { + "@smithy/config-resolver": "^3.0.13", + "@smithy/credential-provider-imds": "^3.2.8", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/property-provider": "^3.1.11", + "@smithy/smithy-client": "^3.7.0", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/util-endpoints": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.1.7.tgz", + "integrity": "sha512-tSfcqKcN/Oo2STEYCABVuKgJ76nyyr6skGl9t15hs+YaiU06sgMkN7QYjo0BbVw+KT26zok3IzbdSOksQ4YzVw==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.12", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/util-retry": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.11.tgz", + "integrity": "sha512-hJUC6W7A3DQgaee3Hp9ZFcOxVDZzmBIRBPlUAk8/fSOEl7pE/aX7Dci0JycNOnm9Mfr0KV2XjIlUOcGWXQUdVQ==", + "dependencies": { + "@smithy/service-error-classification": "^3.0.11", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/abort-controller": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.1.tgz", + "integrity": "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/core": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.1.2.tgz", + "integrity": "sha512-htwQXkbdF13uwwDevz9BEzL5ABK+1sJpVQXywwGSH973AVOvisHNfpcB8A8761G6XgHoS2kHPqc9DqHJ2gp+/Q==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/middleware-serde": "^4.0.2", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-stream": "^4.0.2", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/fetch-http-handler": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.0.1.tgz", + "integrity": "sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^5.0.1", + "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-base64": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/is-array-buffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.0.0.tgz", + "integrity": "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/middleware-endpoint": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.0.3.tgz", + "integrity": "sha512-YdbmWhQF5kIxZjWqPIgboVfi8i5XgiYMM7GGKFMTvBei4XjNQfNv8sukT50ITvgnWKKKpOtp0C0h7qixLgb77Q==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.1.2", + "@smithy/middleware-serde": "^4.0.2", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-middleware": "^4.0.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/middleware-serde": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.0.2.tgz", + "integrity": "sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/middleware-stack": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.0.1.tgz", + "integrity": "sha512-dHwDmrtR/ln8UTHpaIavRSzeIk5+YZTBtLnKwDW3G2t6nAupCiQUvNzNoHBpik63fwUaJPtlnMzXbQrNFWssIA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/node-config-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.0.1.tgz", + "integrity": "sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/node-http-handler": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.2.tgz", + "integrity": "sha512-X66H9aah9hisLLSnGuzRYba6vckuFtGE+a5DcHLliI/YlqKrGoxhisD5XbX44KyoeRzoNlGr94eTsMVHFAzPOw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/abort-controller": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/property-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.1.tgz", + "integrity": "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/protocol-http": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.0.1.tgz", + "integrity": "sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/querystring-builder": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.0.1.tgz", + "integrity": "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "@smithy/util-uri-escape": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/querystring-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.0.1.tgz", + "integrity": "sha512-Ma2XC7VS9aV77+clSFylVUnPZRindhB7BbmYiNOdr+CHt/kZNJoPP0cd3QxCnCFyPXC4eybmyE98phEHkqZ5Jw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/shared-ini-file-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.1.tgz", + "integrity": "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/smithy-client": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.1.3.tgz", + "integrity": "sha512-A2Hz85pu8BJJaYFdX8yb1yocqigyqBzn+OVaVgm+Kwi/DkN8vhN2kbDVEfADo6jXf5hPKquMLGA3UINA64UZ7A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.1.2", + "@smithy/middleware-endpoint": "^4.0.3", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-stream": "^4.0.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/url-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.0.1.tgz", + "integrity": "sha512-gPXcIEUtw7VlK8f/QcruNXm7q+T5hhvGu9tl63LsJPZ27exB6dtNwvh2HIi0v7JcXJ5emBxB+CJxwaLEdJfA+g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/querystring-parser": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/util-base64": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.0.0.tgz", + "integrity": "sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/util-body-length-browser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.0.0.tgz", + "integrity": "sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/util-buffer-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.0.0.tgz", + "integrity": "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/util-hex-encoding": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.0.0.tgz", + "integrity": "sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/util-middleware": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.0.1.tgz", + "integrity": "sha512-HiLAvlcqhbzhuiOa0Lyct5IIlyIz0PQO5dnMlmQ/ubYM46dPInB+3yQGkfxsk6Q24Y0n3/JmcA1v5iEhmOF5mA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/util-stream": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.0.2.tgz", + "integrity": "sha512-0eZ4G5fRzIoewtHtwaYyl8g2C+osYOT4KClXgfdNEDAgkbe2TYPqcnw4GAWabqkZCax2ihRGPe9LZnsPdIUIHA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/node-http-handler": "^4.0.2", + "@smithy/types": "^4.1.0", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-hex-encoding": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/util-uri-escape": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.0.0.tgz", + "integrity": "sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/util-utf8": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", + "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sts": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.709.0.tgz", + "integrity": "sha512-cBAvlPg6yslXNL385UUGFPw+XY+lA9BzioNdIFkMo3fEUlTShogTtiWz4LsyLHoN6LhKojssP9DSmmWKWjCZIw==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.709.0", + "@aws-sdk/core": "3.709.0", + "@aws-sdk/credential-provider-node": "3.709.0", + "@aws-sdk/middleware-host-header": "3.709.0", + "@aws-sdk/middleware-logger": "3.709.0", + "@aws-sdk/middleware-recursion-detection": "3.709.0", + "@aws-sdk/middleware-user-agent": "3.709.0", + "@aws-sdk/region-config-resolver": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@aws-sdk/util-endpoints": "3.709.0", + "@aws-sdk/util-user-agent-browser": "3.709.0", + "@aws-sdk/util-user-agent-node": "3.709.0", + "@smithy/config-resolver": "^3.0.13", + "@smithy/core": "^2.5.5", + "@smithy/fetch-http-handler": "^4.1.2", + "@smithy/hash-node": "^3.0.11", + "@smithy/invalid-dependency": "^3.0.11", + "@smithy/middleware-content-length": "^3.0.13", + "@smithy/middleware-endpoint": "^3.2.5", + "@smithy/middleware-retry": "^3.0.30", + "@smithy/middleware-serde": "^3.0.11", + "@smithy/middleware-stack": "^3.0.11", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/node-http-handler": "^3.3.2", + "@smithy/protocol-http": "^4.1.8", + "@smithy/smithy-client": "^3.5.0", + "@smithy/types": "^3.7.2", + "@smithy/url-parser": "^3.0.11", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.30", + "@smithy/util-defaults-mode-node": "^3.0.30", + "@smithy/util-endpoints": "^2.1.7", + "@smithy/util-middleware": "^3.0.11", + "@smithy/util-retry": "^3.0.11", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/client-sso": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.709.0.tgz", + "integrity": "sha512-Qxeo8cN0jNy6Wnbqq4wucffAGJM6sJjofoTgNtPA6cC7sPYx7aYC6OAAAo6NaMRY+WywOKdS9Wgjx2QYRxKx7w==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.709.0", + "@aws-sdk/middleware-host-header": "3.709.0", + "@aws-sdk/middleware-logger": "3.709.0", + "@aws-sdk/middleware-recursion-detection": "3.709.0", + "@aws-sdk/middleware-user-agent": "3.709.0", + "@aws-sdk/region-config-resolver": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@aws-sdk/util-endpoints": "3.709.0", + "@aws-sdk/util-user-agent-browser": "3.709.0", + "@aws-sdk/util-user-agent-node": "3.709.0", + "@smithy/config-resolver": "^3.0.13", + "@smithy/core": "^2.5.5", + "@smithy/fetch-http-handler": "^4.1.2", + "@smithy/hash-node": "^3.0.11", + "@smithy/invalid-dependency": "^3.0.11", + "@smithy/middleware-content-length": "^3.0.13", + "@smithy/middleware-endpoint": "^3.2.5", + "@smithy/middleware-retry": "^3.0.30", + "@smithy/middleware-serde": "^3.0.11", + "@smithy/middleware-stack": "^3.0.11", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/node-http-handler": "^3.3.2", + "@smithy/protocol-http": "^4.1.8", + "@smithy/smithy-client": "^3.5.0", + "@smithy/types": "^3.7.2", + "@smithy/url-parser": "^3.0.11", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.30", + "@smithy/util-defaults-mode-node": "^3.0.30", + "@smithy/util-endpoints": "^2.1.7", + "@smithy/util-middleware": "^3.0.11", + "@smithy/util-retry": "^3.0.11", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/core": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.709.0.tgz", + "integrity": "sha512-7kuSpzdOTAE026j85wq/fN9UDZ70n0OHw81vFqMWwlEFtm5IQ/MRCLKcC4HkXxTdfy1PqFlmoXxWqeBa15tujw==", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@smithy/core": "^2.5.5", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/property-provider": "^3.1.11", + "@smithy/protocol-http": "^4.1.8", + "@smithy/signature-v4": "^4.2.4", + "@smithy/smithy-client": "^3.5.0", + "@smithy/types": "^3.7.2", + "@smithy/util-middleware": "^3.0.11", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/credential-provider-env": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.709.0.tgz", + "integrity": "sha512-ZMAp9LSikvHDFVa84dKpQmow6wsg956Um20cKuioPpX2GGreJFur7oduD+tRJT6FtIOHn+64YH+0MwiXLhsaIQ==", + "dependencies": { + "@aws-sdk/core": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@smithy/property-provider": "^3.1.11", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/credential-provider-http": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.709.0.tgz", + "integrity": "sha512-lIS7XLwCOyJnLD70f+VIRr8DNV1HPQe9oN6aguYrhoczqz7vDiVZLe3lh714cJqq9rdxzFypK5DqKHmcscMEPQ==", + "dependencies": { + "@aws-sdk/core": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@smithy/fetch-http-handler": "^4.1.2", + "@smithy/node-http-handler": "^3.3.2", + "@smithy/property-provider": "^3.1.11", + "@smithy/protocol-http": "^4.1.8", + "@smithy/smithy-client": "^3.5.0", + "@smithy/types": "^3.7.2", + "@smithy/util-stream": "^3.3.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.709.0.tgz", + "integrity": "sha512-qCF8IIGcPoUp+Ib3ANhbF5gElxFd+kIrtv2/1tKdvhudMANstQbMiWV0LTH47ZZR6c3as4iSrm09NZnpEoD/pA==", + "dependencies": { + "@aws-sdk/core": "3.709.0", + "@aws-sdk/credential-provider-env": "3.709.0", + "@aws-sdk/credential-provider-http": "3.709.0", + "@aws-sdk/credential-provider-process": "3.709.0", + "@aws-sdk/credential-provider-sso": "3.709.0", + "@aws-sdk/credential-provider-web-identity": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@smithy/credential-provider-imds": "^3.2.8", + "@smithy/property-provider": "^3.1.11", + "@smithy/shared-ini-file-loader": "^3.1.12", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.709.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.709.0.tgz", + "integrity": "sha512-4HRX9KYWPSjO5O/Vg03YAsebKpvTjTvpK1n7zHYBmlLMBLxUrVsL1nNKKC5p2/7OW3RL8XR1ki3QkoV7kGRxUQ==", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.709.0", + "@aws-sdk/credential-provider-http": "3.709.0", + "@aws-sdk/credential-provider-ini": "3.709.0", + "@aws-sdk/credential-provider-process": "3.709.0", + "@aws-sdk/credential-provider-sso": "3.709.0", + "@aws-sdk/credential-provider-web-identity": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@smithy/credential-provider-imds": "^3.2.8", + "@smithy/property-provider": "^3.1.11", + "@smithy/shared-ini-file-loader": "^3.1.12", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/credential-provider-process": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.709.0.tgz", + "integrity": "sha512-IAC+jPlGQII6jhIylHOwh3RgSobqlgL59nw2qYTURr8hMCI0Z1p5y2ee646HTVt4WeCYyzUAXfxr6YI/Vitv+Q==", + "dependencies": { + "@aws-sdk/core": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@smithy/property-provider": "^3.1.11", + "@smithy/shared-ini-file-loader": "^3.1.12", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.709.0.tgz", + "integrity": "sha512-rYdTDOxazS2GdGScelsRK5CAkktRLCCdRjlwXaxrcW57j749hEqxcF5uTv9RD6WBwInfedcSywErNZB+hylQlg==", + "dependencies": { + "@aws-sdk/client-sso": "3.709.0", + "@aws-sdk/core": "3.709.0", + "@aws-sdk/token-providers": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@smithy/property-provider": "^3.1.11", + "@smithy/shared-ini-file-loader": "^3.1.12", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.709.0.tgz", + "integrity": "sha512-q5Ar6k71nci43IbULFgC8a89d/3EHpmd7HvBzqVGRcHnoPwh8eZDBfbBXKH83NGwcS1qPSRYiDbVfeWPm4/1jA==", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@smithy/property-provider": "^3.1.11", + "@smithy/shared-ini-file-loader": "^3.1.12", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sso-oidc": "^3.709.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.709.0.tgz", + "integrity": "sha512-2lbDfE0IQ6gma/7BB2JpkjW5G0wGe4AS0x80oybYAYYviJmUtIR3Cn2pXun6bnAWElt4wYKl4su7oC36rs5rNA==", + "dependencies": { + "@aws-sdk/core": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@smithy/property-provider": "^3.1.11", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.709.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/middleware-host-header": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.709.0.tgz", + "integrity": "sha512-8gQYCYAaIw4lOCd5WYdf15Y/61MgRsAnrb2eiTl+icMlUOOzl8aOl5iDwm/Idp0oHZTflwxM4XSvGXO83PRWcw==", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/middleware-logger": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.709.0.tgz", + "integrity": "sha512-jDoGSccXv9zebnpUoisjWd5u5ZPIalrmm6TjvPzZ8UqzQt3Beiz0tnQwmxQD6KRc7ADweWP5Ntiqzbw9xpVajg==", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.709.0.tgz", + "integrity": "sha512-PObL/wLr4lkfbQ0yXUWaoCWu/jcwfwZzCjsUiXW/H6hW9b/00enZxmx7OhtJYaR6xmh/Lcx5wbhIoDCbzdv0tw==", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.709.0.tgz", + "integrity": "sha512-ooc9ZJvgkjPhi9q05XwSfNTXkEBEIfL4hleo5rQBKwHG3aTHvwOM7LLzhdX56QZVa6sorPBp6fwULuRDSqiQHw==", + "dependencies": { + "@aws-sdk/core": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@aws-sdk/util-endpoints": "3.709.0", + "@smithy/core": "^2.5.5", + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/region-config-resolver": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.709.0.tgz", + "integrity": "sha512-/NoCAMEVKAg3kBKOrNtgOfL+ECt6nrl+L7q2SyYmrcY4tVCmwuECVqewQaHc03fTnJijfKLccw0Fj+6wOCnB6w==", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/types": "^3.7.2", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.11", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/types": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.709.0.tgz", + "integrity": "sha512-ArtLTMxgjf13Kfu3gWH3Ez9Q5TkDdcRZUofpKH3pMGB/C6KAbeSCtIIDKfoRTUABzyGlPyCrZdnFjKyH+ypIpg==", + "dependencies": { + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/util-endpoints": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.709.0.tgz", + "integrity": "sha512-Mbc7AtL5WGCTKC16IGeUTz+sjpC3ptBda2t0CcK0kMVw3THDdcSq6ZlNKO747cNqdbwUvW34oHteUiHv4/z88Q==", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@smithy/types": "^3.7.2", + "@smithy/util-endpoints": "^2.1.7", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.709.0.tgz", + "integrity": "sha512-/rL2GasJzdTWUURCQKFldw2wqBtY4k4kCiA2tVZSKg3y4Ey7zO34SW8ebaeCE2/xoWOyLR2/etdKyphoo4Zrtg==", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@smithy/types": "^3.7.2", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.709.0.tgz", + "integrity": "sha512-trBfzSCVWy7ILgqhEXgiuM7hfRCw4F4a8IK90tjk9YL0jgoJ6eJuOp7+DfCtHJaygoBxD3cdMFkOu+lluFmGBA==", + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@smithy/config-resolver": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.13.tgz", + "integrity": "sha512-Gr/qwzyPaTL1tZcq8WQyHhTZREER5R1Wytmz4WnVGL4onA3dNk6Btll55c8Vr58pLdvWZmtG8oZxJTw3t3q7Jg==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.12", + "@smithy/types": "^3.7.2", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.11", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@smithy/credential-provider-imds": { + "version": "3.2.8", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.2.8.tgz", + "integrity": "sha512-ZCY2yD0BY+K9iMXkkbnjo+08T2h8/34oHd0Jmh6BZUSZwaaGlGCyBT/3wnS7u7Xl33/EEfN4B6nQr3Gx5bYxgw==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.12", + "@smithy/property-provider": "^3.1.11", + "@smithy/types": "^3.7.2", + "@smithy/url-parser": "^3.0.11", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@smithy/hash-node": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.11.tgz", + "integrity": "sha512-emP23rwYyZhQBvklqTtwetkQlqbNYirDiEEwXl2v0GYWMnCzxst7ZaRAnWuy28njp5kAH54lvkdG37MblZzaHA==", + "dependencies": { + "@smithy/types": "^3.7.2", + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@smithy/invalid-dependency": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.11.tgz", + "integrity": "sha512-NuQmVPEJjUX6c+UELyVz8kUx8Q539EDeNwbRyu4IIF8MeV7hUtq1FB3SHVyki2u++5XLMFqngeMKk7ccspnNyQ==", + "dependencies": { + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@smithy/middleware-content-length": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.13.tgz", + "integrity": "sha512-zfMhzojhFpIX3P5ug7jxTjfUcIPcGjcQYzB9t+rv0g1TX7B0QdwONW+ATouaLoD7h7LOw/ZlXfkq4xJ/g2TrIw==", + "dependencies": { + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@smithy/middleware-retry": { + "version": "3.0.34", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.34.tgz", + "integrity": "sha512-yVRr/AAtPZlUvwEkrq7S3x7Z8/xCd97m2hLDaqdz6ucP2RKHsBjEqaUA2ebNv2SsZoPEi+ZD0dZbOB1u37tGCA==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.12", + "@smithy/protocol-http": "^4.1.8", + "@smithy/service-error-classification": "^3.0.11", + "@smithy/smithy-client": "^3.7.0", + "@smithy/types": "^3.7.2", + "@smithy/util-middleware": "^3.0.11", + "@smithy/util-retry": "^3.0.11", + "tslib": "^2.6.2", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@smithy/service-error-classification": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.11.tgz", + "integrity": "sha512-QnYDPkyewrJzCyaeI2Rmp7pDwbUETe+hU8ADkXmgNusO1bgHBH7ovXJiYmba8t0fNfJx75fE8dlM6SEmZxheog==", + "dependencies": { + "@smithy/types": "^3.7.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@smithy/signature-v4": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-4.2.4.tgz", + "integrity": "sha512-5JWeMQYg81TgU4cG+OexAWdvDTs5JDdbEZx+Qr1iPbvo91QFGzjy0IkXAKaXUHqmKUJgSHK0ZxnCkgZpzkeNTA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", + "@smithy/util-hex-encoding": "^3.0.0", + "@smithy/util-middleware": "^3.0.11", + "@smithy/util-uri-escape": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@smithy/util-body-length-node": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-3.0.0.tgz", + "integrity": "sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@smithy/util-config-provider": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-3.0.0.tgz", + "integrity": "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@smithy/util-defaults-mode-browser": { + "version": "3.0.34", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.34.tgz", + "integrity": "sha512-FumjjF631lR521cX+svMLBj3SwSDh9VdtyynTYDAiBDEf8YPP5xORNXKQ9j0105o5+ARAGnOOP/RqSl40uXddA==", + "dependencies": { + "@smithy/property-provider": "^3.1.11", + "@smithy/smithy-client": "^3.7.0", + "@smithy/types": "^3.7.2", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@smithy/util-defaults-mode-node": { + "version": "3.0.34", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.34.tgz", + "integrity": "sha512-vN6aHfzW9dVVzkI0wcZoUXvfjkl4CSbM9nE//08lmUMyf00S75uuCpTrqF9uD4bD9eldIXlt53colrlwKAT8Gw==", + "dependencies": { + "@smithy/config-resolver": "^3.0.13", + "@smithy/credential-provider-imds": "^3.2.8", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/property-provider": "^3.1.11", + "@smithy/smithy-client": "^3.7.0", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@smithy/util-endpoints": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.1.7.tgz", + "integrity": "sha512-tSfcqKcN/Oo2STEYCABVuKgJ76nyyr6skGl9t15hs+YaiU06sgMkN7QYjo0BbVw+KT26zok3IzbdSOksQ4YzVw==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.12", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@smithy/util-retry": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.11.tgz", + "integrity": "sha512-hJUC6W7A3DQgaee3Hp9ZFcOxVDZzmBIRBPlUAk8/fSOEl7pE/aX7Dci0JycNOnm9Mfr0KV2XjIlUOcGWXQUdVQ==", + "dependencies": { + "@smithy/service-error-classification": "^3.0.11", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/core": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.734.0.tgz", + "integrity": "sha512-SxnDqf3vobdm50OLyAKfqZetv6zzwnSqwIwd3jrbopxxHKqNIM/I0xcYjD6Tn+mPig+u7iRKb9q3QnEooFTlmg==", + "dependencies": { + "@aws-sdk/types": "3.734.0", + "@smithy/core": "^3.1.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/signature-v4": "^5.0.1", + "@smithy/smithy-client": "^4.1.2", + "@smithy/types": "^4.1.0", + "@smithy/util-middleware": "^4.0.1", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/abort-controller": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.1.tgz", + "integrity": "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/core": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.1.2.tgz", + "integrity": "sha512-htwQXkbdF13uwwDevz9BEzL5ABK+1sJpVQXywwGSH973AVOvisHNfpcB8A8761G6XgHoS2kHPqc9DqHJ2gp+/Q==", + "dependencies": { + "@smithy/middleware-serde": "^4.0.2", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-stream": "^4.0.2", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/fetch-http-handler": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.0.1.tgz", + "integrity": "sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA==", + "dependencies": { + "@smithy/protocol-http": "^5.0.1", + "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-base64": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/is-array-buffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.0.0.tgz", + "integrity": "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/middleware-endpoint": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.0.3.tgz", + "integrity": "sha512-YdbmWhQF5kIxZjWqPIgboVfi8i5XgiYMM7GGKFMTvBei4XjNQfNv8sukT50ITvgnWKKKpOtp0C0h7qixLgb77Q==", + "dependencies": { + "@smithy/core": "^3.1.2", + "@smithy/middleware-serde": "^4.0.2", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-middleware": "^4.0.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/middleware-serde": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.0.2.tgz", + "integrity": "sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/middleware-stack": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.0.1.tgz", + "integrity": "sha512-dHwDmrtR/ln8UTHpaIavRSzeIk5+YZTBtLnKwDW3G2t6nAupCiQUvNzNoHBpik63fwUaJPtlnMzXbQrNFWssIA==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/node-config-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.0.1.tgz", + "integrity": "sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ==", + "dependencies": { + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/node-http-handler": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.2.tgz", + "integrity": "sha512-X66H9aah9hisLLSnGuzRYba6vckuFtGE+a5DcHLliI/YlqKrGoxhisD5XbX44KyoeRzoNlGr94eTsMVHFAzPOw==", + "dependencies": { + "@smithy/abort-controller": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/property-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.1.tgz", + "integrity": "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/protocol-http": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.0.1.tgz", + "integrity": "sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/querystring-builder": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.0.1.tgz", + "integrity": "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg==", + "dependencies": { + "@smithy/types": "^4.1.0", + "@smithy/util-uri-escape": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/querystring-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.0.1.tgz", + "integrity": "sha512-Ma2XC7VS9aV77+clSFylVUnPZRindhB7BbmYiNOdr+CHt/kZNJoPP0cd3QxCnCFyPXC4eybmyE98phEHkqZ5Jw==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/shared-ini-file-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.1.tgz", + "integrity": "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/smithy-client": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.1.3.tgz", + "integrity": "sha512-A2Hz85pu8BJJaYFdX8yb1yocqigyqBzn+OVaVgm+Kwi/DkN8vhN2kbDVEfADo6jXf5hPKquMLGA3UINA64UZ7A==", + "dependencies": { + "@smithy/core": "^3.1.2", + "@smithy/middleware-endpoint": "^4.0.3", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-stream": "^4.0.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/url-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.0.1.tgz", + "integrity": "sha512-gPXcIEUtw7VlK8f/QcruNXm7q+T5hhvGu9tl63LsJPZ27exB6dtNwvh2HIi0v7JcXJ5emBxB+CJxwaLEdJfA+g==", + "dependencies": { + "@smithy/querystring-parser": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/util-base64": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.0.0.tgz", + "integrity": "sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/util-body-length-browser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.0.0.tgz", + "integrity": "sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/util-buffer-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.0.0.tgz", + "integrity": "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==", + "dependencies": { + "@smithy/is-array-buffer": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/util-hex-encoding": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.0.0.tgz", + "integrity": "sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/util-middleware": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.0.1.tgz", + "integrity": "sha512-HiLAvlcqhbzhuiOa0Lyct5IIlyIz0PQO5dnMlmQ/ubYM46dPInB+3yQGkfxsk6Q24Y0n3/JmcA1v5iEhmOF5mA==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/util-stream": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.0.2.tgz", + "integrity": "sha512-0eZ4G5fRzIoewtHtwaYyl8g2C+osYOT4KClXgfdNEDAgkbe2TYPqcnw4GAWabqkZCax2ihRGPe9LZnsPdIUIHA==", + "dependencies": { + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/node-http-handler": "^4.0.2", + "@smithy/types": "^4.1.0", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-hex-encoding": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/util-uri-escape": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.0.0.tgz", + "integrity": "sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/util-utf8": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", + "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.734.0.tgz", + "integrity": "sha512-gtRkzYTGafnm1FPpiNO8VBmJrYMoxhDlGPYDVcijzx3DlF8dhWnowuSBCxLSi+MJMx5hvwrX2A+e/q0QAeHqmw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env/node_modules/@smithy/property-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.1.tgz", + "integrity": "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.696.0.tgz", - "integrity": "sha512-GV6EbvPi2eq1+WgY/o2RFA3P7HGmnkIzCNmhwtALFlqMroLYWKE7PSeHw66Uh1dFQeVESn0/+hiUNhu1mB0emA==", + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.734.0.tgz", + "integrity": "sha512-JFSL6xhONsq+hKM8xroIPhM5/FOhiQ1cov0lZxhzZWj6Ai3UAjucy3zyIFDr9MgP1KfCYNdvyaUq9/o+HWvEDg==", + "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.696.0", - "@aws-sdk/types": "3.696.0", - "@smithy/fetch-http-handler": "^4.1.1", - "@smithy/node-http-handler": "^3.3.1", - "@smithy/property-provider": "^3.1.9", - "@smithy/protocol-http": "^4.1.7", - "@smithy/smithy-client": "^3.4.4", - "@smithy/types": "^3.7.1", - "@smithy/util-stream": "^3.3.1", + "@aws-sdk/core": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/node-http-handler": "^4.0.2", + "@smithy/property-provider": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.2", + "@smithy/types": "^4.1.0", + "@smithy/util-stream": "^4.0.2", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/abort-controller": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.1.tgz", + "integrity": "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/core": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.1.2.tgz", + "integrity": "sha512-htwQXkbdF13uwwDevz9BEzL5ABK+1sJpVQXywwGSH973AVOvisHNfpcB8A8761G6XgHoS2kHPqc9DqHJ2gp+/Q==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/middleware-serde": "^4.0.2", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-stream": "^4.0.2", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/fetch-http-handler": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.0.1.tgz", + "integrity": "sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^5.0.1", + "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-base64": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/is-array-buffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.0.0.tgz", + "integrity": "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/middleware-endpoint": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.0.3.tgz", + "integrity": "sha512-YdbmWhQF5kIxZjWqPIgboVfi8i5XgiYMM7GGKFMTvBei4XjNQfNv8sukT50ITvgnWKKKpOtp0C0h7qixLgb77Q==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.1.2", + "@smithy/middleware-serde": "^4.0.2", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-middleware": "^4.0.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/middleware-serde": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.0.2.tgz", + "integrity": "sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/middleware-stack": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.0.1.tgz", + "integrity": "sha512-dHwDmrtR/ln8UTHpaIavRSzeIk5+YZTBtLnKwDW3G2t6nAupCiQUvNzNoHBpik63fwUaJPtlnMzXbQrNFWssIA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/node-config-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.0.1.tgz", + "integrity": "sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/node-http-handler": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.2.tgz", + "integrity": "sha512-X66H9aah9hisLLSnGuzRYba6vckuFtGE+a5DcHLliI/YlqKrGoxhisD5XbX44KyoeRzoNlGr94eTsMVHFAzPOw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/abort-controller": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/property-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.1.tgz", + "integrity": "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/protocol-http": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.0.1.tgz", + "integrity": "sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/querystring-builder": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.0.1.tgz", + "integrity": "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "@smithy/util-uri-escape": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/querystring-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.0.1.tgz", + "integrity": "sha512-Ma2XC7VS9aV77+clSFylVUnPZRindhB7BbmYiNOdr+CHt/kZNJoPP0cd3QxCnCFyPXC4eybmyE98phEHkqZ5Jw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/shared-ini-file-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.1.tgz", + "integrity": "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/smithy-client": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.1.3.tgz", + "integrity": "sha512-A2Hz85pu8BJJaYFdX8yb1yocqigyqBzn+OVaVgm+Kwi/DkN8vhN2kbDVEfADo6jXf5hPKquMLGA3UINA64UZ7A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.1.2", + "@smithy/middleware-endpoint": "^4.0.3", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-stream": "^4.0.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/url-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.0.1.tgz", + "integrity": "sha512-gPXcIEUtw7VlK8f/QcruNXm7q+T5hhvGu9tl63LsJPZ27exB6dtNwvh2HIi0v7JcXJ5emBxB+CJxwaLEdJfA+g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/querystring-parser": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/util-base64": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.0.0.tgz", + "integrity": "sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/util-body-length-browser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.0.0.tgz", + "integrity": "sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/util-buffer-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.0.0.tgz", + "integrity": "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/util-hex-encoding": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.0.0.tgz", + "integrity": "sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/util-middleware": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.0.1.tgz", + "integrity": "sha512-HiLAvlcqhbzhuiOa0Lyct5IIlyIz0PQO5dnMlmQ/ubYM46dPInB+3yQGkfxsk6Q24Y0n3/JmcA1v5iEhmOF5mA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/util-stream": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.0.2.tgz", + "integrity": "sha512-0eZ4G5fRzIoewtHtwaYyl8g2C+osYOT4KClXgfdNEDAgkbe2TYPqcnw4GAWabqkZCax2ihRGPe9LZnsPdIUIHA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/node-http-handler": "^4.0.2", + "@smithy/types": "^4.1.0", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-hex-encoding": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/util-uri-escape": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.0.0.tgz", + "integrity": "sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/util-utf8": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", + "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.699.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.699.0.tgz", - "integrity": "sha512-dXmCqjJnKmG37Q+nLjPVu22mNkrGHY8hYoOt3Jo9R2zr5MYV7s/NHsCHr+7E+BZ+tfZYLRPeB1wkpTeHiEcdRw==", + "version": "3.741.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.741.0.tgz", + "integrity": "sha512-/XvnVp6zZXsyUlP1FtmspcWnd+Z1u2WK0wwzTE/x277M0oIhAezCW79VmcY4jcDQbYH+qMbtnBexfwgFDARxQg==", + "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.696.0", - "@aws-sdk/credential-provider-env": "3.696.0", - "@aws-sdk/credential-provider-http": "3.696.0", - "@aws-sdk/credential-provider-process": "3.696.0", - "@aws-sdk/credential-provider-sso": "3.699.0", - "@aws-sdk/credential-provider-web-identity": "3.696.0", - "@aws-sdk/types": "3.696.0", - "@smithy/credential-provider-imds": "^3.2.6", - "@smithy/property-provider": "^3.1.9", - "@smithy/shared-ini-file-loader": "^3.1.10", - "@smithy/types": "^3.7.1", + "@aws-sdk/core": "3.734.0", + "@aws-sdk/credential-provider-env": "3.734.0", + "@aws-sdk/credential-provider-http": "3.734.0", + "@aws-sdk/credential-provider-process": "3.734.0", + "@aws-sdk/credential-provider-sso": "3.734.0", + "@aws-sdk/credential-provider-web-identity": "3.734.0", + "@aws-sdk/nested-clients": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@smithy/credential-provider-imds": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/property-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.1.tgz", + "integrity": "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.699.0" + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/shared-ini-file-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.1.tgz", + "integrity": "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.699.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.699.0.tgz", - "integrity": "sha512-MmEmNDo1bBtTgRmdNfdQksXu4uXe66s0p1hi1YPrn1h59Q605eq/xiWbGL6/3KdkViH6eGUuABeV2ODld86ylg==", + "version": "3.741.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.741.0.tgz", + "integrity": "sha512-iz/puK9CZZkZjrKXX2W+PaiewHtlcD7RKUIsw4YHFyb8lrOt7yTYpM6VjeI+T//1sozjymmAnnp1SST9TXApLQ==", + "license": "Apache-2.0", "dependencies": { - "@aws-sdk/credential-provider-env": "3.696.0", - "@aws-sdk/credential-provider-http": "3.696.0", - "@aws-sdk/credential-provider-ini": "3.699.0", - "@aws-sdk/credential-provider-process": "3.696.0", - "@aws-sdk/credential-provider-sso": "3.699.0", - "@aws-sdk/credential-provider-web-identity": "3.696.0", - "@aws-sdk/types": "3.696.0", - "@smithy/credential-provider-imds": "^3.2.6", - "@smithy/property-provider": "^3.1.9", - "@smithy/shared-ini-file-loader": "^3.1.10", - "@smithy/types": "^3.7.1", + "@aws-sdk/credential-provider-env": "3.734.0", + "@aws-sdk/credential-provider-http": "3.734.0", + "@aws-sdk/credential-provider-ini": "3.741.0", + "@aws-sdk/credential-provider-process": "3.734.0", + "@aws-sdk/credential-provider-sso": "3.734.0", + "@aws-sdk/credential-provider-web-identity": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@smithy/credential-provider-imds": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node/node_modules/@smithy/property-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.1.tgz", + "integrity": "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node/node_modules/@smithy/shared-ini-file-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.1.tgz", + "integrity": "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.696.0.tgz", - "integrity": "sha512-mL1RcFDe9sfmyU5K1nuFkO8UiJXXxLX4JO1gVaDIOvPqwStpUAwi3A1BoeZhWZZNQsiKI810RnYGo0E0WB/hUA==", + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.734.0.tgz", + "integrity": "sha512-zvjsUo+bkYn2vjT+EtLWu3eD6me+uun+Hws1IyWej/fKFAqiBPwyeyCgU7qjkiPQSXqk1U9+/HG9IQ6Iiz+eBw==", + "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.696.0", - "@aws-sdk/types": "3.696.0", - "@smithy/property-provider": "^3.1.9", - "@smithy/shared-ini-file-loader": "^3.1.10", - "@smithy/types": "^3.7.1", + "@aws-sdk/core": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process/node_modules/@smithy/property-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.1.tgz", + "integrity": "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process/node_modules/@smithy/shared-ini-file-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.1.tgz", + "integrity": "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.699.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.699.0.tgz", - "integrity": "sha512-Ekp2cZG4pl9D8+uKWm4qO1xcm8/MeiI8f+dnlZm8aQzizeC+aXYy9GyoclSf6daK8KfRPiRfM7ZHBBL5dAfdMA==", + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.734.0.tgz", + "integrity": "sha512-cCwwcgUBJOsV/ddyh1OGb4gKYWEaTeTsqaAK19hiNINfYV/DO9r4RMlnWAo84sSBfJuj9shUNsxzyoe6K7R92Q==", + "license": "Apache-2.0", "dependencies": { - "@aws-sdk/client-sso": "3.696.0", - "@aws-sdk/core": "3.696.0", - "@aws-sdk/token-providers": "3.699.0", - "@aws-sdk/types": "3.696.0", - "@smithy/property-provider": "^3.1.9", - "@smithy/shared-ini-file-loader": "^3.1.10", - "@smithy/types": "^3.7.1", + "@aws-sdk/client-sso": "3.734.0", + "@aws-sdk/core": "3.734.0", + "@aws-sdk/token-providers": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso/node_modules/@smithy/property-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.1.tgz", + "integrity": "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso/node_modules/@smithy/shared-ini-file-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.1.tgz", + "integrity": "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.696.0.tgz", - "integrity": "sha512-XJ/CVlWChM0VCoc259vWguFUjJDn/QwDqHwbx+K9cg3v6yrqXfK5ai+p/6lx0nQpnk4JzPVeYYxWRpaTsGC9rg==", + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.734.0.tgz", + "integrity": "sha512-t4OSOerc+ppK541/Iyn1AS40+2vT/qE+MFMotFkhCgCJbApeRF2ozEdnDN6tGmnl4ybcUuxnp9JWLjwDVlR/4g==", + "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.696.0", - "@aws-sdk/types": "3.696.0", - "@smithy/property-provider": "^3.1.9", - "@smithy/types": "^3.7.1", + "@aws-sdk/core": "3.734.0", + "@aws-sdk/nested-clients": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@smithy/property-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.1.tgz", + "integrity": "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.696.0" + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@aws-sdk/lib-storage": { @@ -940,290 +3609,2185 @@ } }, "node_modules/@aws-sdk/middleware-bucket-endpoint": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.696.0.tgz", - "integrity": "sha512-V07jishKHUS5heRNGFpCWCSTjRJyQLynS/ncUeE8ZYtG66StOOQWftTwDfFOSoXlIqrXgb4oT9atryzXq7Z4LQ==", + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.734.0.tgz", + "integrity": "sha512-etC7G18aF7KdZguW27GE/wpbrNmYLVT755EsFc8kXpZj8D6AFKxc7OuveinJmiy0bYXAMspJUWsF6CrGpOw6CQ==", "dependencies": { - "@aws-sdk/types": "3.696.0", - "@aws-sdk/util-arn-parser": "3.693.0", - "@smithy/node-config-provider": "^3.1.11", - "@smithy/protocol-http": "^4.1.7", - "@smithy/types": "^3.7.1", - "@smithy/util-config-provider": "^3.0.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-arn-parser": "3.723.0", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-config-provider": "^4.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-bucket-endpoint/node_modules/@smithy/node-config-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.0.1.tgz", + "integrity": "sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ==", + "dependencies": { + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-bucket-endpoint/node_modules/@smithy/property-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.1.tgz", + "integrity": "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-bucket-endpoint/node_modules/@smithy/protocol-http": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.0.1.tgz", + "integrity": "sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-bucket-endpoint/node_modules/@smithy/shared-ini-file-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.1.tgz", + "integrity": "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-bucket-endpoint/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@aws-sdk/middleware-expect-continue": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.696.0.tgz", - "integrity": "sha512-vpVukqY3U2pb+ULeX0shs6L0aadNep6kKzjme/MyulPjtUDJpD3AekHsXRrCCGLmOqSKqRgQn5zhV9pQhHsb6Q==", + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.734.0.tgz", + "integrity": "sha512-P38/v1l6HjuB2aFUewt7ueAW5IvKkFcv5dalPtbMGRhLeyivBOHwbCyuRKgVs7z7ClTpu9EaViEGki2jEQqEsQ==", "dependencies": { - "@aws-sdk/types": "3.696.0", - "@smithy/protocol-http": "^4.1.7", - "@smithy/types": "^3.7.1", + "@aws-sdk/types": "3.734.0", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-expect-continue/node_modules/@smithy/protocol-http": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.0.1.tgz", + "integrity": "sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-expect-continue/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@aws-sdk/middleware-flexible-checksums": { - "version": "3.697.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.697.0.tgz", - "integrity": "sha512-K/y43P+NuHu5+21/29BoJSltcPekvcCU8i74KlGGHbW2Z105e5QVZlFjxivcPOjOA3gdC0W4SoFSIWam5RBhzw==", + "version": "3.735.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.735.0.tgz", + "integrity": "sha512-Tx7lYTPwQFRe/wQEHMR6Drh/S+X0ToAEq1Ava9QyxV1riwtepzRLojpNDELFb3YQVVYbX7FEiBMCJLMkmIIY+A==", "dependencies": { "@aws-crypto/crc32": "5.2.0", "@aws-crypto/crc32c": "5.2.0", "@aws-crypto/util": "5.2.0", - "@aws-sdk/core": "3.696.0", - "@aws-sdk/types": "3.696.0", - "@smithy/is-array-buffer": "^3.0.0", - "@smithy/node-config-provider": "^3.1.11", - "@smithy/protocol-http": "^4.1.7", - "@smithy/types": "^3.7.1", - "@smithy/util-middleware": "^3.0.10", - "@smithy/util-stream": "^3.3.1", - "@smithy/util-utf8": "^3.0.0", + "@aws-sdk/core": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@smithy/is-array-buffer": "^4.0.0", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-stream": "^4.0.2", + "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@smithy/abort-controller": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.1.tgz", + "integrity": "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@smithy/fetch-http-handler": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.0.1.tgz", + "integrity": "sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA==", + "dependencies": { + "@smithy/protocol-http": "^5.0.1", + "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-base64": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@smithy/is-array-buffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.0.0.tgz", + "integrity": "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@smithy/node-config-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.0.1.tgz", + "integrity": "sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ==", + "dependencies": { + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@smithy/node-http-handler": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.2.tgz", + "integrity": "sha512-X66H9aah9hisLLSnGuzRYba6vckuFtGE+a5DcHLliI/YlqKrGoxhisD5XbX44KyoeRzoNlGr94eTsMVHFAzPOw==", + "dependencies": { + "@smithy/abort-controller": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@smithy/property-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.1.tgz", + "integrity": "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@smithy/protocol-http": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.0.1.tgz", + "integrity": "sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@smithy/querystring-builder": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.0.1.tgz", + "integrity": "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg==", + "dependencies": { + "@smithy/types": "^4.1.0", + "@smithy/util-uri-escape": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@smithy/shared-ini-file-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.1.tgz", + "integrity": "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@smithy/util-base64": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.0.0.tgz", + "integrity": "sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@smithy/util-buffer-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.0.0.tgz", + "integrity": "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==", + "dependencies": { + "@smithy/is-array-buffer": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@smithy/util-hex-encoding": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.0.0.tgz", + "integrity": "sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@smithy/util-middleware": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.0.1.tgz", + "integrity": "sha512-HiLAvlcqhbzhuiOa0Lyct5IIlyIz0PQO5dnMlmQ/ubYM46dPInB+3yQGkfxsk6Q24Y0n3/JmcA1v5iEhmOF5mA==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@smithy/util-stream": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.0.2.tgz", + "integrity": "sha512-0eZ4G5fRzIoewtHtwaYyl8g2C+osYOT4KClXgfdNEDAgkbe2TYPqcnw4GAWabqkZCax2ihRGPe9LZnsPdIUIHA==", + "dependencies": { + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/node-http-handler": "^4.0.2", + "@smithy/types": "^4.1.0", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-hex-encoding": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@smithy/util-uri-escape": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.0.0.tgz", + "integrity": "sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@smithy/util-utf8": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", + "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@aws-sdk/middleware-host-header": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.696.0.tgz", - "integrity": "sha512-zELJp9Ta2zkX7ELggMN9qMCgekqZhFC5V2rOr4hJDEb/Tte7gpfKSObAnw/3AYiVqt36sjHKfdkoTsuwGdEoDg==", + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.734.0.tgz", + "integrity": "sha512-LW7RRgSOHHBzWZnigNsDIzu3AiwtjeI2X66v+Wn1P1u+eXssy1+up4ZY/h+t2sU4LU36UvEf+jrZti9c6vRnFw==", + "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.696.0", - "@smithy/protocol-http": "^4.1.7", - "@smithy/types": "^3.7.1", + "@aws-sdk/types": "3.734.0", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-host-header/node_modules/@smithy/protocol-http": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.0.1.tgz", + "integrity": "sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-host-header/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@aws-sdk/middleware-location-constraint": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.696.0.tgz", - "integrity": "sha512-FgH12OB0q+DtTrP2aiDBddDKwL4BPOrm7w3VV9BJrSdkqQCNBPz8S1lb0y5eVH4tBG+2j7gKPlOv1wde4jF/iw==", + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.734.0.tgz", + "integrity": "sha512-EJEIXwCQhto/cBfHdm3ZOeLxd2NlJD+X2F+ZTOxzokuhBtY0IONfC/91hOo5tWQweerojwshSMHRCKzRv1tlwg==", "dependencies": { - "@aws-sdk/types": "3.696.0", - "@smithy/types": "^3.7.1", + "@aws-sdk/types": "3.734.0", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-location-constraint/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@aws-sdk/middleware-logger": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.696.0.tgz", - "integrity": "sha512-KhkHt+8AjCxcR/5Zp3++YPJPpFQzxpr+jmONiT/Jw2yqnSngZ0Yspm5wGoRx2hS1HJbyZNuaOWEGuJoxLeBKfA==", + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.734.0.tgz", + "integrity": "sha512-mUMFITpJUW3LcKvFok176eI5zXAUomVtahb9IQBwLzkqFYOrMJvWAvoV4yuxrJ8TlQBG8gyEnkb9SnhZvjg67w==", + "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.696.0", - "@smithy/types": "^3.7.1", + "@aws-sdk/types": "3.734.0", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-logger/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.696.0.tgz", - "integrity": "sha512-si/maV3Z0hH7qa99f9ru2xpS5HlfSVcasRlNUXKSDm611i7jFMWwGNLUOXFAOLhXotPX5G3Z6BLwL34oDeBMug==", + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.734.0.tgz", + "integrity": "sha512-CUat2d9ITsFc2XsmeiRQO96iWpxSKYFjxvj27Hc7vo87YUHRnfMfnc8jw1EpxEwMcvBD7LsRa6vDNky6AjcrFA==", + "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.696.0", - "@smithy/protocol-http": "^4.1.7", - "@smithy/types": "^3.7.1", + "@aws-sdk/types": "3.734.0", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-recursion-detection/node_modules/@smithy/protocol-http": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.0.1.tgz", + "integrity": "sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-recursion-detection/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@aws-sdk/middleware-sdk-s3": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.696.0.tgz", - "integrity": "sha512-M7fEiAiN7DBMHflzOFzh1I2MNSlLpbiH2ubs87bdRc2wZsDPSbs4l3v6h3WLhxoQK0bq6vcfroudrLBgvCuX3Q==", + "version": "3.740.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.740.0.tgz", + "integrity": "sha512-VML9TzNoQdAs5lSPQSEgZiPgMUSz2H7SltaLb9g4tHwKK5xQoTq5WcDd6V1d2aPxSN5Q2Q63aiVUBby6MdUN/Q==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.696.0", - "@aws-sdk/types": "3.696.0", - "@aws-sdk/util-arn-parser": "3.693.0", - "@smithy/core": "^2.5.3", - "@smithy/node-config-provider": "^3.1.11", - "@smithy/protocol-http": "^4.1.7", - "@smithy/signature-v4": "^4.2.2", - "@smithy/smithy-client": "^3.4.4", - "@smithy/types": "^3.7.1", - "@smithy/util-config-provider": "^3.0.0", - "@smithy/util-middleware": "^3.0.10", - "@smithy/util-stream": "^3.3.1", - "@smithy/util-utf8": "^3.0.0", + "@aws-sdk/core": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-arn-parser": "3.723.0", + "@smithy/core": "^3.1.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/signature-v4": "^5.0.1", + "@smithy/smithy-client": "^4.1.2", + "@smithy/types": "^4.1.0", + "@smithy/util-config-provider": "^4.0.0", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-stream": "^4.0.2", + "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/abort-controller": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.1.tgz", + "integrity": "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/core": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.1.2.tgz", + "integrity": "sha512-htwQXkbdF13uwwDevz9BEzL5ABK+1sJpVQXywwGSH973AVOvisHNfpcB8A8761G6XgHoS2kHPqc9DqHJ2gp+/Q==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/middleware-serde": "^4.0.2", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-stream": "^4.0.2", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/fetch-http-handler": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.0.1.tgz", + "integrity": "sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^5.0.1", + "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-base64": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/is-array-buffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.0.0.tgz", + "integrity": "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/middleware-endpoint": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.0.3.tgz", + "integrity": "sha512-YdbmWhQF5kIxZjWqPIgboVfi8i5XgiYMM7GGKFMTvBei4XjNQfNv8sukT50ITvgnWKKKpOtp0C0h7qixLgb77Q==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.1.2", + "@smithy/middleware-serde": "^4.0.2", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-middleware": "^4.0.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/middleware-serde": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.0.2.tgz", + "integrity": "sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/middleware-stack": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.0.1.tgz", + "integrity": "sha512-dHwDmrtR/ln8UTHpaIavRSzeIk5+YZTBtLnKwDW3G2t6nAupCiQUvNzNoHBpik63fwUaJPtlnMzXbQrNFWssIA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/node-config-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.0.1.tgz", + "integrity": "sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/node-http-handler": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.2.tgz", + "integrity": "sha512-X66H9aah9hisLLSnGuzRYba6vckuFtGE+a5DcHLliI/YlqKrGoxhisD5XbX44KyoeRzoNlGr94eTsMVHFAzPOw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/abort-controller": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/property-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.1.tgz", + "integrity": "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/protocol-http": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.0.1.tgz", + "integrity": "sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/querystring-builder": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.0.1.tgz", + "integrity": "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "@smithy/util-uri-escape": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/querystring-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.0.1.tgz", + "integrity": "sha512-Ma2XC7VS9aV77+clSFylVUnPZRindhB7BbmYiNOdr+CHt/kZNJoPP0cd3QxCnCFyPXC4eybmyE98phEHkqZ5Jw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/shared-ini-file-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.1.tgz", + "integrity": "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/smithy-client": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.1.3.tgz", + "integrity": "sha512-A2Hz85pu8BJJaYFdX8yb1yocqigyqBzn+OVaVgm+Kwi/DkN8vhN2kbDVEfADo6jXf5hPKquMLGA3UINA64UZ7A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.1.2", + "@smithy/middleware-endpoint": "^4.0.3", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-stream": "^4.0.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/url-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.0.1.tgz", + "integrity": "sha512-gPXcIEUtw7VlK8f/QcruNXm7q+T5hhvGu9tl63LsJPZ27exB6dtNwvh2HIi0v7JcXJ5emBxB+CJxwaLEdJfA+g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/querystring-parser": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/util-base64": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.0.0.tgz", + "integrity": "sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/util-body-length-browser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.0.0.tgz", + "integrity": "sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/util-buffer-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.0.0.tgz", + "integrity": "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/util-hex-encoding": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.0.0.tgz", + "integrity": "sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/util-middleware": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.0.1.tgz", + "integrity": "sha512-HiLAvlcqhbzhuiOa0Lyct5IIlyIz0PQO5dnMlmQ/ubYM46dPInB+3yQGkfxsk6Q24Y0n3/JmcA1v5iEhmOF5mA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/util-stream": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.0.2.tgz", + "integrity": "sha512-0eZ4G5fRzIoewtHtwaYyl8g2C+osYOT4KClXgfdNEDAgkbe2TYPqcnw4GAWabqkZCax2ihRGPe9LZnsPdIUIHA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/node-http-handler": "^4.0.2", + "@smithy/types": "^4.1.0", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-hex-encoding": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/util-uri-escape": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.0.0.tgz", + "integrity": "sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/util-utf8": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", + "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@aws-sdk/middleware-ssec": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.696.0.tgz", - "integrity": "sha512-w/d6O7AOZ7Pg3w2d3BxnX5RmGNWb5X4RNxF19rJqcgu/xqxxE/QwZTNd5a7eTsqLXAUIfbbR8hh0czVfC1pJLA==", + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.734.0.tgz", + "integrity": "sha512-d4yd1RrPW/sspEXizq2NSOUivnheac6LPeLSLnaeTbBG9g1KqIqvCzP1TfXEqv2CrWfHEsWtJpX7oyjySSPvDQ==", "dependencies": { - "@aws-sdk/types": "3.696.0", - "@smithy/types": "^3.7.1", + "@aws-sdk/types": "3.734.0", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-ssec/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.696.0.tgz", - "integrity": "sha512-Lvyj8CTyxrHI6GHd2YVZKIRI5Fmnugt3cpJo0VrKKEgK5zMySwEZ1n4dqPK6czYRWKd5+WnYHYAuU+Wdk6Jsjw==", + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.734.0.tgz", + "integrity": "sha512-MFVzLWRkfFz02GqGPjqSOteLe5kPfElUrXZft1eElnqulqs6RJfVSpOV7mO90gu293tNAeggMWAVSGRPKIYVMg==", + "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.696.0", - "@aws-sdk/types": "3.696.0", - "@aws-sdk/util-endpoints": "3.696.0", - "@smithy/core": "^2.5.3", - "@smithy/protocol-http": "^4.1.7", - "@smithy/types": "^3.7.1", + "@aws-sdk/core": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.734.0", + "@smithy/core": "^3.1.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent/node_modules/@smithy/abort-controller": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.1.tgz", + "integrity": "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent/node_modules/@smithy/core": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.1.2.tgz", + "integrity": "sha512-htwQXkbdF13uwwDevz9BEzL5ABK+1sJpVQXywwGSH973AVOvisHNfpcB8A8761G6XgHoS2kHPqc9DqHJ2gp+/Q==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/middleware-serde": "^4.0.2", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-stream": "^4.0.2", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent/node_modules/@smithy/fetch-http-handler": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.0.1.tgz", + "integrity": "sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^5.0.1", + "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-base64": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent/node_modules/@smithy/is-array-buffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.0.0.tgz", + "integrity": "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent/node_modules/@smithy/middleware-serde": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.0.2.tgz", + "integrity": "sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent/node_modules/@smithy/node-http-handler": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.2.tgz", + "integrity": "sha512-X66H9aah9hisLLSnGuzRYba6vckuFtGE+a5DcHLliI/YlqKrGoxhisD5XbX44KyoeRzoNlGr94eTsMVHFAzPOw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/abort-controller": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent/node_modules/@smithy/protocol-http": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.0.1.tgz", + "integrity": "sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent/node_modules/@smithy/querystring-builder": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.0.1.tgz", + "integrity": "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "@smithy/util-uri-escape": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent/node_modules/@smithy/util-base64": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.0.0.tgz", + "integrity": "sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent/node_modules/@smithy/util-body-length-browser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.0.0.tgz", + "integrity": "sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent/node_modules/@smithy/util-buffer-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.0.0.tgz", + "integrity": "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent/node_modules/@smithy/util-hex-encoding": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.0.0.tgz", + "integrity": "sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent/node_modules/@smithy/util-middleware": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.0.1.tgz", + "integrity": "sha512-HiLAvlcqhbzhuiOa0Lyct5IIlyIz0PQO5dnMlmQ/ubYM46dPInB+3yQGkfxsk6Q24Y0n3/JmcA1v5iEhmOF5mA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent/node_modules/@smithy/util-stream": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.0.2.tgz", + "integrity": "sha512-0eZ4G5fRzIoewtHtwaYyl8g2C+osYOT4KClXgfdNEDAgkbe2TYPqcnw4GAWabqkZCax2ihRGPe9LZnsPdIUIHA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/node-http-handler": "^4.0.2", + "@smithy/types": "^4.1.0", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-hex-encoding": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent/node_modules/@smithy/util-uri-escape": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.0.0.tgz", + "integrity": "sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent/node_modules/@smithy/util-utf8": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", + "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.734.0.tgz", + "integrity": "sha512-iph2XUy8UzIfdJFWo1r0Zng9uWj3253yvW9gljhtu+y/LNmNvSnJxQk1f3D2BC5WmcoPZqTS3UsycT3mLPSzWA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.734.0", + "@aws-sdk/middleware-host-header": "3.734.0", + "@aws-sdk/middleware-logger": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.734.0", + "@aws-sdk/middleware-user-agent": "3.734.0", + "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.734.0", + "@aws-sdk/util-user-agent-browser": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.734.0", + "@smithy/config-resolver": "^4.0.1", + "@smithy/core": "^3.1.1", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/hash-node": "^4.0.1", + "@smithy/invalid-dependency": "^4.0.1", + "@smithy/middleware-content-length": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.2", + "@smithy/middleware-retry": "^4.0.3", + "@smithy/middleware-serde": "^4.0.1", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/node-http-handler": "^4.0.2", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.2", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.3", + "@smithy/util-defaults-mode-node": "^4.0.3", + "@smithy/util-endpoints": "^3.0.1", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/abort-controller": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.1.tgz", + "integrity": "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/core": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.1.2.tgz", + "integrity": "sha512-htwQXkbdF13uwwDevz9BEzL5ABK+1sJpVQXywwGSH973AVOvisHNfpcB8A8761G6XgHoS2kHPqc9DqHJ2gp+/Q==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/middleware-serde": "^4.0.2", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-stream": "^4.0.2", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/fetch-http-handler": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.0.1.tgz", + "integrity": "sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^5.0.1", + "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-base64": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/is-array-buffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.0.0.tgz", + "integrity": "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/middleware-endpoint": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.0.3.tgz", + "integrity": "sha512-YdbmWhQF5kIxZjWqPIgboVfi8i5XgiYMM7GGKFMTvBei4XjNQfNv8sukT50ITvgnWKKKpOtp0C0h7qixLgb77Q==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.1.2", + "@smithy/middleware-serde": "^4.0.2", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-middleware": "^4.0.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/middleware-serde": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.0.2.tgz", + "integrity": "sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/middleware-stack": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.0.1.tgz", + "integrity": "sha512-dHwDmrtR/ln8UTHpaIavRSzeIk5+YZTBtLnKwDW3G2t6nAupCiQUvNzNoHBpik63fwUaJPtlnMzXbQrNFWssIA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/node-config-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.0.1.tgz", + "integrity": "sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/node-http-handler": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.2.tgz", + "integrity": "sha512-X66H9aah9hisLLSnGuzRYba6vckuFtGE+a5DcHLliI/YlqKrGoxhisD5XbX44KyoeRzoNlGr94eTsMVHFAzPOw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/abort-controller": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/property-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.1.tgz", + "integrity": "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/protocol-http": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.0.1.tgz", + "integrity": "sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/querystring-builder": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.0.1.tgz", + "integrity": "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "@smithy/util-uri-escape": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/querystring-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.0.1.tgz", + "integrity": "sha512-Ma2XC7VS9aV77+clSFylVUnPZRindhB7BbmYiNOdr+CHt/kZNJoPP0cd3QxCnCFyPXC4eybmyE98phEHkqZ5Jw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/shared-ini-file-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.1.tgz", + "integrity": "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/smithy-client": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.1.3.tgz", + "integrity": "sha512-A2Hz85pu8BJJaYFdX8yb1yocqigyqBzn+OVaVgm+Kwi/DkN8vhN2kbDVEfADo6jXf5hPKquMLGA3UINA64UZ7A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.1.2", + "@smithy/middleware-endpoint": "^4.0.3", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-stream": "^4.0.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/url-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.0.1.tgz", + "integrity": "sha512-gPXcIEUtw7VlK8f/QcruNXm7q+T5hhvGu9tl63LsJPZ27exB6dtNwvh2HIi0v7JcXJ5emBxB+CJxwaLEdJfA+g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/querystring-parser": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-base64": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.0.0.tgz", + "integrity": "sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-body-length-browser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.0.0.tgz", + "integrity": "sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-buffer-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.0.0.tgz", + "integrity": "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-hex-encoding": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.0.0.tgz", + "integrity": "sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-middleware": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.0.1.tgz", + "integrity": "sha512-HiLAvlcqhbzhuiOa0Lyct5IIlyIz0PQO5dnMlmQ/ubYM46dPInB+3yQGkfxsk6Q24Y0n3/JmcA1v5iEhmOF5mA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-stream": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.0.2.tgz", + "integrity": "sha512-0eZ4G5fRzIoewtHtwaYyl8g2C+osYOT4KClXgfdNEDAgkbe2TYPqcnw4GAWabqkZCax2ihRGPe9LZnsPdIUIHA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/node-http-handler": "^4.0.2", + "@smithy/types": "^4.1.0", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-hex-encoding": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-uri-escape": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.0.0.tgz", + "integrity": "sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-utf8": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", + "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@aws-sdk/region-config-resolver": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.696.0.tgz", - "integrity": "sha512-7EuH142lBXjI8yH6dVS/CZeiK/WZsmb/8zP6bQbVYpMrppSTgB3MzZZdxVZGzL5r8zPQOU10wLC4kIMy0qdBVQ==", + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.734.0.tgz", + "integrity": "sha512-Lvj1kPRC5IuJBr9DyJ9T9/plkh+EfKLy+12s/mykOy1JaKHDpvj+XGy2YO6YgYVOb8JFtaqloid+5COtje4JTQ==", + "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.696.0", - "@smithy/node-config-provider": "^3.1.11", - "@smithy/types": "^3.7.1", - "@smithy/util-config-provider": "^3.0.0", - "@smithy/util-middleware": "^3.0.10", + "@aws-sdk/types": "3.734.0", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-config-provider": "^4.0.0", + "@smithy/util-middleware": "^4.0.1", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/region-config-resolver/node_modules/@smithy/node-config-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.0.1.tgz", + "integrity": "sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/region-config-resolver/node_modules/@smithy/property-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.1.tgz", + "integrity": "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/region-config-resolver/node_modules/@smithy/shared-ini-file-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.1.tgz", + "integrity": "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/region-config-resolver/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/region-config-resolver/node_modules/@smithy/util-middleware": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.0.1.tgz", + "integrity": "sha512-HiLAvlcqhbzhuiOa0Lyct5IIlyIz0PQO5dnMlmQ/ubYM46dPInB+3yQGkfxsk6Q24Y0n3/JmcA1v5iEhmOF5mA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@aws-sdk/s3-request-presigner": { - "version": "3.700.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/s3-request-presigner/-/s3-request-presigner-3.700.0.tgz", - "integrity": "sha512-1M84DaDsRuRZHC9tKyRNAGXUNg7/WeHgizpHVVeDo62s83E4I+mHHOf4Cmzui+KxbXEVkcnjJyIiXqbCQJY43w==", + "version": "3.741.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/s3-request-presigner/-/s3-request-presigner-3.741.0.tgz", + "integrity": "sha512-qrYYS+XG6wRwNDt60tcFKDCkQoLiBHhNlHaUtsHwdmSnlwA4aIuxCGXMkuskX93FsoLUDpuxtA0MZth3JL36dw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/signature-v4-multi-region": "3.696.0", - "@aws-sdk/types": "3.696.0", - "@aws-sdk/util-format-url": "3.696.0", - "@smithy/middleware-endpoint": "^3.2.3", - "@smithy/protocol-http": "^4.1.7", - "@smithy/smithy-client": "^3.4.4", - "@smithy/types": "^3.7.1", + "@aws-sdk/signature-v4-multi-region": "3.740.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-format-url": "3.734.0", + "@smithy/middleware-endpoint": "^4.0.2", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.2", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/s3-request-presigner/node_modules/@smithy/abort-controller": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.1.tgz", + "integrity": "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/s3-request-presigner/node_modules/@smithy/core": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.1.2.tgz", + "integrity": "sha512-htwQXkbdF13uwwDevz9BEzL5ABK+1sJpVQXywwGSH973AVOvisHNfpcB8A8761G6XgHoS2kHPqc9DqHJ2gp+/Q==", + "dependencies": { + "@smithy/middleware-serde": "^4.0.2", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-stream": "^4.0.2", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/s3-request-presigner/node_modules/@smithy/fetch-http-handler": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.0.1.tgz", + "integrity": "sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA==", + "dependencies": { + "@smithy/protocol-http": "^5.0.1", + "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-base64": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/s3-request-presigner/node_modules/@smithy/is-array-buffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.0.0.tgz", + "integrity": "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/s3-request-presigner/node_modules/@smithy/middleware-endpoint": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.0.3.tgz", + "integrity": "sha512-YdbmWhQF5kIxZjWqPIgboVfi8i5XgiYMM7GGKFMTvBei4XjNQfNv8sukT50ITvgnWKKKpOtp0C0h7qixLgb77Q==", + "dependencies": { + "@smithy/core": "^3.1.2", + "@smithy/middleware-serde": "^4.0.2", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-middleware": "^4.0.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/s3-request-presigner/node_modules/@smithy/middleware-serde": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.0.2.tgz", + "integrity": "sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/s3-request-presigner/node_modules/@smithy/middleware-stack": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.0.1.tgz", + "integrity": "sha512-dHwDmrtR/ln8UTHpaIavRSzeIk5+YZTBtLnKwDW3G2t6nAupCiQUvNzNoHBpik63fwUaJPtlnMzXbQrNFWssIA==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/s3-request-presigner/node_modules/@smithy/node-config-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.0.1.tgz", + "integrity": "sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ==", + "dependencies": { + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/s3-request-presigner/node_modules/@smithy/node-http-handler": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.2.tgz", + "integrity": "sha512-X66H9aah9hisLLSnGuzRYba6vckuFtGE+a5DcHLliI/YlqKrGoxhisD5XbX44KyoeRzoNlGr94eTsMVHFAzPOw==", + "dependencies": { + "@smithy/abort-controller": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/s3-request-presigner/node_modules/@smithy/property-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.1.tgz", + "integrity": "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/s3-request-presigner/node_modules/@smithy/protocol-http": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.0.1.tgz", + "integrity": "sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/s3-request-presigner/node_modules/@smithy/querystring-builder": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.0.1.tgz", + "integrity": "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg==", + "dependencies": { + "@smithy/types": "^4.1.0", + "@smithy/util-uri-escape": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/s3-request-presigner/node_modules/@smithy/querystring-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.0.1.tgz", + "integrity": "sha512-Ma2XC7VS9aV77+clSFylVUnPZRindhB7BbmYiNOdr+CHt/kZNJoPP0cd3QxCnCFyPXC4eybmyE98phEHkqZ5Jw==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/s3-request-presigner/node_modules/@smithy/shared-ini-file-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.1.tgz", + "integrity": "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/s3-request-presigner/node_modules/@smithy/smithy-client": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.1.3.tgz", + "integrity": "sha512-A2Hz85pu8BJJaYFdX8yb1yocqigyqBzn+OVaVgm+Kwi/DkN8vhN2kbDVEfADo6jXf5hPKquMLGA3UINA64UZ7A==", + "dependencies": { + "@smithy/core": "^3.1.2", + "@smithy/middleware-endpoint": "^4.0.3", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-stream": "^4.0.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/s3-request-presigner/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/s3-request-presigner/node_modules/@smithy/url-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.0.1.tgz", + "integrity": "sha512-gPXcIEUtw7VlK8f/QcruNXm7q+T5hhvGu9tl63LsJPZ27exB6dtNwvh2HIi0v7JcXJ5emBxB+CJxwaLEdJfA+g==", + "dependencies": { + "@smithy/querystring-parser": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/s3-request-presigner/node_modules/@smithy/util-base64": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.0.0.tgz", + "integrity": "sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/s3-request-presigner/node_modules/@smithy/util-body-length-browser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.0.0.tgz", + "integrity": "sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/s3-request-presigner/node_modules/@smithy/util-buffer-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.0.0.tgz", + "integrity": "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==", + "dependencies": { + "@smithy/is-array-buffer": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/s3-request-presigner/node_modules/@smithy/util-hex-encoding": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.0.0.tgz", + "integrity": "sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/s3-request-presigner/node_modules/@smithy/util-middleware": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.0.1.tgz", + "integrity": "sha512-HiLAvlcqhbzhuiOa0Lyct5IIlyIz0PQO5dnMlmQ/ubYM46dPInB+3yQGkfxsk6Q24Y0n3/JmcA1v5iEhmOF5mA==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/s3-request-presigner/node_modules/@smithy/util-stream": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.0.2.tgz", + "integrity": "sha512-0eZ4G5fRzIoewtHtwaYyl8g2C+osYOT4KClXgfdNEDAgkbe2TYPqcnw4GAWabqkZCax2ihRGPe9LZnsPdIUIHA==", + "dependencies": { + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/node-http-handler": "^4.0.2", + "@smithy/types": "^4.1.0", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-hex-encoding": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/s3-request-presigner/node_modules/@smithy/util-uri-escape": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.0.0.tgz", + "integrity": "sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/s3-request-presigner/node_modules/@smithy/util-utf8": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", + "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@aws-sdk/signature-v4-multi-region": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.696.0.tgz", - "integrity": "sha512-ijPkoLjXuPtgxAYlDoYls8UaG/VKigROn9ebbvPL/orEY5umedd3iZTcS9T+uAf4Ur3GELLxMQiERZpfDKaz3g==", + "version": "3.740.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.740.0.tgz", + "integrity": "sha512-w+psidN3i+kl51nQEV3V+fKjKUqcEbqUA1GtubruDBvBqrl5El/fU2NF3Lo53y8CfI9wCdf3V7KOEpHIqxHNng==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/middleware-sdk-s3": "3.696.0", - "@aws-sdk/types": "3.696.0", - "@smithy/protocol-http": "^4.1.7", - "@smithy/signature-v4": "^4.2.2", - "@smithy/types": "^3.7.1", + "@aws-sdk/middleware-sdk-s3": "3.740.0", + "@aws-sdk/types": "3.734.0", + "@smithy/protocol-http": "^5.0.1", + "@smithy/signature-v4": "^5.0.1", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/signature-v4-multi-region/node_modules/@smithy/protocol-http": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.0.1.tgz", + "integrity": "sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/signature-v4-multi-region/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@aws-sdk/token-providers": { - "version": "3.699.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.699.0.tgz", - "integrity": "sha512-kuiEW9DWs7fNos/SM+y58HCPhcIzm1nEZLhe2/7/6+TvAYLuEWURYsbK48gzsxXlaJ2k/jGY3nIsA7RptbMOwA==", + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.734.0.tgz", + "integrity": "sha512-2U6yWKrjWjZO8Y5SHQxkFvMVWHQWbS0ufqfAIBROqmIZNubOL7jXCiVdEFekz6MZ9LF2tvYGnOW4jX8OKDGfIw==", + "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.696.0", - "@smithy/property-provider": "^3.1.9", - "@smithy/shared-ini-file-loader": "^3.1.10", - "@smithy/types": "^3.7.1", + "@aws-sdk/nested-clients": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/token-providers/node_modules/@smithy/property-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.1.tgz", + "integrity": "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" }, - "peerDependencies": { - "@aws-sdk/client-sso-oidc": "^3.699.0" + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/token-providers/node_modules/@smithy/shared-ini-file-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.1.tgz", + "integrity": "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/token-providers/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@aws-sdk/types": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.696.0.tgz", - "integrity": "sha512-9rTvUJIAj5d3//U5FDPWGJ1nFJLuWb30vugGOrWk7aNZ6y9tuA3PI7Cc9dP8WEXKVyK1vuuk8rSFP2iqXnlgrw==", - "license": "Apache-2.0", + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.734.0.tgz", + "integrity": "sha512-o11tSPTT70nAkGV1fN9wm/hAIiLPyWX6SuGf+9JyTp7S/rC2cFWhR26MvA69nplcjNaXVzB0f+QFrLXXjOqCrg==", "dependencies": { - "@smithy/types": "^3.7.1", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/types/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@aws-sdk/util-arn-parser": { - "version": "3.693.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.693.0.tgz", - "integrity": "sha512-WC8x6ca+NRrtpAH64rWu+ryDZI3HuLwlEr8EU6/dbC/pt+r/zC0PBoC15VEygUaBA+isppCikQpGyEDu0Yj7gQ==", - "license": "Apache-2.0", + "version": "3.723.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.723.0.tgz", + "integrity": "sha512-ZhEfvUwNliOQROcAk34WJWVYTlTa4694kSVhDSjW6lE1bMataPnIN8A0ycukEzBXmd8ZSoBcQLn6lKGl7XIJ5w==", "dependencies": { "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, "node_modules/@aws-sdk/util-endpoints": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.696.0.tgz", - "integrity": "sha512-T5s0IlBVX+gkb9g/I6CLt4yAZVzMSiGnbUqWihWsHvQR1WOoIcndQy/Oz/IJXT9T2ipoy7a80gzV6a5mglrioA==", + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.734.0.tgz", + "integrity": "sha512-w2+/E88NUbqql6uCVAsmMxDQKu7vsKV0KqhlQb0lL+RCq4zy07yXYptVNs13qrnuTfyX7uPXkXrlugvK9R1Ucg==", + "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.696.0", - "@smithy/types": "^3.7.1", - "@smithy/util-endpoints": "^2.1.6", + "@aws-sdk/types": "3.734.0", + "@smithy/types": "^4.1.0", + "@smithy/util-endpoints": "^3.0.1", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/util-endpoints/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@aws-sdk/util-format-url": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-format-url/-/util-format-url-3.696.0.tgz", - "integrity": "sha512-R6yK1LozUD1GdAZRPhNsIow6VNFJUTyyoIar1OCWaknlucBMcq7musF3DN3TlORBwfFMj5buHc2ET9OtMtzvuA==", - "license": "Apache-2.0", + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-format-url/-/util-format-url-3.734.0.tgz", + "integrity": "sha512-TxZMVm8V4aR/QkW9/NhujvYpPZjUYqzLwSge5imKZbWFR806NP7RMwc5ilVuHF/bMOln/cVHkl42kATElWBvNw==", "dependencies": { - "@aws-sdk/types": "3.696.0", - "@smithy/querystring-builder": "^3.0.10", - "@smithy/types": "^3.7.1", + "@aws-sdk/types": "3.734.0", + "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/util-format-url/node_modules/@smithy/querystring-builder": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.0.1.tgz", + "integrity": "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg==", + "dependencies": { + "@smithy/types": "^4.1.0", + "@smithy/util-uri-escape": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/util-format-url/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/util-format-url/node_modules/@smithy/util-uri-escape": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.0.0.tgz", + "integrity": "sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@aws-sdk/util-locate-window": { @@ -1238,29 +5802,43 @@ } }, "node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.696.0.tgz", - "integrity": "sha512-Z5rVNDdmPOe6ELoM5AhF/ja5tSjbe6ctSctDPb0JdDf4dT0v2MfwhJKzXju2RzX8Es/77Glh7MlaXLE0kCB9+Q==", + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.734.0.tgz", + "integrity": "sha512-xQTCus6Q9LwUuALW+S76OL0jcWtMOVu14q+GoLnWPUM7QeUw963oQcLhF7oq0CtaLLKyl4GOUfcwc773Zmwwng==", + "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.696.0", - "@smithy/types": "^3.7.1", + "@aws-sdk/types": "3.734.0", + "@smithy/types": "^4.1.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, - "node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.696.0.tgz", - "integrity": "sha512-KhKqcfyXIB0SCCt+qsu4eJjsfiOrNzK5dCV7RAW2YIpp+msxGUUX0NdRE9rkzjiv+3EMktgJm3eEIS+yxtlVdQ==", + "node_modules/@aws-sdk/util-user-agent-browser/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "license": "Apache-2.0", "dependencies": { - "@aws-sdk/middleware-user-agent": "3.696.0", - "@aws-sdk/types": "3.696.0", - "@smithy/node-config-provider": "^3.1.11", - "@smithy/types": "^3.7.1", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.734.0.tgz", + "integrity": "sha512-c6Iinh+RVQKs6jYUFQ64htOU2HUXFQ3TVx+8Tu3EDF19+9vzWi9UukhIMH9rqyyEXIAkk9XL7avt8y2Uyw2dGA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" }, "peerDependencies": { "aws-crt": ">=1.0.0" @@ -1271,16 +5849,80 @@ } } }, - "node_modules/@aws-sdk/xml-builder": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.696.0.tgz", - "integrity": "sha512-dn1mX+EeqivoLYnY7p2qLrir0waPnCgS/0YdRCAVU2x14FgfUYCH6Im3w3oi2dMwhxfKY5lYVB5NKvZu7uI9lQ==", + "node_modules/@aws-sdk/util-user-agent-node/node_modules/@smithy/node-config-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.0.1.tgz", + "integrity": "sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ==", + "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.7.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-node/node_modules/@smithy/property-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.1.tgz", + "integrity": "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-node/node_modules/@smithy/shared-ini-file-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.1.tgz", + "integrity": "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-node/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/xml-builder": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.734.0.tgz", + "integrity": "sha512-Zrjxi5qwGEcUsJ0ru7fRtW74WcTS0rbLcehoFB+rN1GRi2hbLcFaYs4PwVA5diLeAJH0gszv3x4Hr/S87MfbKQ==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/xml-builder/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@babel/code-frame": { @@ -1333,9 +5975,9 @@ } }, "node_modules/@babel/eslint-parser": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.25.9.tgz", - "integrity": "sha512-5UXfgpK0j0Xr/xIdgdLEhOFxaDZ0bRPWJJchRpqOSur/3rZoPbqqki5mm0p4NE2cs28krBEiSM2MB7//afRSQQ==", + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.26.5.tgz", + "integrity": "sha512-Kkm8C8uxI842AwQADxl0GbcG1rupELYLShazYEZO/2DYjhyWXJIOUVOE3tBYm6JXzUCNJOZEzqc4rCW/jsEQYQ==", "dev": true, "dependencies": { "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", @@ -1485,9 +6127,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz", - "integrity": "sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", + "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -1569,9 +6211,9 @@ } }, "node_modules/@emnapi/core": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.2.0.tgz", - "integrity": "sha512-E7Vgw78I93we4ZWdYCb4DGAwRROGkMIXk7/y87UmANR+J6qsWusmC3gLt0H+O0KOt5e6O38U8oJamgbudrES/w==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.3.1.tgz", + "integrity": "sha512-pVGjBIt1Y6gg3EJN8jTcfpP/+uuRksIo055oE/OBkDNcjZqVbfkWCksG1Jp4yZnj3iKWyWX8fdG/j6UDYPbFog==", "optional": true, "dependencies": { "@emnapi/wasi-threads": "1.0.1", @@ -1579,9 +6221,9 @@ } }, "node_modules/@emnapi/runtime": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.2.0.tgz", - "integrity": "sha512-bV21/9LQmcQeCPEg3BDFtvwL6cwiTMksYNWQQ4KOxCZikEGalWtenoZ0wCiukJINlGCIi2KXx01g4FoH/LxpzQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.3.1.tgz", + "integrity": "sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==", "optional": true, "dependencies": { "tslib": "^2.4.0" @@ -1630,9 +6272,9 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", - "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.0.tgz", + "integrity": "sha512-zdHg2FPIFNKPdcHWtiNT+jEFCHYVplAXRDlQDyqy0zGx/q2parwh7brGJSiTxRk/TSMkbM//zt/f5CHgyTyaSQ==", "dependencies": { "@eslint/object-schema": "^2.1.4", "debug": "^4.3.1", @@ -1643,17 +6285,20 @@ } }, "node_modules/@eslint/core": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.7.0.tgz", - "integrity": "sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.10.0.tgz", + "integrity": "sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw==", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/eslintrc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", - "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", + "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -1684,9 +6329,10 @@ } }, "node_modules/@eslint/js": { - "version": "9.14.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.14.0.tgz", - "integrity": "sha512-pFoEtFWCPyDOl+C6Ift+wC7Ro89otjigCf5vcuWqWgqNSQbRrpjSvdeE6ofLz4dHmyxD5f7gIdGT4+p36L6Twg==", + "version": "9.20.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.20.0.tgz", + "integrity": "sha512-iZA07H9io9Wn836aVTytRaNqh00Sad+EamwOVJT12GTLw1VGMFV/4JaME+JjLtr9fiGaoWgYnS54wrfWsSs4oQ==", + "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } @@ -1700,10 +6346,11 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.3.tgz", - "integrity": "sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==", + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.5.tgz", + "integrity": "sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A==", "dependencies": { + "@eslint/core": "^0.10.0", "levn": "^0.4.1" }, "engines": { @@ -1711,93 +6358,105 @@ } }, "node_modules/@fastify/busboy": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", - "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", - "engines": { - "node": ">=14" - } + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-3.1.1.tgz", + "integrity": "sha512-5DGmA8FTdB2XbDeEwc/5ZXBl6UbBAyBOOLlPuBnZ/N1SwdH9Ii+cOX3tBROlDgcTXxjOYnLMVoKk9+FXAw0CJw==" }, "node_modules/@firebase/app-check-interop-types": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.2.tgz", - "integrity": "sha512-LMs47Vinv2HBMZi49C09dJxp0QT5LwDzFaVGf/+ITHe3BlIhUiLNttkATSXplc89A2lAaeTqjgqVkiRfUGyQiQ==" + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.3.tgz", + "integrity": "sha512-gAlxfPLT2j8bTI/qfe3ahl2I2YcBQ8cFIBdhAQA4I2f3TndcO+22YizyGYuttLHPQEpWkhmpFW60VCFEPg4g5A==" }, "node_modules/@firebase/app-types": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.2.tgz", - "integrity": "sha512-oMEZ1TDlBz479lmABwWsWjzHwheQKiAgnuKxE0pz0IXCVx7/rtlkx1fQ6GfgK24WCrxDKMplZrT50Kh04iMbXQ==" + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.3.tgz", + "integrity": "sha512-kRVpIl4vVGJ4baogMDINbyrIOtOxqhkZQg4jTq3l8Lw6WSk0xfpEYzezFu+Kl4ve4fbPl79dvwRtaFqAC/ucCw==" }, "node_modules/@firebase/auth-interop-types": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.3.tgz", - "integrity": "sha512-Fc9wuJGgxoxQeavybiuwgyi+0rssr76b+nHpj+eGhXFYAdudMWyfBHvFL/I5fEHniUM/UQdFzi9VXJK2iZF7FQ==" + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.4.tgz", + "integrity": "sha512-JPgcXKCuO+CWqGDnigBtvo09HeBs5u/Ktc2GaFj2m01hLarbxthLNm7Fk8iOP1aqAtXV+fnnGj7U28xmk7IwVA==" }, "node_modules/@firebase/component": { - "version": "0.6.8", - "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.8.tgz", - "integrity": "sha512-LcNvxGLLGjBwB0dJUsBGCej2fqAepWyBubs4jt1Tiuns7QLbXHuyObZ4aMeBjZjWx4m8g1LoVI9QFpSaq/k4/g==", + "version": "0.6.11", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.11.tgz", + "integrity": "sha512-eQbeCgPukLgsKD0Kw5wQgsMDX5LeoI1MIrziNDjmc6XDq5ZQnuUymANQgAb2wp1tSF9zDSXyxJmIUXaKgN58Ug==", "dependencies": { - "@firebase/util": "1.9.7", + "@firebase/util": "1.10.2", "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@firebase/database": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.0.7.tgz", - "integrity": "sha512-wjXr5AO8RPxVVg7rRCYffT7FMtBjHRfJ9KMwi19MbOf0vBf0H9YqW3WCgcnLpXI6ehiUcU3z3qgPnnU0nK6SnA==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.0.10.tgz", + "integrity": "sha512-sWp2g92u7xT4BojGbTXZ80iaSIaL6GAL0pwvM0CO/hb0nHSnABAqsH7AhnWGsGvXuEvbPr7blZylPaR9J+GSuQ==", "dependencies": { - "@firebase/app-check-interop-types": "0.3.2", - "@firebase/auth-interop-types": "0.2.3", - "@firebase/component": "0.6.8", - "@firebase/logger": "0.4.2", - "@firebase/util": "1.9.7", + "@firebase/app-check-interop-types": "0.3.3", + "@firebase/auth-interop-types": "0.2.4", + "@firebase/component": "0.6.11", + "@firebase/logger": "0.4.4", + "@firebase/util": "1.10.2", "faye-websocket": "0.11.4", "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@firebase/database-compat": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-1.0.7.tgz", - "integrity": "sha512-R/3B+VVzEFN5YcHmfWns3eitA8fHLTL03io+FIoMcTYkajFnrBdS3A+g/KceN9omP7FYYYGTQWF9lvbEx6eMEg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-2.0.1.tgz", + "integrity": "sha512-IsFivOjdE1GrjTeKoBU/ZMenESKDXidFDzZzHBPQ/4P20ptGdrl3oLlWrV/QJqJ9lND4IidE3z4Xr5JyfUW1vg==", "dependencies": { - "@firebase/component": "0.6.8", - "@firebase/database": "1.0.7", - "@firebase/database-types": "1.0.4", - "@firebase/logger": "0.4.2", - "@firebase/util": "1.9.7", + "@firebase/component": "0.6.11", + "@firebase/database": "1.0.10", + "@firebase/database-types": "1.0.7", + "@firebase/logger": "0.4.4", + "@firebase/util": "1.10.2", "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@firebase/database-types": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.4.tgz", - "integrity": "sha512-mz9ZzbH6euFXbcBo+enuJ36I5dR5w+enJHHjy9Y5ThCdKUseqfDjW3vCp1YxE9zygFCSjJJ/z1cQ+zodvUcwPQ==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.7.tgz", + "integrity": "sha512-I7zcLfJXrM0WM+ksFmFdAMdlq/DFmpeMNa+/GNsLyFo5u/lX5zzkPzGe3srVWqaBQBY5KprylDGxOsP6ETfL0A==", "dependencies": { - "@firebase/app-types": "0.9.2", - "@firebase/util": "1.9.7" + "@firebase/app-types": "0.9.3", + "@firebase/util": "1.10.2" } }, "node_modules/@firebase/logger": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.2.tgz", - "integrity": "sha512-Q1VuA5M1Gjqrwom6I6NUU4lQXdo9IAQieXlujeHZWvRt1b7qQ0KwBaNAjgxG27jgF9/mUwsNmO8ptBCGVYhB0A==", + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.4.tgz", + "integrity": "sha512-mH0PEh1zoXGnaR8gD1DeGeNZtWFKbnz9hDO91dIml3iou1gpOnLqXQ2dJfB71dj6dpmUjcQ6phY3ZZJbjErr9g==", "dependencies": { "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@firebase/util": { - "version": "1.9.7", - "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.9.7.tgz", - "integrity": "sha512-fBVNH/8bRbYjqlbIhZ+lBtdAAS4WqZumx03K06/u7fJSpz1TGjEMm1ImvKD47w+xaFKIP2ori6z8BrbakRfjJA==", + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.10.2.tgz", + "integrity": "sha512-qnSHIoE9FK+HYnNhTI8q14evyqbc/vHRivfB4TgCIUOl4tosmKSQlp7ltymOlMP4xVIJTg5wrkfcZ60X4nUf7Q==", "dependencies": { "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@google-cloud/firestore": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-7.10.0.tgz", - "integrity": "sha512-VFNhdHvfnmqcHHs6YhmSNHHxQqaaD64GwiL0c+e1qz85S8SWZPC2XFRf8p9yHRTF40Kow424s1KBU9f0fdQa+Q==", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-7.11.0.tgz", + "integrity": "sha512-88uZ+jLsp1aVMj7gh3EKYH1aulTAMFAp8sH/v5a9w8q8iqSG27RiWLoxSAFr/XocZ9hGiWH1kEnBw+zl3xAgNA==", "optional": true, "dependencies": { "@opentelemetry/api": "^1.3.0", @@ -1842,9 +6501,9 @@ } }, "node_modules/@google-cloud/storage": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-7.12.1.tgz", - "integrity": "sha512-Z3ZzOnF3YKLuvpkvF+TjQ6lztxcAyTILp+FjKonmVpEwPa9vFvxpZjubLR4sB6bf19i/8HL2AXRjA0YFgHFRmQ==", + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-7.14.0.tgz", + "integrity": "sha512-H41bPL2cMfSi4EEnFzKvg7XSb7T67ocSXrmF7MPjfgFB0L6CKGzfIYJheAZi1iqXjz6XaCT1OBf6HCG5vDBTOQ==", "optional": true, "dependencies": { "@google-cloud/paginator": "^5.0.0", @@ -1867,6 +6526,18 @@ "node": ">=14" } }, + "node_modules/@google-cloud/storage/node_modules/mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "optional": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/@google-cloud/storage/node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -1877,11 +6548,11 @@ } }, "node_modules/@graphql-tools/merge": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-9.0.4.tgz", - "integrity": "sha512-MivbDLUQ+4Q8G/Hp/9V72hbn810IJDEZQ57F01sHnlrrijyadibfVhaQfW/pNH+9T/l8ySZpaR/DpL5i+ruZ+g==", + "version": "9.0.14", + "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-9.0.14.tgz", + "integrity": "sha512-MO7VXnm3ShpdG51hs4hYsLyu+8o/tSLjNYQmLmR4rkHoFi3kQCDu2r8B4IVwd+Ve39cechj0NyCmMsg+mRvwDQ==", "dependencies": { - "@graphql-tools/utils": "^10.0.13", + "@graphql-tools/utils": "^10.6.4", "tslib": "^2.4.0" }, "engines": { @@ -1892,9 +6563,9 @@ } }, "node_modules/@graphql-tools/merge/node_modules/@graphql-tools/utils": { - "version": "10.5.4", - "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.5.4.tgz", - "integrity": "sha512-XHnyCWSlg1ccsD8s0y6ugo5GZ5TpkTiFVNPSYms5G0s6Z/xTuSmiLBfeqgkfaCwLmLaQnRCmNDL2JRnqc2R5bQ==", + "version": "10.6.4", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.6.4.tgz", + "integrity": "sha512-itCgjwVxbO+3uI/K73G9heedG8KelNFzgn368rUhPjTrkJX6NyLQwT5EMq/A8tvazMXyJYdtnN5nD+tT4DUpbQ==", "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", "cross-inspect": "1.0.1", @@ -1909,12 +6580,12 @@ } }, "node_modules/@graphql-tools/schema": { - "version": "10.0.4", - "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-10.0.4.tgz", - "integrity": "sha512-HuIwqbKxPaJujox25Ra4qwz0uQzlpsaBOzO6CVfzB/MemZdd+Gib8AIvfhQArK0YIN40aDran/yi+E5Xf0mQww==", + "version": "10.0.13", + "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-10.0.13.tgz", + "integrity": "sha512-1gvTTuSKej9bR5O2SP9dCKSHaQkVmg9fWU0Aia34HMsAZl2bzosUfXjwBu3ze8MWqb+gRVjdhukDpGA5ZC+5nA==", "dependencies": { - "@graphql-tools/merge": "^9.0.3", - "@graphql-tools/utils": "^10.2.1", + "@graphql-tools/merge": "^9.0.14", + "@graphql-tools/utils": "^10.6.4", "tslib": "^2.4.0", "value-or-promise": "^1.0.12" }, @@ -1926,9 +6597,9 @@ } }, "node_modules/@graphql-tools/schema/node_modules/@graphql-tools/utils": { - "version": "10.5.4", - "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.5.4.tgz", - "integrity": "sha512-XHnyCWSlg1ccsD8s0y6ugo5GZ5TpkTiFVNPSYms5G0s6Z/xTuSmiLBfeqgkfaCwLmLaQnRCmNDL2JRnqc2R5bQ==", + "version": "10.6.4", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.6.4.tgz", + "integrity": "sha512-itCgjwVxbO+3uI/K73G9heedG8KelNFzgn368rUhPjTrkJX6NyLQwT5EMq/A8tvazMXyJYdtnN5nD+tT4DUpbQ==", "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", "cross-inspect": "1.0.1", @@ -1943,12 +6614,18 @@ } }, "node_modules/@graphql-tools/utils": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-8.12.0.tgz", - "integrity": "sha512-TeO+MJWGXjUTS52qfK4R8HiPoF/R7X+qmgtOYd8DTH0l6b+5Y/tlg5aGeUJefqImRq7nvi93Ms40k/Uz4D5CWw==", + "version": "10.6.3", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.6.3.tgz", + "integrity": "sha512-hEaQTGyQUG3DJqCaIsiu4M+jUgWUf+h6kDwC8MtGElwkL1HWi+qX2qyynw8h9WoV7STmmHDSwkk2ET1IC3nRPw==", "dependencies": { + "@graphql-typed-document-node/core": "^3.1.1", + "cross-inspect": "1.0.1", + "dset": "^3.1.2", "tslib": "^2.4.0" }, + "engines": { + "node": ">=16.0.0" + }, "peerDependencies": { "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } @@ -1962,9 +6639,9 @@ } }, "node_modules/@grpc/grpc-js": { - "version": "1.11.2", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.11.2.tgz", - "integrity": "sha512-DWp92gDD7/Qkj7r8kus6/HCINeo3yPZWZ3paKgDgsbKbSpoxKg1yvN8xe2Q8uE3zOsPe3bX8FQX2+XValq2yTw==", + "version": "1.12.5", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.12.5.tgz", + "integrity": "sha512-d3iiHxdpg5+ZcJ6jnDSOT8Z0O0VMVGy34jAnYLUX8yd36b1qn8f1TwOA/Lc7TsOh03IkPJ38eGI5qD2EjNkoEA==", "optional": true, "dependencies": { "@grpc/proto-loader": "^0.7.13", @@ -2367,13 +7044,13 @@ } }, "node_modules/@napi-rs/wasm-runtime": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.4.tgz", - "integrity": "sha512-9zESzOO5aDByvhIAsOy9TbpZ0Ur2AJbUI7UT73kcUTS2mxAMHOBaa1st/jAymNoCtvrit99kkzT1FZuXVcgfIQ==", + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.6.tgz", + "integrity": "sha512-z8YVS3XszxFTO73iwvFDNpQIzdMmSDTP/mB3E/ucR37V3Sx57hSExcXyMoNwaucWxnsWf4xfbZv0iZ30jr0M4Q==", "optional": true, "dependencies": { - "@emnapi/core": "^1.1.0", - "@emnapi/runtime": "^1.1.0", + "@emnapi/core": "^1.3.1", + "@emnapi/runtime": "^1.3.1", "@tybys/wasm-util": "^0.9.0" } }, @@ -2386,20 +7063,20 @@ } }, "node_modules/@noble/hashes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.5.0.tgz", + "integrity": "sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==", "engines": { - "node": ">= 16" + "node": "^14.21.3 || >=16" }, "funding": { "url": "https://paulmillr.com/funding/" } }, "node_modules/@node-rs/bcrypt": { - "version": "1.10.4", - "resolved": "https://registry.npmjs.org/@node-rs/bcrypt/-/bcrypt-1.10.4.tgz", - "integrity": "sha512-Kzs8HKt2eBeT5VnkeKgiz/QKTjOO3URcvSNEQZahNwZnL6dBeeJQTxxYisc/6969+5n6c3+gNwKvqJsZzmGe7g==", + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt/-/bcrypt-1.10.7.tgz", + "integrity": "sha512-1wk0gHsUQC/ap0j6SJa2K34qNhomxXRcEe3T8cI5s+g6fgHBgLTN7U9LzWTG/HE6G4+2tWWLeCabk1wiYGEQSA==", "optional": true, "engines": { "node": ">= 10" @@ -2409,26 +7086,26 @@ "url": "https://github.com/sponsors/Brooooooklyn" }, "optionalDependencies": { - "@node-rs/bcrypt-android-arm-eabi": "1.10.4", - "@node-rs/bcrypt-android-arm64": "1.10.4", - "@node-rs/bcrypt-darwin-arm64": "1.10.4", - "@node-rs/bcrypt-darwin-x64": "1.10.4", - "@node-rs/bcrypt-freebsd-x64": "1.10.4", - "@node-rs/bcrypt-linux-arm-gnueabihf": "1.10.4", - "@node-rs/bcrypt-linux-arm64-gnu": "1.10.4", - "@node-rs/bcrypt-linux-arm64-musl": "1.10.4", - "@node-rs/bcrypt-linux-x64-gnu": "1.10.4", - "@node-rs/bcrypt-linux-x64-musl": "1.10.4", - "@node-rs/bcrypt-wasm32-wasi": "1.10.4", - "@node-rs/bcrypt-win32-arm64-msvc": "1.10.4", - "@node-rs/bcrypt-win32-ia32-msvc": "1.10.4", - "@node-rs/bcrypt-win32-x64-msvc": "1.10.4" + "@node-rs/bcrypt-android-arm-eabi": "1.10.7", + "@node-rs/bcrypt-android-arm64": "1.10.7", + "@node-rs/bcrypt-darwin-arm64": "1.10.7", + "@node-rs/bcrypt-darwin-x64": "1.10.7", + "@node-rs/bcrypt-freebsd-x64": "1.10.7", + "@node-rs/bcrypt-linux-arm-gnueabihf": "1.10.7", + "@node-rs/bcrypt-linux-arm64-gnu": "1.10.7", + "@node-rs/bcrypt-linux-arm64-musl": "1.10.7", + "@node-rs/bcrypt-linux-x64-gnu": "1.10.7", + "@node-rs/bcrypt-linux-x64-musl": "1.10.7", + "@node-rs/bcrypt-wasm32-wasi": "1.10.7", + "@node-rs/bcrypt-win32-arm64-msvc": "1.10.7", + "@node-rs/bcrypt-win32-ia32-msvc": "1.10.7", + "@node-rs/bcrypt-win32-x64-msvc": "1.10.7" } }, "node_modules/@node-rs/bcrypt-android-arm-eabi": { - "version": "1.10.4", - "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-android-arm-eabi/-/bcrypt-android-arm-eabi-1.10.4.tgz", - "integrity": "sha512-55ajutuTdfK1hKseyliflnxzNtxszQQ/EoLtgJlgCe7rI24vGP9EEEZDznB/u9OaJ14/AYzZtIhkEOYdbIdw0A==", + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-android-arm-eabi/-/bcrypt-android-arm-eabi-1.10.7.tgz", + "integrity": "sha512-8dO6/PcbeMZXS3VXGEtct9pDYdShp2WBOWlDvSbcRwVqyB580aCBh0BEFmKYtXLzLvUK8Wf+CG3U6sCdILW1lA==", "cpu": [ "arm" ], @@ -2441,9 +7118,9 @@ } }, "node_modules/@node-rs/bcrypt-android-arm64": { - "version": "1.10.4", - "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-android-arm64/-/bcrypt-android-arm64-1.10.4.tgz", - "integrity": "sha512-dCgQT7nH65tORmJw2hQ6zQgFmmC+/JBYZUWtf7pPZI76AVAn5tc7cIUrxYoV4OT1+uD63b9Av+mS1fT2EPzWEg==", + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-android-arm64/-/bcrypt-android-arm64-1.10.7.tgz", + "integrity": "sha512-UASFBS/CucEMHiCtL/2YYsAY01ZqVR1N7vSb94EOvG5iwW7BQO06kXXCTgj+Xbek9azxixrCUmo3WJnkJZ0hTQ==", "cpu": [ "arm64" ], @@ -2456,9 +7133,9 @@ } }, "node_modules/@node-rs/bcrypt-darwin-arm64": { - "version": "1.10.4", - "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-darwin-arm64/-/bcrypt-darwin-arm64-1.10.4.tgz", - "integrity": "sha512-gmHdWikHL3YVZgqXAHT+X/PG+kqIyNlPeFAWKdby83RkDI8FUiPV4qqGilgNnBmVWKkobRae9/I1HDbc4Sbhyg==", + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-darwin-arm64/-/bcrypt-darwin-arm64-1.10.7.tgz", + "integrity": "sha512-DgzFdAt455KTuiJ/zYIyJcKFobjNDR/hnf9OS7pK5NRS13Nq4gLcSIIyzsgHwZHxsJWbLpHmFc1H23Y7IQoQBw==", "cpu": [ "arm64" ], @@ -2471,9 +7148,9 @@ } }, "node_modules/@node-rs/bcrypt-darwin-x64": { - "version": "1.10.4", - "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-darwin-x64/-/bcrypt-darwin-x64-1.10.4.tgz", - "integrity": "sha512-WDzL1WKRtoyTkH6IMPx95Mkd6XaeN0VWJbSDMqQY6AFBOk03yJEj7YYXshCcF+Ur6KBBVSwRf6sdFJ15NI1Z3g==", + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-darwin-x64/-/bcrypt-darwin-x64-1.10.7.tgz", + "integrity": "sha512-SPWVfQ6sxSokoUWAKWD0EJauvPHqOGQTd7CxmYatcsUgJ/bruvEHxZ4bIwX1iDceC3FkOtmeHO0cPwR480n/xA==", "cpu": [ "x64" ], @@ -2486,9 +7163,9 @@ } }, "node_modules/@node-rs/bcrypt-freebsd-x64": { - "version": "1.10.4", - "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-freebsd-x64/-/bcrypt-freebsd-x64-1.10.4.tgz", - "integrity": "sha512-seSPJi+4MIUd1faL/n/wmDdDwaynd/FTkvTnb7qzCk8LBT+/dxi7MTz+uaD8KYDREcB9Wmhv+lwr0S9/jBTcjg==", + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-freebsd-x64/-/bcrypt-freebsd-x64-1.10.7.tgz", + "integrity": "sha512-gpa+Ixs6GwEx6U6ehBpsQetzUpuAGuAFbOiuLB2oo4N58yU4AZz1VIcWyWAHrSWRs92O0SHtmo2YPrMrwfBbSw==", "cpu": [ "x64" ], @@ -2501,9 +7178,9 @@ } }, "node_modules/@node-rs/bcrypt-linux-arm-gnueabihf": { - "version": "1.10.4", - "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-arm-gnueabihf/-/bcrypt-linux-arm-gnueabihf-1.10.4.tgz", - "integrity": "sha512-YcMLUtN9cGNTWKnaXslxGO1M0S5b4QN9KYhuyG6Kju27RfqvU5UbmpKElCsEUO2EIjxGwzvPu59T+Fyh6sVbwg==", + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-arm-gnueabihf/-/bcrypt-linux-arm-gnueabihf-1.10.7.tgz", + "integrity": "sha512-kYgJnTnpxrzl9sxYqzflobvMp90qoAlaX1oDL7nhNTj8OYJVDIk0jQgblj0bIkjmoPbBed53OJY/iu4uTS+wig==", "cpu": [ "arm" ], @@ -2516,9 +7193,9 @@ } }, "node_modules/@node-rs/bcrypt-linux-arm64-gnu": { - "version": "1.10.4", - "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-arm64-gnu/-/bcrypt-linux-arm64-gnu-1.10.4.tgz", - "integrity": "sha512-uYGUK/mO8SiftqmVSAePWxgK82vg+X/gtrVRJi95yq2iwp1+fYJX3ndxCyYPmeplBbd3NJ/F5lPT3FC/IHTTGw==", + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-arm64-gnu/-/bcrypt-linux-arm64-gnu-1.10.7.tgz", + "integrity": "sha512-7cEkK2RA+gBCj2tCVEI1rDSJV40oLbSq7bQ+PNMHNI6jCoXGmj9Uzo7mg7ZRbNZ7piIyNH5zlJqutjo8hh/tmA==", "cpu": [ "arm64" ], @@ -2531,9 +7208,9 @@ } }, "node_modules/@node-rs/bcrypt-linux-arm64-musl": { - "version": "1.10.4", - "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-arm64-musl/-/bcrypt-linux-arm64-musl-1.10.4.tgz", - "integrity": "sha512-rLvSMW/gVUBd2k2gAqQfuOReHWd9+jvz58E3i1TbkRE3a5ChvjOFc9qKPEmXuXuD9Mdj7gUwcYwpq8MdB5MtNw==", + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-arm64-musl/-/bcrypt-linux-arm64-musl-1.10.7.tgz", + "integrity": "sha512-X7DRVjshhwxUqzdUKDlF55cwzh+wqWJ2E/tILvZPboO3xaNO07Um568Vf+8cmKcz+tiZCGP7CBmKbBqjvKN/Pw==", "cpu": [ "arm64" ], @@ -2546,9 +7223,9 @@ } }, "node_modules/@node-rs/bcrypt-linux-x64-gnu": { - "version": "1.10.4", - "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-x64-gnu/-/bcrypt-linux-x64-gnu-1.10.4.tgz", - "integrity": "sha512-I++6bh+BIp70X/D/crlSgCq8K0s9nGvzmvAGFkqSG4h3LBtjJx4RKbygnoWvcBV9ErK1rvcjfMyjwZt1ukueFA==", + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-x64-gnu/-/bcrypt-linux-x64-gnu-1.10.7.tgz", + "integrity": "sha512-LXRZsvG65NggPD12hn6YxVgH0W3VR5fsE/o1/o2D5X0nxKcNQGeLWnRzs5cP8KpoFOuk1ilctXQJn8/wq+Gn/Q==", "cpu": [ "x64" ], @@ -2561,9 +7238,9 @@ } }, "node_modules/@node-rs/bcrypt-linux-x64-musl": { - "version": "1.10.4", - "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-x64-musl/-/bcrypt-linux-x64-musl-1.10.4.tgz", - "integrity": "sha512-f9RPl/5n2NS0mMJXB4IYbodKnq5HzOK5x1b9eKbcjsY0rw3mJC3K0XRFc8iaw1a5chA+xV1TPXz5mkykmr2CQQ==", + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-x64-musl/-/bcrypt-linux-x64-musl-1.10.7.tgz", + "integrity": "sha512-tCjHmct79OfcO3g5q21ME7CNzLzpw1MAsUXCLHLGWH+V6pp/xTvMbIcLwzkDj6TI3mxK6kehTn40SEjBkZ3Rog==", "cpu": [ "x64" ], @@ -2576,24 +7253,24 @@ } }, "node_modules/@node-rs/bcrypt-wasm32-wasi": { - "version": "1.10.4", - "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-wasm32-wasi/-/bcrypt-wasm32-wasi-1.10.4.tgz", - "integrity": "sha512-VaDOf+wic0yoHFimMkC5VMa/33BNqg6ieD+C/ibb7Av3NnVW4/W9YpDpqAWMR2w3fA40uTLWZ7FZSrcFck27oA==", + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-wasm32-wasi/-/bcrypt-wasm32-wasi-1.10.7.tgz", + "integrity": "sha512-4qXSihIKeVXYglfXZEq/QPtYtBUvR8d3S85k15Lilv3z5B6NSGQ9mYiNleZ7QHVLN2gEc5gmi7jM353DMH9GkA==", "cpu": [ "wasm32" ], "optional": true, "dependencies": { - "@napi-rs/wasm-runtime": "^0.2.3" + "@napi-rs/wasm-runtime": "^0.2.5" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@node-rs/bcrypt-win32-arm64-msvc": { - "version": "1.10.4", - "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-win32-arm64-msvc/-/bcrypt-win32-arm64-msvc-1.10.4.tgz", - "integrity": "sha512-M7sGnbKPvhYJ5b76ywXiEwR4mIs/JSDHjRrhm9fshKAvltQrwc3Mou22TJggvDN3gKOF1W85uPiM2OgGX/jxMg==", + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-win32-arm64-msvc/-/bcrypt-win32-arm64-msvc-1.10.7.tgz", + "integrity": "sha512-FdfUQrqmDfvC5jFhntMBkk8EI+fCJTx/I1v7Rj+Ezlr9rez1j1FmuUnywbBj2Cg15/0BDhwYdbyZ5GCMFli2aQ==", "cpu": [ "arm64" ], @@ -2606,9 +7283,9 @@ } }, "node_modules/@node-rs/bcrypt-win32-ia32-msvc": { - "version": "1.10.4", - "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-win32-ia32-msvc/-/bcrypt-win32-ia32-msvc-1.10.4.tgz", - "integrity": "sha512-zn/n4DYnuOfC2JgmVDa0JHP+5DUqAOTl2jmV3yrMrmN+StDT4Om5wtvWxvEmgv3CkeZAuAU3Y/fwjSXIpZ0Fhg==", + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-win32-ia32-msvc/-/bcrypt-win32-ia32-msvc-1.10.7.tgz", + "integrity": "sha512-lZLf4Cx+bShIhU071p5BZft4OvP4PGhyp542EEsb3zk34U5GLsGIyCjOafcF/2DGewZL6u8/aqoxbSuROkgFXg==", "cpu": [ "ia32" ], @@ -2621,9 +7298,9 @@ } }, "node_modules/@node-rs/bcrypt-win32-x64-msvc": { - "version": "1.10.4", - "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-win32-x64-msvc/-/bcrypt-win32-x64-msvc-1.10.4.tgz", - "integrity": "sha512-ynQokTTGbuLu/cckaD8dNcE+Zsfam1zElE+teNol8AxcL7Jv+ghJItSnRthPRV/vLxuycDF2DIICgpXG/p9jrQ==", + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-win32-x64-msvc/-/bcrypt-win32-x64-msvc-1.10.7.tgz", + "integrity": "sha512-hdw7tGmN1DxVAMTzICLdaHpXjy+4rxaxnBMgI8seG1JL5e3VcRGsd1/1vVDogVp2cbsmgq+6d6yAY+D9lW/DCg==", "cpu": [ "x64" ], @@ -2679,15 +7356,16 @@ "node_modules/@parse/fs-files-adapter": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@parse/fs-files-adapter/-/fs-files-adapter-3.0.0.tgz", - "integrity": "sha512-Bb+qLtXQ/1SA2Ck6JLVhfD9JQf6cCwgeDZZJjcIdHzUtdPTFu1hj51xdD7tUCL47Ed2i3aAx6K/M6AjLWYVs3A==" + "integrity": "sha512-Bb+qLtXQ/1SA2Ck6JLVhfD9JQf6cCwgeDZZJjcIdHzUtdPTFu1hj51xdD7tUCL47Ed2i3aAx6K/M6AjLWYVs3A==", + "license": "MIT" }, "node_modules/@parse/node-apn": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@parse/node-apn/-/node-apn-6.0.1.tgz", - "integrity": "sha512-QQxqEN/zbtEkSgj41oX/tQUavML+G+JHeQi2YVlgZlponnwIxA3fb5tEbXPm+fdR6rL1pi2/z2PcOwINOyx2eA==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@parse/node-apn/-/node-apn-6.2.1.tgz", + "integrity": "sha512-MsNmXpysKwMJGIqgv4kFukUVJx0YYXNoKBJ70NZ5G3Mg99uVoBptJAJ366UhdVedd8r1xJzgVPFaKZMMRTHZqw==", "dependencies": { "debug": "4.3.3", - "jsonwebtoken": "9.0.0", + "jsonwebtoken": "9.0.2", "node-forge": "1.3.1", "verror": "1.10.1" }, @@ -2711,51 +7389,6 @@ } } }, - "node_modules/@parse/node-apn/node_modules/jsonwebtoken": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", - "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", - "dependencies": { - "jws": "^3.2.2", - "lodash": "^4.17.21", - "ms": "^2.1.1", - "semver": "^7.3.8" - }, - "engines": { - "node": ">=12", - "npm": ">=6" - } - }, - "node_modules/@parse/node-apn/node_modules/jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "dependencies": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/@parse/node-apn/node_modules/jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "dependencies": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/@parse/node-apn/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@parse/node-gcm": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@parse/node-gcm/-/node-gcm-1.0.2.tgz", @@ -2778,16 +7411,16 @@ } }, "node_modules/@parse/push-adapter": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/@parse/push-adapter/-/push-adapter-6.4.1.tgz", - "integrity": "sha512-0PcWvP1l0dqs8MhOIPDs4eNnHpOM5YGbDRR+VRvkazePDuLHnWWTRM2Kk2xojFLK/sOMSkuYh7zE3I1oo3Gb+w==", + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/@parse/push-adapter/-/push-adapter-6.8.0.tgz", + "integrity": "sha512-aXbcJqryIvLScLo5zCb50u/4T3FTHmZlKK4EudUBLTv6gGCQsBkb8Z4L/Icxfa929tj2cLflmoqXjsXDQFZUjw==", "dependencies": { - "@parse/node-apn": "6.0.1", + "@parse/node-apn": "6.2.1", "@parse/node-gcm": "1.0.2", - "expo-server-sdk": "3.10.0", - "firebase-admin": "12.1.1", + "expo-server-sdk": "3.13.0", + "firebase-admin": "13.0.1", "npmlog": "7.0.1", - "parse": "5.2.0", + "parse": "5.3.0", "web-push": "3.6.7" }, "engines": { @@ -2795,51 +7428,1030 @@ } }, "node_modules/@parse/s3-files-adapter": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@parse/s3-files-adapter/-/s3-files-adapter-3.0.0.tgz", - "integrity": "sha512-kVDGqaYCILQM3JqU3pVQqmq/fRCA+Edqpl6mfrhcZa3E3Mn4oSHbyp2m88h1TOCufES2ptm7znf1RFZ2QsQ8fg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@parse/s3-files-adapter/-/s3-files-adapter-4.1.0.tgz", + "integrity": "sha512-cwgQEmWpu0b6RYKo49eXAbd/FhkIlDUhlHvOAk4FHFPoC2XGLzunmCiOIW8PwPdyFM/VYx7elFtptsrYtK1KyA==", + "license": "ISC", "dependencies": { - "aws-sdk": "2.1399.0" + "@aws-sdk/client-s3": "3.709.0", + "@aws-sdk/s3-request-presigner": "3.668.0" + }, + "engines": { + "node": ">=18.20.5 <19.0.0 || >=20.18.1 <21.0.0 || >=22.12.0 <23.0.0" } }, - "node_modules/@parse/s3-files-adapter/node_modules/aws-sdk": { - "version": "2.1399.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1399.0.tgz", - "integrity": "sha512-u9G78zs4vN/jl/AI+wNA0qnId2bUmXaCUrzRjTqN8/MWMda7igXmWHbcLmUC3BKmQPrp3EzgC+jBzFWoz5QL9A==", + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/client-s3": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.709.0.tgz", + "integrity": "sha512-IvC7coELoQ4YenTdULArVdL5yk6jNRVUALX1aqv9JlPdrXxb3Om6YrM9e7AlSTLxrULTsAe1ubm8i/DmcSY/Ng==", "dependencies": { - "buffer": "4.9.2", - "events": "1.1.1", - "ieee754": "1.1.13", - "jmespath": "0.16.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "util": "^0.12.4", - "uuid": "8.0.0", - "xml2js": "0.5.0" + "@aws-crypto/sha1-browser": "5.2.0", + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.709.0", + "@aws-sdk/client-sts": "3.709.0", + "@aws-sdk/core": "3.709.0", + "@aws-sdk/credential-provider-node": "3.709.0", + "@aws-sdk/middleware-bucket-endpoint": "3.709.0", + "@aws-sdk/middleware-expect-continue": "3.709.0", + "@aws-sdk/middleware-flexible-checksums": "3.709.0", + "@aws-sdk/middleware-host-header": "3.709.0", + "@aws-sdk/middleware-location-constraint": "3.709.0", + "@aws-sdk/middleware-logger": "3.709.0", + "@aws-sdk/middleware-recursion-detection": "3.709.0", + "@aws-sdk/middleware-sdk-s3": "3.709.0", + "@aws-sdk/middleware-ssec": "3.709.0", + "@aws-sdk/middleware-user-agent": "3.709.0", + "@aws-sdk/region-config-resolver": "3.709.0", + "@aws-sdk/signature-v4-multi-region": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@aws-sdk/util-endpoints": "3.709.0", + "@aws-sdk/util-user-agent-browser": "3.709.0", + "@aws-sdk/util-user-agent-node": "3.709.0", + "@aws-sdk/xml-builder": "3.709.0", + "@smithy/config-resolver": "^3.0.13", + "@smithy/core": "^2.5.5", + "@smithy/eventstream-serde-browser": "^3.0.14", + "@smithy/eventstream-serde-config-resolver": "^3.0.11", + "@smithy/eventstream-serde-node": "^3.0.13", + "@smithy/fetch-http-handler": "^4.1.2", + "@smithy/hash-blob-browser": "^3.1.10", + "@smithy/hash-node": "^3.0.11", + "@smithy/hash-stream-node": "^3.1.10", + "@smithy/invalid-dependency": "^3.0.11", + "@smithy/md5-js": "^3.0.11", + "@smithy/middleware-content-length": "^3.0.13", + "@smithy/middleware-endpoint": "^3.2.5", + "@smithy/middleware-retry": "^3.0.30", + "@smithy/middleware-serde": "^3.0.11", + "@smithy/middleware-stack": "^3.0.11", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/node-http-handler": "^3.3.2", + "@smithy/protocol-http": "^4.1.8", + "@smithy/smithy-client": "^3.5.0", + "@smithy/types": "^3.7.2", + "@smithy/url-parser": "^3.0.11", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.30", + "@smithy/util-defaults-mode-node": "^3.0.30", + "@smithy/util-endpoints": "^2.1.7", + "@smithy/util-middleware": "^3.0.11", + "@smithy/util-retry": "^3.0.11", + "@smithy/util-stream": "^3.3.2", + "@smithy/util-utf8": "^3.0.0", + "@smithy/util-waiter": "^3.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/client-sso": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.709.0.tgz", + "integrity": "sha512-Qxeo8cN0jNy6Wnbqq4wucffAGJM6sJjofoTgNtPA6cC7sPYx7aYC6OAAAo6NaMRY+WywOKdS9Wgjx2QYRxKx7w==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.709.0", + "@aws-sdk/middleware-host-header": "3.709.0", + "@aws-sdk/middleware-logger": "3.709.0", + "@aws-sdk/middleware-recursion-detection": "3.709.0", + "@aws-sdk/middleware-user-agent": "3.709.0", + "@aws-sdk/region-config-resolver": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@aws-sdk/util-endpoints": "3.709.0", + "@aws-sdk/util-user-agent-browser": "3.709.0", + "@aws-sdk/util-user-agent-node": "3.709.0", + "@smithy/config-resolver": "^3.0.13", + "@smithy/core": "^2.5.5", + "@smithy/fetch-http-handler": "^4.1.2", + "@smithy/hash-node": "^3.0.11", + "@smithy/invalid-dependency": "^3.0.11", + "@smithy/middleware-content-length": "^3.0.13", + "@smithy/middleware-endpoint": "^3.2.5", + "@smithy/middleware-retry": "^3.0.30", + "@smithy/middleware-serde": "^3.0.11", + "@smithy/middleware-stack": "^3.0.11", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/node-http-handler": "^3.3.2", + "@smithy/protocol-http": "^4.1.8", + "@smithy/smithy-client": "^3.5.0", + "@smithy/types": "^3.7.2", + "@smithy/url-parser": "^3.0.11", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.30", + "@smithy/util-defaults-mode-node": "^3.0.30", + "@smithy/util-endpoints": "^2.1.7", + "@smithy/util-middleware": "^3.0.11", + "@smithy/util-retry": "^3.0.11", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/core": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.709.0.tgz", + "integrity": "sha512-7kuSpzdOTAE026j85wq/fN9UDZ70n0OHw81vFqMWwlEFtm5IQ/MRCLKcC4HkXxTdfy1PqFlmoXxWqeBa15tujw==", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@smithy/core": "^2.5.5", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/property-provider": "^3.1.11", + "@smithy/protocol-http": "^4.1.8", + "@smithy/signature-v4": "^4.2.4", + "@smithy/smithy-client": "^3.5.0", + "@smithy/types": "^3.7.2", + "@smithy/util-middleware": "^3.0.11", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/credential-provider-env": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.709.0.tgz", + "integrity": "sha512-ZMAp9LSikvHDFVa84dKpQmow6wsg956Um20cKuioPpX2GGreJFur7oduD+tRJT6FtIOHn+64YH+0MwiXLhsaIQ==", + "dependencies": { + "@aws-sdk/core": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@smithy/property-provider": "^3.1.11", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/credential-provider-http": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.709.0.tgz", + "integrity": "sha512-lIS7XLwCOyJnLD70f+VIRr8DNV1HPQe9oN6aguYrhoczqz7vDiVZLe3lh714cJqq9rdxzFypK5DqKHmcscMEPQ==", + "dependencies": { + "@aws-sdk/core": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@smithy/fetch-http-handler": "^4.1.2", + "@smithy/node-http-handler": "^3.3.2", + "@smithy/property-provider": "^3.1.11", + "@smithy/protocol-http": "^4.1.8", + "@smithy/smithy-client": "^3.5.0", + "@smithy/types": "^3.7.2", + "@smithy/util-stream": "^3.3.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.709.0.tgz", + "integrity": "sha512-4HRX9KYWPSjO5O/Vg03YAsebKpvTjTvpK1n7zHYBmlLMBLxUrVsL1nNKKC5p2/7OW3RL8XR1ki3QkoV7kGRxUQ==", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.709.0", + "@aws-sdk/credential-provider-http": "3.709.0", + "@aws-sdk/credential-provider-ini": "3.709.0", + "@aws-sdk/credential-provider-process": "3.709.0", + "@aws-sdk/credential-provider-sso": "3.709.0", + "@aws-sdk/credential-provider-web-identity": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@smithy/credential-provider-imds": "^3.2.8", + "@smithy/property-provider": "^3.1.11", + "@smithy/shared-ini-file-loader": "^3.1.12", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/credential-provider-node/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.709.0.tgz", + "integrity": "sha512-qCF8IIGcPoUp+Ib3ANhbF5gElxFd+kIrtv2/1tKdvhudMANstQbMiWV0LTH47ZZR6c3as4iSrm09NZnpEoD/pA==", + "dependencies": { + "@aws-sdk/core": "3.709.0", + "@aws-sdk/credential-provider-env": "3.709.0", + "@aws-sdk/credential-provider-http": "3.709.0", + "@aws-sdk/credential-provider-process": "3.709.0", + "@aws-sdk/credential-provider-sso": "3.709.0", + "@aws-sdk/credential-provider-web-identity": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@smithy/credential-provider-imds": "^3.2.8", + "@smithy/property-provider": "^3.1.11", + "@smithy/shared-ini-file-loader": "^3.1.12", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.709.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/credential-provider-node/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.709.0.tgz", + "integrity": "sha512-2lbDfE0IQ6gma/7BB2JpkjW5G0wGe4AS0x80oybYAYYviJmUtIR3Cn2pXun6bnAWElt4wYKl4su7oC36rs5rNA==", + "dependencies": { + "@aws-sdk/core": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@smithy/property-provider": "^3.1.11", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.709.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/credential-provider-process": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.709.0.tgz", + "integrity": "sha512-IAC+jPlGQII6jhIylHOwh3RgSobqlgL59nw2qYTURr8hMCI0Z1p5y2ee646HTVt4WeCYyzUAXfxr6YI/Vitv+Q==", + "dependencies": { + "@aws-sdk/core": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@smithy/property-provider": "^3.1.11", + "@smithy/shared-ini-file-loader": "^3.1.12", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.709.0.tgz", + "integrity": "sha512-rYdTDOxazS2GdGScelsRK5CAkktRLCCdRjlwXaxrcW57j749hEqxcF5uTv9RD6WBwInfedcSywErNZB+hylQlg==", + "dependencies": { + "@aws-sdk/client-sso": "3.709.0", + "@aws-sdk/core": "3.709.0", + "@aws-sdk/token-providers": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@smithy/property-provider": "^3.1.11", + "@smithy/shared-ini-file-loader": "^3.1.12", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.709.0.tgz", + "integrity": "sha512-q5Ar6k71nci43IbULFgC8a89d/3EHpmd7HvBzqVGRcHnoPwh8eZDBfbBXKH83NGwcS1qPSRYiDbVfeWPm4/1jA==", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@smithy/property-provider": "^3.1.11", + "@smithy/shared-ini-file-loader": "^3.1.12", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sso-oidc": "^3.709.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/middleware-bucket-endpoint": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.709.0.tgz", + "integrity": "sha512-03+tJOd7KIZOiqWH7Z8BOfQIWkKJgjcpKOJKZ6FR2KjWGUOE1G+bo11wF4UuHQ0RmpKnApt+pQghZmSnE7WEeg==", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@aws-sdk/util-arn-parser": "3.693.0", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", + "@smithy/util-config-provider": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/middleware-expect-continue": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.709.0.tgz", + "integrity": "sha512-Tbl/DFvE4rHl8lMb9IzetwK4tf5R3VeHZkvEXQalsWoK0tbEQ8kXWi7wAYO4qbE7bFVvaxKX+irjJjTxf3BrCQ==", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/middleware-flexible-checksums": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.709.0.tgz", + "integrity": "sha512-wbYm9tkyCaqMeU82yjaXw7V5BxCSlSLNupENW63LC7Fvyo/aQzj6LjSMHcBpR2QwjBEhXCtF47L7aQ8SPTNhdw==", + "dependencies": { + "@aws-crypto/crc32": "5.2.0", + "@aws-crypto/crc32c": "5.2.0", + "@aws-crypto/util": "5.2.0", + "@aws-sdk/core": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@smithy/is-array-buffer": "^3.0.0", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", + "@smithy/util-middleware": "^3.0.11", + "@smithy/util-stream": "^3.3.2", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/middleware-host-header": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.709.0.tgz", + "integrity": "sha512-8gQYCYAaIw4lOCd5WYdf15Y/61MgRsAnrb2eiTl+icMlUOOzl8aOl5iDwm/Idp0oHZTflwxM4XSvGXO83PRWcw==", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/middleware-location-constraint": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.709.0.tgz", + "integrity": "sha512-5YQWPXfZq7OE0jB2G0PP8K10GBod/YPJXb+1CfJS6FbQaglRoIm8KZmVEvJNnptSKyGtE62veeCcCQcfAUfFig==", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/middleware-logger": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.709.0.tgz", + "integrity": "sha512-jDoGSccXv9zebnpUoisjWd5u5ZPIalrmm6TjvPzZ8UqzQt3Beiz0tnQwmxQD6KRc7ADweWP5Ntiqzbw9xpVajg==", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.709.0.tgz", + "integrity": "sha512-PObL/wLr4lkfbQ0yXUWaoCWu/jcwfwZzCjsUiXW/H6hW9b/00enZxmx7OhtJYaR6xmh/Lcx5wbhIoDCbzdv0tw==", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/middleware-sdk-s3": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.709.0.tgz", + "integrity": "sha512-FwtOG9t9xsLoLOQZ6qAdsWOjx9dsO6t28IjIDV1l6Ixiu2oC0Yks7goONjJUH0IDE4pDDDGzmuq0sn1XtHhheA==", + "dependencies": { + "@aws-sdk/core": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@aws-sdk/util-arn-parser": "3.693.0", + "@smithy/core": "^2.5.5", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/protocol-http": "^4.1.8", + "@smithy/signature-v4": "^4.2.4", + "@smithy/smithy-client": "^3.5.0", + "@smithy/types": "^3.7.2", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.11", + "@smithy/util-stream": "^3.3.2", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/middleware-ssec": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.709.0.tgz", + "integrity": "sha512-2muiLe7YkmlwZp2SKz+goZrDThGfRq3o0FcJF3Puc0XGmcEPEDjih537mCoTrGgcXNFlBc7YChd84r3t72ySaQ==", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.709.0.tgz", + "integrity": "sha512-ooc9ZJvgkjPhi9q05XwSfNTXkEBEIfL4hleo5rQBKwHG3aTHvwOM7LLzhdX56QZVa6sorPBp6fwULuRDSqiQHw==", + "dependencies": { + "@aws-sdk/core": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@aws-sdk/util-endpoints": "3.709.0", + "@smithy/core": "^2.5.5", + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/region-config-resolver": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.709.0.tgz", + "integrity": "sha512-/NoCAMEVKAg3kBKOrNtgOfL+ECt6nrl+L7q2SyYmrcY4tVCmwuECVqewQaHc03fTnJijfKLccw0Fj+6wOCnB6w==", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/types": "^3.7.2", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.11", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/s3-request-presigner": { + "version": "3.668.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/s3-request-presigner/-/s3-request-presigner-3.668.0.tgz", + "integrity": "sha512-y4xLR9dXU10ViesXEZ3UyO1PeaRhmYz2Gm2ylmJufTm2fIQu6vwVa0Ot43zZSKBUOtnm1/vJg8qIVPr2K8eRMQ==", + "dependencies": { + "@aws-sdk/signature-v4-multi-region": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@aws-sdk/util-format-url": "3.667.0", + "@smithy/middleware-endpoint": "^3.1.4", + "@smithy/protocol-http": "^4.1.4", + "@smithy/smithy-client": "^3.4.0", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/s3-request-presigner/node_modules/@aws-sdk/core": { + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.667.0.tgz", + "integrity": "sha512-pMcDVI7Tmdsc8R3sDv0Omj/4iRParGY+uJtAfF669WnZfDfaBQaix2Mq7+Mu08vdjqO9K3gicFvjk9S1VLmOKA==", + "dependencies": { + "@aws-sdk/types": "3.667.0", + "@smithy/core": "^2.4.8", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/property-provider": "^3.1.7", + "@smithy/protocol-http": "^4.1.4", + "@smithy/signature-v4": "^4.2.0", + "@smithy/smithy-client": "^3.4.0", + "@smithy/types": "^3.5.0", + "@smithy/util-middleware": "^3.0.7", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/s3-request-presigner/node_modules/@aws-sdk/middleware-sdk-s3": { + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.667.0.tgz", + "integrity": "sha512-31SqWDEH340kwRyql6II4wgVTNa2GJypIry5bmEzuSR30tsuWnVQg8y7zgUCDanph2GnlIFp6U+vqC9R8kDRmw==", + "dependencies": { + "@aws-sdk/core": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@aws-sdk/util-arn-parser": "3.568.0", + "@smithy/core": "^2.4.8", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/protocol-http": "^4.1.4", + "@smithy/signature-v4": "^4.2.0", + "@smithy/smithy-client": "^3.4.0", + "@smithy/types": "^3.5.0", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.7", + "@smithy/util-stream": "^3.1.9", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/s3-request-presigner/node_modules/@aws-sdk/signature-v4-multi-region": { + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.667.0.tgz", + "integrity": "sha512-9HBgapQOvrb3qvZfPcIY41D3YRNfcOuyIKqZ3h9FYbM06qOZXmIN7Y8bYL31ANGR3Mce6yu3mcnaqvrC/j1Q1w==", + "dependencies": { + "@aws-sdk/middleware-sdk-s3": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@smithy/protocol-http": "^4.1.4", + "@smithy/signature-v4": "^4.2.0", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/s3-request-presigner/node_modules/@aws-sdk/types": { + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.667.0.tgz", + "integrity": "sha512-gYq0xCsqFfQaSL/yT1Gl1vIUjtsg7d7RhnUfsXaHt8xTxOKRTdH9GjbesBjXOzgOvB0W0vfssfreSNGFlOOMJg==", + "dependencies": { + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/s3-request-presigner/node_modules/@aws-sdk/util-arn-parser": { + "version": "3.568.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.568.0.tgz", + "integrity": "sha512-XUKJWWo+KOB7fbnPP0+g/o5Ulku/X53t7i/h+sPHr5xxYTJJ9CYnbToo95mzxe7xWvkLrsNtJ8L+MnNn9INs2w==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/signature-v4-multi-region": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.709.0.tgz", + "integrity": "sha512-m0vhJEy6SLbjL11K9cHzX/ZhCIj//1GkTbYk2d4tTQFSuPyJEkjmoeHk9dYm2mJy0wH48j29OJadI1JUsR5bOw==", + "dependencies": { + "@aws-sdk/middleware-sdk-s3": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@smithy/protocol-http": "^4.1.8", + "@smithy/signature-v4": "^4.2.4", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/types": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.709.0.tgz", + "integrity": "sha512-ArtLTMxgjf13Kfu3gWH3Ez9Q5TkDdcRZUofpKH3pMGB/C6KAbeSCtIIDKfoRTUABzyGlPyCrZdnFjKyH+ypIpg==", + "dependencies": { + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/util-arn-parser": { + "version": "3.693.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.693.0.tgz", + "integrity": "sha512-WC8x6ca+NRrtpAH64rWu+ryDZI3HuLwlEr8EU6/dbC/pt+r/zC0PBoC15VEygUaBA+isppCikQpGyEDu0Yj7gQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/util-endpoints": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.709.0.tgz", + "integrity": "sha512-Mbc7AtL5WGCTKC16IGeUTz+sjpC3ptBda2t0CcK0kMVw3THDdcSq6ZlNKO747cNqdbwUvW34oHteUiHv4/z88Q==", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@smithy/types": "^3.7.2", + "@smithy/util-endpoints": "^2.1.7", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/util-format-url": { + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-format-url/-/util-format-url-3.667.0.tgz", + "integrity": "sha512-S0D731SnEPnTfbJ/Dldw5dDrOc8uipK6NLXHDs2xIq0t61iwZLMEiN8yWCs2wAZVVJKpldUM1THLaaufU9SSSA==", + "dependencies": { + "@aws-sdk/types": "3.667.0", + "@smithy/querystring-builder": "^3.0.7", + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/util-format-url/node_modules/@aws-sdk/types": { + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.667.0.tgz", + "integrity": "sha512-gYq0xCsqFfQaSL/yT1Gl1vIUjtsg7d7RhnUfsXaHt8xTxOKRTdH9GjbesBjXOzgOvB0W0vfssfreSNGFlOOMJg==", + "dependencies": { + "@smithy/types": "^3.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.709.0.tgz", + "integrity": "sha512-/rL2GasJzdTWUURCQKFldw2wqBtY4k4kCiA2tVZSKg3y4Ey7zO34SW8ebaeCE2/xoWOyLR2/etdKyphoo4Zrtg==", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@smithy/types": "^3.7.2", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.709.0.tgz", + "integrity": "sha512-trBfzSCVWy7ILgqhEXgiuM7hfRCw4F4a8IK90tjk9YL0jgoJ6eJuOp7+DfCtHJaygoBxD3cdMFkOu+lluFmGBA==", + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@aws-sdk/xml-builder": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.709.0.tgz", + "integrity": "sha512-2GPCwlNxeHspoK/Mc8nbk9cBOkSpp3j2SJUQmFnyQK6V/pR6II2oPRyZkMomug1Rc10hqlBHByMecq4zhV2uUw==", + "dependencies": { + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@smithy/chunked-blob-reader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader/-/chunked-blob-reader-4.0.0.tgz", + "integrity": "sha512-jSqRnZvkT4egkq/7b6/QRCNXmmYVcHwnJldqJ3IhVpQE2atObVJ137xmGeuGFhjFUr8gCEVAOKwSY79OvpbDaQ==", + "dependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@smithy/chunked-blob-reader-native": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader-native/-/chunked-blob-reader-native-3.0.1.tgz", + "integrity": "sha512-VEYtPvh5rs/xlyqpm5NRnfYLZn+q0SRPELbvBV+C/G7IQ+ouTuo+NKKa3ShG5OaFR8NYVMXls9hPYLTvIKKDrQ==", + "dependencies": { + "@smithy/util-base64": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@smithy/config-resolver": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.13.tgz", + "integrity": "sha512-Gr/qwzyPaTL1tZcq8WQyHhTZREER5R1Wytmz4WnVGL4onA3dNk6Btll55c8Vr58pLdvWZmtG8oZxJTw3t3q7Jg==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.12", + "@smithy/types": "^3.7.2", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.11", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@smithy/credential-provider-imds": { + "version": "3.2.8", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.2.8.tgz", + "integrity": "sha512-ZCY2yD0BY+K9iMXkkbnjo+08T2h8/34oHd0Jmh6BZUSZwaaGlGCyBT/3wnS7u7Xl33/EEfN4B6nQr3Gx5bYxgw==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.12", + "@smithy/property-provider": "^3.1.11", + "@smithy/types": "^3.7.2", + "@smithy/url-parser": "^3.0.11", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@smithy/eventstream-codec": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-3.1.10.tgz", + "integrity": "sha512-323B8YckSbUH0nMIpXn7HZsAVKHYHFUODa8gG9cHo0ySvA1fr5iWaNT+iIL0UCqUzG6QPHA3BSsBtRQou4mMqQ==", + "dependencies": { + "@aws-crypto/crc32": "5.2.0", + "@smithy/types": "^3.7.2", + "@smithy/util-hex-encoding": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@smithy/eventstream-serde-browser": { + "version": "3.0.14", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-3.0.14.tgz", + "integrity": "sha512-kbrt0vjOIihW3V7Cqj1SXQvAI5BR8SnyQYsandva0AOR307cXAc+IhPngxIPslxTLfxwDpNu0HzCAq6g42kCPg==", + "dependencies": { + "@smithy/eventstream-serde-universal": "^3.0.13", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@smithy/eventstream-serde-config-resolver": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-3.0.11.tgz", + "integrity": "sha512-P2pnEp4n75O+QHjyO7cbw/vsw5l93K/8EWyjNCAAybYwUmj3M+hjSQZ9P5TVdUgEG08ueMAP5R4FkuSkElZ5tQ==", + "dependencies": { + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@smithy/eventstream-serde-node": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-3.0.13.tgz", + "integrity": "sha512-zqy/9iwbj8Wysmvi7Lq7XFLeDgjRpTbCfwBhJa8WbrylTAHiAu6oQTwdY7iu2lxigbc9YYr9vPv5SzYny5tCXQ==", + "dependencies": { + "@smithy/eventstream-serde-universal": "^3.0.13", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@smithy/eventstream-serde-universal": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-3.0.13.tgz", + "integrity": "sha512-L1Ib66+gg9uTnqp/18Gz4MDpJPKRE44geOjOQ2SVc0eiaO5l255ADziATZgjQjqumC7yPtp1XnjHlF1srcwjKw==", + "dependencies": { + "@smithy/eventstream-codec": "^3.1.10", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@smithy/hash-blob-browser": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-3.1.10.tgz", + "integrity": "sha512-elwslXOoNunmfS0fh55jHggyhccobFkexLYC1ZeZ1xP2BTSrcIBaHV2b4xUQOdctrSNOpMqOZH1r2XzWTEhyfA==", + "dependencies": { + "@smithy/chunked-blob-reader": "^4.0.0", + "@smithy/chunked-blob-reader-native": "^3.0.1", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@smithy/hash-node": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.11.tgz", + "integrity": "sha512-emP23rwYyZhQBvklqTtwetkQlqbNYirDiEEwXl2v0GYWMnCzxst7ZaRAnWuy28njp5kAH54lvkdG37MblZzaHA==", + "dependencies": { + "@smithy/types": "^3.7.2", + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@smithy/hash-stream-node": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-3.1.10.tgz", + "integrity": "sha512-olomK/jZQ93OMayW1zfTHwcbwBdhcZOHsyWyiZ9h9IXvc1mCD/VuvzbLb3Gy/qNJwI4MANPLctTp2BucV2oU/Q==", + "dependencies": { + "@smithy/types": "^3.7.2", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@smithy/invalid-dependency": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.11.tgz", + "integrity": "sha512-NuQmVPEJjUX6c+UELyVz8kUx8Q539EDeNwbRyu4IIF8MeV7hUtq1FB3SHVyki2u++5XLMFqngeMKk7ccspnNyQ==", + "dependencies": { + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@smithy/md5-js": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-3.0.11.tgz", + "integrity": "sha512-3NM0L3i2Zm4bbgG6Ymi9NBcxXhryi3uE8fIfHJZIOfZVxOkGdjdgjR9A06SFIZCfnEIWKXZdm6Yq5/aPXFFhsQ==", + "dependencies": { + "@smithy/types": "^3.7.2", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@smithy/middleware-content-length": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.13.tgz", + "integrity": "sha512-zfMhzojhFpIX3P5ug7jxTjfUcIPcGjcQYzB9t+rv0g1TX7B0QdwONW+ATouaLoD7h7LOw/ZlXfkq4xJ/g2TrIw==", + "dependencies": { + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@smithy/middleware-retry": { + "version": "3.0.34", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.34.tgz", + "integrity": "sha512-yVRr/AAtPZlUvwEkrq7S3x7Z8/xCd97m2hLDaqdz6ucP2RKHsBjEqaUA2ebNv2SsZoPEi+ZD0dZbOB1u37tGCA==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.12", + "@smithy/protocol-http": "^4.1.8", + "@smithy/service-error-classification": "^3.0.11", + "@smithy/smithy-client": "^3.7.0", + "@smithy/types": "^3.7.2", + "@smithy/util-middleware": "^3.0.11", + "@smithy/util-retry": "^3.0.11", + "tslib": "^2.6.2", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@smithy/service-error-classification": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.11.tgz", + "integrity": "sha512-QnYDPkyewrJzCyaeI2Rmp7pDwbUETe+hU8ADkXmgNusO1bgHBH7ovXJiYmba8t0fNfJx75fE8dlM6SEmZxheog==", + "dependencies": { + "@smithy/types": "^3.7.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@smithy/signature-v4": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-4.2.4.tgz", + "integrity": "sha512-5JWeMQYg81TgU4cG+OexAWdvDTs5JDdbEZx+Qr1iPbvo91QFGzjy0IkXAKaXUHqmKUJgSHK0ZxnCkgZpzkeNTA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", + "@smithy/util-hex-encoding": "^3.0.0", + "@smithy/util-middleware": "^3.0.11", + "@smithy/util-uri-escape": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@smithy/util-body-length-node": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-3.0.0.tgz", + "integrity": "sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@smithy/util-config-provider": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-3.0.0.tgz", + "integrity": "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@smithy/util-defaults-mode-browser": { + "version": "3.0.34", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.34.tgz", + "integrity": "sha512-FumjjF631lR521cX+svMLBj3SwSDh9VdtyynTYDAiBDEf8YPP5xORNXKQ9j0105o5+ARAGnOOP/RqSl40uXddA==", + "dependencies": { + "@smithy/property-provider": "^3.1.11", + "@smithy/smithy-client": "^3.7.0", + "@smithy/types": "^3.7.2", + "bowser": "^2.11.0", + "tslib": "^2.6.2" }, "engines": { "node": ">= 10.0.0" } }, - "node_modules/@parse/s3-files-adapter/node_modules/uuid": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", - "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/@parse/s3-files-adapter/node_modules/xml2js": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", - "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "node_modules/@parse/s3-files-adapter/node_modules/@smithy/util-defaults-mode-node": { + "version": "3.0.34", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.34.tgz", + "integrity": "sha512-vN6aHfzW9dVVzkI0wcZoUXvfjkl4CSbM9nE//08lmUMyf00S75uuCpTrqF9uD4bD9eldIXlt53colrlwKAT8Gw==", "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" + "@smithy/config-resolver": "^3.0.13", + "@smithy/credential-provider-imds": "^3.2.8", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/property-provider": "^3.1.11", + "@smithy/smithy-client": "^3.7.0", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" }, "engines": { - "node": ">=4.0.0" + "node": ">= 10.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@smithy/util-endpoints": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.1.7.tgz", + "integrity": "sha512-tSfcqKcN/Oo2STEYCABVuKgJ76nyyr6skGl9t15hs+YaiU06sgMkN7QYjo0BbVw+KT26zok3IzbdSOksQ4YzVw==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.12", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@smithy/util-retry": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.11.tgz", + "integrity": "sha512-hJUC6W7A3DQgaee3Hp9ZFcOxVDZzmBIRBPlUAk8/fSOEl7pE/aX7Dci0JycNOnm9Mfr0KV2XjIlUOcGWXQUdVQ==", + "dependencies": { + "@smithy/service-error-classification": "^3.0.11", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@parse/s3-files-adapter/node_modules/@smithy/util-waiter": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-3.2.0.tgz", + "integrity": "sha512-PpjSboaDUE6yl+1qlg3Si57++e84oXdWGbuFUSAciXsVfEZJJJupR2Nb0QuXHiunt2vGR+1PTizOMvnUPaG2Qg==", + "dependencies": { + "@smithy/abort-controller": "^3.1.9", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, "node_modules/@pdf-lib/fontkit": { @@ -2939,9 +8551,9 @@ } }, "node_modules/@redis/client": { - "version": "1.5.14", - "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.14.tgz", - "integrity": "sha512-YGn0GqsRBFUQxklhY7v562VMOP0DcmlrHHs3IV1mFE3cbxe31IITUkqhBcIhVSI/2JqtWAJXg5mjV4aU+zD0HA==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.6.0.tgz", + "integrity": "sha512-aR0uffYI700OEEH4gYnitAnv3vzVGXCFvYfdpu/CJKvk4pHfLPEy/JSZyrpQ+15WhXe1yJRXLtfQ84s4mEXnPg==", "dependencies": { "cluster-key-slot": "1.1.2", "generic-pool": "3.9.0", @@ -2965,25 +8577,25 @@ } }, "node_modules/@redis/json": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.6.tgz", - "integrity": "sha512-rcZO3bfQbm2zPRpqo82XbW8zg4G/w4W3tI7X8Mqleq9goQjAGLL7q/1n1ZX4dXEAmORVZ4s1+uKLaUOg7LrUhw==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.7.tgz", + "integrity": "sha512-6UyXfjVaTBTJtKNG4/9Z8PSpKE6XgSyEb8iwaqDcy+uKrd/DGYHTWkUdnQDyzm727V7p21WUMhsqz5oy65kPcQ==", "peerDependencies": { "@redis/client": "^1.0.0" } }, "node_modules/@redis/search": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.6.tgz", - "integrity": "sha512-mZXCxbTYKBQ3M2lZnEddwEAks0Kc7nauire8q20oA0oA/LoA+E/b5Y5KZn232ztPb1FkIGqo12vh3Lf+Vw5iTw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.2.0.tgz", + "integrity": "sha512-tYoDBbtqOVigEDMAcTGsRlMycIIjwMCgD8eR2t0NANeQmgK/lvxNAvYyb6bZDD4frHRhIHkJu2TBRvB0ERkOmw==", "peerDependencies": { "@redis/client": "^1.0.0" } }, "node_modules/@redis/time-series": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.5.tgz", - "integrity": "sha512-IFjIgTusQym2B5IZJG3XKr5llka7ey84fw/NOYqESP5WUfQs9zz1ww/9+qoz4ka/S6KcGBodzlCeZ5UImKbscg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.1.0.tgz", + "integrity": "sha512-c1Q99M5ljsIuc4YdaCwfUEXsofakb9c8+Zse2qxTadu8TalLXuAESzLvFAvNVbkmSlvlzIQOLpBCmWI9wTOt+g==", "peerDependencies": { "@redis/client": "^1.0.0" } @@ -3063,11 +8675,11 @@ } }, "node_modules/@smithy/abort-controller": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.8.tgz", - "integrity": "sha512-+3DOBcUn5/rVjlxGvUPKc416SExarAQ+Qe0bqk30YSUjbepwpS7QN0cyKUSifvLJhdMZ0WPzPP5ymut0oonrpQ==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.9.tgz", + "integrity": "sha512-yiW0WI30zj8ZKoSYNx90no7ugVn3khlyH/z5W8qtKBtVE6awRALbhSG+2SAHA1r6bO/6M9utxYKVZ3PCJ1rWxw==", "dependencies": { - "@smithy/types": "^3.7.1", + "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, "engines": { @@ -3075,48 +8687,169 @@ } }, "node_modules/@smithy/chunked-blob-reader": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader/-/chunked-blob-reader-4.0.0.tgz", - "integrity": "sha512-jSqRnZvkT4egkq/7b6/QRCNXmmYVcHwnJldqJ3IhVpQE2atObVJ137xmGeuGFhjFUr8gCEVAOKwSY79OvpbDaQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader/-/chunked-blob-reader-5.0.0.tgz", + "integrity": "sha512-+sKqDBQqb036hh4NPaUiEkYFkTUGYzRsn3EuFhyfQfMy6oGHEUJDurLP9Ufb5dasr/XiAmPNMr6wa9afjQB+Gw==", "dependencies": { "tslib": "^2.6.2" - } - }, - "node_modules/@smithy/chunked-blob-reader-native": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader-native/-/chunked-blob-reader-native-3.0.1.tgz", - "integrity": "sha512-VEYtPvh5rs/xlyqpm5NRnfYLZn+q0SRPELbvBV+C/G7IQ+ouTuo+NKKa3ShG5OaFR8NYVMXls9hPYLTvIKKDrQ==", - "dependencies": { - "@smithy/util-base64": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@smithy/config-resolver": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.12.tgz", - "integrity": "sha512-YAJP9UJFZRZ8N+UruTeq78zkdjUHmzsY62J4qKWZ4SXB4QXJ/+680EfXXgkYA2xj77ooMqtUY9m406zGNqwivQ==", - "dependencies": { - "@smithy/node-config-provider": "^3.1.11", - "@smithy/types": "^3.7.1", - "@smithy/util-config-provider": "^3.0.0", - "@smithy/util-middleware": "^3.0.10", - "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/chunked-blob-reader-native": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader-native/-/chunked-blob-reader-native-4.0.0.tgz", + "integrity": "sha512-R9wM2yPmfEMsUmlMlIgSzOyICs0x9uu7UTHoccMyt7BWw8shcGM8HqB355+BZCPBcySvbTYMs62EgEQkNxz2ig==", + "dependencies": { + "@smithy/util-base64": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/chunked-blob-reader-native/node_modules/@smithy/is-array-buffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.0.0.tgz", + "integrity": "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/chunked-blob-reader-native/node_modules/@smithy/util-base64": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.0.0.tgz", + "integrity": "sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/chunked-blob-reader-native/node_modules/@smithy/util-buffer-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.0.0.tgz", + "integrity": "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==", + "dependencies": { + "@smithy/is-array-buffer": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/chunked-blob-reader-native/node_modules/@smithy/util-utf8": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", + "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/config-resolver": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.0.1.tgz", + "integrity": "sha512-Igfg8lKu3dRVkTSEm98QpZUvKEOa71jDX4vKRcvJVyRc3UgN3j7vFMf0s7xLQhYmKa8kyJGQgUJDOV5V3neVlQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-config-provider": "^4.0.0", + "@smithy/util-middleware": "^4.0.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/config-resolver/node_modules/@smithy/node-config-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.0.1.tgz", + "integrity": "sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/config-resolver/node_modules/@smithy/property-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.1.tgz", + "integrity": "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/config-resolver/node_modules/@smithy/shared-ini-file-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.1.tgz", + "integrity": "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/config-resolver/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/config-resolver/node_modules/@smithy/util-middleware": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.0.1.tgz", + "integrity": "sha512-HiLAvlcqhbzhuiOa0Lyct5IIlyIz0PQO5dnMlmQ/ubYM46dPInB+3yQGkfxsk6Q24Y0n3/JmcA1v5iEhmOF5mA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@smithy/core": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.5.4.tgz", - "integrity": "sha512-iFh2Ymn2sCziBRLPuOOxRPkuCx/2gBdXtBGuCUFLUe6bWYjKnhHyIPqGeNkLZ5Aco/5GjebRTBFiWID3sDbrKw==", + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.5.7.tgz", + "integrity": "sha512-8olpW6mKCa0v+ibCjoCzgZHQx1SQmZuW/WkrdZo73wiTprTH6qhmskT60QLFdT9DRa5mXxjz89kQPZ7ZSsoqqg==", "dependencies": { - "@smithy/middleware-serde": "^3.0.10", - "@smithy/protocol-http": "^4.1.7", - "@smithy/types": "^3.7.1", + "@smithy/middleware-serde": "^3.0.11", + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-middleware": "^3.0.10", - "@smithy/util-stream": "^3.3.1", + "@smithy/util-middleware": "^3.0.11", + "@smithy/util-stream": "^3.3.4", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, @@ -3125,139 +8858,416 @@ } }, "node_modules/@smithy/credential-provider-imds": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.2.7.tgz", - "integrity": "sha512-cEfbau+rrWF8ylkmmVAObOmjbTIzKyUC5TkBL58SbLywD0RCBC4JAUKbmtSm2w5KUJNRPGgpGFMvE2FKnuNlWQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.0.1.tgz", + "integrity": "sha512-l/qdInaDq1Zpznpmev/+52QomsJNZ3JkTl5yrTl02V6NBgJOQ4LY0SFw/8zsMwj3tLe8vqiIuwF6nxaEwgf6mg==", + "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^3.1.11", - "@smithy/property-provider": "^3.1.10", - "@smithy/types": "^3.7.1", - "@smithy/url-parser": "^3.0.10", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds/node_modules/@smithy/node-config-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.0.1.tgz", + "integrity": "sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds/node_modules/@smithy/property-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.1.tgz", + "integrity": "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds/node_modules/@smithy/querystring-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.0.1.tgz", + "integrity": "sha512-Ma2XC7VS9aV77+clSFylVUnPZRindhB7BbmYiNOdr+CHt/kZNJoPP0cd3QxCnCFyPXC4eybmyE98phEHkqZ5Jw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds/node_modules/@smithy/shared-ini-file-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.1.tgz", + "integrity": "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds/node_modules/@smithy/url-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.0.1.tgz", + "integrity": "sha512-gPXcIEUtw7VlK8f/QcruNXm7q+T5hhvGu9tl63LsJPZ27exB6dtNwvh2HIi0v7JcXJ5emBxB+CJxwaLEdJfA+g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/querystring-parser": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@smithy/eventstream-codec": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-3.1.9.tgz", - "integrity": "sha512-F574nX0hhlNOjBnP+noLtsPFqXnWh2L0+nZKCwcu7P7J8k+k+rdIDs+RMnrMwrzhUE4mwMgyN0cYnEn0G8yrnQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-4.0.1.tgz", + "integrity": "sha512-Q2bCAAR6zXNVtJgifsU16ZjKGqdw/DyecKNgIgi7dlqw04fqDu0mnq+JmGphqheypVc64CYq3azSuCpAdFk2+A==", "dependencies": { "@aws-crypto/crc32": "5.2.0", - "@smithy/types": "^3.7.1", - "@smithy/util-hex-encoding": "^3.0.0", + "@smithy/types": "^4.1.0", + "@smithy/util-hex-encoding": "^4.0.0", "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/eventstream-codec/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/eventstream-codec/node_modules/@smithy/util-hex-encoding": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.0.0.tgz", + "integrity": "sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@smithy/eventstream-serde-browser": { - "version": "3.0.13", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-3.0.13.tgz", - "integrity": "sha512-Nee9m+97o9Qj6/XeLz2g2vANS2SZgAxV4rDBMKGHvFJHU/xz88x2RwCkwsvEwYjSX4BV1NG1JXmxEaDUzZTAtw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.0.1.tgz", + "integrity": "sha512-HbIybmz5rhNg+zxKiyVAnvdM3vkzjE6ccrJ620iPL8IXcJEntd3hnBl+ktMwIy12Te/kyrSbUb8UCdnUT4QEdA==", "dependencies": { - "@smithy/eventstream-serde-universal": "^3.0.12", - "@smithy/types": "^3.7.1", + "@smithy/eventstream-serde-universal": "^4.0.1", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-browser/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@smithy/eventstream-serde-config-resolver": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-3.0.10.tgz", - "integrity": "sha512-K1M0x7P7qbBUKB0UWIL5KOcyi6zqV5mPJoL0/o01HPJr0CSq3A9FYuJC6e11EX6hR8QTIR++DBiGrYveOu6trw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-4.0.1.tgz", + "integrity": "sha512-lSipaiq3rmHguHa3QFF4YcCM3VJOrY9oq2sow3qlhFY+nBSTF/nrO82MUQRPrxHQXA58J5G1UnU2WuJfi465BA==", "dependencies": { - "@smithy/types": "^3.7.1", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-config-resolver/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@smithy/eventstream-serde-node": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-3.0.12.tgz", - "integrity": "sha512-kiZymxXvZ4tnuYsPSMUHe+MMfc4FTeFWJIc0Q5wygJoUQM4rVHNghvd48y7ppuulNMbuYt95ah71pYc2+o4JOA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-4.0.1.tgz", + "integrity": "sha512-o4CoOI6oYGYJ4zXo34U8X9szDe3oGjmHgsMGiZM0j4vtNoT+h80TLnkUcrLZR3+E6HIxqW+G+9WHAVfl0GXK0Q==", "dependencies": { - "@smithy/eventstream-serde-universal": "^3.0.12", - "@smithy/types": "^3.7.1", + "@smithy/eventstream-serde-universal": "^4.0.1", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-node/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@smithy/eventstream-serde-universal": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-3.0.12.tgz", - "integrity": "sha512-1i8ifhLJrOZ+pEifTlF0EfZzMLUGQggYQ6WmZ4d5g77zEKf7oZ0kvh1yKWHPjofvOwqrkwRDVuxuYC8wVd662A==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-4.0.1.tgz", + "integrity": "sha512-Z94uZp0tGJuxds3iEAZBqGU2QiaBHP4YytLUjwZWx+oUeohCsLyUm33yp4MMBmhkuPqSbQCXq5hDet6JGUgHWA==", "dependencies": { - "@smithy/eventstream-codec": "^3.1.9", - "@smithy/types": "^3.7.1", + "@smithy/eventstream-codec": "^4.0.1", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-universal/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@smithy/fetch-http-handler": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-4.1.1.tgz", - "integrity": "sha512-bH7QW0+JdX0bPBadXt8GwMof/jz0H28I84hU1Uet9ISpzUqXqRQ3fEZJ+ANPOhzSEczYvANNl3uDQDYArSFDtA==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-4.1.3.tgz", + "integrity": "sha512-6SxNltSncI8s689nvnzZQc/dPXcpHQ34KUj6gR/HBroytKOd/isMG3gJF/zBE1TBmTT18TXyzhg3O3SOOqGEhA==", "dependencies": { - "@smithy/protocol-http": "^4.1.7", - "@smithy/querystring-builder": "^3.0.10", - "@smithy/types": "^3.7.1", + "@smithy/protocol-http": "^4.1.8", + "@smithy/querystring-builder": "^3.0.11", + "@smithy/types": "^3.7.2", "@smithy/util-base64": "^3.0.0", "tslib": "^2.6.2" } }, "node_modules/@smithy/hash-blob-browser": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-3.1.9.tgz", - "integrity": "sha512-wOu78omaUuW5DE+PVWXiRKWRZLecARyP3xcq5SmkXUw9+utgN8HnSnBfrjL2B/4ZxgqPjaAJQkC/+JHf1ITVaQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-4.0.1.tgz", + "integrity": "sha512-rkFIrQOKZGS6i1D3gKJ8skJ0RlXqDvb1IyAphksaFOMzkn3v3I1eJ8m7OkLj0jf1McP63rcCEoLlkAn/HjcTRw==", "dependencies": { - "@smithy/chunked-blob-reader": "^4.0.0", - "@smithy/chunked-blob-reader-native": "^3.0.1", - "@smithy/types": "^3.7.1", + "@smithy/chunked-blob-reader": "^5.0.0", + "@smithy/chunked-blob-reader-native": "^4.0.0", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/hash-blob-browser/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@smithy/hash-node": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.10.tgz", - "integrity": "sha512-3zWGWCHI+FlJ5WJwx73Mw2llYR8aflVyZN5JhoqLxbdPZi6UyKSdCeXAWJw9ja22m6S6Tzz1KZ+kAaSwvydi0g==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.0.1.tgz", + "integrity": "sha512-TJ6oZS+3r2Xu4emVse1YPB3Dq3d8RkZDKcPr71Nj/lJsdAP1c7oFzYqEn1IBc915TsgLl2xIJNuxCz+gLbLE0w==", + "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.7.1", - "@smithy/util-buffer-from": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", + "@smithy/types": "^4.1.0", + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/hash-node/node_modules/@smithy/is-array-buffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.0.0.tgz", + "integrity": "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/hash-node/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/hash-node/node_modules/@smithy/util-buffer-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.0.0.tgz", + "integrity": "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/hash-node/node_modules/@smithy/util-utf8": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", + "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@smithy/hash-stream-node": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-3.1.9.tgz", - "integrity": "sha512-3XfHBjSP3oDWxLmlxnt+F+FqXpL3WlXs+XXaB6bV9Wo8BBu87fK1dSEsyH7Z4ZHRmwZ4g9lFMdf08m9hoX1iRA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-4.0.1.tgz", + "integrity": "sha512-U1rAE1fxmReCIr6D2o/4ROqAQX+GffZpyMt3d7njtGDr2pUNmAKRWa49gsNVhCh2vVAuf3wXzWwNr2YN8PAXIw==", "dependencies": { - "@smithy/types": "^3.7.1", - "@smithy/util-utf8": "^3.0.0", + "@smithy/types": "^4.1.0", + "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/hash-stream-node/node_modules/@smithy/is-array-buffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.0.0.tgz", + "integrity": "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/hash-stream-node/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/hash-stream-node/node_modules/@smithy/util-buffer-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.0.0.tgz", + "integrity": "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==", + "dependencies": { + "@smithy/is-array-buffer": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/hash-stream-node/node_modules/@smithy/util-utf8": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", + "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@smithy/invalid-dependency": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.10.tgz", - "integrity": "sha512-Lp2L65vFi+cj0vFMu2obpPW69DU+6O5g3086lmI4XcnRCG8PxvpWC7XyaVwJCxsZFzueHjXnrOH/E0pl0zikfA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.0.1.tgz", + "integrity": "sha512-gdudFPf4QRQ5pzj7HEnu6FhKRi61BfH/Gk5Yf6O0KiSbr1LlVhgjThcvjdu658VE6Nve8vaIWB8/fodmS1rBPQ==", + "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.7.1", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/invalid-dependency/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@smithy/is-array-buffer": { @@ -3272,40 +9282,115 @@ } }, "node_modules/@smithy/md5-js": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-3.0.10.tgz", - "integrity": "sha512-m3bv6dApflt3fS2Y1PyWPUtRP7iuBlvikEOGwu0HsCZ0vE7zcIX+dBoh3e+31/rddagw8nj92j0kJg2TfV+SJA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-4.0.1.tgz", + "integrity": "sha512-HLZ647L27APi6zXkZlzSFZIjpo8po45YiyjMGJZM3gyDY8n7dPGdmxIIljLm4gPt/7rRvutLTTkYJpZVfG5r+A==", "dependencies": { - "@smithy/types": "^3.7.1", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@smithy/middleware-content-length": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.12.tgz", - "integrity": "sha512-1mDEXqzM20yywaMDuf5o9ue8OkJ373lSPbaSjyEvkWdqELhFMyNNgKGWL/rCSf4KME8B+HlHKuR8u9kRj8HzEQ==", - "dependencies": { - "@smithy/protocol-http": "^4.1.7", - "@smithy/types": "^3.7.1", + "@smithy/types": "^4.1.0", + "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/md5-js/node_modules/@smithy/is-array-buffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.0.0.tgz", + "integrity": "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/md5-js/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/md5-js/node_modules/@smithy/util-buffer-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.0.0.tgz", + "integrity": "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==", + "dependencies": { + "@smithy/is-array-buffer": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/md5-js/node_modules/@smithy/util-utf8": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", + "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-content-length": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.0.1.tgz", + "integrity": "sha512-OGXo7w5EkB5pPiac7KNzVtfCW2vKBTZNuCctn++TTSOMpe6RZO/n6WEC1AxJINn3+vWLKW49uad3lo/u0WJ9oQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-content-length/node_modules/@smithy/protocol-http": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.0.1.tgz", + "integrity": "sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-content-length/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@smithy/middleware-endpoint": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.2.4.tgz", - "integrity": "sha512-TybiW2LA3kYVd3e+lWhINVu1o26KJbBwOpADnf0L4x/35vLVica77XVR5hvV9+kWeTGeSJ3IHTcYxbRxlbwhsg==", + "version": "3.2.8", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.2.8.tgz", + "integrity": "sha512-OEJZKVUEhMOqMs3ktrTWp7UvvluMJEvD5XgQwRePSbDg1VvBaL8pX8mwPltFn6wk1GySbcVwwyldL8S+iqnrEQ==", "dependencies": { - "@smithy/core": "^2.5.4", - "@smithy/middleware-serde": "^3.0.10", - "@smithy/node-config-provider": "^3.1.11", - "@smithy/shared-ini-file-loader": "^3.1.11", - "@smithy/types": "^3.7.1", - "@smithy/url-parser": "^3.0.10", - "@smithy/util-middleware": "^3.0.10", + "@smithy/core": "^2.5.7", + "@smithy/middleware-serde": "^3.0.11", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/shared-ini-file-loader": "^3.1.12", + "@smithy/types": "^3.7.2", + "@smithy/url-parser": "^3.0.11", + "@smithy/util-middleware": "^3.0.11", "tslib": "^2.6.2" }, "engines": { @@ -3313,30 +9398,385 @@ } }, "node_modules/@smithy/middleware-retry": { - "version": "3.0.28", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.28.tgz", - "integrity": "sha512-vK2eDfvIXG1U64FEUhYxoZ1JSj4XFbYWkK36iz02i3pFwWiDz1Q7jKhGTBCwx/7KqJNk4VS7d7cDLXFOvP7M+g==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.0.4.tgz", + "integrity": "sha512-wmxyUBGHaYUqul0wZiset4M39SMtDBOtUr2KpDuftKNN74Do9Y36Go6Eqzj9tL0mIPpr31ulB5UUtxcsCeGXsQ==", + "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^3.1.11", - "@smithy/protocol-http": "^4.1.7", - "@smithy/service-error-classification": "^3.0.10", - "@smithy/smithy-client": "^3.4.5", - "@smithy/types": "^3.7.1", - "@smithy/util-middleware": "^3.0.10", - "@smithy/util-retry": "^3.0.10", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/service-error-classification": "^4.0.1", + "@smithy/smithy-client": "^4.1.3", + "@smithy/types": "^4.1.0", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", "tslib": "^2.6.2", "uuid": "^9.0.1" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry/node_modules/@smithy/abort-controller": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.1.tgz", + "integrity": "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry/node_modules/@smithy/core": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.1.2.tgz", + "integrity": "sha512-htwQXkbdF13uwwDevz9BEzL5ABK+1sJpVQXywwGSH973AVOvisHNfpcB8A8761G6XgHoS2kHPqc9DqHJ2gp+/Q==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/middleware-serde": "^4.0.2", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-stream": "^4.0.2", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry/node_modules/@smithy/fetch-http-handler": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.0.1.tgz", + "integrity": "sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^5.0.1", + "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-base64": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry/node_modules/@smithy/is-array-buffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.0.0.tgz", + "integrity": "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry/node_modules/@smithy/middleware-endpoint": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.0.3.tgz", + "integrity": "sha512-YdbmWhQF5kIxZjWqPIgboVfi8i5XgiYMM7GGKFMTvBei4XjNQfNv8sukT50ITvgnWKKKpOtp0C0h7qixLgb77Q==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.1.2", + "@smithy/middleware-serde": "^4.0.2", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-middleware": "^4.0.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry/node_modules/@smithy/middleware-serde": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.0.2.tgz", + "integrity": "sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry/node_modules/@smithy/middleware-stack": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.0.1.tgz", + "integrity": "sha512-dHwDmrtR/ln8UTHpaIavRSzeIk5+YZTBtLnKwDW3G2t6nAupCiQUvNzNoHBpik63fwUaJPtlnMzXbQrNFWssIA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry/node_modules/@smithy/node-config-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.0.1.tgz", + "integrity": "sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry/node_modules/@smithy/node-http-handler": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.2.tgz", + "integrity": "sha512-X66H9aah9hisLLSnGuzRYba6vckuFtGE+a5DcHLliI/YlqKrGoxhisD5XbX44KyoeRzoNlGr94eTsMVHFAzPOw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/abort-controller": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry/node_modules/@smithy/property-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.1.tgz", + "integrity": "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry/node_modules/@smithy/protocol-http": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.0.1.tgz", + "integrity": "sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry/node_modules/@smithy/querystring-builder": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.0.1.tgz", + "integrity": "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "@smithy/util-uri-escape": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry/node_modules/@smithy/querystring-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.0.1.tgz", + "integrity": "sha512-Ma2XC7VS9aV77+clSFylVUnPZRindhB7BbmYiNOdr+CHt/kZNJoPP0cd3QxCnCFyPXC4eybmyE98phEHkqZ5Jw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry/node_modules/@smithy/shared-ini-file-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.1.tgz", + "integrity": "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry/node_modules/@smithy/smithy-client": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.1.3.tgz", + "integrity": "sha512-A2Hz85pu8BJJaYFdX8yb1yocqigyqBzn+OVaVgm+Kwi/DkN8vhN2kbDVEfADo6jXf5hPKquMLGA3UINA64UZ7A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.1.2", + "@smithy/middleware-endpoint": "^4.0.3", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-stream": "^4.0.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry/node_modules/@smithy/url-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.0.1.tgz", + "integrity": "sha512-gPXcIEUtw7VlK8f/QcruNXm7q+T5hhvGu9tl63LsJPZ27exB6dtNwvh2HIi0v7JcXJ5emBxB+CJxwaLEdJfA+g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/querystring-parser": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry/node_modules/@smithy/util-base64": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.0.0.tgz", + "integrity": "sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry/node_modules/@smithy/util-body-length-browser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.0.0.tgz", + "integrity": "sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry/node_modules/@smithy/util-buffer-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.0.0.tgz", + "integrity": "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry/node_modules/@smithy/util-hex-encoding": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.0.0.tgz", + "integrity": "sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry/node_modules/@smithy/util-middleware": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.0.1.tgz", + "integrity": "sha512-HiLAvlcqhbzhuiOa0Lyct5IIlyIz0PQO5dnMlmQ/ubYM46dPInB+3yQGkfxsk6Q24Y0n3/JmcA1v5iEhmOF5mA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry/node_modules/@smithy/util-stream": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.0.2.tgz", + "integrity": "sha512-0eZ4G5fRzIoewtHtwaYyl8g2C+osYOT4KClXgfdNEDAgkbe2TYPqcnw4GAWabqkZCax2ihRGPe9LZnsPdIUIHA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/node-http-handler": "^4.0.2", + "@smithy/types": "^4.1.0", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-hex-encoding": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry/node_modules/@smithy/util-uri-escape": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.0.0.tgz", + "integrity": "sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry/node_modules/@smithy/util-utf8": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", + "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@smithy/middleware-serde": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.10.tgz", - "integrity": "sha512-MnAuhh+dD14F428ubSJuRnmRsfOpxSzvRhaGVTvd/lrUDE3kxzCCmH8lnVTvoNQnV2BbJ4c15QwZ3UdQBtFNZA==", + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.11.tgz", + "integrity": "sha512-KzPAeySp/fOoQA82TpnwItvX8BBURecpx6ZMu75EZDkAcnPtO6vf7q4aH5QHs/F1s3/snQaSFbbUMcFFZ086Mw==", "dependencies": { - "@smithy/types": "^3.7.1", + "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, "engines": { @@ -3344,11 +9784,11 @@ } }, "node_modules/@smithy/middleware-stack": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.10.tgz", - "integrity": "sha512-grCHyoiARDBBGPyw2BeicpjgpsDFWZZxptbVKb3CRd/ZA15F/T6rZjCCuBUjJwdck1nwUuIxYtsS4H9DDpbP5w==", + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.11.tgz", + "integrity": "sha512-1HGo9a6/ikgOMrTrWL/WiN9N8GSVYpuRQO5kjstAq4CvV59bjqnh7TbdXGQ4vxLD3xlSjfBjq5t1SOELePsLnA==", "dependencies": { - "@smithy/types": "^3.7.1", + "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, "engines": { @@ -3356,13 +9796,13 @@ } }, "node_modules/@smithy/node-config-provider": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.11.tgz", - "integrity": "sha512-URq3gT3RpDikh/8MBJUB+QGZzfS7Bm6TQTqoh4CqE8NBuyPkWa5eUXj0XFcFfeZVgg3WMh1u19iaXn8FvvXxZw==", + "version": "3.1.12", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.12.tgz", + "integrity": "sha512-O9LVEu5J/u/FuNlZs+L7Ikn3lz7VB9hb0GtPT9MQeiBmtK8RSY3ULmsZgXhe6VAlgTw0YO+paQx4p8xdbs43vQ==", "dependencies": { - "@smithy/property-provider": "^3.1.10", - "@smithy/shared-ini-file-loader": "^3.1.11", - "@smithy/types": "^3.7.1", + "@smithy/property-provider": "^3.1.11", + "@smithy/shared-ini-file-loader": "^3.1.12", + "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, "engines": { @@ -3370,14 +9810,14 @@ } }, "node_modules/@smithy/node-http-handler": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.3.1.tgz", - "integrity": "sha512-fr+UAOMGWh6bn4YSEezBCpJn9Ukp9oR4D32sCjCo7U81evE11YePOQ58ogzyfgmjIO79YeOdfXXqr0jyhPQeMg==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.3.3.tgz", + "integrity": "sha512-BrpZOaZ4RCbcJ2igiSNG16S+kgAc65l/2hmxWdmhyoGWHTLlzQzr06PXavJp9OBlPEG/sHlqdxjWmjzV66+BSQ==", "dependencies": { - "@smithy/abort-controller": "^3.1.8", - "@smithy/protocol-http": "^4.1.7", - "@smithy/querystring-builder": "^3.0.10", - "@smithy/types": "^3.7.1", + "@smithy/abort-controller": "^3.1.9", + "@smithy/protocol-http": "^4.1.8", + "@smithy/querystring-builder": "^3.0.11", + "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, "engines": { @@ -3385,11 +9825,11 @@ } }, "node_modules/@smithy/property-provider": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.10.tgz", - "integrity": "sha512-n1MJZGTorTH2DvyTVj+3wXnd4CzjJxyXeOgnTlgNVFxaaMeT4OteEp4QrzF8p9ee2yg42nvyVK6R/awLCakjeQ==", + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.11.tgz", + "integrity": "sha512-I/+TMc4XTQ3QAjXfOcUWbSS073oOEAxgx4aZy8jHaf8JQnRkq2SZWw8+PfDtBvLUjcGMdxl+YwtzWe6i5uhL/A==", "dependencies": { - "@smithy/types": "^3.7.1", + "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, "engines": { @@ -3397,11 +9837,11 @@ } }, "node_modules/@smithy/protocol-http": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.7.tgz", - "integrity": "sha512-FP2LepWD0eJeOTm0SjssPcgqAlDFzOmRXqXmGhfIM52G7Lrox/pcpQf6RP4F21k0+O12zaqQt5fCDOeBtqY6Cg==", + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.8.tgz", + "integrity": "sha512-hmgIAVyxw1LySOwkgMIUN0kjN8TG9Nc85LJeEmEE/cNEe2rkHDUWhnJf2gxcSRFLWsyqWsrZGw40ROjUogg+Iw==", "dependencies": { - "@smithy/types": "^3.7.1", + "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, "engines": { @@ -3409,11 +9849,11 @@ } }, "node_modules/@smithy/querystring-builder": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.10.tgz", - "integrity": "sha512-nT9CQF3EIJtIUepXQuBFb8dxJi3WVZS3XfuDksxSCSn+/CzZowRLdhDn+2acbBv8R6eaJqPupoI/aRFIImNVPQ==", + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.11.tgz", + "integrity": "sha512-u+5HV/9uJaeLj5XTb6+IEF/dokWWkEqJ0XiaRRogyREmKGUgZnNecLucADLdauWFKUNbQfulHFEZEdjwEBjXRg==", "dependencies": { - "@smithy/types": "^3.7.1", + "@smithy/types": "^3.7.2", "@smithy/util-uri-escape": "^3.0.0", "tslib": "^2.6.2" }, @@ -3422,11 +9862,11 @@ } }, "node_modules/@smithy/querystring-parser": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.10.tgz", - "integrity": "sha512-Oa0XDcpo9SmjhiDD9ua2UyM3uU01ZTuIrNdZvzwUTykW1PM8o2yJvMh1Do1rY5sUQg4NDV70dMi0JhDx4GyxuQ==", + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.11.tgz", + "integrity": "sha512-Je3kFvCsFMnso1ilPwA7GtlbPaTixa3WwC+K21kmMZHsBEOZYQaqxcMqeFFoU7/slFjKDIpiiPydvdJm8Q/MCw==", "dependencies": { - "@smithy/types": "^3.7.1", + "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, "engines": { @@ -3434,22 +9874,35 @@ } }, "node_modules/@smithy/service-error-classification": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.10.tgz", - "integrity": "sha512-zHe642KCqDxXLuhs6xmHVgRwy078RfqxP2wRDpIyiF8EmsWXptMwnMwbVa50lw+WOGNrYm9zbaEg0oDe3PTtvQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.0.1.tgz", + "integrity": "sha512-3JNjBfOWpj/mYfjXJHB4Txc/7E4LVq32bwzE7m28GN79+M1f76XHflUaSUkhOriprPDzev9cX/M+dEB80DNDKA==", + "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.7.1" + "@smithy/types": "^4.1.0" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/service-error-classification/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@smithy/shared-ini-file-loader": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.11.tgz", - "integrity": "sha512-AUdrIZHFtUgmfSN4Gq9nHu3IkHMa1YDcN+s061Nfm+6pQ0mJy85YQDB0tZBCmls0Vuj22pLwDPmL92+Hvfwwlg==", + "version": "3.1.12", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.12.tgz", + "integrity": "sha512-1xKSGI+U9KKdbG2qDvIR9dGrw3CNx+baqJfyr0igKEpjbHL5stsqAesYBzHChYHlelWtb87VnLWlhvfCz13H8Q==", "dependencies": { - "@smithy/types": "^3.7.1", + "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, "engines": { @@ -3457,34 +9910,126 @@ } }, "node_modules/@smithy/signature-v4": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-4.2.3.tgz", - "integrity": "sha512-pPSQQ2v2vu9vc8iew7sszLd0O09I5TRc5zhY71KA+Ao0xYazIG+uLeHbTJfIWGO3BGVLiXjUr3EEeCcEQLjpWQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.0.1.tgz", + "integrity": "sha512-nCe6fQ+ppm1bQuw5iKoeJ0MJfz2os7Ic3GBjOkLOPtavbD1ONoyE3ygjBfz2ythFWm4YnRm6OxW+8p/m9uCoIA==", "dependencies": { - "@smithy/is-array-buffer": "^3.0.0", - "@smithy/protocol-http": "^4.1.7", - "@smithy/types": "^3.7.1", - "@smithy/util-hex-encoding": "^3.0.0", - "@smithy/util-middleware": "^3.0.10", - "@smithy/util-uri-escape": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", + "@smithy/is-array-buffer": "^4.0.0", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-hex-encoding": "^4.0.0", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-uri-escape": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/signature-v4/node_modules/@smithy/is-array-buffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.0.0.tgz", + "integrity": "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/signature-v4/node_modules/@smithy/protocol-http": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.0.1.tgz", + "integrity": "sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/signature-v4/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/signature-v4/node_modules/@smithy/util-buffer-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.0.0.tgz", + "integrity": "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==", + "dependencies": { + "@smithy/is-array-buffer": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/signature-v4/node_modules/@smithy/util-hex-encoding": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.0.0.tgz", + "integrity": "sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/signature-v4/node_modules/@smithy/util-middleware": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.0.1.tgz", + "integrity": "sha512-HiLAvlcqhbzhuiOa0Lyct5IIlyIz0PQO5dnMlmQ/ubYM46dPInB+3yQGkfxsk6Q24Y0n3/JmcA1v5iEhmOF5mA==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/signature-v4/node_modules/@smithy/util-uri-escape": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.0.0.tgz", + "integrity": "sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/signature-v4/node_modules/@smithy/util-utf8": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", + "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@smithy/smithy-client": { - "version": "3.4.5", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.4.5.tgz", - "integrity": "sha512-k0sybYT9zlP79sIKd1XGm4TmK0AS1nA2bzDHXx7m0nGi3RQ8dxxQUs4CPkSmQTKAo+KF9aINU3KzpGIpV7UoMw==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.7.0.tgz", + "integrity": "sha512-9wYrjAZFlqWhgVo3C4y/9kpc68jgiSsKUnsFPzr/MSiRL93+QRDafGTfhhKAb2wsr69Ru87WTiqSfQusSmWipA==", "dependencies": { - "@smithy/core": "^2.5.4", - "@smithy/middleware-endpoint": "^3.2.4", - "@smithy/middleware-stack": "^3.0.10", - "@smithy/protocol-http": "^4.1.7", - "@smithy/types": "^3.7.1", - "@smithy/util-stream": "^3.3.1", + "@smithy/core": "^2.5.7", + "@smithy/middleware-endpoint": "^3.2.8", + "@smithy/middleware-stack": "^3.0.11", + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", + "@smithy/util-stream": "^3.3.4", "tslib": "^2.6.2" }, "engines": { @@ -3492,9 +10037,9 @@ } }, "node_modules/@smithy/types": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.7.1.tgz", - "integrity": "sha512-XKLcLXZY7sUQgvvWyeaL/qwNPp6V3dWcUjqrQKjSb+tzYiCy340R/c64LV5j+Tnb2GhmunEX0eou+L+m2hJNYA==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.7.2.tgz", + "integrity": "sha512-bNwBYYmN8Eh9RyjS1p2gW6MIhSO2rl7X9QeLM8iTdcGRP+eDiIWDt66c9IysCc22gefKszZv+ubV9qZc7hdESg==", "dependencies": { "tslib": "^2.6.2" }, @@ -3503,12 +10048,12 @@ } }, "node_modules/@smithy/url-parser": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.10.tgz", - "integrity": "sha512-j90NUalTSBR2NaZTuruEgavSdh8MLirf58LoGSk4AtQfyIymogIhgnGUU2Mga2bkMkpSoC9gxb74xBXL5afKAQ==", + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.11.tgz", + "integrity": "sha512-TmlqXkSk8ZPhfc+SQutjmFr5FjC0av3GZP4B/10caK1SbRwe/v+Wzu/R6xEKxoNqL+8nY18s1byiy6HqPG37Aw==", "dependencies": { - "@smithy/querystring-parser": "^3.0.10", - "@smithy/types": "^3.7.1", + "@smithy/querystring-parser": "^3.0.11", + "@smithy/types": "^3.7.2", "tslib": "^2.6.2" } }, @@ -3534,14 +10079,15 @@ } }, "node_modules/@smithy/util-body-length-node": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-3.0.0.tgz", - "integrity": "sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-4.0.0.tgz", + "integrity": "sha512-q0iDP3VsZzqJyje8xJWEJCNIu3lktUGVoSy1KB0UWym2CL1siV3artm+u1DFYTLejpsrdGyCSWBdGNjJzfDPjg==", + "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, "node_modules/@smithy/util-buffer-from": { @@ -3557,59 +10103,823 @@ } }, "node_modules/@smithy/util-config-provider": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-3.0.0.tgz", - "integrity": "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-4.0.0.tgz", + "integrity": "sha512-L1RBVzLyfE8OXH+1hsJ8p+acNUSirQnWQ6/EgpchV88G6zGBTDPdXiiExei6Z1wR2RxYvxY/XLw6AMNCCt8H3w==", "dependencies": { "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, "node_modules/@smithy/util-defaults-mode-browser": { - "version": "3.0.28", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.28.tgz", - "integrity": "sha512-6bzwAbZpHRFVJsOztmov5PGDmJYsbNSoIEfHSJJyFLzfBGCCChiO3od9k7E/TLgrCsIifdAbB9nqbVbyE7wRUw==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.0.4.tgz", + "integrity": "sha512-Ej1bV5sbrIfH++KnWxjjzFNq9nyP3RIUq2c9Iqq7SmMO/idUR24sqvKH2LUQFTSPy/K7G4sB2m8n7YYlEAfZaw==", + "license": "Apache-2.0", "dependencies": { - "@smithy/property-provider": "^3.1.10", - "@smithy/smithy-client": "^3.4.5", - "@smithy/types": "^3.7.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/smithy-client": "^4.1.3", + "@smithy/types": "^4.1.0", "bowser": "^2.11.0", "tslib": "^2.6.2" }, "engines": { - "node": ">= 10.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser/node_modules/@smithy/abort-controller": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.1.tgz", + "integrity": "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser/node_modules/@smithy/core": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.1.2.tgz", + "integrity": "sha512-htwQXkbdF13uwwDevz9BEzL5ABK+1sJpVQXywwGSH973AVOvisHNfpcB8A8761G6XgHoS2kHPqc9DqHJ2gp+/Q==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/middleware-serde": "^4.0.2", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-stream": "^4.0.2", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser/node_modules/@smithy/fetch-http-handler": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.0.1.tgz", + "integrity": "sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^5.0.1", + "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-base64": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser/node_modules/@smithy/is-array-buffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.0.0.tgz", + "integrity": "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser/node_modules/@smithy/middleware-endpoint": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.0.3.tgz", + "integrity": "sha512-YdbmWhQF5kIxZjWqPIgboVfi8i5XgiYMM7GGKFMTvBei4XjNQfNv8sukT50ITvgnWKKKpOtp0C0h7qixLgb77Q==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.1.2", + "@smithy/middleware-serde": "^4.0.2", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-middleware": "^4.0.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser/node_modules/@smithy/middleware-serde": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.0.2.tgz", + "integrity": "sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser/node_modules/@smithy/middleware-stack": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.0.1.tgz", + "integrity": "sha512-dHwDmrtR/ln8UTHpaIavRSzeIk5+YZTBtLnKwDW3G2t6nAupCiQUvNzNoHBpik63fwUaJPtlnMzXbQrNFWssIA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser/node_modules/@smithy/node-config-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.0.1.tgz", + "integrity": "sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser/node_modules/@smithy/node-http-handler": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.2.tgz", + "integrity": "sha512-X66H9aah9hisLLSnGuzRYba6vckuFtGE+a5DcHLliI/YlqKrGoxhisD5XbX44KyoeRzoNlGr94eTsMVHFAzPOw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/abort-controller": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser/node_modules/@smithy/property-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.1.tgz", + "integrity": "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser/node_modules/@smithy/protocol-http": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.0.1.tgz", + "integrity": "sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser/node_modules/@smithy/querystring-builder": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.0.1.tgz", + "integrity": "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "@smithy/util-uri-escape": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser/node_modules/@smithy/querystring-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.0.1.tgz", + "integrity": "sha512-Ma2XC7VS9aV77+clSFylVUnPZRindhB7BbmYiNOdr+CHt/kZNJoPP0cd3QxCnCFyPXC4eybmyE98phEHkqZ5Jw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser/node_modules/@smithy/shared-ini-file-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.1.tgz", + "integrity": "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser/node_modules/@smithy/smithy-client": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.1.3.tgz", + "integrity": "sha512-A2Hz85pu8BJJaYFdX8yb1yocqigyqBzn+OVaVgm+Kwi/DkN8vhN2kbDVEfADo6jXf5hPKquMLGA3UINA64UZ7A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.1.2", + "@smithy/middleware-endpoint": "^4.0.3", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-stream": "^4.0.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser/node_modules/@smithy/url-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.0.1.tgz", + "integrity": "sha512-gPXcIEUtw7VlK8f/QcruNXm7q+T5hhvGu9tl63LsJPZ27exB6dtNwvh2HIi0v7JcXJ5emBxB+CJxwaLEdJfA+g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/querystring-parser": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser/node_modules/@smithy/util-base64": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.0.0.tgz", + "integrity": "sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser/node_modules/@smithy/util-body-length-browser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.0.0.tgz", + "integrity": "sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser/node_modules/@smithy/util-buffer-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.0.0.tgz", + "integrity": "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser/node_modules/@smithy/util-hex-encoding": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.0.0.tgz", + "integrity": "sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser/node_modules/@smithy/util-middleware": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.0.1.tgz", + "integrity": "sha512-HiLAvlcqhbzhuiOa0Lyct5IIlyIz0PQO5dnMlmQ/ubYM46dPInB+3yQGkfxsk6Q24Y0n3/JmcA1v5iEhmOF5mA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser/node_modules/@smithy/util-stream": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.0.2.tgz", + "integrity": "sha512-0eZ4G5fRzIoewtHtwaYyl8g2C+osYOT4KClXgfdNEDAgkbe2TYPqcnw4GAWabqkZCax2ihRGPe9LZnsPdIUIHA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/node-http-handler": "^4.0.2", + "@smithy/types": "^4.1.0", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-hex-encoding": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser/node_modules/@smithy/util-uri-escape": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.0.0.tgz", + "integrity": "sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser/node_modules/@smithy/util-utf8": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", + "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@smithy/util-defaults-mode-node": { - "version": "3.0.28", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.28.tgz", - "integrity": "sha512-78ENJDorV1CjOQselGmm3+z7Yqjj5HWCbjzh0Ixuq736dh1oEnD9sAttSBNSLlpZsX8VQnmERqA2fEFlmqWn8w==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.0.4.tgz", + "integrity": "sha512-HE1I7gxa6yP7ZgXPCFfZSDmVmMtY7SHqzFF55gM/GPegzZKaQWZZ+nYn9C2Cc3JltCMyWe63VPR3tSFDEvuGjw==", + "license": "Apache-2.0", "dependencies": { - "@smithy/config-resolver": "^3.0.12", - "@smithy/credential-provider-imds": "^3.2.7", - "@smithy/node-config-provider": "^3.1.11", - "@smithy/property-provider": "^3.1.10", - "@smithy/smithy-client": "^3.4.5", - "@smithy/types": "^3.7.1", + "@smithy/config-resolver": "^4.0.1", + "@smithy/credential-provider-imds": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/smithy-client": "^4.1.3", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">= 10.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node/node_modules/@smithy/abort-controller": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.1.tgz", + "integrity": "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node/node_modules/@smithy/core": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.1.2.tgz", + "integrity": "sha512-htwQXkbdF13uwwDevz9BEzL5ABK+1sJpVQXywwGSH973AVOvisHNfpcB8A8761G6XgHoS2kHPqc9DqHJ2gp+/Q==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/middleware-serde": "^4.0.2", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-stream": "^4.0.2", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node/node_modules/@smithy/fetch-http-handler": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.0.1.tgz", + "integrity": "sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^5.0.1", + "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-base64": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node/node_modules/@smithy/is-array-buffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.0.0.tgz", + "integrity": "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node/node_modules/@smithy/middleware-endpoint": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.0.3.tgz", + "integrity": "sha512-YdbmWhQF5kIxZjWqPIgboVfi8i5XgiYMM7GGKFMTvBei4XjNQfNv8sukT50ITvgnWKKKpOtp0C0h7qixLgb77Q==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.1.2", + "@smithy/middleware-serde": "^4.0.2", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-middleware": "^4.0.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node/node_modules/@smithy/middleware-serde": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.0.2.tgz", + "integrity": "sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node/node_modules/@smithy/middleware-stack": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.0.1.tgz", + "integrity": "sha512-dHwDmrtR/ln8UTHpaIavRSzeIk5+YZTBtLnKwDW3G2t6nAupCiQUvNzNoHBpik63fwUaJPtlnMzXbQrNFWssIA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node/node_modules/@smithy/node-config-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.0.1.tgz", + "integrity": "sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node/node_modules/@smithy/node-http-handler": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.2.tgz", + "integrity": "sha512-X66H9aah9hisLLSnGuzRYba6vckuFtGE+a5DcHLliI/YlqKrGoxhisD5XbX44KyoeRzoNlGr94eTsMVHFAzPOw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/abort-controller": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node/node_modules/@smithy/property-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.1.tgz", + "integrity": "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node/node_modules/@smithy/protocol-http": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.0.1.tgz", + "integrity": "sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node/node_modules/@smithy/querystring-builder": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.0.1.tgz", + "integrity": "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "@smithy/util-uri-escape": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node/node_modules/@smithy/querystring-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.0.1.tgz", + "integrity": "sha512-Ma2XC7VS9aV77+clSFylVUnPZRindhB7BbmYiNOdr+CHt/kZNJoPP0cd3QxCnCFyPXC4eybmyE98phEHkqZ5Jw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node/node_modules/@smithy/shared-ini-file-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.1.tgz", + "integrity": "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node/node_modules/@smithy/smithy-client": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.1.3.tgz", + "integrity": "sha512-A2Hz85pu8BJJaYFdX8yb1yocqigyqBzn+OVaVgm+Kwi/DkN8vhN2kbDVEfADo6jXf5hPKquMLGA3UINA64UZ7A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.1.2", + "@smithy/middleware-endpoint": "^4.0.3", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-stream": "^4.0.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node/node_modules/@smithy/url-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.0.1.tgz", + "integrity": "sha512-gPXcIEUtw7VlK8f/QcruNXm7q+T5hhvGu9tl63LsJPZ27exB6dtNwvh2HIi0v7JcXJ5emBxB+CJxwaLEdJfA+g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/querystring-parser": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node/node_modules/@smithy/util-base64": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.0.0.tgz", + "integrity": "sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node/node_modules/@smithy/util-body-length-browser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.0.0.tgz", + "integrity": "sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node/node_modules/@smithy/util-buffer-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.0.0.tgz", + "integrity": "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node/node_modules/@smithy/util-hex-encoding": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.0.0.tgz", + "integrity": "sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node/node_modules/@smithy/util-middleware": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.0.1.tgz", + "integrity": "sha512-HiLAvlcqhbzhuiOa0Lyct5IIlyIz0PQO5dnMlmQ/ubYM46dPInB+3yQGkfxsk6Q24Y0n3/JmcA1v5iEhmOF5mA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node/node_modules/@smithy/util-stream": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.0.2.tgz", + "integrity": "sha512-0eZ4G5fRzIoewtHtwaYyl8g2C+osYOT4KClXgfdNEDAgkbe2TYPqcnw4GAWabqkZCax2ihRGPe9LZnsPdIUIHA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/node-http-handler": "^4.0.2", + "@smithy/types": "^4.1.0", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-hex-encoding": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node/node_modules/@smithy/util-uri-escape": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.0.0.tgz", + "integrity": "sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node/node_modules/@smithy/util-utf8": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", + "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@smithy/util-endpoints": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.1.6.tgz", - "integrity": "sha512-mFV1t3ndBh0yZOJgWxO9J/4cHZVn5UG1D8DeCc6/echfNkeEJWu9LD7mgGH5fHrEdR7LDoWw7PQO6QiGpHXhgA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.0.1.tgz", + "integrity": "sha512-zVdUENQpdtn9jbpD9SCFK4+aSiavRb9BxEtw9ZGUR1TYo6bBHbIoi7VkrFQ0/RwZlzx0wRBaRmPclj8iAoJCLA==", + "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^3.1.11", - "@smithy/types": "^3.7.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-endpoints/node_modules/@smithy/node-config-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.0.1.tgz", + "integrity": "sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-endpoints/node_modules/@smithy/property-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.1.tgz", + "integrity": "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-endpoints/node_modules/@smithy/shared-ini-file-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.1.tgz", + "integrity": "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-endpoints/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@smithy/util-hex-encoding": { @@ -3624,11 +10934,11 @@ } }, "node_modules/@smithy/util-middleware": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.10.tgz", - "integrity": "sha512-eJO+/+RsrG2RpmY68jZdwQtnfsxjmPxzMlQpnHKjFPwrYqvlcT+fHdT+ZVwcjlWSrByOhGr9Ff2GG17efc192A==", + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.11.tgz", + "integrity": "sha512-dWpyc1e1R6VoXrwLoLDd57U1z6CwNSdkM69Ie4+6uYh2GC7Vg51Qtan7ITzczuVpqezdDTKJGJB95fFvvjU/ow==", "dependencies": { - "@smithy/types": "^3.7.1", + "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, "engines": { @@ -3636,26 +10946,39 @@ } }, "node_modules/@smithy/util-retry": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.10.tgz", - "integrity": "sha512-1l4qatFp4PiU6j7UsbasUHL2VU023NRB/gfaa1M0rDqVrRN4g3mCArLRyH3OuktApA4ye+yjWQHjdziunw2eWA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.0.1.tgz", + "integrity": "sha512-WmRHqNVwn3kI3rKk1LsKcVgPBG6iLTBGC1iYOV3GQegwJ3E8yjzHytPt26VNzOWr1qu0xE03nK0Ug8S7T7oufw==", + "license": "Apache-2.0", "dependencies": { - "@smithy/service-error-classification": "^3.0.10", - "@smithy/types": "^3.7.1", + "@smithy/service-error-classification": "^4.0.1", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-retry/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@smithy/util-stream": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.3.1.tgz", - "integrity": "sha512-Ff68R5lJh2zj+AUTvbAU/4yx+6QPRzg7+pI7M1FbtQHcRIp7xvguxVsQBKyB3fwiOwhAKu0lnNyYBaQfSW6TNw==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.3.4.tgz", + "integrity": "sha512-SGhGBG/KupieJvJSZp/rfHHka8BFgj56eek9px4pp7lZbOF+fRiVr4U7A3y3zJD8uGhxq32C5D96HxsTC9BckQ==", "dependencies": { - "@smithy/fetch-http-handler": "^4.1.1", - "@smithy/node-http-handler": "^3.3.1", - "@smithy/types": "^3.7.1", + "@smithy/fetch-http-handler": "^4.1.3", + "@smithy/node-http-handler": "^3.3.3", + "@smithy/types": "^3.7.2", "@smithy/util-base64": "^3.0.0", "@smithy/util-buffer-from": "^3.0.0", "@smithy/util-hex-encoding": "^3.0.0", @@ -3690,16 +11013,39 @@ } }, "node_modules/@smithy/util-waiter": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-3.1.9.tgz", - "integrity": "sha512-/aMXPANhMOlMPjfPtSrDfPeVP8l56SJlz93xeiLmhLe5xvlXA5T3abZ2ilEsDEPeY9T/wnN/vNGn9wa1SbufWA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-4.0.2.tgz", + "integrity": "sha512-piUTHyp2Axx3p/kc2CIJkYSv0BAaheBQmbACZgQSSfWUumWNW+R1lL+H9PDBxKJkvOeEX+hKYEFiwO8xagL8AQ==", "dependencies": { - "@smithy/abort-controller": "^3.1.8", - "@smithy/types": "^3.7.1", + "@smithy/abort-controller": "^4.0.1", + "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-waiter/node_modules/@smithy/abort-controller": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.1.tgz", + "integrity": "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-waiter/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@tootallnate/once": { @@ -3789,9 +11135,9 @@ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" }, "node_modules/@types/jsonwebtoken": { - "version": "9.0.6", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.6.tgz", - "integrity": "sha512-/5hndP5dCjloafCXns6SZyESp3Ldq7YjH3zwzwczYnjxIT0Fqzk5ROSYVGfFyczIue7IUEj8hkvLbPoLQ18vQw==", + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.7.tgz", + "integrity": "sha512-ugo316mmTYBl2g81zDFnZ7cfxlut3o+/EQdaP7J8QN2kY6lJ22hmQYCK5EHcJHbrW+dkCGSCPgbG8JtYj6qSrg==", "dependencies": { "@types/node": "*" } @@ -3807,17 +11153,17 @@ "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==" }, "node_modules/@types/node": { - "version": "22.5.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.5.tgz", - "integrity": "sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==", + "version": "22.10.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz", + "integrity": "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==", "dependencies": { - "undici-types": "~6.19.2" + "undici-types": "~6.20.0" } }, "node_modules/@types/node-fetch": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", - "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==", "dependencies": { "@types/node": "*", "form-data": "^4.0.0" @@ -3851,14 +11197,15 @@ } }, "node_modules/@types/request/node_modules/form-data": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", - "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.2.tgz", + "integrity": "sha512-GgwY0PS7DbXqajuGf4OYlsrIu3zgxD6Vvql43IBhm6MahqA5SK/7mwhtNj2AdH2z35YR34ujJ7BN+3fFC3jP5Q==", "optional": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" + "mime-types": "^2.1.12", + "safe-buffer": "^5.2.1" }, "engines": { "node": ">= 0.12" @@ -4102,9 +11449,9 @@ } }, "node_modules/assert-options": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/assert-options/-/assert-options-0.8.1.tgz", - "integrity": "sha512-5lNGRB5g5i2bGIzb+J1QQE1iKU/WEMVBReFIc5pPDWjcPj23otPL0eI6PB2v7QPi0qU6Mhym5D3y0ZiSIOf3GA==", + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/assert-options/-/assert-options-0.8.2.tgz", + "integrity": "sha512-XaXoMxY0zuwAb0YuZjxIm8FeWvNq0aWNIbrzHhFjme8Smxw4JlPoyrAKQ6808k5UvQdhvnWqHZCphq5mXd4TDA==", "engines": { "node": ">=10.0.0" } @@ -4295,9 +11642,9 @@ } }, "node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==" }, "node_modules/body-parser": { "version": "1.20.3", @@ -4392,9 +11739,9 @@ } }, "node_modules/bson": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-6.8.0.tgz", - "integrity": "sha512-iOJg8pr7wq2tg/zSlCCHMi3hMm5JTOxLTagf3zxhcenHsFp+c6uOs6K7W5UE7A4QIJGtqh/ZovFNMP4mOPJynQ==", + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.10.1.tgz", + "integrity": "sha512-P92xmHDQjSKPLHqFxefqMxASNq/aWJMEZugpCjf+AF/pgcUpMMQCg7t7+ewko0/u8AapvF3luf/FoehddEK+sA==", "engines": { "node": ">=16.20.1" } @@ -4903,9 +12250,9 @@ } }, "node_modules/cross-spawn": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.5.tgz", - "integrity": "sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -4945,18 +12292,21 @@ } }, "node_modules/date-fns": { - "version": "2.30.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", - "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", - "dependencies": { - "@babel/runtime": "^7.21.0" - }, - "engines": { - "node": ">=0.11" - }, + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "peer": true, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/date-fns" + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, + "node_modules/date-fns-tz": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/date-fns-tz/-/date-fns-tz-3.2.0.tgz", + "integrity": "sha512-sg8HqoTEulcbbbVXeg84u5UnlsQa8GS5QXMqjjYIhS4abEVVKIUwe0/l/UhrZdKaL/W5eWZNlbTeEIiOXTcsBQ==", + "peerDependencies": { + "date-fns": "^3.0.0 || ^4.0.0" } }, "node_modules/debug": { @@ -5003,20 +12353,6 @@ "node": ">=4" } }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/decompress-tar": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", @@ -5121,14 +12457,6 @@ "node": ">=0.10.0" } }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "engines": { - "node": ">=4.0.0" - } - }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -5198,18 +12526,10 @@ "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/detect-libc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", - "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", - "engines": { - "node": ">=8" - } - }, "node_modules/dotenv": { - "version": "16.4.5", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", - "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "version": "16.4.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", "engines": { "node": ">=12" }, @@ -5307,6 +12627,7 @@ "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "devOptional": true, "dependencies": { "once": "^1.4.0" } @@ -5411,25 +12732,26 @@ } }, "node_modules/eslint": { - "version": "9.14.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.14.0.tgz", - "integrity": "sha512-c2FHsVBr87lnUtjP4Yhvk4yEhKrQavGafRA/Se1ouse8PfbfC/Qh9Mxa00yWsZRlqeUB9raXip0aiiUZkgnr9g==", + "version": "9.20.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.20.0.tgz", + "integrity": "sha512-aL4F8167Hg4IvsW89ejnpTwx+B/UQRzJPGgbIOl+4XqffWsahVVsLEWoZvnrVuwpWmnRd7XeXmQI1zlKcFDteA==", + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.18.0", - "@eslint/core": "^0.7.0", - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.14.0", - "@eslint/plugin-kit": "^0.2.0", + "@eslint/config-array": "^0.19.0", + "@eslint/core": "^0.11.0", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "9.20.0", + "@eslint/plugin-kit": "^0.2.5", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.0", + "@humanwhocodes/retry": "^0.4.1", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", + "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.2.0", @@ -5448,8 +12770,7 @@ "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "text-table": "^0.2.0" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" @@ -5489,6 +12810,18 @@ "node": ">=10" } }, + "node_modules/eslint/node_modules/@eslint/core": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.11.0.tgz", + "integrity": "sha512-DWUB2pksgNEb6Bz2fggIy1wh6fGgZP4Xyy/Mt0QZPiloKKXerbqq9D3SBQTlCRYOrcRPu4vuz+CGjwdfqxnoWA==", + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/eslint/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -5745,18 +13078,10 @@ "node": ">=0.4.x" } }, - "node_modules/expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "engines": { - "node": ">=6" - } - }, "node_modules/expo-server-sdk": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/expo-server-sdk/-/expo-server-sdk-3.10.0.tgz", - "integrity": "sha512-isymUVz18Syp9G+TPs2MVZ6WdMoyLw8hDLhpywOd8JqM6iGTka6Dr8Dzq7mjGQ8C8486rxLawZx/W+ps+vkjLQ==", + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/expo-server-sdk/-/expo-server-sdk-3.13.0.tgz", + "integrity": "sha512-EeGs8PlXmnP2uDpjVhnclQmlua3A0swEj3BzqoRiHfU4WPsN5v3eHhqjjwl+Lf2rleKW2L9lhWp6sCL1vPMnAg==", "dependencies": { "node-fetch": "^2.6.0", "promise-limit": "^2.7.0", @@ -5764,9 +13089,9 @@ } }, "node_modules/express": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", - "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", @@ -5787,7 +13112,7 @@ "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.10", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", @@ -5802,12 +13127,16 @@ }, "engines": { "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/express-rate-limit": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.3.1.tgz", - "integrity": "sha512-BbaryvkY4wEgDqLgD18/NSy2lDO2jTuT9Y8c1Mpx0X63Yz0sYd5zN6KPe7UvpuSVvV33T6RaE1o1IVZQjHMYgw==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.4.1.tgz", + "integrity": "sha512-KS3efpnpIDVIXopMc65EMbWbUht7qvTCdtCR2dD/IZmi9MIkopYESwyRqLgv8Pfu589+KqDqOdzJWW7AHoACeg==", "engines": { "node": ">= 16" }, @@ -5860,17 +13189,12 @@ "node >=0.6.0" ] }, - "node_modules/farmhash": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/farmhash/-/farmhash-3.3.1.tgz", - "integrity": "sha512-XUizHanzlr/v7suBr/o85HSakOoWh6HKXZjFYl5C2+Gj0f0rkw+XTUZzrd9odDsgI9G5tRUcF4wSbKaX04T0DQ==", - "hasInstallScript": true, - "dependencies": { - "node-addon-api": "^5.1.0", - "prebuild-install": "^7.1.2" - }, + "node_modules/farmhash-modern": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/farmhash-modern/-/farmhash-modern-1.1.0.tgz", + "integrity": "sha512-6ypT4XfgqJk/F3Yuv4SX26I3doUjt0GTG4a+JgWxXQpxXzTBq8fPUeGHfcYMMDPHJHm3yPOSjaeBwBGAHWXCdA==", "engines": { - "node": ">=10" + "node": ">=18.0.0" } }, "node_modules/fast-deep-equal": { @@ -6093,42 +13417,41 @@ } }, "node_modules/firebase-admin": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-12.1.1.tgz", - "integrity": "sha512-Nuoxk//gaYrspS7TvwBINdGvFhh2QeiaWpRW6+PJ+tWyn2/CugBc7jKa1NaBg0AvhGSOXFOCIsXhzCzHA47Rew==", + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-13.0.1.tgz", + "integrity": "sha512-sKQ/Yw8o/WdC9qTKvuLMBjTbdcBISIXW4+M9PXk0bNjxEbZf1Er7EVq47eRb5+bnKof10xlns6zAIbj4tmSexg==", "dependencies": { - "@fastify/busboy": "^2.1.0", - "@firebase/database-compat": "^1.0.2", - "@firebase/database-types": "^1.0.0", - "@types/node": "^20.10.3", - "farmhash": "^3.3.1", + "@fastify/busboy": "^3.0.0", + "@firebase/database-compat": "^2.0.0", + "@firebase/database-types": "^1.0.6", + "@types/node": "^22.8.7", + "farmhash-modern": "^1.1.0", + "google-auth-library": "^9.14.2", "jsonwebtoken": "^9.0.0", "jwks-rsa": "^3.1.0", - "long": "^5.2.3", "node-forge": "^1.3.1", - "uuid": "^9.0.0" + "uuid": "^11.0.2" }, "engines": { - "node": ">=14" + "node": ">=18" }, "optionalDependencies": { - "@google-cloud/firestore": "^7.7.0", - "@google-cloud/storage": "^7.7.0" + "@google-cloud/firestore": "^7.10.0", + "@google-cloud/storage": "^7.14.0" } }, - "node_modules/firebase-admin/node_modules/@types/node": { - "version": "20.16.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.5.tgz", - "integrity": "sha512-VwYCweNo3ERajwy0IUlqqcyZ8/A7Zwa9ZP3MnENWcB11AejO+tLy3pu850goUW2FC/IJMdZUfKpX/yxL1gymCA==", - "dependencies": { - "undici-types": "~6.19.2" + "node_modules/firebase-admin/node_modules/uuid": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.0.3.tgz", + "integrity": "sha512-d0z310fCWv5dJwnX1Y/MncBAqGMKEzlBb1AOf7z9K8ALnd0utBX/msg/fA0+sbyN1ihbMsLhrBlnl1ak7Wa0rg==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/esm/bin/uuid" } }, - "node_modules/firebase-admin/node_modules/long": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", - "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" - }, "node_modules/flat-cache": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", @@ -6152,9 +13475,9 @@ "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" }, "node_modules/follow-redirects": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", "funding": [ { "type": "individual", @@ -6262,7 +13585,8 @@ "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true }, "node_modules/fs-minipass": { "version": "2.1.0", @@ -6381,15 +13705,60 @@ } }, "node_modules/gcp-metadata": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.0.tgz", - "integrity": "sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-5.3.0.tgz", + "integrity": "sha512-FNTkdNEnBdlqF2oatizolQqNANMrcqJt6AAYt99B3y1aLLC8Hc5IOBb+ZnnzllodEEf6xMBp6wRcBbc16fa65w==", + "optional": true, + "peer": true, "dependencies": { - "gaxios": "^6.0.0", + "gaxios": "^5.0.0", "json-bigint": "^1.0.0" }, "engines": { - "node": ">=14" + "node": ">=12" + } + }, + "node_modules/gcp-metadata/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "optional": true, + "peer": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/gcp-metadata/node_modules/gaxios": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-5.1.3.tgz", + "integrity": "sha512-95hVgBRgEIRQQQHIbnxBXeHbW4TqFk4ZDJW7wmVtvYar72FdhRIo1UGOLS2eRAKCPEdPBWu+M7+A33D9CdX9rA==", + "optional": true, + "peer": true, + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/gcp-metadata/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "optional": true, + "peer": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" } }, "node_modules/generate-api-key": { @@ -6486,11 +13855,6 @@ "assert-plus": "^1.0.0" } }, - "node_modules/github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" - }, "node_modules/glob": { "version": "10.4.5", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", @@ -6555,9 +13919,9 @@ } }, "node_modules/google-auth-library": { - "version": "9.13.0", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.13.0.tgz", - "integrity": "sha512-p9Y03Uzp/Igcs36zAaB0XTSwZ8Y0/tpYiz5KIde5By+H9DCVUSYtDWZu6aFXsWTqENMb8BD/pDT3hR8NVrPkfA==", + "version": "9.15.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.15.0.tgz", + "integrity": "sha512-7ccSEJFDFO7exFbO6NRyC+xH8/mZ1GZGG2xxx9iHxZWcjUjJpjWxIMw3cofAKcueZ6DATiukmmprD7yavQHOyQ==", "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", @@ -6570,6 +13934,18 @@ "node": ">=14" } }, + "node_modules/google-auth-library/node_modules/gcp-metadata": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.0.tgz", + "integrity": "sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg==", + "dependencies": { + "gaxios": "^6.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/google-gax": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-4.4.1.tgz", @@ -6639,9 +14015,9 @@ "dev": true }, "node_modules/graphql": { - "version": "16.8.1", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz", - "integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==", + "version": "16.9.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.9.0.tgz", + "integrity": "sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==", "engines": { "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" } @@ -7019,11 +14395,6 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" - }, "node_modules/intersect": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/intersect/-/intersect-1.0.1.tgz", @@ -7033,6 +14404,8 @@ "version": "9.0.5", "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "optional": true, + "peer": true, "dependencies": { "jsbn": "1.1.0", "sprintf-js": "^1.1.3" @@ -7044,12 +14417,16 @@ "node_modules/ip-address/node_modules/jsbn": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", - "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "optional": true, + "peer": true }, "node_modules/ip-address/node_modules/sprintf-js": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==" + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "optional": true, + "peer": true }, "node_modules/ipaddr.js": { "version": "1.9.1", @@ -7401,23 +14778,25 @@ } }, "node_modules/jasmine": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-5.4.0.tgz", - "integrity": "sha512-E2u4ylX5tgGYvbynImU6EUBKKrSVB1L72FEPjGh4M55ov1VsxR26RA2JU91L9YSPFgcjo4mCLyKn/QXvEYGBkA==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-5.6.0.tgz", + "integrity": "sha512-6frlW22jhgRjtlp68QY/DDVCUfrYqmSxDBWM13mrBzYQGx1XITfVcJltnY15bk8B5cRfN5IpKvemkDiDTSRCsA==", "dev": true, + "license": "MIT", "dependencies": { "glob": "^10.2.2", - "jasmine-core": "~5.4.0" + "jasmine-core": "~5.6.0" }, "bin": { "jasmine": "bin/jasmine.js" } }, "node_modules/jasmine-core": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.4.0.tgz", - "integrity": "sha512-T4fio3W++llLd7LGSGsioriDHgWyhoL6YTu4k37uwJLF7DzOzspz7mNxRoM3cQdLWtL/ebazQpIf/yZGJx/gzg==", - "dev": true + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.6.0.tgz", + "integrity": "sha512-niVlkeYVRwKFpmfWg6suo6H9CrNnydfBLEqefM5UjibYS+UoTjZdmvPJSiuyrRLGnFj1eYRhFd/ch+5hSlsFVA==", + "dev": true, + "license": "MIT" }, "node_modules/jmespath": { "version": "0.16.0", @@ -7629,14 +15008,6 @@ "safe-buffer": "^5.0.1" } }, - "node_modules/kareem": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz", - "integrity": "sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==", - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -7771,9 +15142,9 @@ "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==" }, "node_modules/logform": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.1.tgz", - "integrity": "sha512-CdaO738xRapbKIMVn2m4F6KTj4j7ooJ8POVnebSgKo3KBz5axNXRAL7ZdRjIV6NOr2Uf4vjtRkxrFETOioCqSA==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", + "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", "dependencies": { "@colors/colors": "1.6.0", "@types/triple-beam": "^1.3.2", @@ -7845,11 +15216,11 @@ } }, "node_modules/mailgun.js": { - "version": "10.2.3", - "resolved": "https://registry.npmjs.org/mailgun.js/-/mailgun.js-10.2.3.tgz", - "integrity": "sha512-7Mcw5IFtzN21i+qFQoWI+aQFDpLYSMUIWvDUXKLlpGFVVGfYVL8GIiveS+LIXpEJTQcF1hoNhOhDwenFqNSKmw==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/mailgun.js/-/mailgun.js-11.1.0.tgz", + "integrity": "sha512-pXYcQT3nU32gMjUjZpl2FdQN4Vv2iobqYiXqyyevk0vXTKQj8Or0ifLXLNAGqMHnymTjV0OphBpurkchvHsRAg==", "dependencies": { - "axios": "^1.7.2", + "axios": "^1.7.4", "base-64": "^1.0.0", "url-join": "^4.0.1" }, @@ -7946,14 +15317,17 @@ } }, "node_modules/mime": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", - "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-4.0.4.tgz", + "integrity": "sha512-v8yqInVjhXyqP6+Kw4fV3ZzeMRqEW6FotRsKXjRS5VMTNIuXsdRoAvklpoRgSqXm6o9VNH4/C0mgedko9DdLsQ==", + "funding": [ + "https://github.com/sponsors/broofa" + ], "bin": { - "mime": "cli.js" + "mime": "bin/cli.js" }, "engines": { - "node": ">=10.0.0" + "node": ">=16" } }, "node_modules/mime-db": { @@ -7975,17 +15349,6 @@ "node": ">= 0.6" } }, - "node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", @@ -8061,11 +15424,6 @@ "mkdirp": "bin/cmd.js" } }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" - }, "node_modules/moment": { "version": "2.30.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", @@ -8074,6 +15432,52 @@ "node": "*" } }, + "node_modules/mongodb": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.13.0.tgz", + "integrity": "sha512-KeESYR5TEaFxOuwRqkOm3XOsMqCSkdeDMjaW5u2nuKfX7rqaofp7JQGoi7sVqQcNJTKuveNbzZtWMstb8ABP6Q==", + "license": "Apache-2.0", + "dependencies": { + "@mongodb-js/saslprep": "^1.1.9", + "bson": "^6.10.1", + "mongodb-connection-string-url": "^3.0.0" + }, + "engines": { + "node": ">=16.20.1" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.1.0 || ^2.0.0", + "gcp-metadata": "^5.2.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.2.2", + "socks": "^2.7.1" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + }, + "socks": { + "optional": true + } + } + }, "node_modules/mongodb-connection-string-url": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.1.tgz", @@ -8127,260 +15531,6 @@ "mongodb-runner": "bin/runner.js" } }, - "node_modules/mongodb-runner/node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/mongodb-runner/node_modules/gaxios": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-5.1.3.tgz", - "integrity": "sha512-95hVgBRgEIRQQQHIbnxBXeHbW4TqFk4ZDJW7wmVtvYar72FdhRIo1UGOLS2eRAKCPEdPBWu+M7+A33D9CdX9rA==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "extend": "^3.0.2", - "https-proxy-agent": "^5.0.0", - "is-stream": "^2.0.0", - "node-fetch": "^2.6.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/mongodb-runner/node_modules/gcp-metadata": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-5.3.0.tgz", - "integrity": "sha512-FNTkdNEnBdlqF2oatizolQqNANMrcqJt6AAYt99B3y1aLLC8Hc5IOBb+ZnnzllodEEf6xMBp6wRcBbc16fa65w==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "gaxios": "^5.0.0", - "json-bigint": "^1.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/mongodb-runner/node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/mongodb-runner/node_modules/mongodb": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.9.0.tgz", - "integrity": "sha512-UMopBVx1LmEUbW/QE0Hw18u583PEDVQmUmVzzBRH0o/xtE9DBRA5ZYLOjpLIa03i8FXjzvQECJcqoMvCXftTUA==", - "dev": true, - "dependencies": { - "@mongodb-js/saslprep": "^1.1.5", - "bson": "^6.7.0", - "mongodb-connection-string-url": "^3.0.0" - }, - "engines": { - "node": ">=16.20.1" - }, - "peerDependencies": { - "@aws-sdk/credential-providers": "^3.188.0", - "@mongodb-js/zstd": "^1.1.0", - "gcp-metadata": "^5.2.0", - "kerberos": "^2.0.1", - "mongodb-client-encryption": ">=6.0.0 <7", - "snappy": "^7.2.2", - "socks": "^2.7.1" - }, - "peerDependenciesMeta": { - "@aws-sdk/credential-providers": { - "optional": true - }, - "@mongodb-js/zstd": { - "optional": true - }, - "gcp-metadata": { - "optional": true - }, - "kerberos": { - "optional": true - }, - "mongodb-client-encryption": { - "optional": true - }, - "snappy": { - "optional": true - }, - "socks": { - "optional": true - } - } - }, - "node_modules/mongoose": { - "version": "8.8.4", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.8.4.tgz", - "integrity": "sha512-yJbn695qCsqDO+xyPII29x2R7flzXhxCDv09mMZPSGllf0sm4jKw3E9s9uvQ9hjO6bL2xjU8KKowYqcY9eSTMQ==", - "dependencies": { - "bson": "^6.7.0", - "kareem": "2.6.3", - "mongodb": "~6.10.0", - "mpath": "0.9.0", - "mquery": "5.0.0", - "ms": "2.1.3", - "sift": "17.1.3" - }, - "engines": { - "node": ">=16.20.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mongoose" - } - }, - "node_modules/mongoose/node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "optional": true, - "peer": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/mongoose/node_modules/gaxios": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-5.1.3.tgz", - "integrity": "sha512-95hVgBRgEIRQQQHIbnxBXeHbW4TqFk4ZDJW7wmVtvYar72FdhRIo1UGOLS2eRAKCPEdPBWu+M7+A33D9CdX9rA==", - "optional": true, - "peer": true, - "dependencies": { - "extend": "^3.0.2", - "https-proxy-agent": "^5.0.0", - "is-stream": "^2.0.0", - "node-fetch": "^2.6.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/mongoose/node_modules/gcp-metadata": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-5.3.0.tgz", - "integrity": "sha512-FNTkdNEnBdlqF2oatizolQqNANMrcqJt6AAYt99B3y1aLLC8Hc5IOBb+ZnnzllodEEf6xMBp6wRcBbc16fa65w==", - "optional": true, - "peer": true, - "dependencies": { - "gaxios": "^5.0.0", - "json-bigint": "^1.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/mongoose/node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "optional": true, - "peer": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/mongoose/node_modules/mongodb": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.10.0.tgz", - "integrity": "sha512-gP9vduuYWb9ZkDM546M+MP2qKVk5ZG2wPF63OvSRuUbqCR+11ZCAE1mOfllhlAG0wcoJY5yDL/rV3OmYEwXIzg==", - "dependencies": { - "@mongodb-js/saslprep": "^1.1.5", - "bson": "^6.7.0", - "mongodb-connection-string-url": "^3.0.0" - }, - "engines": { - "node": ">=16.20.1" - }, - "peerDependencies": { - "@aws-sdk/credential-providers": "^3.188.0", - "@mongodb-js/zstd": "^1.1.0", - "gcp-metadata": "^5.2.0", - "kerberos": "^2.0.1", - "mongodb-client-encryption": ">=6.0.0 <7", - "snappy": "^7.2.2", - "socks": "^2.7.1" - }, - "peerDependenciesMeta": { - "@aws-sdk/credential-providers": { - "optional": true - }, - "@mongodb-js/zstd": { - "optional": true - }, - "gcp-metadata": { - "optional": true - }, - "kerberos": { - "optional": true - }, - "mongodb-client-encryption": { - "optional": true - }, - "snappy": { - "optional": true - }, - "socks": { - "optional": true - } - } - }, - "node_modules/mongoose/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/mpath": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", - "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/mquery": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz", - "integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==", - "dependencies": { - "debug": "4.x" - }, - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -8436,11 +15586,6 @@ "mustache": "bin/mustache" } }, - "node_modules/napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -8459,38 +15604,11 @@ "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" }, - "node_modules/node-abi": { - "version": "3.67.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.67.0.tgz", - "integrity": "sha512-bLn/fU/ALVBE9wj+p4Y21ZJWYFjUXLXPi/IewyLZkx3ApxKDNBWCKdReeKOtD8dWpOdDCeMyLh6ZewzcLsG2Nw==", - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-abi/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/node-abort-controller": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==" }, - "node_modules/node-addon-api": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", - "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==" - }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", @@ -8555,17 +15673,17 @@ "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==" }, "node_modules/nodemailer": { - "version": "6.9.16", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.16.tgz", - "integrity": "sha512-psAuZdTIRN08HKVd/E8ObdV6NO7NTBY3KsC30F7M4H1OnmLCUNaS56FpYxyb26zWLSyYF9Ozch9KYHhHegsiOQ==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.10.0.tgz", + "integrity": "sha512-SQ3wZCExjeSatLE/HBaXS5vqUOQk6GtBdIIKxiFdmm01mOQZX/POJkO3SUX1wDiYcwUOJwT23scFSC9fY2H8IA==", "engines": { "node": ">=6.0.0" } }, "node_modules/nodemon": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.7.tgz", - "integrity": "sha512-hLj7fuMow6f0lbB0cD14Lz2xNjwsyruH251Pk4t/yIitCFJbmY1myuLlHm/q06aST4jg6EgAh74PIBBrRqpVAQ==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.9.tgz", + "integrity": "sha512-hdr1oIb2p6ZSxu3PB2JWWYS7ZQ0qvaZsc3hK8DR8f02kRzc8rjYmxAIvdz+aYC+8F2IjNaB7HMcSDg8nQpJxyg==", "dev": true, "dependencies": { "chokidar": "^3.5.2", @@ -8982,11 +16100,11 @@ } }, "node_modules/otpauth": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/otpauth/-/otpauth-9.3.1.tgz", - "integrity": "sha512-E6d2tMxPofHNk4sRFp+kqW7vQ+WJGO9VLI2N/W00DnI+ThskU12Qa10kyNSGklrzhN5c+wRUsN4GijVgCU2N9w==", + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/otpauth/-/otpauth-9.3.5.tgz", + "integrity": "sha512-jQyqOuQExeIl4YIiOUz4TdEcamgAgPX6UYeeS9Iit4lkvs7bwHb0JNDqchGRccbRfvWHV6oRwH36tOsVmc+7hQ==", "dependencies": { - "@noble/hashes": "1.4.0" + "@noble/hashes": "1.5.0" }, "funding": { "url": "https://github.com/hectorm/otpauth?sponsor=1" @@ -9082,6 +16200,7 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/parse/-/parse-5.3.0.tgz", "integrity": "sha512-mWBnE6hHJhdvlx5KPQcYgCGRdgqKhPw+5fSC0j7vOfse3Lkh3xtDwOfmDpvv2LXZVBj72G/mgVKMRmbAICRzkQ==", + "license": "Apache-2.0", "dependencies": { "@babel/runtime-corejs3": "7.24.7", "idb-keyval": "6.2.1", @@ -9101,6 +16220,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/parse-dbtool/-/parse-dbtool-1.2.0.tgz", "integrity": "sha512-APRMPdQ2jyJ7SBouPYZsCD4BjB0zIrSEgALgeYZsVSDrrtoqXhUHJHi42tF/0ocTA/nolteUMzlHT+msrqPvjQ==", + "license": "ISC", "dependencies": { "chalk": "^4.1.1", "date-fns": "^2.21.3", @@ -9159,6 +16279,21 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "node_modules/parse-dbtool/node_modules/date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, "node_modules/parse-dbtool/node_modules/dotenv": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", @@ -9187,27 +16322,28 @@ } }, "node_modules/parse-server": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/parse-server/-/parse-server-7.3.0.tgz", - "integrity": "sha512-YL6hypvVpwxMvi3HCaL7o6wAIwiDbf2uwoy9z72t5A1iphy9fqzwdtefG8P27xWaO3HlUhQ+CuusuoKADcavpA==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/parse-server/-/parse-server-7.4.0.tgz", + "integrity": "sha512-Jw71jGesZruXW1BA3Stg10Y0d1xt28SxlbYyAhKFzhC3D/BPWFOo8VUrK0HyWko9CItrX0f+Wf3wDz0pNXZwTg==", "hasInstallScript": true, + "license": "Apache-2.0", "dependencies": { - "@apollo/server": "4.10.5", - "@babel/eslint-parser": "7.24.7", - "@graphql-tools/merge": "9.0.4", - "@graphql-tools/schema": "10.0.4", - "@graphql-tools/utils": "8.12.0", + "@apollo/server": "4.11.2", + "@babel/eslint-parser": "7.25.9", + "@graphql-tools/merge": "9.0.14", + "@graphql-tools/schema": "10.0.13", + "@graphql-tools/utils": "10.6.3", "@parse/fs-files-adapter": "3.0.0", - "@parse/push-adapter": "6.4.1", + "@parse/push-adapter": "6.8.0", "bcryptjs": "2.4.3", "body-parser": "1.20.3", "commander": "12.1.0", "cors": "2.8.5", "deepcopy": "2.1.0", - "express": "4.21.0", - "express-rate-limit": "7.3.1", - "follow-redirects": "1.15.6", - "graphql": "16.8.1", + "express": "4.21.2", + "express-rate-limit": "7.4.1", + "follow-redirects": "1.15.9", + "graphql": "16.9.0", "graphql-list-fields": "2.0.4", "graphql-relay": "0.10.2", "graphql-tag": "2.12.6", @@ -9217,24 +16353,24 @@ "jwks-rsa": "3.1.0", "ldapjs": "3.0.7", "lodash": "4.17.21", - "lru-cache": "10.2.2", - "mime": "3.0.0", - "mongodb": "5.9.0", + "lru-cache": "10.4.0", + "mime": "4.0.4", + "mongodb": "6.12.0", "mustache": "4.2.0", - "otpauth": "9.3.1", + "otpauth": "9.3.5", "parse": "5.3.0", "path-to-regexp": "6.3.0", "pg-monitor": "2.1.0", - "pg-promise": "11.9.1", + "pg-promise": "11.10.2", "pluralize": "8.0.0", "punycode": "2.3.1", "rate-limit-redis": "4.2.0", - "redis": "4.6.13", + "redis": "4.7.0", "semver": "7.6.3", "subscriptions-transport-ws": "0.11.0", "tv4": "1.3.0", - "uuid": "10.0.0", - "winston": "3.13.1", + "uuid": "11.0.3", + "winston": "3.17.0", "winston-daily-rotate-file": "5.0.0", "ws": "8.18.0" }, @@ -9249,7 +16385,7 @@ "url": "https://opencollective.com/parse-server" }, "optionalDependencies": { - "@node-rs/bcrypt": "1.10.4" + "@node-rs/bcrypt": "1.10.7" } }, "node_modules/parse-server-api-mail-adapter": { @@ -9264,9 +16400,9 @@ } }, "node_modules/parse-server/node_modules/@babel/eslint-parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.24.7.tgz", - "integrity": "sha512-SO5E3bVxDuxyNxM5agFv480YA2HO6ohZbGxbazZdIk3KQOPOGVNw6q78I9/lbviIf95eq6tPozeYnJLbjnC8IA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.25.9.tgz", + "integrity": "sha512-5UXfgpK0j0Xr/xIdgdLEhOFxaDZ0bRPWJJchRpqOSur/3rZoPbqqki5mm0p4NE2cs28krBEiSM2MB7//afRSQQ==", "dependencies": { "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", "eslint-visitor-keys": "^2.1.0", @@ -9288,122 +16424,35 @@ "semver": "bin/semver.js" } }, - "node_modules/parse-server/node_modules/@types/whatwg-url": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", - "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", - "dependencies": { - "@types/node": "*", - "@types/webidl-conversions": "*" - } - }, - "node_modules/parse-server/node_modules/bson": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/bson/-/bson-5.5.1.tgz", - "integrity": "sha512-ix0EwukN2EpC0SRWIj/7B5+A6uQMQy6KMREI9qQqvgpkV2frH63T0UDVd1SYedL6dNCmDBYB3QtXi4ISk9YT+g==", - "engines": { - "node": ">=14.20.1" - } - }, - "node_modules/parse-server/node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/parse-server/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/parse-server/node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/parse-server/node_modules/express": { - "version": "4.21.0", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", - "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.3", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.6.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.3.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.10", - "proxy-addr": "~2.0.7", - "qs": "6.13.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.19.0", - "serve-static": "1.16.2", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/parse-server/node_modules/express/node_modules/path-to-regexp": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", - "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" - }, "node_modules/parse-server/node_modules/lru-cache": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", - "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.0.tgz", + "integrity": "sha512-bfJaPTuEiTYBu+ulDaeQ0F+uLmlfFkMgXj4cbwfuMSjgObGMzb55FMMbDvbRU0fAHZ4sLGkz2mKwcMg8Dvm8Ww==", "engines": { - "node": "14 || >=16.14" + "node": ">=18" } }, "node_modules/parse-server/node_modules/mongodb": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.9.0.tgz", - "integrity": "sha512-g+GCMHN1CoRUA+wb1Agv0TI4YTSiWr42B5ulkiAfLLHitGK1R+PkSAf3Lr5rPZwi/3F04LiaZEW0Kxro9Fi2TA==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.12.0.tgz", + "integrity": "sha512-RM7AHlvYfS7jv7+BXund/kR64DryVI+cHbVAy9P61fnb1RcWZqOW1/Wj2YhqMCx+MuYhqTRGv7AwHBzmsCKBfA==", + "license": "Apache-2.0", "dependencies": { - "bson": "^5.5.0", - "mongodb-connection-string-url": "^2.6.0", - "socks": "^2.7.1" + "@mongodb-js/saslprep": "^1.1.9", + "bson": "^6.10.1", + "mongodb-connection-string-url": "^3.0.0" }, "engines": { - "node": ">=14.20.1" - }, - "optionalDependencies": { - "@mongodb-js/saslprep": "^1.1.0" + "node": ">=16.20.1" }, "peerDependencies": { "@aws-sdk/credential-providers": "^3.188.0", - "@mongodb-js/zstd": "^1.0.0", - "kerberos": "^1.0.0 || ^2.0.0", - "mongodb-client-encryption": ">=2.3.0 <3", - "snappy": "^7.2.2" + "@mongodb-js/zstd": "^1.1.0 || ^2.0.0", + "gcp-metadata": "^5.2.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.2.2", + "socks": "^2.7.1" }, "peerDependenciesMeta": { "@aws-sdk/credential-providers": { @@ -9412,6 +16461,9 @@ "@mongodb-js/zstd": { "optional": true }, + "gcp-metadata": { + "optional": true + }, "kerberos": { "optional": true }, @@ -9420,36 +16472,17 @@ }, "snappy": { "optional": true + }, + "socks": { + "optional": true } } }, - "node_modules/parse-server/node_modules/mongodb-connection-string-url": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", - "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", - "dependencies": { - "@types/whatwg-url": "^8.2.1", - "whatwg-url": "^11.0.0" - } - }, - "node_modules/parse-server/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, "node_modules/parse-server/node_modules/path-to-regexp": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==" }, - "node_modules/parse-server/node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "engines": { - "node": ">=6" - } - }, "node_modules/parse-server/node_modules/semver": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", @@ -9461,39 +16494,16 @@ "node": ">=10" } }, - "node_modules/parse-server/node_modules/tr46": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", - "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", - "dependencies": { - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/parse-server/node_modules/uuid": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.0.3.tgz", + "integrity": "sha512-d0z310fCWv5dJwnX1Y/MncBAqGMKEzlBb1AOf7z9K8ALnd0utBX/msg/fA0+sbyN1ihbMsLhrBlnl1ak7Wa0rg==", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/parse-server/node_modules/whatwg-url": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", - "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", - "dependencies": { - "tr46": "^3.0.0", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=12" + "uuid": "dist/esm/bin/uuid" } }, "node_modules/parse/node_modules/uuid": { @@ -9564,9 +16574,9 @@ "dev": true }, "node_modules/path-to-regexp": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", - "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" }, "node_modules/pdf-lib": { "version": "1.17.1", @@ -9596,13 +16606,13 @@ "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" }, "node_modules/pg": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/pg/-/pg-8.12.0.tgz", - "integrity": "sha512-A+LHUSnwnxrnL/tZ+OLfqR1SxLN3c/pgDztZ47Rpbsd4jUytsTtwQo/TLPRzPJMp/1pbhYVhH9cuSZLAajNfjQ==", + "version": "8.13.1", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.13.1.tgz", + "integrity": "sha512-OUir1A0rPNZlX//c7ksiu7crsGZTKSOXJPgtNiHGIlC9H0lO+NC6ZDYksSgBYY/thSWhnSRBv8w1lieNNGATNQ==", "dependencies": { - "pg-connection-string": "^2.6.4", - "pg-pool": "^3.6.2", - "pg-protocol": "^1.6.1", + "pg-connection-string": "^2.7.0", + "pg-pool": "^3.7.0", + "pg-protocol": "^1.7.0", "pg-types": "^2.1.0", "pgpass": "1.x" }, @@ -9632,6 +16642,15 @@ "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.7.0.tgz", "integrity": "sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA==" }, + "node_modules/pg-cursor": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/pg-cursor/-/pg-cursor-2.12.1.tgz", + "integrity": "sha512-V13tEaA9Oq1w+V6Q3UBIB/blxJrwbbr35/dY54r/86soBJ7xkP236bXaORUTVXUPt9B6Ql2BQu+uwQiuMfRVgg==", + "peer": true, + "peerDependencies": { + "pg": "^8" + } + }, "node_modules/pg-int8": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", @@ -9668,17 +16687,20 @@ } }, "node_modules/pg-promise": { - "version": "11.9.1", - "resolved": "https://registry.npmjs.org/pg-promise/-/pg-promise-11.9.1.tgz", - "integrity": "sha512-qvMmyDvWd64X0a25hCuWV40GLMbgeYf4z7ZmzxQqGHtUIlzMtxcMtaBHAMr7XVOL62wFv2ZVKW5pFruD/4ZAOg==", + "version": "11.10.2", + "resolved": "https://registry.npmjs.org/pg-promise/-/pg-promise-11.10.2.tgz", + "integrity": "sha512-wK4yjxZdfxBmAMcs40q6IsC1SOzdLilc1yNvJqlbOjtm2syayqLDCt1JQ9lhS6yNSgVlGOQZT88yb/SADJmEBw==", "dependencies": { - "assert-options": "0.8.1", - "pg": "8.12.0", + "assert-options": "0.8.2", + "pg": "8.13.1", "pg-minify": "1.6.5", - "spex": "3.3.0" + "spex": "3.4.0" }, "engines": { "node": ">=14.0" + }, + "peerDependencies": { + "pg-query-stream": "4.7.1" } }, "node_modules/pg-protocol": { @@ -9686,6 +16708,18 @@ "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.7.0.tgz", "integrity": "sha512-hTK/mE36i8fDDhgDFjy6xNOG+LCorxLG3WO17tku+ij6sVHXh1jQUJ8hYAnRhNla4QVD2H8er/FOjc/+EgC6yQ==" }, + "node_modules/pg-query-stream": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/pg-query-stream/-/pg-query-stream-4.7.1.tgz", + "integrity": "sha512-UMgsgn/pOIYsIifRySp59vwlpTpLADMK9HWJtq5ff0Z3MxBnPMGnCQeaQl5VuL+7ov4F96mSzIRIcz+Duo6OiQ==", + "peer": true, + "dependencies": { + "pg-cursor": "^2.12.1" + }, + "peerDependencies": { + "pg": "^8" + } + }, "node_modules/pg-types": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", @@ -9871,42 +16905,17 @@ } }, "node_modules/posthog-node": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/posthog-node/-/posthog-node-4.2.3.tgz", - "integrity": "sha512-6GUvk8gEyXUyiVQEipgcs4uconjF01HHQ/vvEVFlpDzHxHo1G2ts0yaf8a34U1zvryHTAXHoOXHS3dn/WUPkpQ==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/posthog-node/-/posthog-node-4.5.0.tgz", + "integrity": "sha512-h1WTHYvgOZ7kBGH0XfKVOVsSyFgCEbgzC2RIw7fetsW6RrSvxPYcaycKUDfqa5EGbvU0SYLbqAeeqNZjPDaznA==", + "license": "MIT", "dependencies": { - "axios": "^1.7.4", - "rusha": "^0.8.14" + "axios": "^1.7.4" }, "engines": { "node": ">=15.0.0" } }, - "node_modules/prebuild-install": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.2.tgz", - "integrity": "sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==", - "dependencies": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^3.3.0", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - }, - "bin": { - "prebuild-install": "bin.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/precond": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/precond/-/precond-0.2.3.tgz", @@ -9924,10 +16933,11 @@ } }, "node_modules/prettier": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", - "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.0.tgz", + "integrity": "sha512-quyMrVt6svPS7CjQ9gKb3GLEX/rl3BCL2oa/QkNcXv4YNVBC9olt3s+H7ukto06q7B1Qz46PbrKLO34PR6vXcA==", "dev": true, + "license": "MIT", "bin": { "prettier": "bin/prettier.cjs" }, @@ -10045,9 +17055,15 @@ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, "node_modules/psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", + "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", + "dependencies": { + "punycode": "^2.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/lupomontero" + } }, "node_modules/pstree.remy": { "version": "1.1.8", @@ -10055,19 +17071,13 @@ "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", "dev": true }, - "node_modules/pump": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", - "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "node_modules/punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==" + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" + } }, "node_modules/qs": { "version": "6.13.0", @@ -10144,28 +17154,6 @@ "node": ">= 0.8" } }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/react-native-crypto-js": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/react-native-crypto-js/-/react-native-crypto-js-1.0.0.tgz", @@ -10203,16 +17191,16 @@ } }, "node_modules/redis": { - "version": "4.6.13", - "resolved": "https://registry.npmjs.org/redis/-/redis-4.6.13.tgz", - "integrity": "sha512-MHgkS4B+sPjCXpf+HfdetBwbRz6vCtsceTmw1pHNYJAsYxrfpOP6dz+piJWGos8wqG7qb3vj/Rrc5qOlmInUuA==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.7.0.tgz", + "integrity": "sha512-zvmkHEAdGMn+hMRXuMBtu4Vo5P6rHQjLoHftu+lBqq8ZTA3RCVC/WzD790bkKKiNFp7d5/9PcSD19fJyyRvOdQ==", "dependencies": { "@redis/bloom": "1.2.0", - "@redis/client": "1.5.14", + "@redis/client": "1.6.0", "@redis/graph": "1.1.1", - "@redis/json": "1.0.6", - "@redis/search": "1.1.6", - "@redis/time-series": "1.0.5" + "@redis/json": "1.0.7", + "@redis/search": "1.2.0", + "@redis/time-series": "1.1.0" } }, "node_modules/regenerator-runtime": { @@ -10410,11 +17398,6 @@ "queue-microtask": "^1.2.2" } }, - "node_modules/rusha": { - "version": "0.8.14", - "resolved": "https://registry.npmjs.org/rusha/-/rusha-0.8.14.tgz", - "integrity": "sha512-cLgakCUf6PedEu15t8kbsjnwIFFR2D4RfL+W3iWFJ4iac7z4B0ZI8fxy4R3J956kAI68HclCFGL8MPoUVC3qVA==" - }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -10627,11 +17610,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/sift": { - "version": "17.1.3", - "resolved": "https://registry.npmjs.org/sift/-/sift-17.1.3.tgz", - "integrity": "sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==" - }, "node_modules/signal-exit": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", @@ -10643,49 +17621,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/simple-get": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "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", @@ -10722,6 +17657,8 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "optional": true, + "peer": true, "engines": { "node": ">= 6.0.0", "npm": ">= 3.0.0" @@ -10731,6 +17668,8 @@ "version": "2.8.3", "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", + "optional": true, + "peer": true, "dependencies": { "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" @@ -10809,11 +17748,11 @@ "dev": true }, "node_modules/spex": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/spex/-/spex-3.3.0.tgz", - "integrity": "sha512-VNiXjFp6R4ldPbVRYbpxlD35yRHceecVXlct1J4/X80KuuPnW2AXMq3sGwhnJOhKkUsOxAT6nRGfGE5pocVw5w==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/spex/-/spex-3.4.0.tgz", + "integrity": "sha512-8JeZJ7QlEBnSj1W1fKXgbB2KUPA8k4BxFMf6lZX/c1ZagU/1b9uZWZK0yD6yjfzqAIuTNG4YlRmtMpQiXuohsg==", "engines": { - "node": ">=10.0.0" + "node": ">=14.0.0" } }, "node_modules/split2": { @@ -11109,83 +18048,6 @@ "node": ">=10" } }, - "node_modules/tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/tar-fs/node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/tar-fs/node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/tar-fs/node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" - }, - "node_modules/tar-fs/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/tar-fs/node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/tar-stream": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", @@ -11312,11 +18174,6 @@ "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" - }, "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -11389,6 +18246,11 @@ "node": ">=0.8" } }, + "node_modules/tough-cookie/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==" + }, "node_modules/tr46": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", @@ -11400,14 +18262,6 @@ "node": ">=14" } }, - "node_modules/tr46/node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "engines": { - "node": ">=6" - } - }, "node_modules/triple-beam": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", @@ -11553,9 +18407,9 @@ "dev": true }, "node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==" }, "node_modules/unpipe": { "version": "1.0.0", @@ -11602,14 +18456,6 @@ "punycode": "^2.1.0" } }, - "node_modules/uri-js/node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "engines": { - "node": ">=6" - } - }, "node_modules/url": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", @@ -11866,21 +18712,21 @@ } }, "node_modules/winston": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.13.1.tgz", - "integrity": "sha512-SvZit7VFNvXRzbqGHsv5KSmgbEYR5EiQfDAL9gxYkRqa934Hnk++zze0wANKtMHcy/gI4W/3xmSDwlhf865WGw==", + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.17.0.tgz", + "integrity": "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==", "dependencies": { "@colors/colors": "^1.6.0", "@dabh/diagnostics": "^2.0.2", "async": "^3.2.3", "is-stream": "^2.0.0", - "logform": "^2.6.0", + "logform": "^2.7.0", "one-time": "^1.0.0", "readable-stream": "^3.4.0", "safe-stable-stringify": "^2.3.1", "stack-trace": "0.0.x", "triple-beam": "^1.3.0", - "winston-transport": "^4.7.0" + "winston-transport": "^4.9.0" }, "engines": { "node": ">= 12.0.0" @@ -11904,11 +18750,11 @@ } }, "node_modules/winston-transport": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.1.tgz", - "integrity": "sha512-wQCXXVgfv/wUPOfb2x0ruxzwkcZfxcktz6JIMUaPLmcNhO4bZTwA/WtDWK74xV3F2dKu8YadrFv0qhwYjVEwhA==", + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", + "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==", "dependencies": { - "logform": "^2.6.1", + "logform": "^2.7.0", "readable-stream": "^3.6.2", "triple-beam": "^1.3.0" }, diff --git a/apps/OpenSignServer/package.json b/apps/OpenSignServer/package.json index 885e1fe3b..8c3b51102 100644 --- a/apps/OpenSignServer/package.json +++ b/apps/OpenSignServer/package.json @@ -18,10 +18,10 @@ "watch": "nodemon index.js" }, "dependencies": { - "@aws-sdk/client-s3": "^3.699.0", - "@aws-sdk/s3-request-presigner": "^3.700.0", + "@aws-sdk/client-s3": "^3.741.0", + "@aws-sdk/s3-request-presigner": "^3.741.0", "@parse/fs-files-adapter": "^3.0.0", - "@parse/s3-files-adapter": "^3.0.0", + "@parse/s3-files-adapter": "^4.1.0", "@pdf-lib/fontkit": "^1.1.1", "@signpdf/placeholder-pdf-lib": "^3.2.4", "@signpdf/signer-p12": "^3.2.4", @@ -29,34 +29,35 @@ "aws-sdk": "^2.1692.0", "axios": "^1.7.9", "cors": "^2.8.5", - "dotenv": "^16.4.5", + "date-fns-tz": "^3.2.0", + "dotenv": "^16.4.7", "express": "^4.21.1", "form-data": "^4.0.1", "generate-api-key": "^1.0.2", "googleapis": "^144.0.0", - "mailgun.js": "^10.2.3", - "mongoose": "^8.8.4", + "mailgun.js": "^11.1.0", + "mongodb": "^6.13.0", "multer": "^1.4.5-lts.1", "multer-s3": "^3.0.1", "node-forge": "^1.3.1", - "nodemailer": "^6.9.16", + "nodemailer": "^6.10.0", "parse": "^5.3.0", "parse-dbtool": "^1.2.0", - "parse-server": "^7.3.0", + "parse-server": "^7.4.0", "parse-server-api-mail-adapter": "^4.1.0", "pdf-lib": "^1.17.1", - "posthog-node": "^4.2.3", + "posthog-node": "^4.5.0", "ws": "^8.18.0" }, "type": "module", "devDependencies": { - "@babel/eslint-parser": "^7.25.9", - "eslint": "^9.14.0", - "jasmine": "^5.4.0", + "@babel/eslint-parser": "^7.26.5", + "eslint": "^9.20.0", + "jasmine": "^5.6.0", "mongodb-runner": "^5.7.1", - "nodemon": "^3.1.7", + "nodemon": "^3.1.9", "nyc": "^17.1.0", - "prettier": "^3.3.3" + "prettier": "^3.5.0" }, "overrides": { "ws": "$ws", diff --git a/apps/OpenSignServer/test.pdf b/apps/OpenSignServer/test.pdf index dfe01c088..d2727e664 100644 Binary files a/apps/OpenSignServer/test.pdf and b/apps/OpenSignServer/test.pdf differ