diff --git a/apps/OpenSign/package-lock.json b/apps/OpenSign/package-lock.json index 63a43ea2b..286d6642a 100644 --- a/apps/OpenSign/package-lock.json +++ b/apps/OpenSign/package-lock.json @@ -50,6 +50,7 @@ "react-scrollbars-custom": "^4.1.1", "react-select": "^5.8.0", "react-signature-canvas": "^1.0.6", + "react-syntax-highlighter": "^15.5.0", "react-tooltip": "^5.28.0", "react-web-share": "^2.0.2", "reactour": "^1.19.4", @@ -5994,6 +5995,15 @@ "@types/node": "*" } }, + "node_modules/@types/hast": { + "version": "2.3.10", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz", + "integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2" + } + }, "node_modules/@types/hoist-non-react-statics": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz", @@ -6197,6 +6207,12 @@ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==" }, + "node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, "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", @@ -8128,6 +8144,36 @@ "node": ">=10" } }, + "node_modules/character-entities": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", + "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", + "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", + "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/chardet": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", @@ -8598,6 +8644,16 @@ "node": ">= 0.8" } }, + "node_modules/comma-separated-tokens": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", + "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/commander": { "version": "12.1.0", "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", @@ -11222,6 +11278,19 @@ "reusify": "^1.0.4" } }, + "node_modules/fault": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz", + "integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==", + "license": "MIT", + "dependencies": { + "format": "^0.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/faye-websocket": { "version": "0.11.4", "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", @@ -11799,6 +11868,14 @@ "node": ">= 6" } }, + "node_modules/format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", + "engines": { + "node": ">=0.4.x" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -12314,6 +12391,33 @@ "node": ">= 0.4" } }, + "node_modules/hast-util-parse-selector": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", + "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", + "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", + "license": "MIT", + "dependencies": { + "@types/hast": "^2.0.0", + "comma-separated-tokens": "^1.0.0", + "hast-util-parse-selector": "^2.0.0", + "property-information": "^5.0.0", + "space-separated-tokens": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -12322,6 +12426,15 @@ "he": "bin/he" } }, + "node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, "node_modules/hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -13042,6 +13155,30 @@ "node": ">= 10" } }, + "node_modules/is-alphabetical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", + "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", + "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", + "license": "MIT", + "dependencies": { + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/is-arguments": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", @@ -13181,6 +13318,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-decimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", + "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/is-docker": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", @@ -13259,6 +13406,16 @@ "node": ">=0.10.0" } }, + "node_modules/is-hexadecimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", + "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/is-interactive": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", @@ -16893,6 +17050,20 @@ "tslib": "^2.0.3" } }, + "node_modules/lowlight": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.20.0.tgz", + "integrity": "sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==", + "license": "MIT", + "dependencies": { + "fault": "^1.0.0", + "highlight.js": "~10.7.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -17889,6 +18060,24 @@ "crypto-js": "4.2.0" } }, + "node_modules/parse-entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", + "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", + "license": "MIT", + "dependencies": { + "character-entities": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "character-reference-invalid": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-hexadecimal": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -19738,6 +19927,15 @@ "resolved": "https://registry.npmjs.org/print-js/-/print-js-1.6.0.tgz", "integrity": "sha512-BfnOIzSKbqGRtO4o0rnj/K3681BSd2QUrsIZy/+WdCIugjIswjmx3lDEZpXB2ruGf9d4b3YNINri81+J0FsBWg==" }, + "node_modules/prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -19795,6 +19993,19 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/property-information": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", + "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -21540,6 +21751,22 @@ } } }, + "node_modules/react-syntax-highlighter": { + "version": "15.5.0", + "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.5.0.tgz", + "integrity": "sha512-+zq2myprEnQmH5yw6Gqc8lD55QHnpKaU8TOcFeC/Lg/MQSs8UknEA0JC4nTZGFAXC2J2Hyj/ijJ7NlabyPi2gg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.3.1", + "highlight.js": "^10.4.1", + "lowlight": "^1.17.0", + "prismjs": "^1.27.0", + "refractor": "^3.6.0" + }, + "peerDependencies": { + "react": ">= 0.14.0" + } + }, "node_modules/react-tooltip": { "version": "5.28.0", "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-5.28.0.tgz", @@ -21714,6 +21941,30 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/refractor": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz", + "integrity": "sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==", + "license": "MIT", + "dependencies": { + "hastscript": "^6.0.0", + "parse-entities": "^2.0.0", + "prismjs": "~1.27.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/refractor/node_modules/prismjs": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.27.0.tgz", + "integrity": "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -22936,6 +23187,16 @@ "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", "deprecated": "Please use @jridgewell/sourcemap-codec instead" }, + "node_modules/space-separated-tokens": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", + "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/spawn-command": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2.tgz", @@ -25698,6 +25959,15 @@ "node": ">=0.4.0" } }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/apps/OpenSign/package.json b/apps/OpenSign/package.json index 826591c69..aeab9aa30 100644 --- a/apps/OpenSign/package.json +++ b/apps/OpenSign/package.json @@ -45,6 +45,7 @@ "react-scrollbars-custom": "^4.1.1", "react-select": "^5.8.0", "react-signature-canvas": "^1.0.6", + "react-syntax-highlighter": "^15.5.0", "react-tooltip": "^5.28.0", "react-web-share": "^2.0.2", "reactour": "^1.19.4", diff --git a/apps/OpenSign/public/locales/en/translation.json b/apps/OpenSign/public/locales/en/translation.json index fda8fe8d6..2498764b2 100644 --- a/apps/OpenSign/public/locales/en/translation.json +++ b/apps/OpenSign/public/locales/en/translation.json @@ -131,7 +131,8 @@ "Share": "Share", "View": "View", "option": "Option", - "Embed": "Embed" + "Embed": "Embed", + "Copy TemplateId":"Copy TemplateId" }, "report-heading": { "Sr.No": "Sr.No", @@ -264,7 +265,8 @@ "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 URL", - "public-url-copy-mssg": " Here’s your public URL: Copy it or share it with the signer, and you will be able to see all your publicly set templates.", + "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 add your public URL, and you will be able to make a public template.", "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", @@ -632,6 +634,19 @@ "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" :"You need to set this template as public before you can utilize this code snippet.", + "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": "You've reached your limit of 15 signature request emails for this month. Upgrade now to continue sending emails directly.", diff --git a/apps/OpenSign/public/locales/fr/translation.json b/apps/OpenSign/public/locales/fr/translation.json index bc27e512b..48e6c23bb 100644 --- a/apps/OpenSign/public/locales/fr/translation.json +++ b/apps/OpenSign/public/locales/fr/translation.json @@ -151,7 +151,8 @@ "Share": "Partager", "View": "Voir", "option": "Option", - "Embed": "Intégrer" + "Embed": "Intégrer", + "Copy TemplateId": "Copier l'ID du modèle" }, "report-help": { "Draft Documents": "Il s'agit de documents que vous avez commencés mais que vous n'avez pas finalisés pour envoi.", @@ -263,7 +264,8 @@ "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": "URL publique", - "public-url-copy-mssg": "Voici votre URL publique : copiez-la ou partagez-le avec le signataire et vous pouvoir voir tous vos paramètres publics modèles.", + "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 ajouter votre URL publique et vous pourra rendre public modèle.", "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", @@ -631,6 +633,19 @@ "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":"Vous devez définir ce modèle comme public avant de pouvoir utiliser cet extrait de code.", + "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": "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.", diff --git a/apps/OpenSign/src/components/pdf/EmbedTab.js b/apps/OpenSign/src/components/pdf/EmbedTab.js new file mode 100644 index 000000000..8891d0dcc --- /dev/null +++ b/apps/OpenSign/src/components/pdf/EmbedTab.js @@ -0,0 +1,267 @@ +import React, { useState } from "react"; +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"; + +function EmbedTab(props) { + const { t } = useTranslation(); + const tabName = [ + { title: "React/Next.js", icon: "fa-brands fa-react", color: "#61dafb" }, + { title: "JavaScript", icon: "fa-brands fa-js", color: "#ffd43b" }, + { title: "Angular", icon: "fa-brands fa-angular", color: "#ff5733" } + ]; + const [activeTab, setActiveTab] = useState(0); + // State to track if the code has been copied + const [isCopied, setIsCopied] = useState(false); + const reactCode = [ + { + id: 0, + title: "Installation", + codeString: ` +npm install opensign-react` + }, + { + id: 1, + title: "Usage", + codeString: ` +import React from "react"; +import Opensign from "opensign-react"; + +export function App() { + return ( +
+ console.log("success")} + onLoadError={(error) => console.log(error)} + templateId= {"${props.templateId}"} + /> +
+ ); +} + + +` + } + ]; + + const angularCode = [ + { + id: 0, + title: "Installation", + codeString: ` +npm install opensign-angular` + }, + { + id: 1, + title: "Usage", + codeString: ` +import { Component } from '@angular/core'; +import {OpensignComponent} from "opensign-angular" + +@Component({ + selector:'app-root', + standalone: true, + imports: [OpensignComponent], + template: '', +}) +export class AppComponent{ + handleLoad() { + console.log("success"); + } + handleError(error: string) { + console.log(error); + } + +} + + +` + } + ]; + const jsCodeString = ` + + `; + + const handleCopy = (code, ind) => { + copytoData(code); + setIsCopied({ ...isCopied, [ind]: true }); + setTimeout(() => setIsCopied(false), 3000); + }; + + return ( +
+
+
+ {tabName.map((tabData, ind) => ( +
setActiveTab(ind)} + key={ind} + role="tab" + className={`${ + activeTab === ind ? "op-tab-active" : "" + } op-tab flex items-center`} + > + + + {tabData.title} + +
+ ))} +
+
+
+ {activeTab === 0 ? ( +
+ {reactCode.map((data, ind) => { + return ( +
+

+ {t(`${data.title}`)} +

+

+ {t("public-template-mssg-1")} +

+
+
handleCopy(data.codeString, ind)} + className="absolute top-[20px] right-[20px] cursor-pointer" + > + + + {isCopied[ind] ? t("copied-code") : t("copy-code")} + +
+ + {data.codeString} + +
+
+ ); + })} + +

+ {t("public-template-mssg-3")} +

+

+ {" "} + {t("public-template-mssg-4")} + + {" "} + OpenSign React package{" "} + + {t("public-template-mssg-5")} +

+
+ ) : activeTab === 1 ? ( +
+
+ {/*

{t(`${data.title}`)}

*/} + +
+
handleCopy(jsCodeString, 0)} + className="absolute top-[20px] right-[20px] cursor-pointer" + > + + + {isCopied[0] ? t("copied-code") : t("copy-code")} + +
+ + {jsCodeString} + +
+
+
+ ) : ( + activeTab === 2 && ( +
+ {angularCode.map((data, ind) => { + return ( +
+

+ {t(`${data.title}`)} +

+ +

+ {t("angular-npm-mssg-1")} +

+ +
+
handleCopy(data.codeString, ind)} + className="absolute top-[20px] right-[20px] cursor-pointer" + > + + + {isCopied[ind] ? t("copied-code") : t("copy-code")} + +
+ + {data.codeString} + +
+
+ ); + })} + +

+ {t("public-template-mssg-3")} +

+

+ {" "} + {t("public-template-mssg-4")} + + {" "} + OpenSign Angular package{" "} + + {t("public-template-mssg-5")} +

+
+ ) + )} +
+
+ ); +} + +export default EmbedTab; diff --git a/apps/OpenSign/src/constant/Utils.js b/apps/OpenSign/src/constant/Utils.js index 8787a7e3c..c900b3c70 100644 --- a/apps/OpenSign/src/constant/Utils.js +++ b/apps/OpenSign/src/constant/Utils.js @@ -33,14 +33,15 @@ export const openInNewTab = (url, target) => { export async function fetchSubscription( extUserId, contactObjId, - isGuestSign = false + isGuestSign = false, + isPublic = false ) { 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) { + if (extClass && extClass.length > 0 && !isPublic) { extUser = extClass[0].objectId; } else { extUser = extUserId; @@ -54,7 +55,7 @@ export async function fetchSubscription( }; const params = isGuestSign ? { contactId: contactObjId } - : { extUserId: extUser }; + : { extUserId: extUser, ispublic: isPublic }; const tenatRes = await axios.post(url, params, { headers: headers }); let plan, status, billingDate, adminId; if (isGuestSign) { diff --git a/apps/OpenSign/src/json/ReportJson.js b/apps/OpenSign/src/json/ReportJson.js index 52dee8fd2..ada3a0da7 100644 --- a/apps/OpenSign/src/json/ReportJson.js +++ b/apps/OpenSign/src/json/ReportJson.js @@ -370,6 +370,13 @@ export default function reportJson(id) { btnIcon: "fa-light fa-code", action: "Embed" }, + { + btnId: "2434", + btnLabel: "Copy TemplateId", + hoverLabel: "Copy TemplateId", + btnIcon: "fa-light fa-copy", + action: "CopyTemplateId" + }, { btnId: "1834", btnLabel: "Delete", diff --git a/apps/OpenSign/src/pages/PdfRequestFiles.js b/apps/OpenSign/src/pages/PdfRequestFiles.js index 2d318c177..ea6fa89f4 100644 --- a/apps/OpenSign/src/pages/PdfRequestFiles.js +++ b/apps/OpenSign/src/pages/PdfRequestFiles.js @@ -244,7 +244,13 @@ function PdfRequestFiles(props) { }; async function checkIsSubscribed(extUserId, contactId) { const isGuestSign = isGuestSignFlow || false; - const res = await fetchSubscription(extUserId, contactId, isGuestSign); + 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; @@ -292,19 +298,21 @@ function PdfRequestFiles(props) { } } ); - const documentData = - templateDeatils.data && templateDeatils.data.result - ? [templateDeatils.data.result] - : []; + const documentData = templateDeatils?.data?.result + ? [templateDeatils?.data?.result] + : []; if (documentData && documentData[0]?.error) { - props?.setTemplateStatus({ - status: "Invalid" - }); + props?.setTemplateStatus && + props?.setTemplateStatus({ + status: "Invalid" + }); + throw new Error("error: Invalid TemplateId"); } else if (documentData && documentData.length > 0) { if (documentData[0]?.IsPublic) { - props?.setTemplateStatus({ - status: "Success" - }); + props?.setTemplateStatus && + props?.setTemplateStatus({ + status: "Success" + }); const url = documentData[0] && (documentData[0]?.SignedUrl || documentData[0]?.URL); @@ -348,22 +356,34 @@ function PdfRequestFiles(props) { isLoad: false }); } else { - props?.setTemplateStatus({ - status: "Private" - }); + props?.setTemplateStatus && + props?.setTemplateStatus({ + status: "Private" + }); + setIsLoading(false); + setHandleError(t("something-went-wrong-mssg")); + console.error("error: TemplateId is not public"); + return; } } else { - props?.setTemplateStatus({ - status: "Invalid" - }); + props?.setTemplateStatus && + props?.setTemplateStatus({ + status: "Invalid" + }); + setIsLoading(false); + setHandleError(t("something-went-wrong-mssg")); + console.error("error: Invalid TemplateId"); + return; } } catch (err) { - console.log("err in get template details ", 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; } }; //function for get document details for perticular signer with signer'object id @@ -1287,7 +1307,11 @@ function PdfRequestFiles(props) { .catch((err) => { console.log("error updating field is decline ", err); setIsUiLoading(false); - alert(t("something-went-wrong-mssg")); + setIsAlert({ + title: "Error", + isShow: true, + alertMessage: t("something-went-wrong-mssg") + }); }); }; //function to add default signature for all requested placeholder of sign @@ -1488,11 +1512,32 @@ function PdfRequestFiles(props) { await SendOtp(); } else { console.log("error in public-sign to create user details"); - alert(t("something-went-wrong-mssg")); + setIsAlert({ + title: "Error", + isShow: true, + alertMessage: t("something-went-wrong-mssg") + }); } } catch (e) { console.log("e", e); - // setIsLoader(false); + 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") + }); + } } }; @@ -1524,7 +1569,11 @@ function PdfRequestFiles(props) { } } catch (error) { console.log("error in verify otp in public-sign", error); - alert(t("something-went-wrong-mssg")); + setIsAlert({ + title: "Error", + isShow: true, + alertMessage: t("something-went-wrong-mssg") + }); } }; @@ -1680,27 +1729,6 @@ function PdfRequestFiles(props) { {!requestSignTour && signerObjectId && requestSignTourFunction()} - - setIsAlert({ isShow: false, alertMessage: "" }) - } - > -
-

{isAlert.alertMessage}

- -
-
- + setIsAlert({ isShow: false, alertMessage: "" })} + > +
+

{isAlert.alertMessage}

+ +
+
)} diff --git a/apps/OpenSign/src/pages/PlaceHolderSign.js b/apps/OpenSign/src/pages/PlaceHolderSign.js index 904505b23..819351290 100644 --- a/apps/OpenSign/src/pages/PlaceHolderSign.js +++ b/apps/OpenSign/src/pages/PlaceHolderSign.js @@ -1047,7 +1047,7 @@ function PlaceHolderSign() { type="button" className="flex flex-row items-center op-link op-link-primary" > - + {t("copy-link")} diff --git a/apps/OpenSign/src/pages/UserProfile.js b/apps/OpenSign/src/pages/UserProfile.js index 1e8182728..8fba409c0 100644 --- a/apps/OpenSign/src/pages/UserProfile.js +++ b/apps/OpenSign/src/pages/UserProfile.js @@ -596,7 +596,7 @@ function UserProfile() { className="op-btn op-btn-primary op-btn-outline op-btn-xs md:op-btn-sm" onClick={() => copytoclipboard()} > - {" "} + diff --git a/apps/OpenSign/src/primitives/Alert.js b/apps/OpenSign/src/primitives/Alert.js index b0a6e00e7..1d84d9b07 100644 --- a/apps/OpenSign/src/primitives/Alert.js +++ b/apps/OpenSign/src/primitives/Alert.js @@ -25,8 +25,8 @@ const Alert = ({ children, type, className }) => { : "z-[1000] fixed top-20 left-1/2 transform -translate-x-1/2 text-sm" } `} > -
- {children} +
+ {children}
) diff --git a/apps/OpenSign/src/primitives/GetReportDisplay.js b/apps/OpenSign/src/primitives/GetReportDisplay.js index fdd623f97..538da5e6d 100644 --- a/apps/OpenSign/src/primitives/GetReportDisplay.js +++ b/apps/OpenSign/src/primitives/GetReportDisplay.js @@ -32,6 +32,7 @@ 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"; const ReportTable = (props) => { const { t } = useTranslation(); @@ -74,6 +75,7 @@ const ReportTable = (props) => { const [isModal, setIsModal] = useState({}); const [reason, setReason] = useState(""); const [isDownloadModal, setIsDownloadModal] = useState(false); + const [isEmbed, setIsEmbed] = useState(false); const Extand_Class = localStorage.getItem("Extand_Class"); const extClass = Extand_Class && JSON.parse(Extand_Class); const startIndex = (currentPage - 1) * props.docPerPage; @@ -369,6 +371,8 @@ const ReportTable = (props) => { setIsShareWith({ [item.objectId]: true }); } else if (act.action === "Embed") { handleEmbedFunction(item); + } else if (act.action === "CopyTemplateId") { + copyTemplateId(item.objectId); } }; // Get current list @@ -1121,12 +1125,14 @@ const ReportTable = (props) => { } }; const handleEmbedFunction = async (item) => { + setIsEmbed(true); setIsPublicProfile({ - [item.objectId]: props.isPublic[item.objectId] + [item.objectId]: true }); let extendUser = JSON.parse(localStorage.getItem("Extand_Class")); setIsPublicUserName(extendUser[0]?.UserName || ""); }; + return (
{Object.keys(actLoader)?.length > 0 && ( @@ -1444,22 +1450,27 @@ const ReportTable = (props) => { setIsPublicProfile({})} + handleClose={() => { + setIsPublicProfile({}); + setIsEmbed(false); + }} >
- {publicUserName ? ( + {isEmbed && !item?.IsPublic ? ( + <> +

{t("public-template-mssg-6")}

+ + + ) : publicUserName ? (
-

{t("public-url-copy-mssg")}

-
+ {t("public-url-copy")} +
- - {t("public-url")} : - copytoProfileLink() } - className="ml-[2px] underline underline-offset-2 cursor-pointer" + className="ml-[2px] underline underline-offset-2 cursor-pointer text-blue-800" > {publicUrl()} @@ -1484,7 +1495,7 @@ const ReportTable = (props) => { copytoProfileLink() } > - {" "} + {copied["publicprofile"] ? t("copied") @@ -1493,36 +1504,10 @@ const ReportTable = (props) => {
-
-
- - {t("templateid")} : - - - copyTemplateId(item.objectId) - } - className="underline ml-[2px] underline-offset-2 w-[150px] md:w-[350px] whitespace-nowrap overflow-hidden text-ellipsis cursor-pointer" - > - {item.objectId} - -
-
- -
-
+

+ {t("public-url-copy-mssg")} +

+
) : (
@@ -1582,65 +1567,33 @@ const ReportTable = (props) => { {isOption[item.objectId] && act.action === "option" && (
    - {act.subaction?.map((subact) => - props.isPublic[ - item.objectId - ] ? ( -
  • - handleActionBtn( - subact, - item - ) - } - title={t( - `btnLabel.${subact.btnLabel}` - )} - > - - - {subact.btnLabel && ( - - {t( - `btnLabel.${subact.btnLabel}` - )} - - )} - -
  • - ) : ( - subact.action !== "Embed" && ( -
  • - handleActionBtn( - subact, - item - ) - } - title={t( - `btnLabel.${subact.btnLabel}` - )} - > - - - {subact.btnLabel && ( - - {t( - `btnLabel.${subact.btnLabel}` - )} - + {act.subaction?.map((subact) => ( +
  • + handleActionBtn( + subact, + item + ) + } + title={t( + `btnLabel.${subact.btnLabel}` + )} + > + + + {subact.btnLabel && ( + + {t( + `btnLabel.${subact.btnLabel}` )} -
  • - ) - ) - )} + )} + + + ))}
)}
@@ -1961,7 +1914,7 @@ const ReportTable = (props) => { className="op-btn op-btn-primary op-btn-outline op-btn-xs md:op-btn-sm" onClick={() => copytoclipboard(share)} > - {" "} + {copied[share.email] ? t("copied") : t("copy")} diff --git a/apps/OpenSign/src/script/PublicTemplate.js b/apps/OpenSign/src/script/PublicTemplate.js index 741c66f7c..c684b00b0 100644 --- a/apps/OpenSign/src/script/PublicTemplate.js +++ b/apps/OpenSign/src/script/PublicTemplate.js @@ -11,28 +11,37 @@ 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 = ({ initialProps }) => { - const [props, setProps] = useState(initialProps); +const PublicScriptFileWrapper = () => { + const [props, setProps] = useState(""); - // Make the setProps function globally accessible 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 ; }; const appId = isPublicStaging ? "opensign" : "legadranaxn"; -//"opensign" - const serverUrl = isPublicStaging ? "https://staging-app.opensignlabs.com/api/app" : "https://app.opensignlabs.com/api/app"; -// "https://staging-app.opensignlabs.com/api/app" localStorage.setItem("baseUrl", `${serverUrl}/`); localStorage.setItem("parseAppId", appId); @@ -58,7 +67,7 @@ const root = ReactDOM.createRoot(document.getElementById("script-component")); root.render(
- +
); diff --git a/apps/OpenSign/src/script/locales/en/translation.json b/apps/OpenSign/src/script/locales/en/translation.json index 1c891706b..bb4f4d9f9 100644 --- a/apps/OpenSign/src/script/locales/en/translation.json +++ b/apps/OpenSign/src/script/locales/en/translation.json @@ -41,7 +41,7 @@ "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", @@ -131,7 +131,8 @@ "Share": "Share", "View": "View", "option": "Option", - "Embed": "Embed" + "Embed": "Embed", + "Copy TemplateId":"Copy TemplateId" }, "report-heading": { "Sr.No": "Sr.No", @@ -264,7 +265,8 @@ "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 URL", - "public-url-copy-mssg": " Here’s your public URL: Copy it or share it with the signer, and you will be able to see all your publicly set templates.", + "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 add your public URL, and you will be able to make a public template.", "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", @@ -595,7 +597,7 @@ "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", @@ -616,31 +618,44 @@ "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", + "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", - "quota-mail-info-head": "Monthly request signatures email limit", + "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" :"You need to set this template as public before you can utilize this code snippet.", + "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": "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)?", @@ -648,10 +663,10 @@ "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" } diff --git a/apps/OpenSign/src/script/locales/fr/translation.json b/apps/OpenSign/src/script/locales/fr/translation.json index a182f6229..48e6c23bb 100644 --- a/apps/OpenSign/src/script/locales/fr/translation.json +++ b/apps/OpenSign/src/script/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", @@ -151,7 +151,8 @@ "Share": "Partager", "View": "Voir", "option": "Option", - "Embed": "Intégrer" + "Embed": "Intégrer", + "Copy TemplateId": "Copier l'ID du modèle" }, "report-help": { "Draft Documents": "Il s'agit de documents que vous avez commencés mais que vous n'avez pas finalisés pour envoi.", @@ -263,7 +264,8 @@ "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": "URL publique", - "public-url-copy-mssg": "Voici votre URL publique : copiez-la ou partagez-le avec le signataire et vous pouvoir voir tous vos paramètres publics modèles.", + "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 ajouter votre URL publique et vous pourra rendre public modèle.", "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", @@ -613,33 +615,46 @@ "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é", - "quota-mail-info-head": "Limite mensuelle d'e-mails de signatures de demandes", + "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":"Vous devez définir ce modèle comme public avant de pouvoir utiliser cet extrait de code.", + "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": "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)?", @@ -647,10 +662,11 @@ "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" + } diff --git a/apps/OpenSignServer/cloud/parsefunction/PublicUserLinkContactToDoc.js b/apps/OpenSignServer/cloud/parsefunction/PublicUserLinkContactToDoc.js index 863769996..0b103d83b 100644 --- a/apps/OpenSignServer/cloud/parsefunction/PublicUserLinkContactToDoc.js +++ b/apps/OpenSignServer/cloud/parsefunction/PublicUserLinkContactToDoc.js @@ -222,6 +222,25 @@ const sendMailToAllSigners = async docId => { } }; +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) { @@ -241,126 +260,163 @@ export default async function PublicUserLinkContactToDoc(req) { throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Template not found.'); } const _tempRes = JSON.parse(JSON.stringify(tempRes)); - 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)); - //update contact in placeholder, signers and update ACl in provide document - const docRes = await createDocumentFromTemplate(template_json, existContact, index); - if (docRes) { - //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 }; + 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, ''); } - } 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, - }; - const template_json = JSON.parse(JSON.stringify(tempRes)); - // 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) { - //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); + 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)); + //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 }; } - 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) { + } 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: { __type: 'Pointer', className: '_User', objectId: userRes.id }, - Name: name, + UserId: _extUser.UserId, + Name: _extUser.Name, Email: email, - Phone: phone, + Phone: _extUser?.Phone ? _extUser.Phone : '', CreatedBy: _tempRes.CreatedBy, TenantId: _tempRes.ExtUserPtr.TenantId, }; const template_json = JSON.parse(JSON.stringify(tempRes)); - // Create new contract on the basis provided contact details by user and userId from _User class + // if user present on platform create contact on the basis of extended user details 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 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, + }; + const template_json = JSON.parse(JSON.stringify(tempRes)); + // 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, + }; + const template_json = JSON.parse(JSON.stringify(tempRes)); + // 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 { - // 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, - }; - const template_json = JSON.parse(JSON.stringify(tempRes)); - // 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) { - //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 }; - } + throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.'); } - } catch (err) { - console.log('Err', err); } } else { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.'); + 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, 'Please provide required parameters!'); + throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Plan expired'); } } else { throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Template not found.');