commit f2f64384a10e72a3fb60a9a7667276aa2f2b4051 Author: JaiPandey425 Date: Tue Jul 7 14:08:20 2026 +0530 sme v1 setup diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..948c489 --- /dev/null +++ b/.gitignore @@ -0,0 +1,29 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local +.env +.env.development +.env.production +private +*.zip + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/README.md b/README.md new file mode 100644 index 0000000..7059a96 --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +# React + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project. diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..cee1e2c --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,29 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import { defineConfig, globalIgnores } from 'eslint/config' + +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{js,jsx}'], + extends: [ + js.configs.recommended, + reactHooks.configs['recommended-latest'], + reactRefresh.configs.vite, + ], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + parserOptions: { + ecmaVersion: 'latest', + ecmaFeatures: { jsx: true }, + sourceType: 'module', + }, + }, + rules: { + 'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }], + }, + }, +]) diff --git a/index.html b/index.html new file mode 100644 index 0000000..4aa80a8 --- /dev/null +++ b/index.html @@ -0,0 +1,17 @@ + + + + + + + + SME + + + + +
+ + + + \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..0be816d --- /dev/null +++ b/package-lock.json @@ -0,0 +1,4308 @@ +{ + "name": "sme-client", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "sme-client", + "version": "0.0.0", + "dependencies": { + "@tabler/icons-react": "^3.44.0", + "@tailwindcss/vite": "^4.1.10", + "axios": "^1.11.0", + "canvas-confetti": "^1.9.3", + "i18next": "^26.0.6", + "i18next-browser-languagedetector": "^8.2.1", + "i18next-http-backend": "^4.0.0", + "immer": "^11.1.8", + "lodash": "^4.17.21", + "lucide-react": "^0.523.0", + "react": "^19.1.0", + "react-dom": "^19.1.0", + "react-i18next": "^17.0.4", + "react-router-dom": "^7.9.4", + "tailwindcss": "^4.1.10", + "vite": "^6.3.5", + "vite-plugin-svgr": "^4.5.0", + "zustand": "^5.0.12" + }, + "devDependencies": { + "@eslint/js": "^9.29.0", + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitejs/plugin-react": "^4.5.2", + "daisyui": "^5.1.29", + "eslint": "^9.29.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.20", + "globals": "^16.2.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.27.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.5.tgz", + "integrity": "sha512-KiRAp/VoJaWkkte84TvUd9qjdbZAdiqyvMxrGl1N6vzFogKmaLgoM3L1kgtLicp2HP5fBJS8JrZKLVIZGVJAVg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.27.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.4.tgz", + "integrity": "sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g==", + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.27.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.27.3", + "@babel/helpers": "^7.27.4", + "@babel/parser": "^7.27.4", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.27.4", + "@babel/types": "^7.27.3", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.27.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.5.tgz", + "integrity": "sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.27.5", + "@babel/types": "^7.27.3", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz", + "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.27.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.6.tgz", + "integrity": "sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.27.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.27.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.5.tgz", + "integrity": "sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.3" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", + "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.27.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.4.tgz", + "integrity": "sha512-oNcu2QbHqts9BtOWJosOVJapWjBDSxGCpFvikNR5TGDYDQf3JwpIoMzIKrvfoti93cLfPJEG4tH9SPVeyCGgdA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.27.3", + "@babel/parser": "^7.27.4", + "@babel/template": "^7.27.2", + "@babel/types": "^7.27.3", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.27.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.6.tgz", + "integrity": "sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz", + "integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz", + "integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz", + "integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz", + "integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz", + "integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz", + "integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz", + "integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz", + "integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz", + "integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz", + "integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz", + "integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz", + "integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz", + "integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz", + "integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz", + "integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz", + "integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz", + "integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz", + "integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz", + "integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz", + "integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz", + "integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz", + "integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz", + "integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz", + "integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz", + "integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.1.tgz", + "integrity": "sha512-OL0RJzC/CBzli0DrrR31qzj6d6i6Mm3HByuhflhl4LOBiWxN+3i6/t/ZQQNii4tjksXi8r2CRW1wMpWA2ULUEw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.3.tgz", + "integrity": "sha512-u180qk2Um1le4yf0ruXH3PYFeEZeYC3p/4wCTKrr2U1CmGdzGi3KtY0nuPDH48UJxlKCC5RDzbcbh4X0XlqgHg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.14.0.tgz", + "integrity": "sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==", + "dev": true, + "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/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.29.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.29.0.tgz", + "integrity": "sha512-3PIF4cBw/y+1u2EazflInpV+lYsSG0aByVIQzAgb1m1MhHFSbqTyNqtBKHgWf/9Ykud+DhILS9EGkmekVhbKoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.3.tgz", + "integrity": "sha512-1+WqvgNMhmlAambTvT3KPtCl/Ibr68VldY2XY40SL1CE0ZXiakFR/cbTspaF5HsnpDMvcYYoJHfl4980NBjGag==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.15.1", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit/node_modules/@eslint/core": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz", + "integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.19", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.19.tgz", + "integrity": "sha512-3FL3mnMbPu0muGOCaKAhhFEYmqv9eTfPSJRJmANrCwtgK8VuxpsZDGK+m0LYAGoyO8+0j5uRe4PeyPDK1yA/hA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/pluginutils": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", + "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.44.1.tgz", + "integrity": "sha512-JAcBr1+fgqx20m7Fwe1DxPUl/hPkee6jA6Pl7n1v2EFiktAHenTaXl5aIFjUIEsfn9w3HE4gK1lEgNGMzBDs1w==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.44.1.tgz", + "integrity": "sha512-RurZetXqTu4p+G0ChbnkwBuAtwAbIwJkycw1n6GvlGlBuS4u5qlr5opix8cBAYFJgaY05TWtM+LaoFggUmbZEQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.44.1.tgz", + "integrity": "sha512-fM/xPesi7g2M7chk37LOnmnSTHLG/v2ggWqKj3CCA1rMA4mm5KVBT1fNoswbo1JhPuNNZrVwpTvlCVggv8A2zg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.44.1.tgz", + "integrity": "sha512-gDnWk57urJrkrHQ2WVx9TSVTH7lSlU7E3AFqiko+bgjlh78aJ88/3nycMax52VIVjIm3ObXnDL2H00e/xzoipw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.44.1.tgz", + "integrity": "sha512-wnFQmJ/zPThM5zEGcnDcCJeYJgtSLjh1d//WuHzhf6zT3Md1BvvhJnWoy+HECKu2bMxaIcfWiu3bJgx6z4g2XA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.44.1.tgz", + "integrity": "sha512-uBmIxoJ4493YATvU2c0upGz87f99e3wop7TJgOA/bXMFd2SvKCI7xkxY/5k50bv7J6dw1SXT4MQBQSLn8Bb/Uw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.44.1.tgz", + "integrity": "sha512-n0edDmSHlXFhrlmTK7XBuwKlG5MbS7yleS1cQ9nn4kIeW+dJH+ExqNgQ0RrFRew8Y+0V/x6C5IjsHrJmiHtkxQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.44.1.tgz", + "integrity": "sha512-8WVUPy3FtAsKSpyk21kV52HCxB+me6YkbkFHATzC2Yd3yuqHwy2lbFL4alJOLXKljoRw08Zk8/xEj89cLQ/4Nw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.44.1.tgz", + "integrity": "sha512-yuktAOaeOgorWDeFJggjuCkMGeITfqvPgkIXhDqsfKX8J3jGyxdDZgBV/2kj/2DyPaLiX6bPdjJDTu9RB8lUPQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.44.1.tgz", + "integrity": "sha512-W+GBM4ifET1Plw8pdVaecwUgxmiH23CfAUj32u8knq0JPFyK4weRy6H7ooxYFD19YxBulL0Ktsflg5XS7+7u9g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.44.1.tgz", + "integrity": "sha512-1zqnUEMWp9WrGVuVak6jWTl4fEtrVKfZY7CvcBmUUpxAJ7WcSowPSAWIKa/0o5mBL/Ij50SIf9tuirGx63Ovew==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.44.1.tgz", + "integrity": "sha512-Rl3JKaRu0LHIx7ExBAAnf0JcOQetQffaw34T8vLlg9b1IhzcBgaIdnvEbbsZq9uZp3uAH+JkHd20Nwn0h9zPjA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.44.1.tgz", + "integrity": "sha512-j5akelU3snyL6K3N/iX7otLBIl347fGwmd95U5gS/7z6T4ftK288jKq3A5lcFKcx7wwzb5rgNvAg3ZbV4BqUSw==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.44.1.tgz", + "integrity": "sha512-ppn5llVGgrZw7yxbIm8TTvtj1EoPgYUAbfw0uDjIOzzoqlZlZrLJ/KuiE7uf5EpTpCTrNt1EdtzF0naMm0wGYg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.44.1.tgz", + "integrity": "sha512-Hu6hEdix0oxtUma99jSP7xbvjkUM/ycke/AQQ4EC5g7jNRLLIwjcNwaUy95ZKBJJwg1ZowsclNnjYqzN4zwkAw==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.44.1.tgz", + "integrity": "sha512-EtnsrmZGomz9WxK1bR5079zee3+7a+AdFlghyd6VbAjgRJDbTANJ9dcPIPAi76uG05micpEL+gPGmAKYTschQw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.44.1.tgz", + "integrity": "sha512-iAS4p+J1az6Usn0f8xhgL4PaU878KEtutP4hqw52I4IO6AGoyOkHCxcc4bqufv1tQLdDWFx8lR9YlwxKuv3/3g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.44.1.tgz", + "integrity": "sha512-NtSJVKcXwcqozOl+FwI41OH3OApDyLk3kqTJgx8+gp6On9ZEt5mYhIsKNPGuaZr3p9T6NWPKGU/03Vw4CNU9qg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.44.1.tgz", + "integrity": "sha512-JYA3qvCOLXSsnTR3oiyGws1Dm0YTuxAAeaYGVlGpUsHqloPcFjPg+X0Fj2qODGLNwQOAcCiQmHub/V007kiH5A==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.44.1.tgz", + "integrity": "sha512-J8o22LuF0kTe7m+8PvW9wk3/bRq5+mRo5Dqo6+vXb7otCm3TPhYOJqOaQtGU9YMWQSL3krMnoOxMr0+9E6F3Ug==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@svgr/babel-plugin-add-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", + "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz", + "integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-dynamic-title": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz", + "integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-em-dimensions": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz", + "integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-react-native-svg": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz", + "integrity": "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-svg-component": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz", + "integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-preset": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz", + "integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==", + "license": "MIT", + "dependencies": { + "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0", + "@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0", + "@svgr/babel-plugin-svg-dynamic-title": "8.0.0", + "@svgr/babel-plugin-svg-em-dimensions": "8.0.0", + "@svgr/babel-plugin-transform-react-native-svg": "8.1.0", + "@svgr/babel-plugin-transform-svg-component": "8.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/core": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", + "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "camelcase": "^6.2.0", + "cosmiconfig": "^8.1.3", + "snake-case": "^3.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/hast-util-to-babel-ast": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz", + "integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.21.3", + "entities": "^4.4.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/plugin-jsx": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz", + "integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "@svgr/hast-util-to-babel-ast": "8.0.0", + "svg-parser": "^2.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" + } + }, + "node_modules/@tabler/icons": { + "version": "3.44.0", + "resolved": "https://registry.npmjs.org/@tabler/icons/-/icons-3.44.0.tgz", + "integrity": "sha512-Wn0AOZG9sg0L+bjfMqq4eNhC6pQjIrk94LvvWYNYkY8KH8wC3YILRzQlrnVJc4FUeMxH/AK97QsYCX35H3LndA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/codecalm" + } + }, + "node_modules/@tabler/icons-react": { + "version": "3.44.0", + "resolved": "https://registry.npmjs.org/@tabler/icons-react/-/icons-react-3.44.0.tgz", + "integrity": "sha512-8+rvzBbVm/1Z3sG3x7GUNAaxIKxwgz8xaMhRs23nrCnMTKRFAhEC+82zAIFeAA0seXdrAGX5HFCkaLpGK2rVHg==", + "license": "MIT", + "dependencies": { + "@tabler/icons": "3.44.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/codecalm" + }, + "peerDependencies": { + "react": ">= 16" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.10.tgz", + "integrity": "sha512-2ACf1znY5fpRBwRhMgj9ZXvb2XZW8qs+oTfotJ2C5xR0/WNL7UHZ7zXl6s+rUqedL1mNi+0O+WQr5awGowS3PQ==", + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.3.0", + "enhanced-resolve": "^5.18.1", + "jiti": "^2.4.2", + "lightningcss": "1.30.1", + "magic-string": "^0.30.17", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.10" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.10.tgz", + "integrity": "sha512-v0C43s7Pjw+B9w21htrQwuFObSkio2aV/qPx/mhrRldbqxbWJK6KizM+q7BF1/1CmuLqZqX3CeYF7s7P9fbA8Q==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.4", + "tar": "^7.4.3" + }, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.10", + "@tailwindcss/oxide-darwin-arm64": "4.1.10", + "@tailwindcss/oxide-darwin-x64": "4.1.10", + "@tailwindcss/oxide-freebsd-x64": "4.1.10", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.10", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.10", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.10", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.10", + "@tailwindcss/oxide-linux-x64-musl": "4.1.10", + "@tailwindcss/oxide-wasm32-wasi": "4.1.10", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.10", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.10" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.10.tgz", + "integrity": "sha512-VGLazCoRQ7rtsCzThaI1UyDu/XRYVyH4/EWiaSX6tFglE+xZB5cvtC5Omt0OQ+FfiIVP98su16jDVHDEIuH4iQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.10.tgz", + "integrity": "sha512-ZIFqvR1irX2yNjWJzKCqTCcHZbgkSkSkZKbRM3BPzhDL/18idA8uWCoopYA2CSDdSGFlDAxYdU2yBHwAwx8euQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.10.tgz", + "integrity": "sha512-eCA4zbIhWUFDXoamNztmS0MjXHSEJYlvATzWnRiTqJkcUteSjO94PoRHJy1Xbwp9bptjeIxxBHh+zBWFhttbrQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.10.tgz", + "integrity": "sha512-8/392Xu12R0cc93DpiJvNpJ4wYVSiciUlkiOHOSOQNH3adq9Gi/dtySK7dVQjXIOzlpSHjeCL89RUUI8/GTI6g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.10.tgz", + "integrity": "sha512-t9rhmLT6EqeuPT+MXhWhlRYIMSfh5LZ6kBrC4FS6/+M1yXwfCtp24UumgCWOAJVyjQwG+lYva6wWZxrfvB+NhQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.10.tgz", + "integrity": "sha512-3oWrlNlxLRxXejQ8zImzrVLuZ/9Z2SeKoLhtCu0hpo38hTO2iL86eFOu4sVR8cZc6n3z7eRXXqtHJECa6mFOvA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.10.tgz", + "integrity": "sha512-saScU0cmWvg/Ez4gUmQWr9pvY9Kssxt+Xenfx1LG7LmqjcrvBnw4r9VjkFcqmbBb7GCBwYNcZi9X3/oMda9sqQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.10.tgz", + "integrity": "sha512-/G3ao/ybV9YEEgAXeEg28dyH6gs1QG8tvdN9c2MNZdUXYBaIY/Gx0N6RlJzfLy/7Nkdok4kaxKPHKJUlAaoTdA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.10.tgz", + "integrity": "sha512-LNr7X8fTiKGRtQGOerSayc2pWJp/9ptRYAa4G+U+cjw9kJZvkopav1AQc5HHD+U364f71tZv6XamaHKgrIoVzA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.10.tgz", + "integrity": "sha512-d6ekQpopFQJAcIK2i7ZzWOYGZ+A6NzzvQ3ozBvWFdeyqfOZdYHU66g5yr+/HC4ipP1ZgWsqa80+ISNILk+ae/Q==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@emnapi/wasi-threads": "^1.0.2", + "@napi-rs/wasm-runtime": "^0.2.10", + "@tybys/wasm-util": "^0.9.0", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.10.tgz", + "integrity": "sha512-i1Iwg9gRbwNVOCYmnigWCCgow8nDWSFmeTUU5nbNx3rqbe4p0kRbEqLwLJbYZKmSSp23g4N6rCDmm7OuPBXhDA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.10.tgz", + "integrity": "sha512-sGiJTjcBSfGq2DVRtaSljq5ZgZS2SDHSIfhOylkBvHVjwOsodBhnb3HdmiKkVuUGKD0I7G63abMOVaskj1KpOA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.10.tgz", + "integrity": "sha512-QWnD5HDY2IADv+vYR82lOhqOlS1jSCUUAmfem52cXAhRTKxpDh3ARX8TTXJTCCO7Rv7cD2Nlekabv02bwP3a2A==", + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.1.10", + "@tailwindcss/oxide": "4.1.10", + "tailwindcss": "4.1.10" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.7.tgz", + "integrity": "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.1.8", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.8.tgz", + "integrity": "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.1.6", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.6.tgz", + "integrity": "sha512-4hOiT/dwO8Ko0gV1m/TJZYk3y0KBnY9vzDh7W+DH17b2HFSOGgdj33dhihPeuy3l0q23+4e+hoXHV6hCC4dCXw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.0.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.6.0.tgz", + "integrity": "sha512-5Kgff+m8e2PB+9j51eGHEpn5kUzRKH2Ry0qGoe8ItJg7pqnkPrYPkDQZGgGmTa0EGarHrkjLvOdU3b1fzI8otQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.19", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "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/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.11.0.tgz", + "integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/browserslist": { + "version": "4.25.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", + "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001726", + "electron-to-chromium": "^1.5.173", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001726", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001726.tgz", + "integrity": "sha512-VQAUIUzBiZ/UnlM28fSp2CRF3ivUn1BWEvxMcVTNwpw91Py1pGbPIyIKtd+tzct9C3ouceCVdGAXxZOpZAsgdw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/canvas-confetti": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/canvas-confetti/-/canvas-confetti-1.9.3.tgz", + "integrity": "sha512-rFfTURMvmVEX1gyXFgn5QMn81bYk70qa0HLzcIOSVEyl57n6o9ItHeBtUSWdvKAPY0xlvBHno4/v3QPrT83q9g==", + "license": "ISC", + "funding": { + "type": "donate", + "url": "https://www.paypal.me/kirilvatev" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, + "node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "license": "MIT", + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/daisyui": { + "version": "5.1.29", + "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-5.1.29.tgz", + "integrity": "sha512-4eZhqCXO7CJVNGytTZEIQYJz3fah2gPleuqp4qUD4fD8WoEQIYzKwlOewi8nPaz6NX7vvSLZ+YSjt5Z5zqacGw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/saadeghi/daisyui?sponsor=1" + } + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-libc": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.176", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.176.tgz", + "integrity": "sha512-2nDK9orkm7M9ZZkjO3PjbEd3VUulQLyg5T9O3enJdFvUg46Hzd4DUvTvAuEgbdHYXyFsiG4A5sO9IzToMH1cDg==", + "license": "ISC" + }, + "node_modules/enhanced-resolve": { + "version": "5.18.2", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.2.tgz", + "integrity": "sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "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==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz", + "integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.5", + "@esbuild/android-arm": "0.25.5", + "@esbuild/android-arm64": "0.25.5", + "@esbuild/android-x64": "0.25.5", + "@esbuild/darwin-arm64": "0.25.5", + "@esbuild/darwin-x64": "0.25.5", + "@esbuild/freebsd-arm64": "0.25.5", + "@esbuild/freebsd-x64": "0.25.5", + "@esbuild/linux-arm": "0.25.5", + "@esbuild/linux-arm64": "0.25.5", + "@esbuild/linux-ia32": "0.25.5", + "@esbuild/linux-loong64": "0.25.5", + "@esbuild/linux-mips64el": "0.25.5", + "@esbuild/linux-ppc64": "0.25.5", + "@esbuild/linux-riscv64": "0.25.5", + "@esbuild/linux-s390x": "0.25.5", + "@esbuild/linux-x64": "0.25.5", + "@esbuild/netbsd-arm64": "0.25.5", + "@esbuild/netbsd-x64": "0.25.5", + "@esbuild/openbsd-arm64": "0.25.5", + "@esbuild/openbsd-x64": "0.25.5", + "@esbuild/sunos-x64": "0.25.5", + "@esbuild/win32-arm64": "0.25.5", + "@esbuild/win32-ia32": "0.25.5", + "@esbuild/win32-x64": "0.25.5" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.29.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.29.0.tgz", + "integrity": "sha512-GsGizj2Y1rCWDu6XoEekL3RLilp0voSePurjZIkxL3wlm5o5EC9VpgaP7lrCvjnkuLvzFBQWB3vWB3K5KQTveQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.20.1", + "@eslint/config-helpers": "^0.2.1", + "@eslint/core": "^0.14.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.29.0", + "@eslint/plugin-kit": "^0.3.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", + "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.20", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.20.tgz", + "integrity": "sha512-XpbHQ2q5gUF8BGOX4dHe+71qoirYMhApEPZ7sfhF/dNnOF1UXnCMGZf79SFTBO7Bz5YEIT4TMieSlJBWhP9WBA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/follow-redirects": { + "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", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.2.0.tgz", + "integrity": "sha512-O+7l9tPdHCU320IigZZPj5zmRCFG9xHmx9cU8FqU2Rp+JN714seHV+2S9+JslCpY4gJwU2vOGox0wzgae/MCEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-parse-stringify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", + "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "license": "MIT", + "dependencies": { + "void-elements": "3.1.0" + } + }, + "node_modules/i18next": { + "version": "26.0.6", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-26.0.6.tgz", + "integrity": "sha512-A4U6eCXodIbrhf8EarRurB9/4ebyaurH4+fu4gig9bqxmpSt+fCAFm/GpRQDcN1Xzu/LdFCx4nYHsnM1edIIbg==", + "funding": [ + { + "type": "individual", + "url": "https://www.locize.com/i18next" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + }, + { + "type": "individual", + "url": "https://www.locize.com" + } + ], + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.29.2" + }, + "peerDependencies": { + "typescript": "^5 || ^6" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/i18next-browser-languagedetector": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.2.1.tgz", + "integrity": "sha512-bZg8+4bdmaOiApD7N7BPT9W8MLZG+nPTOFlLiJiT8uzKXFjhxw4v2ierCXOwB5sFDMtuA5G4kgYZ0AznZxQ/cw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.2" + } + }, + "node_modules/i18next-http-backend": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-4.0.0.tgz", + "integrity": "sha512-EgSjO3Q1G6f2Q5oy7u9mmxuesE0oSfzAD97NFBjC8EmkK4guBSYLljM0Fng3DarMWIIkU70jfo4+mUzmyVISTA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/immer": { + "version": "11.1.8", + "resolved": "https://registry.npmjs.org/immer/-/immer-11.1.8.tgz", + "integrity": "sha512-/tbkHMW7y10Lx6i1crLjD4/OhNkRG+Fo7byZHtah0547nIeXYcpIXaUh0IAQY6gO5459qpGGYapcEOHtFXkIuA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT" + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jiti": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", + "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" + }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", + "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.30.1", + "lightningcss-darwin-x64": "1.30.1", + "lightningcss-freebsd-x64": "1.30.1", + "lightningcss-linux-arm-gnueabihf": "1.30.1", + "lightningcss-linux-arm64-gnu": "1.30.1", + "lightningcss-linux-arm64-musl": "1.30.1", + "lightningcss-linux-x64-gnu": "1.30.1", + "lightningcss-linux-x64-musl": "1.30.1", + "lightningcss-win32-arm64-msvc": "1.30.1", + "lightningcss-win32-x64-msvc": "1.30.1" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz", + "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz", + "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz", + "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz", + "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz", + "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz", + "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz", + "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz", + "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz", + "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz", + "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lucide-react": { + "version": "0.523.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.523.0.tgz", + "integrity": "sha512-rUjQoy7egZT9XYVXBK1je9ckBnNp7qzRZOhLQx5RcEp2dCGlXo+mv6vf7Am4LimEcFBJIIZzSGfgTqc9QCrPSw==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz", + "integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==", + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "license": "MIT", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "license": "MIT", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-releases": { + "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/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/react": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", + "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", + "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.26.0" + }, + "peerDependencies": { + "react": "^19.1.0" + } + }, + "node_modules/react-i18next": { + "version": "17.0.4", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-17.0.4.tgz", + "integrity": "sha512-hQipmK4EF0y6RO6tt6WuqnmWpWYEXmQUUzecmMBuNsIgYd3smXcG4GtYPWhvgxn0pqMOItKlEO8H24HCs5hc3g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.29.2", + "html-parse-stringify": "^3.0.1", + "use-sync-external-store": "^1.6.0" + }, + "peerDependencies": { + "i18next": ">= 26.0.1", + "react": ">= 16.8.0", + "typescript": "^5 || ^6" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-router": { + "version": "7.9.4", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.9.4.tgz", + "integrity": "sha512-SD3G8HKviFHg9xj7dNODUKDFgpG4xqD5nhyd0mYoB5iISepuZAvzSr8ywxgxKJ52yRzf/HWtVHc9AWwoTbljvA==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.9.4", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.9.4.tgz", + "integrity": "sha512-f30P6bIkmYvnHHa5Gcu65deIXoA2+r3Eb6PJIAddvsT9aGlchMatJ51GgpU470aSqRRbFX22T70yQNUGuW3DfA==", + "license": "MIT", + "dependencies": { + "react-router": "7.9.4" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/rollup": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.44.1.tgz", + "integrity": "sha512-x8H8aPvD+xbl0Do8oez5f5o8eMS3trfCghc4HhLAnCkj7Vl0d1JWGs0UF/D886zLW2rOj2QymV/JcSSsw+XDNg==", + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.44.1", + "@rollup/rollup-android-arm64": "4.44.1", + "@rollup/rollup-darwin-arm64": "4.44.1", + "@rollup/rollup-darwin-x64": "4.44.1", + "@rollup/rollup-freebsd-arm64": "4.44.1", + "@rollup/rollup-freebsd-x64": "4.44.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.44.1", + "@rollup/rollup-linux-arm-musleabihf": "4.44.1", + "@rollup/rollup-linux-arm64-gnu": "4.44.1", + "@rollup/rollup-linux-arm64-musl": "4.44.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.44.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.44.1", + "@rollup/rollup-linux-riscv64-gnu": "4.44.1", + "@rollup/rollup-linux-riscv64-musl": "4.44.1", + "@rollup/rollup-linux-s390x-gnu": "4.44.1", + "@rollup/rollup-linux-x64-gnu": "4.44.1", + "@rollup/rollup-linux-x64-musl": "4.44.1", + "@rollup/rollup-win32-arm64-msvc": "4.44.1", + "@rollup/rollup-win32-ia32-msvc": "4.44.1", + "@rollup/rollup-win32-x64-msvc": "4.44.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/scheduler": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", + "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/snake-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", + "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", + "license": "MIT", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", + "license": "MIT" + }, + "node_modules/tailwindcss": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.10.tgz", + "integrity": "sha512-P3nr6WkvKV/ONsTzj6Gb57sWPMX29EPNPopo7+FcpkQaNsrNpZ1pv8QmrYI2RqEKD7mlGqLnGovlcYnBK0IqUA==", + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz", + "integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz", + "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==", + "license": "ISC", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.0.1", + "mkdirp": "^3.0.1", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/vite": { + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", + "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-plugin-svgr": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/vite-plugin-svgr/-/vite-plugin-svgr-4.5.0.tgz", + "integrity": "sha512-W+uoSpmVkSmNOGPSsDCWVW/DDAyv+9fap9AZXBvWiQqrboJ08j2vh0tFxTD/LjwqwAd3yYSVJgm54S/1GhbdnA==", + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.2.0", + "@svgr/core": "^8.1.0", + "@svgr/plugin-jsx": "^8.1.0" + }, + "peerDependencies": { + "vite": ">=2.6.0" + } + }, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zustand": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.12.tgz", + "integrity": "sha512-i77ae3aZq4dhMlRhJVCYgMLKuSiZAaUPAct2AksxQ+gOtimhGMdXljRT21P5BNpeT4kXlLIckvkPM029OljD7g==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..d670c6e --- /dev/null +++ b/package.json @@ -0,0 +1,44 @@ +{ + "name": "sme-client", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite --host", + "build": "vite build", + "lint": "eslint .", + "preview": "vite build && vite preview --host", + "deploy": "npm run build -- --mode development && pscp -i private\\SME-Test.ppk -r dist root@52.24.109.130:/var/www/sme" + }, + "dependencies": { + "@tabler/icons-react": "^3.44.0", + "@tailwindcss/vite": "^4.1.10", + "axios": "^1.11.0", + "canvas-confetti": "^1.9.3", + "i18next": "^26.0.6", + "i18next-browser-languagedetector": "^8.2.1", + "i18next-http-backend": "^4.0.0", + "immer": "^11.1.8", + "lodash": "^4.17.21", + "lucide-react": "^0.523.0", + "react": "^19.1.0", + "react-dom": "^19.1.0", + "react-i18next": "^17.0.4", + "react-router-dom": "^7.9.4", + "tailwindcss": "^4.1.10", + "vite": "^6.3.5", + "vite-plugin-svgr": "^4.5.0", + "zustand": "^5.0.12" + }, + "devDependencies": { + "@eslint/js": "^9.29.0", + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitejs/plugin-react": "^4.5.2", + "daisyui": "^5.1.29", + "eslint": "^9.29.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.20", + "globals": "^16.2.0" + } +} diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..02d8f6a Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/fonts/albert-sans/albert-sans-700.woff2 b/public/fonts/albert-sans/albert-sans-700.woff2 new file mode 100644 index 0000000..cd30f90 Binary files /dev/null and b/public/fonts/albert-sans/albert-sans-700.woff2 differ diff --git a/public/fonts/albert-sans/albert-sans-700italic.woff2 b/public/fonts/albert-sans/albert-sans-700italic.woff2 new file mode 100644 index 0000000..67631a2 Binary files /dev/null and b/public/fonts/albert-sans/albert-sans-700italic.woff2 differ diff --git a/public/fonts/albert-sans/albert-sans-italic.woff2 b/public/fonts/albert-sans/albert-sans-italic.woff2 new file mode 100644 index 0000000..caf48d6 Binary files /dev/null and b/public/fonts/albert-sans/albert-sans-italic.woff2 differ diff --git a/public/fonts/albert-sans/albert-sans-regular.woff2 b/public/fonts/albert-sans/albert-sans-regular.woff2 new file mode 100644 index 0000000..b688c4d Binary files /dev/null and b/public/fonts/albert-sans/albert-sans-regular.woff2 differ diff --git a/public/fonts/comic-neue/comic-neue-700italic.woff2 b/public/fonts/comic-neue/comic-neue-700italic.woff2 new file mode 100644 index 0000000..24410cd Binary files /dev/null and b/public/fonts/comic-neue/comic-neue-700italic.woff2 differ diff --git a/public/fonts/comic-neue/comic-neue-bold.woff2 b/public/fonts/comic-neue/comic-neue-bold.woff2 new file mode 100644 index 0000000..e25f252 Binary files /dev/null and b/public/fonts/comic-neue/comic-neue-bold.woff2 differ diff --git a/public/fonts/comic-neue/comic-neue-italic.woff2 b/public/fonts/comic-neue/comic-neue-italic.woff2 new file mode 100644 index 0000000..2ef5b7d Binary files /dev/null and b/public/fonts/comic-neue/comic-neue-italic.woff2 differ diff --git a/public/fonts/comic-neue/comic-neue-regular.woff2 b/public/fonts/comic-neue/comic-neue-regular.woff2 new file mode 100644 index 0000000..4f73b72 Binary files /dev/null and b/public/fonts/comic-neue/comic-neue-regular.woff2 differ diff --git a/public/fonts/great-vibes/great-vibes-regular.woff2 b/public/fonts/great-vibes/great-vibes-regular.woff2 new file mode 100644 index 0000000..3dc01f4 Binary files /dev/null and b/public/fonts/great-vibes/great-vibes-regular.woff2 differ diff --git a/public/fonts/noto-serif/noto-serif-700italic.woff2 b/public/fonts/noto-serif/noto-serif-700italic.woff2 new file mode 100644 index 0000000..b826f83 Binary files /dev/null and b/public/fonts/noto-serif/noto-serif-700italic.woff2 differ diff --git a/public/fonts/noto-serif/noto-serif-bold.woff2 b/public/fonts/noto-serif/noto-serif-bold.woff2 new file mode 100644 index 0000000..e250137 Binary files /dev/null and b/public/fonts/noto-serif/noto-serif-bold.woff2 differ diff --git a/public/fonts/noto-serif/noto-serif-italic.woff2 b/public/fonts/noto-serif/noto-serif-italic.woff2 new file mode 100644 index 0000000..ea5b4de Binary files /dev/null and b/public/fonts/noto-serif/noto-serif-italic.woff2 differ diff --git a/public/fonts/noto-serif/noto-serif-regular.woff2 b/public/fonts/noto-serif/noto-serif-regular.woff2 new file mode 100644 index 0000000..c8f0c13 Binary files /dev/null and b/public/fonts/noto-serif/noto-serif-regular.woff2 differ diff --git a/public/fonts/open-sans/open-sans-700italic.woff2 b/public/fonts/open-sans/open-sans-700italic.woff2 new file mode 100644 index 0000000..6056a4f Binary files /dev/null and b/public/fonts/open-sans/open-sans-700italic.woff2 differ diff --git a/public/fonts/open-sans/open-sans-bold.woff2 b/public/fonts/open-sans/open-sans-bold.woff2 new file mode 100644 index 0000000..f5977a4 Binary files /dev/null and b/public/fonts/open-sans/open-sans-bold.woff2 differ diff --git a/public/fonts/open-sans/open-sans-italic.woff2 b/public/fonts/open-sans/open-sans-italic.woff2 new file mode 100644 index 0000000..bb2166e Binary files /dev/null and b/public/fonts/open-sans/open-sans-italic.woff2 differ diff --git a/public/fonts/open-sans/open-sans-regular.woff2 b/public/fonts/open-sans/open-sans-regular.woff2 new file mode 100644 index 0000000..e2d3fa4 Binary files /dev/null and b/public/fonts/open-sans/open-sans-regular.woff2 differ diff --git a/public/fonts/roboto/roboto-700.woff2 b/public/fonts/roboto/roboto-700.woff2 new file mode 100644 index 0000000..85b8ace Binary files /dev/null and b/public/fonts/roboto/roboto-700.woff2 differ diff --git a/public/fonts/roboto/roboto-700italic.woff2 b/public/fonts/roboto/roboto-700italic.woff2 new file mode 100644 index 0000000..859feb5 Binary files /dev/null and b/public/fonts/roboto/roboto-700italic.woff2 differ diff --git a/public/fonts/roboto/roboto-italic.woff2 b/public/fonts/roboto/roboto-italic.woff2 new file mode 100644 index 0000000..04367ca Binary files /dev/null and b/public/fonts/roboto/roboto-italic.woff2 differ diff --git a/public/fonts/roboto/roboto-regular.woff2 b/public/fonts/roboto/roboto-regular.woff2 new file mode 100644 index 0000000..77e4259 Binary files /dev/null and b/public/fonts/roboto/roboto-regular.woff2 differ diff --git a/public/fonts/space-mono/space-mono-v17-latin-700.woff2 b/public/fonts/space-mono/space-mono-v17-latin-700.woff2 new file mode 100644 index 0000000..6563bad Binary files /dev/null and b/public/fonts/space-mono/space-mono-v17-latin-700.woff2 differ diff --git a/public/fonts/space-mono/space-mono-v17-latin-700italic.woff2 b/public/fonts/space-mono/space-mono-v17-latin-700italic.woff2 new file mode 100644 index 0000000..263487c Binary files /dev/null and b/public/fonts/space-mono/space-mono-v17-latin-700italic.woff2 differ diff --git a/public/fonts/space-mono/space-mono-v17-latin-italic.woff2 b/public/fonts/space-mono/space-mono-v17-latin-italic.woff2 new file mode 100644 index 0000000..d9b2583 Binary files /dev/null and b/public/fonts/space-mono/space-mono-v17-latin-italic.woff2 differ diff --git a/public/fonts/space-mono/space-mono-v17-latin-regular.woff2 b/public/fonts/space-mono/space-mono-v17-latin-regular.woff2 new file mode 100644 index 0000000..2752f60 Binary files /dev/null and b/public/fonts/space-mono/space-mono-v17-latin-regular.woff2 differ diff --git a/public/locales/da/translation.json b/public/locales/da/translation.json new file mode 100644 index 0000000..5dc3c3f --- /dev/null +++ b/public/locales/da/translation.json @@ -0,0 +1,380 @@ +{ + "terms": { + "agreementText": "Ved at klikke på <0>Jeg accepterer bekræfter du, at du har gennemgået <1>Elektronisk registrering og signaturdisclosure, og giver samtykke til brugen af elektroniske registreringer og signaturer ved gennemgang og underskrivelse af dette dokument.", + "note": "Bemærk:", + "noteText": "At acceptere dette betyder ikke, at du underskriver dokumentet med det samme. Det giver dig kun mulighed for at gennemgå det elektronisk. Du får mulighed for at gennemgå dokumentet fuldt ud, før du underskriver." + }, + "buttons": { + "agree": "Jeg accepterer", + "processing": "Behandler...", + "close": "Luk", + "downloadPdf": "Download PDF", + "downloading": "Downloader..." + }, + "header": { + "aiSummary": "AI-resumé", + "completeSign": "Fuldfør underskrift", + "sign": "Underskriv", + "processing": "Behandler...", + "options": "Download" + }, + "menu": { + "downloadPdf": "Download PDF", + "auditTrail": "Revisionsspor", + "reassignSigner": "Omfordel underskriver", + "cancelTransaction": "Annuller transaktion", + "viewTerms": "Se vilkår og betingelser", + "helpSupport": "Hjælp og support", + "about": "Om SME" + }, + "sidebar": { + "documents": "Dokumenter", + "pages": "Sider: {{count}}", + "noDocuments": "Ingen dokumenter tilgængelige." + }, + "footer": { + "readyTitle": "Klar til at afslutte?", + "readyDesc": "Du har udfyldt de påkrævede felter. Gennemgå dit arbejde, og vælg derefter Fuldfør.", + "finish": "Fuldfør", + "submitting": "Sender...", + "start": "Start", + "next": "Næste", + "agreementText": "Ved at underskrive accepterer jeg Sign Made Easy's <0>vilkår og betingelser." + }, + "completion": { + "complete": { + "hit": "Helt færdig!", + "title": "Tak for din underskrift", + "message": "Dit dokument er nu fuldført og sikkert opbevaret. Vi har sendt dig en kopi på e-mail." + }, + "declined": { + "hit": "Handling annulleret!", + "title": "Måske næste gang!", + "message": "Din anmodning er blevet afvist." + }, + "cancelled": { + "hit": "Handling annulleret!", + "title": "Måske næste gang!", + "message": "Din anmodning er blevet annulleret." + }, + "download": "Download", + "downloading": "Downloader...", + "downloadSuccess": "Filen blev downloadet.", + "downloadOptions": { + "pdf": "PDF-dokument", + "audit": "Revisionsspor", + "selectFormat": "Vælg format" + }, + "downloadError": "Download mislykkedes. Prøv igen.", + "appsTitle": "Øg effektiviteten med vores apps", + "formsTitle": "Generer formularer nemt", + "docsTitle": "Generer dokumenter (fakturaer, rapporter, tilbud)", + "tryNow": "Prøv nu", + "footerText": "Ophavsret 2026 Sign Made Easy. Alle rettigheder forbeholdes.<0>Privatlivspolitik | <1>Politik for rimelig brug" + }, + "reassign": { + "title": "Omfordel underskriver", + "successSubtitle": "Dokumentet er blevet omfordelt", + "successTitle": "Tak!", + "successMessage": "Dokumentet er blevet omfordelt til den nye underskriver.", + "fields": { + "firstName": "Fornavn", + "lastName": "Efternavn", + "email": "E-mail", + "language": "Sprog", + "message": "Valgfri besked" + }, + "placeholders": { + "firstName": "Indtast dit fornavn", + "lastName": "Indtast dit efternavn", + "email": "your.email@example.com", + "message": "Skriv din besked her..." + }, + "buttons": { + "submit": "Indsend", + "submitting": "Indsender...", + "cancel": "Annuller" + }, + "errors": { + "firstNameRequired": "Fornavn er påkrævet", + "firstNameMin": "Fornavn skal være mindst 2 tegn", + "lastNameRequired": "Efternavn er påkrævet", + "lastNameMin": "Efternavn skal være mindst 2 tegn", + "emailRequired": "E-mail er påkrævet", + "emailInvalid": "Ugyldig e-mailadresse" + } + }, + "cancelModal": { + "title": "Annuller transaktion", + "description": "Er du sikker på, at du vil annullere denne transaktion? Angiv din grund til annullering nedenfor.", + "placeholder": "Angiv venligst din grund til annullering...", + "buttons": { + "no": "Nej, annuller ikke", + "yes": "Ja, annuller den" + }, + "errors": { + "reasonRequired": "Annulleringsgrund er påkrævet" + }, + "inPersonSuccess": { + "title": "Annuller transaktion", + "message": "Transaktionen blev annulleret. Bekræftelsesemails blev sendt.", + "passBackDevice": "Du kan nu give enheden tilbage til {{senderName}}.", + "continueButton": "Fortsæt" + } + }, + "enTranslations": { + "app.name": "Sign Made Easy", + "app.subtitle": "Transaktionsrevision", + "meta.transaction_id": "Transaktions-id", + "meta.transaction_status": "Transaktionsstatus", + "meta.files": "Filer", + "audit.title": "Fuldt revisionsspor", + "audit.description": "Opdater venligst emne og besked nedenfor for en tilpasset besked.", + "table.header.actions": "Handlinger", + "table.header.language": "Sprog", + "table.header.ip_address": "IP-adresse", + "table.header.date": "Dato", + "status.completed": "Fuldført", + "status.pending": "Afventer", + "status.failed": "Mislykkedes", + "action.created": "Oprettet", + "action.updated": "Opdateret", + "action.deleted": "Slettet", + "action.viewed": "Vist", + "action.signed": "Underskrevet", + "action.uploaded": "Uploadet", + "action.downloaded": "Downloadet", + "placeholder.not_available": "—" + }, + "auditPage": { + "appName": "Sign Made Easy", + "subtitle": "Transaktionsrevision", + "meta": { + "transactionId": "Transaktions-id", + "transactionStatus": "Transaktionsstatus", + "files": "Filer" + }, + "audit": { + "title": "Fuldt revisionsspor", + "description": "Opdater venligst emne og besked nedenfor for en tilpasset besked." + }, + "table": { + "actions": "Handlinger", + "language": "Sprog", + "ipAddress": "IP-adresse", + "date": "Dato" + }, + "status": { + "completed": "Fuldført", + "pending": "Afventer", + "failed": "Mislykkedes" + }, + "fallback": { + "notAvailable": "—" + } + }, + "audit": { + "transaction": { + "created": "Transaktion blev oprettet af {{userName}} <{{userEmail}}>", + "sent": "Transaktion blev sendt af {{userName}} <{{userEmail}}>", + "cancelled": "Transaktion blev annulleret af {{userName}} <{{userEmail}}>", + "edited": "Transaktion blev redigeret af {{userName}} <{{userEmail}}>", + "viewed": "Transaktion blev set af {{userName}} <{{userEmail}}>", + "signed": "Transaktion blev underskrevet af {{userName}} <{{userEmail}}>" + }, + "signature": { + "declined": "Transaktionssignatur blev afvist af {{userName}} <{{userEmail}}>" + }, + "ers": { + "accepted": "Elektronisk registrering og signaturerklæring blev accepteret af {{userName}} <{{userEmail}}>" + }, + "language": { + "updated": "{{userName}} <{{userEmail}}> opdaterede deres sprog til {{language}}" + }, + "invitation": { + "sent": "Invitationsmail sendt til {{userName}} <{{userEmail}}>", + "view": "Invitation til at se dokumentet er sendt til {{userName}} <{{userEmail}}>", + "resent": "Invitationsmail genSendt til {{recipientName}} <{{recipientEmail}}> af {{senderName}} <{{senderEmail}}>" + }, + "reassigned": { + "to": "Underskriver blev omfordelt af {{fromName}} <{{fromEmail}}> til {{toName}} <{{toEmail}}>", + "complex": "{{personName}} <{{personEmail}}> blev omfordelt af {{fromName}} <{{fromEmail}}> til {{toName}} <{{toEmail}}>" + }, + "inperson": { + "started": "Personlig transaktion blev startet af {{userName}} <{{userEmail}}>", + "verification": "Personlig signaturverifikation blev accepteret af {{userName}} <{{userEmail}}>" + }, + "facilitator": { + "accepted": "Facilitatorproces blev accepteret af {{userName}} <{{userEmail}}>" + } + }, + "signatureModal": { + "title": { + "signature": "Underskrift", + "initial": "Initialer", + "edit": "Rediger", + "styleSelection": "Stilvalg" + }, + "subtitle": "Opret dine digitale underskrifter", + "tabs": { + "select": "Vælg", + "draw": "Tegn", + "upload": "Upload" + }, + "selectTab": { + "description": "Bekræft dit navn og vælg en underskriftsstil.", + "requiredFields": "Påkrævede felter.", + "fullName": { + "label": "Fulde navn", + "required": "*", + "placeholder": "Indtast fulde navn" + }, + "initials": { + "label": "Initialer", + "required": "*", + "placeholder": "Indtast initialer" + } + }, + "drawTab": { + "description": "Tegn din underskrift.", + "required": "*", + "requiredFields": "Er påkrævede felter.", + "signature": "Underskrift", + "initials": "Initialer", + "clearSignature": "Ryd underskrift", + "fullNameBox": { + "label": "Fuld underskrift", + "required": "*" + }, + "initialsBox": { + "label": "Initialer", + "required": "*", + "placeholder": "Indtast initialer" + } + }, + "uploadTab": { + "requiredMessage": "Både underskrift og initialer er påkrævet.", + "requirements": "Brug billeder på 300×100px til underskrifter og 100×100px til initialer. Max 300KB. Understøttet: .png, .jpg.", + "signature": { + "uploadLabel": "Upload underskrift", + "uploadHint": "JPG, PNG (300×100px, max 300KB)", + "browseButton": "Gennemse", + "uploadedLabel": "Underskrift ✓", + "changeButton": "Skift underskrift", + "altText": "Uploadet underskriftbillede" + }, + "initials": { + "uploadLabel": "Upload initialer", + "uploadHint": "JPG, PNG (100×100px, max 300KB)", + "browseButton": "Gennemse", + "uploadedLabel": "Initialer ✓", + "changeButton": "Skift initialer", + "altText": "Uploadet initialbillede" + } + }, + "footer": { + "agreementText": "Jeg forstår, at jeg underskriver dette dokument.", + "cancelButton": "Annuller", + "adoptButton": "Adopter underskrift og underskriv" + }, + "errors": { + "requiredField": "Dette felt er påkrævet", + "fileTooLarge": "Filstørrelsen skal være under 300KB", + "invalidFileType": "Kun .png, .jpg og .jpeg filer understøttes", + "signatureRequired": "Tilføj venligst en underskrift", + "initialsRequired": "Tilføj venligst initialer" + } + }, + "stampModal": { + "title": { + "add": "Tilføj stempel", + "edit": "Rediger stempel" + }, + "closeButton": "Luk modal", + "fileRequirements": "Maksimal størrelse = 400Kb | Understøttede filtyper = .png, .jpg, .jpeg", + "dragDropLabel": "Træk og slip et billede, eller klik for at uploade", + "previewAltText": "Stempel forhåndsvisning", + "changeImageButton": "Skift billede", + "clearButton": "Luk", + "saveButton": "Gem", + "updateButton": "Opdater", + "errors": { + "fileTooLarge": "Filstørrelsen overstiger grænsen på 400KB", + "invalidFileType": "Kun .png, .jpg og .jpeg filer understøttes", + "uploadFailed": "Kunne ikke uploade billedet. Prøv igen." + } + }, + "attachmentModal": { + "title": "Vedhæftning", + "subtitle": { + "hasFile": "Administrer din vedhæftning", + "noFile": "Upload vedhæftning" + }, + "uploading": { + "status": "Uploader fil...", + "shimmerText": "Uploader fil..." + }, + "uploadArea": { + "dragging": "Slip din fil her", + "default": "Upload eller træk og slip fil", + "fileTypes": "PDF, DOCX, JPG, PNG, TXT (max 10MB)", + "browseButton": "Gennemse filer" + }, + "uploadedFile": { + "status": "Uploadet succesfuldt", + "deleteButton": "Slet fil" + }, + "buttons": { + "close": "Luk", + "uploading": "Uploader...", + "deleting": "Sletter...", + "saved": "Fil gemt!", + "done": "Udført", + "uploadFile": "Upload fil" + }, + "errors": { + "fileTooLarge": "Filstørrelsen overstiger grænsen på 10MB", + "invalidFileType": "Kun PDF, DOCX, JPG, PNG og TXT filer understøttes", + "uploadFailed": "Kunne ikke uploade filen. Prøv igen.", + "deleteFailed": "Kunne ikke slette filen. Prøv igen.", + "noFileSelected": "Vælg venligst en fil før du fortsætter" + }, + "accessibility": { + "fileUpload": "Filupload", + "deleteFile": "Slet fil" + } + }, + "languages": { + "zh_CN": "Kinesisk (Simplificeret)", + "zh_TW": "Kinesisk (Traditionel)", + "da": "Dansk", + "nl_NL": "Hollandsk", + "en": "Engelsk", + "fi": "Finsk", + "fr": "Fransk", + "de": "Tysk", + "it": "Italiensk", + "ja": "Japansk", + "ko": "Koreansk", + "no": "Norsk", + "pt_BR": "Portugisisk (Brasilien)", + "ru": "Russisk", + "es": "Spansk", + "es_MX": "Spansk (Mexico)", + "sv": "Svensk", + "th": "Thai", + "he": "Hebraisk" + }, + "session-expired": { + "title": "Session udløbet", + "description": "Dette dokumentunderskriftslink er udløbet på grund af inaktivitet eller sessionstimeout. Vend tilbage til din e-mail og klik på linket igen for at fortsætte med at underskrive." + }, + "inPersonComplete": { + "title": "🎉 Underskrivning fuldført!", + "subtitle": "Dokumentet er blevet underskrevet", + "thankYou": "Tak for din underskrift!", + "message": "Du vil modtage en bekræftelsesmail, når dokumentet er underskrevet af alle parter.", + "passDevice": "Du kan nu give enheden tilbage til {{senderName}}", + "continueButton": "Fortsæt" + } +} \ No newline at end of file diff --git a/public/locales/de/translation.json b/public/locales/de/translation.json new file mode 100644 index 0000000..cfda53a --- /dev/null +++ b/public/locales/de/translation.json @@ -0,0 +1,380 @@ +{ + "terms": { + "agreementText": "Mit Klick auf <0>Ich stimme zu bestätigen Sie, dass Sie die <1>Offenlegung von elektronischen Aufzeichnungen und Signaturen gelesen haben und der Verwendung von elektronischen Aufzeichnungen und Signaturen bei der Prüfung und Ausführung dieses Dokuments zustimmen.", + "note": "Hinweis:", + "noteText": "Die Zustimmung hierzu bedeutet nicht, dass Sie das Dokument sofort unterzeichnen. Es erlaubt Ihnen lediglich, es elektronisch zu prüfen. Sie haben die Möglichkeit, das Dokument vollständig zu prüfen, bevor Sie es unterzeichnen." + }, + "buttons": { + "agree": "Ich stimme zu", + "processing": "Wird verarbeitet...", + "close": "Schließen", + "downloadPdf": "PDF herunterladen", + "downloading": "Wird heruntergeladen..." + }, + "header": { + "aiSummary": "KI-Zusammenfassung", + "completeSign": "Signatur abschließen", + "sign": "Unterschreiben", + "processing": "Wird verarbeitet...", + "options": "Herunterladen" + }, + "menu": { + "downloadPdf": "PDF herunterladen", + "auditTrail": "Prüfpfad", + "reassignSigner": "Unterzeichner neu zuweisen", + "cancelTransaction": "Transaktion abbrechen", + "viewTerms": "Allgemeine Geschäftsbedingungen anzeigen", + "helpSupport": "Hilfe & Support", + "about": "Über SME" + }, + "sidebar": { + "documents": "Dokumente", + "pages": "Seiten: {{count}}", + "noDocuments": "Keine Dokumente verfügbar." + }, + "footer": { + "readyTitle": "Bereit zum Abschluss?", + "readyDesc": "Sie haben die erforderlichen Felder ausgefüllt. Überprüfen Sie Ihre Arbeit und wählen Sie dann Abschließen.", + "finish": "Abschließen", + "submitting": "Wird gesendet...", + "start": "Start", + "next": "Weiter", + "agreementText": "Mit meiner Unterschrift stimme ich den <0>Allgemeinen Geschäftsbedingungen von Sign Made Easy zu." + }, + "completion": { + "complete": { + "hit": "Alles erledigt!", + "title": "Danke für Ihre Unterschrift", + "message": "Ihr Dokument ist nun abgeschlossen und sicher gespeichert. Wir haben Ihnen eine Kopie per E-Mail gesendet." + }, + "declined": { + "hit": "Aktion abgebrochen!", + "title": "Vielleicht nächstes Mal!", + "message": "Ihre Anfrage wurde abgelehnt." + }, + "cancelled": { + "hit": "Aktion abgebrochen!", + "title": "Vielleicht nächstes Mal!", + "message": "Ihre Anfrage wurde abgebrochen." + }, + "download": "Herunterladen", + "downloading": "Wird heruntergeladen...", + "downloadSuccess": "Datei erfolgreich heruntergeladen.", + "downloadOptions": { + "pdf": "PDF-Dokument", + "audit": "Prüfpfad", + "selectFormat": "Format auswählen" + }, + "downloadError": "Fehler beim Herunterladen der Datei. Bitte versuchen Sie es erneut.", + "appsTitle": "Steigern Sie die Effizienz mit unseren Apps", + "formsTitle": "Erstellen Sie mühelos Formulare", + "docsTitle": "Erstellen Sie Dokumente (Rechnungen, Berichte, Angebote)", + "tryNow": "Jetzt ausprobieren", + "footerText": "Urheberrecht 2026 Sign Made Easy. Alle Rechte vorbehalten.<0>Datenschutzbestimmungen | <1>Richtlinie für angemessene Nutzung" + }, + "reassign": { + "title": "Unterzeichner neu zuweisen", + "successSubtitle": "Dokument wurde erfolgreich neu zugewiesen", + "successTitle": "Danke!", + "successMessage": "Das Dokument wurde erfolgreich dem neuen Unterzeichner zugewiesen.", + "fields": { + "firstName": "Vorname", + "lastName": "Nachname", + "email": "E-Mail", + "language": "Sprache", + "message": "Optionale Nachricht" + }, + "placeholders": { + "firstName": "Geben Sie Ihren Vornamen ein", + "lastName": "Geben Sie Ihren Nachnamen ein", + "email": "your.email@example.com", + "message": "Schreiben Sie Ihre Nachricht hier..." + }, + "buttons": { + "submit": "Absenden", + "submitting": "Wird gesendet...", + "cancel": "Abbrechen" + }, + "errors": { + "firstNameRequired": "Vorname ist erforderlich", + "firstNameMin": "Vorname muss mindestens 2 Zeichen lang sein", + "lastNameRequired": "Nachname ist erforderlich", + "lastNameMin": "Nachname muss mindestens 2 Zeichen lang sein", + "emailRequired": "E-Mail ist erforderlich", + "emailInvalid": "Ungültige E-Mail-Adresse" + } + }, + "cancelModal": { + "title": "Transaktion abbrechen", + "description": "Sind Sie sicher, dass Sie diese Transaktion abbrechen möchten? Geben Sie unten Ihren Grund für den Abbruch an.", + "placeholder": "Bitte geben Sie Ihren Grund für den Abbruch an...", + "buttons": { + "no": "Nein, nicht abbrechen", + "yes": "Ja, abbrechen" + }, + "errors": { + "reasonRequired": "Abbruchgrund ist erforderlich" + }, + "inPersonSuccess": { + "title": "Transaktion abbrechen", + "message": "Die Transaktion wurde erfolgreich abgebrochen. Bestätigungs-E-Mails wurden gesendet.", + "passBackDevice": "Sie können das Gerät jetzt an {{senderName}} zurückgeben.", + "continueButton": "Fortfahren" + } + }, + "enTranslations": { + "app.name": "Sign Made Easy", + "app.subtitle": "Transaktionsprüfung", + "meta.transaction_id": "Transaktions-ID", + "meta.transaction_status": "Transaktionsstatus", + "meta.files": "Dateien", + "audit.title": "Vollständiger Prüfpfad", + "audit.description": "Bitte aktualisieren Sie Betreff und Nachricht unten für eine benutzerdefinierte Nachricht.", + "table.header.actions": "Aktionen", + "table.header.language": "Sprache", + "table.header.ip_address": "IP-Adresse", + "table.header.date": "Datum", + "status.completed": "Abgeschlossen", + "status.pending": "Ausstehend", + "status.failed": "Fehlgeschlagen", + "action.created": "Erstellt", + "action.updated": "Aktualisiert", + "action.deleted": "Gelöscht", + "action.viewed": "Angesehen", + "action.signed": "Unterschrieben", + "action.uploaded": "Hochgeladen", + "action.downloaded": "Heruntergeladen", + "placeholder.not_available": "—" + }, + "auditPage": { + "appName": "Sign Made Easy", + "subtitle": "Transaktionsprüfung", + "meta": { + "transactionId": "Transaktions-ID", + "transactionStatus": "Transaktionsstatus", + "files": "Dateien" + }, + "audit": { + "title": "Vollständiger Prüfpfad", + "description": "Bitte aktualisieren Sie Betreff und Nachricht unten für eine benutzerdefinierte Nachricht." + }, + "table": { + "actions": "Aktionen", + "language": "Sprache", + "ipAddress": "IP-Adresse", + "date": "Datum" + }, + "status": { + "completed": "Abgeschlossen", + "pending": "Ausstehend", + "failed": "Fehlgeschlagen" + }, + "fallback": { + "notAvailable": "—" + } + }, + "audit": { + "transaction": { + "created": "Transaktion wurde erstellt von {{userName}} <{{userEmail}}>", + "sent": "Transaktion wurde gesendet von {{userName}} <{{userEmail}}>", + "cancelled": "Transaktion wurde abgebrochen von {{userName}} <{{userEmail}}>", + "edited": "Transaktion wurde bearbeitet von {{userName}} <{{userEmail}}>", + "viewed": "Transaktion wurde angesehen von {{userName}} <{{userEmail}}>", + "signed": "Transaktion wurde unterschrieben von {{userName}} <{{userEmail}}>" + }, + "signature": { + "declined": "Transaktionssignatur wurde abgelehnt von {{userName}} <{{userEmail}}>" + }, + "ers": { + "accepted": "Elektronische Aufzeichnungs- und Signaturoffenlegung wurde akzeptiert von {{userName}} <{{userEmail}}>" + }, + "language": { + "updated": "{{userName}} <{{userEmail}}> hat ihre Sprache aktualisiert auf {{language}}" + }, + "invitation": { + "sent": "Einladungs-E-Mail gesendet an {{userName}} <{{userEmail}}>", + "view": "Einladung zum Anzeigen des Dokuments wurde an {{userName}} <{{userEmail}}> gesendet", + "resent": "Einladungs-E-Mail erneut gesendet an {{recipientName}} <{{recipientEmail}}> von {{senderName}} <{{senderEmail}}>" + }, + "reassigned": { + "to": "Unterzeichner wurde neu zugewiesen von {{fromName}} <{{fromEmail}}> an {{toName}} <{{toEmail}}>", + "complex": "{{personName}} <{{personEmail}}> wurde neu zugewiesen von {{fromName}} <{{fromEmail}}> an {{toName}} <{{toEmail}}>" + }, + "inperson": { + "started": "Persönliche Transaktion wurde gestartet von {{userName}} <{{userEmail}}>", + "verification": "Persönliche Signaturverifizierung wurde akzeptiert von {{userName}} <{{userEmail}}>" + }, + "facilitator": { + "accepted": "Facilitator-Prozess wurde akzeptiert von {{userName}} <{{userEmail}}>" + } + }, + "signatureModal": { + "title": { + "signature": "Unterschrift", + "initial": "Initiale", + "edit": "Bearbeiten", + "styleSelection": "Stilauswahl" + }, + "subtitle": "Erstellen Sie Ihre digitalen Unterschriften", + "tabs": { + "select": "Auswählen", + "draw": "Zeichnen", + "upload": "Hochladen" + }, + "selectTab": { + "description": "Bestätigen Sie Ihren Namen und wählen Sie einen Unterschriftsstil.", + "requiredFields": "Pflichtfelder.", + "fullName": { + "label": "Vollständiger Name", + "required": "*", + "placeholder": "Vollständigen Namen eingeben" + }, + "initials": { + "label": "Initialen", + "required": "*", + "placeholder": "Initialen eingeben" + } + }, + "drawTab": { + "description": "Zeichnen Sie Ihre Unterschrift.", + "required": "*", + "requiredFields": "Sind Pflichtfelder.", + "signature": "Unterschrift", + "initials": "Initialen", + "clearSignature": "Unterschrift löschen", + "fullNameBox": { + "label": "Vollständige Unterschrift", + "required": "*" + }, + "initialsBox": { + "label": "Initialen", + "required": "*", + "placeholder": "Initialen eingeben" + } + }, + "uploadTab": { + "requiredMessage": "Sowohl Unterschrift als auch Initialen sind erforderlich.", + "requirements": "Verwenden Sie Bilder von 300×100px für Unterschriften und 100×100px für Initialen. Max. 300KB. Unterstützt: .png, .jpg.", + "signature": { + "uploadLabel": "Unterschrift hochladen", + "uploadHint": "JPG, PNG (300×100px, max. 300KB)", + "browseButton": "Durchsuchen", + "uploadedLabel": "Unterschrift ✓", + "changeButton": "Unterschrift ändern", + "altText": "Hochgeladenes Unterschriftsbild" + }, + "initials": { + "uploadLabel": "Initialen hochladen", + "uploadHint": "JPG, PNG (100×100px, max. 300KB)", + "browseButton": "Durchsuchen", + "uploadedLabel": "Initialen ✓", + "changeButton": "Initialen ändern", + "altText": "Hochgeladenes Initialenbild" + } + }, + "footer": { + "agreementText": "Ich verstehe, dass ich dieses Dokument unterschreibe.", + "cancelButton": "Abbrechen", + "adoptButton": "Unterschrift übernehmen & unterschreiben" + }, + "errors": { + "requiredField": "Dieses Feld ist erforderlich", + "fileTooLarge": "Die Dateigröße muss unter 300KB liegen", + "invalidFileType": "Nur .png, .jpg und .jpeg Dateien werden unterstützt", + "signatureRequired": "Bitte fügen Sie eine Unterschrift hinzu", + "initialsRequired": "Bitte fügen Sie Initialen hinzu" + } + }, + "stampModal": { + "title": { + "add": "Stempel hinzufügen", + "edit": "Stempel bearbeiten" + }, + "closeButton": "Modal schließen", + "fileRequirements": "Maximale Größe = 400Kb | Unterstützte Dateitypen = .png, .jpg, .jpeg", + "dragDropLabel": "Bild per Drag & Drop ablegen oder zum Hochladen klicken", + "previewAltText": "Stempelvorschau", + "changeImageButton": "Bild ändern", + "clearButton": "Schließen", + "saveButton": "Speichern", + "updateButton": "Aktualisieren", + "errors": { + "fileTooLarge": "Die Dateigröße überschreitet das 400KB-Limit", + "invalidFileType": "Nur .png, .jpg und .jpeg Dateien werden unterstützt", + "uploadFailed": "Bild konnte nicht hochgeladen werden. Bitte versuchen Sie es erneut." + } + }, + "attachmentModal": { + "title": "Anhang", + "subtitle": { + "hasFile": "Ihren Anhang verwalten", + "noFile": "Anhang hochladen" + }, + "uploading": { + "status": "Datei wird hochgeladen...", + "shimmerText": "Datei wird hochgeladen..." + }, + "uploadArea": { + "dragging": "Datei hier ablegen", + "default": "Datei hochladen oder per Drag & Drop ablegen", + "fileTypes": "PDF, DOCX, JPG, PNG, TXT (max. 10MB)", + "browseButton": "Dateien durchsuchen" + }, + "uploadedFile": { + "status": "Erfolgreich hochgeladen", + "deleteButton": "Datei löschen" + }, + "buttons": { + "close": "Schließen", + "uploading": "Wird hochgeladen...", + "deleting": "Wird gelöscht...", + "saved": "Datei gespeichert!", + "done": "Fertig", + "uploadFile": "Datei hochladen" + }, + "errors": { + "fileTooLarge": "Die Dateigröße überschreitet das 10MB-Limit", + "invalidFileType": "Nur PDF, DOCX, JPG, PNG und TXT Dateien werden unterstützt", + "uploadFailed": "Datei konnte nicht hochgeladen werden. Bitte versuchen Sie es erneut.", + "deleteFailed": "Datei konnte nicht gelöscht werden. Bitte versuchen Sie es erneut.", + "noFileSelected": "Bitte wählen Sie eine Datei aus, bevor Sie fortfahren" + }, + "accessibility": { + "fileUpload": "Datei-Upload", + "deleteFile": "Datei löschen" + } + }, + "languages": { + "zh_CN": "Chinesisch (Vereinfacht)", + "zh_TW": "Chinesisch (Traditionell)", + "da": "Dänisch", + "nl_NL": "Niederländisch", + "en": "Englisch", + "fi": "Finnisch", + "fr": "Französisch", + "de": "Deutsch", + "it": "Italienisch", + "ja": "Japanisch", + "ko": "Koreanisch", + "no": "Norwegisch", + "pt_BR": "Portugiesisch (Brasilien)", + "ru": "Russisch", + "es": "Spanisch", + "es_MX": "Spanisch (Mexiko)", + "sv": "Schwedisch", + "th": "Thailändisch", + "he": "Hebräisch" + }, + "session-expired": { + "title": "Sitzung abgelaufen", + "description": "Dieser Link zum Unterzeichnen des Dokuments ist aufgrund von Inaktivität oder Sitzungszeitüberschreitung abgelaufen. Bitte kehren Sie zu Ihrer E-Mail zurück und klicken Sie erneut auf den Link, um mit der Unterzeichnung fortzufahren." + }, + "inPersonComplete": { + "title": "🎉 Signatur abgeschlossen!", + "subtitle": "Dokument wurde erfolgreich unterschrieben", + "thankYou": "Vielen Dank für Ihre Unterschrift!", + "message": "Sie erhalten eine Bestätigungs-E-Mail, sobald das Dokument von allen Parteien unterschrieben wurde.", + "passDevice": "Sie können das Gerät jetzt an {{senderName}} zurückgeben", + "continueButton": "Weiter" + } +} \ No newline at end of file diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json new file mode 100644 index 0000000..348cd6b --- /dev/null +++ b/public/locales/en/translation.json @@ -0,0 +1,380 @@ +{ + "terms": { + "agreementText": "By clicking <0>I Agree, you confirm that you have reviewed the <1>Electronic Record and Signature Disclosure, and consent to the use of electronic records and signatures in reviewing and executing this document.", + "note": "Note:", + "noteText": "Agreeing to this does not mean you are signing the document immediately. It only allows you to review it electronically. You will have a chance to review the document in full before signing." + }, + "buttons": { + "agree": "I Agree", + "processing": "Processing...", + "close": "Close", + "downloadPdf": "Download PDF", + "downloading": "Downloading..." + }, + "header": { + "aiSummary": "AI Summary", + "completeSign": "Complete Sign", + "sign": "Sign", + "processing": "Processing...", + "options": "Download" + }, + "menu": { + "downloadPdf": "Download PDF", + "auditTrail": "Audit Trail", + "reassignSigner": "Reassign Signer", + "cancelTransaction": "Cancel Transaction", + "viewTerms": "View Terms And Conditions", + "helpSupport": "Help & Support", + "about": "About SME" + }, + "sidebar": { + "documents": "Documents", + "pages": "Pages: {{count}}", + "noDocuments": "No documents available." + }, + "footer": { + "readyTitle": "All Set to Wrap This Up?", + "readyDesc": "You've completed the required fields. Review your work, then select Finish.", + "finish": "Finish", + "submitting": "Submitting...", + "start": "Start", + "next": "Next", + "agreementText": "By signing, I agree to the Sign Made Easy <0>Terms & Conditions." + }, + "completion": { + "complete": { + "hit": "All Done!", + "title": "Thanks for signing", + "message": "Your document is now complete and securely stored. We've emailed you a copy." + }, + "declined": { + "hit": "Action Canceled!", + "title": "Maybe Next Time!", + "message": "Your request has been declined successfully." + }, + "cancelled": { + "hit": "Action Canceled!", + "title": "Maybe Next Time!", + "message": "Your request has been declined successfully." + }, + "download": "Download", + "downloading": "Downloading...", + "downloadSuccess": "File downloaded successfully.", + "downloadOptions": { + "pdf": "PDF Document", + "audit": "Audit Trails", + "selectFormat": "Select format" + }, + "downloadError": "File download failed. Please try again.", + "appsTitle": "Boost Efficiency with Our Apps", + "formsTitle": "Generate Forms with Ease", + "docsTitle": "Generate Documents (Invoices, Reports, Quotes)", + "tryNow": "Try Now", + "footerText": "Copyright 2026 Sign Made Easy. All Rights Reserved. <0>Privacy Policy | <1>Reasonable Use Policy" + }, + "reassign": { + "title": "Reassign Signer", + "successSubtitle": "Document has been successfully reassigned", + "successTitle": "Thank You!", + "successMessage": "The document has been successfully reassigned to the new signer.", + "fields": { + "firstName": "First Name", + "lastName": "Last Name", + "email": "Email", + "language": "Language", + "message": "Optional Message" + }, + "placeholders": { + "firstName": "Enter your first name", + "lastName": "Enter your last name", + "email": "your.email@example.com", + "message": "Write your message here..." + }, + "buttons": { + "submit": "Submit", + "submitting": "Submitting...", + "cancel": "Cancel" + }, + "errors": { + "firstNameRequired": "First name is required", + "firstNameMin": "First name must be at least 2 characters", + "lastNameRequired": "Last name is required", + "lastNameMin": "Last name must be at least 2 characters", + "emailRequired": "Email is required", + "emailInvalid": "Invalid email address" + } + }, + "cancelModal": { + "title": "Cancel Transaction", + "description": "Are you sure you want to cancel this transaction? Provide your reason for cancelling below.", + "placeholder": "Please provide your reason for cancellation...", + "buttons": { + "no": "No, do not cancel", + "yes": "Yes, cancel it" + }, + "errors": { + "reasonRequired": "Cancellation reason is required" + }, + "inPersonSuccess": { + "title": "Cancel Transaction", + "message": "The transaction was successfully cancelled. Confirmation emails were sent.", + "passBackDevice": "You can now pass the device back to {{senderName}}.", + "continueButton": "Continue" + } + }, + "enTranslations": { + "app.name": "Sign Made Easy", + "app.subtitle": "Transaction Audit", + "meta.transaction_id": "Transaction ID", + "meta.transaction_status": "Transaction Status", + "meta.files": "Files", + "audit.title": "Full Audit Trail", + "audit.description": "Please update the Subject and Message below for a custom message.", + "table.header.actions": "Actions", + "table.header.language": "Language", + "table.header.ip_address": "IP Address", + "table.header.date": "Date", + "status.completed": "Completed", + "status.pending": "Pending", + "status.failed": "Failed", + "action.created": "Created", + "action.updated": "Updated", + "action.deleted": "Deleted", + "action.viewed": "Viewed", + "action.signed": "Signed", + "action.uploaded": "Uploaded", + "action.downloaded": "Downloaded", + "placeholder.not_available": "—" + }, + "auditPage": { + "appName": "Sign Made Easy", + "subtitle": "Transaction Audit", + "meta": { + "transactionId": "Transaction ID", + "transactionStatus": "Transaction Status", + "files": "Files" + }, + "audit": { + "title": "Full Audit Trail", + "description": "Please update the Subject and Message below for a custom message." + }, + "table": { + "actions": "Actions", + "language": "Language", + "ipAddress": "IP Address", + "date": "Date" + }, + "status": { + "completed": "Completed", + "pending": "Pending", + "failed": "Failed" + }, + "fallback": { + "notAvailable": "—" + } + }, + "audit": { + "transaction": { + "created": "Transaction was created by {{userName}} <{{userEmail}}>", + "sent": "Transaction was sent by {{userName}} <{{userEmail}}>", + "cancelled": "Transaction was cancelled by {{userName}} <{{userEmail}}>", + "edited": "Transaction was edited by {{userName}} <{{userEmail}}>", + "viewed": "Transaction was viewed by {{userName}} <{{userEmail}}>", + "signed": "Transaction was Signed by {{userName}} <{{userEmail}}>" + }, + "signature": { + "declined": "Transaction signature was declined by {{userName}} <{{userEmail}}>" + }, + "ers": { + "accepted": "Electronic Record and Signature Disclosure was accepted by {{userName}} <{{userEmail}}>" + }, + "language": { + "updated": "{{userName}} <{{userEmail}}> updated their language to {{language}}" + }, + "invitation": { + "sent": "Invitation email sent to {{userName}} <{{userEmail}}>", + "view": "Invitation to view document is sent to {{userName}} <{{userEmail}}>", + "resent": "Invitation email re-sent to {{recipientName}} <{{recipientEmail}}> by {{senderName}} <{{senderEmail}}>" + }, + "reassigned": { + "to": "Signer was reassigned by {{fromName}} <{{fromEmail}}> to {{toName}} <{{toEmail}}>", + "complex": "{{personName}} <{{personEmail}}> was reassigned by {{fromName}} <{{fromEmail}}> to {{toName}} <{{toEmail}}>" + }, + "inperson": { + "started": "In Person transaction was started by {{userName}} <{{userEmail}}>", + "verification": "In Person Signing Verification was accepted by {{userName}} <{{userEmail}}>" + }, + "facilitator": { + "accepted": "Facilitator Process was accepted by {{userName}} <{{userEmail}}>" + } + }, + "signatureModal": { + "title": { + "signature": "Signature", + "initial": "Initial", + "edit": "Edit", + "styleSelection": "Style Selection" + }, + "subtitle": "Create your digital signatures", + "tabs": { + "select": "Select", + "draw": "Draw", + "upload": "Upload" + }, + "selectTab": { + "description": "Confirm your name and choose a signature style.", + "requiredFields": "Required fields.", + "fullName": { + "label": "Full Name", + "required": "*", + "placeholder": "Enter full name" + }, + "initials": { + "label": "Initials", + "required": "*", + "placeholder": "Enter initials" + } + }, + "drawTab": { + "description": "Draw your signature.", + "required": "*", + "requiredFields": "Are required fields.", + "signature": "Signature", + "initials": "Initials", + "clearSignature": "Clear Signature", + "fullNameBox": { + "label": "Full Signature", + "required": "*" + }, + "initialsBox": { + "label": "Initials", + "required": "*", + "placeholder": "Enter initials" + } + }, + "uploadTab": { + "requiredMessage": "Both signature and initials are required.", + "requirements": "Use images of 300×100px for signatures and 100×100px for initials. Max 300KB. Supported: .png, .jpg.", + "signature": { + "uploadLabel": "Upload Signature", + "uploadHint": "JPG, PNG (300×100px, max 300KB)", + "browseButton": "Browse", + "uploadedLabel": "Signature ✓", + "changeButton": "Change Signature", + "altText": "Uploaded signature image" + }, + "initials": { + "uploadLabel": "Upload Initials", + "uploadHint": "JPG, PNG (100×100px, max 300KB)", + "browseButton": "Browse", + "uploadedLabel": "Initials ✓", + "changeButton": "Change Initials", + "altText": "Uploaded initials image" + } + }, + "footer": { + "agreementText": "I understand that, I am signing this document.", + "cancelButton": "Cancel", + "adoptButton": "Adopt Signature & Sign" + }, + "errors": { + "requiredField": "This field is required", + "fileTooLarge": "File size must be under 300KB", + "invalidFileType": "Only .png, .jpg, and .jpeg files are supported", + "signatureRequired": "Please add a signature", + "initialsRequired": "Please add initials" + } + }, + "stampModal": { + "title": { + "add": "Add Stamp", + "edit": "Edit Stamp" + }, + "closeButton": "Close modal", + "fileRequirements": "Maximum size = 400Kb | Supported file types = .png, .jpg, .jpeg", + "dragDropLabel": "Drag & drop an image, or click to upload", + "previewAltText": "Stamp Preview", + "changeImageButton": "Change image", + "clearButton": "Close", + "saveButton": "Save", + "updateButton": "Update", + "errors": { + "fileTooLarge": "File size exceeds 400KB limit", + "invalidFileType": "Only .png, .jpg, and .jpeg files are supported", + "uploadFailed": "Failed to upload image. Please try again." + } + }, + "attachmentModal": { + "title": "Attachment", + "subtitle": { + "hasFile": "Manage your attachment", + "noFile": "Upload attachment" + }, + "uploading": { + "status": "Uploading file...", + "shimmerText": "Uploading file..." + }, + "uploadArea": { + "dragging": "Drop your file here", + "default": "Upload or drag & drop file", + "fileTypes": "PDF, DOCX, JPG, PNG, TXT (max 10MB)", + "browseButton": "Browse Files" + }, + "uploadedFile": { + "status": "Uploaded successfully", + "deleteButton": "Delete file" + }, + "buttons": { + "close": "Close", + "uploading": "Uploading...", + "deleting": "Deleting...", + "saved": "File Saved!", + "done": "Done", + "uploadFile": "Upload File" + }, + "errors": { + "fileTooLarge": "File size exceeds 10MB limit", + "invalidFileType": "Only PDF, DOCX, JPG, PNG, and TXT files are supported", + "uploadFailed": "Failed to upload file. Please try again.", + "deleteFailed": "Failed to delete file. Please try again.", + "noFileSelected": "Please select a file before proceeding" + }, + "accessibility": { + "fileUpload": "File upload", + "deleteFile": "Delete file" + } + }, + "languages": { + "zh_CN": "Chinese (Simplified)", + "zh_TW": "Chinese (Traditional)", + "da": "Danish", + "nl_NL": "Dutch", + "en": "English", + "fi": "Finnish", + "fr": "French", + "de": "German", + "it": "Italian", + "ja": "Japanese", + "ko": "Korean", + "no": "Norwegian", + "pt_BR": "Portuguese (Brazil)", + "ru": "Russian", + "es": "Spanish", + "es_MX": "Spanish (Mexico)", + "sv": "Swedish", + "th": "Thai", + "he": "Hebrew" + }, + "session-expired": { + "title": "Session Expired", + "description": "This document signing link has expired due to inactivity or session timeout. Please return to your email and click the link again to continue signing." + }, + "inPersonComplete": { + "title": "🎉 Signing Complete!", + "subtitle": "Document has been successfully signed", + "thankYou": "Thank You for Signing!", + "message": "You will receive a confirmation email once the document has been signed by all parties.", + "passDevice": "You can now pass the device back to {{senderName}}", + "continueButton": "Continue" + } +} \ No newline at end of file diff --git a/public/locales/es/translation.json b/public/locales/es/translation.json new file mode 100644 index 0000000..59a0996 --- /dev/null +++ b/public/locales/es/translation.json @@ -0,0 +1,380 @@ +{ + "terms": { + "agreementText": "Al hacer clic en <0>Acepto, confirma que ha revisado la <1>Divulgación de registros electrónicos y firmas y consiente el uso de registros y firmas electrónicas en la revisión y ejecución de este documento.", + "note": "Nota:", + "noteText": "Aceptar esto no significa que esté firmando el documento inmediatamente. Solo le permite revisarlo electrónicamente. Tendrá la oportunidad de revisar el documento completo antes de firmar." + }, + "buttons": { + "agree": "Acepto", + "processing": "Procesando...", + "close": "Cerrar", + "downloadPdf": "Descargar PDF", + "downloading": "Descargando..." + }, + "header": { + "aiSummary": "Resumen de IA", + "completeSign": "Completar firma", + "sign": "Firmar", + "processing": "Procesando...", + "options": "Descargar" + }, + "menu": { + "downloadPdf": "Descargar PDF", + "auditTrail": "Pista de auditoría", + "reassignSigner": "Reasignar firmante", + "cancelTransaction": "Cancelar transacción", + "viewTerms": "Ver términos y condiciones", + "helpSupport": "Ayuda y soporte", + "about": "Acerca de SME" + }, + "sidebar": { + "documents": "Documentos", + "pages": "Páginas: {{count}}", + "noDocuments": "No hay documentos disponibles." + }, + "footer": { + "readyTitle": "¿Listo para finalizar?", + "readyDesc": "Ha completado los campos obligatorios. Revise su trabajo y luego seleccione Finalizar.", + "finish": "Finalizar", + "submitting": "Enviando...", + "start": "Comenzar", + "next": "Siguiente", + "agreementText": "Al firmar, acepto los <0>Términos y condiciones de Sign Made Easy." + }, + "completion": { + "complete": { + "hit": "¡Todo listo!", + "title": "Gracias por firmar", + "message": "Su documento ahora está completo y almacenado de forma segura. Le hemos enviado una copia por correo electrónico." + }, + "declined": { + "hit": "¡Acción cancelada!", + "title": "¡Tal vez la próxima vez!", + "message": "Su solicitud ha sido rechazada." + }, + "cancelled": { + "hit": "¡Acción cancelada!", + "title": "¡Tal vez la próxima vez!", + "message": "Su solicitud ha sido cancelada." + }, + "download": "Descargar", + "downloading": "Descargando...", + "downloadSuccess": "Archivo descargado correctamente.", + "downloadOptions": { + "pdf": "Documento PDF", + "audit": "Pistas de auditoría", + "selectFormat": "Seleccionar formato" + }, + "downloadError": "Error al descargar el archivo. Por favor, inténtelo de nuevo.", + "appsTitle": "Aumente la eficiencia con nuestras aplicaciones", + "formsTitle": "Genere formularios con facilidad", + "docsTitle": "Genere documentos (facturas, informes, cotizaciones)", + "tryNow": "Pruebe ahora", + "footerText": "Derechos de autor 2026 Sign Made Easy. Todos los derechos reservados.<0>Política de privacidad | <1>Política de uso razonable" + }, + "reassign": { + "title": "Reasignar firmante", + "successSubtitle": "El documento ha sido reasignado correctamente", + "successTitle": "¡Gracias!", + "successMessage": "El documento ha sido reasignado correctamente al nuevo firmante.", + "fields": { + "firstName": "Nombre", + "lastName": "Apellido", + "email": "Correo electrónico", + "language": "Idioma", + "message": "Mensaje opcional" + }, + "placeholders": { + "firstName": "Ingrese su nombre", + "lastName": "Ingrese su apellido", + "email": "your.email@example.com", + "message": "Escriba su mensaje aquí..." + }, + "buttons": { + "submit": "Enviar", + "submitting": "Enviando...", + "cancel": "Cancelar" + }, + "errors": { + "firstNameRequired": "El nombre es obligatorio", + "firstNameMin": "El nombre debe tener al menos 2 caracteres", + "lastNameRequired": "El apellido es obligatorio", + "lastNameMin": "El apellido debe tener al menos 2 caracteres", + "emailRequired": "El correo electrónico es obligatorio", + "emailInvalid": "Dirección de correo electrónico inválida" + } + }, + "cancelModal": { + "title": "Cancelar transacción", + "description": "¿Está seguro de que desea cancelar esta transacción? Proporcione el motivo de la cancelación a continuación.", + "placeholder": "Por favor, proporcione el motivo de la cancelación...", + "buttons": { + "no": "No, no cancelar", + "yes": "Sí, cancelarla" + }, + "errors": { + "reasonRequired": "El motivo de cancelación es obligatorio" + }, + "inPersonSuccess": { + "title": "Cancelar Transacción", + "message": "La transacción se canceló correctamente. Se enviaron correos de confirmación.", + "passBackDevice": "Ahora puede devolver el dispositivo a {{senderName}}.", + "continueButton": "Continuar" + } + }, + "enTranslations": { + "app.name": "Sign Made Easy", + "app.subtitle": "Auditoría de transacciones", + "meta.transaction_id": "ID de transacción", + "meta.transaction_status": "Estado de la transacción", + "meta.files": "Archivos", + "audit.title": "Pista de auditoría completa", + "audit.description": "Actualice el Asunto y el Mensaje a continuación para un mensaje personalizado.", + "table.header.actions": "Acciones", + "table.header.language": "Idioma", + "table.header.ip_address": "Dirección IP", + "table.header.date": "Fecha", + "status.completed": "Completado", + "status.pending": "Pendiente", + "status.failed": "Fallido", + "action.created": "Creado", + "action.updated": "Actualizado", + "action.deleted": "Eliminado", + "action.viewed": "Visto", + "action.signed": "Firmado", + "action.uploaded": "Cargado", + "action.downloaded": "Descargado", + "placeholder.not_available": "—" + }, + "auditPage": { + "appName": "Sign Made Easy", + "subtitle": "Auditoría de transacciones", + "meta": { + "transactionId": "ID de transacción", + "transactionStatus": "Estado de la transacción", + "files": "Archivos" + }, + "audit": { + "title": "Pista de auditoría completa", + "description": "Actualice el Asunto y el Mensaje a continuación para un mensaje personalizado." + }, + "table": { + "actions": "Acciones", + "language": "Idioma", + "ipAddress": "Dirección IP", + "date": "Fecha" + }, + "status": { + "completed": "Completado", + "pending": "Pendiente", + "failed": "Fallido" + }, + "fallback": { + "notAvailable": "—" + } + }, + "audit": { + "transaction": { + "created": "Transacción creada por {{userName}} <{{userEmail}}>", + "sent": "Transacción enviada por {{userName}} <{{userEmail}}>", + "cancelled": "Transacción cancelada por {{userName}} <{{userEmail}}>", + "edited": "Transacción editada por {{userName}} <{{userEmail}}>", + "viewed": "Transacción vista por {{userName}} <{{userEmail}}>", + "signed": "Transacción firmada por {{userName}} <{{userEmail}}>" + }, + "signature": { + "declined": "Firma de transacción rechazada por {{userName}} <{{userEmail}}>" + }, + "ers": { + "accepted": "Divulgación de Registro Electrónico y Firma aceptada por {{userName}} <{{userEmail}}>" + }, + "language": { + "updated": "{{userName}} <{{userEmail}}> actualizó su idioma a {{language}}" + }, + "invitation": { + "sent": "Invitación por correo enviada a {{userName}} <{{userEmail}}>", + "view": "La invitación para ver el documento se envió a {{userName}} <{{userEmail}}>", + "resent": "Invitación reenviada a {{recipientName}} <{{recipientEmail}}> por {{senderName}} <{{senderEmail}}>" + }, + "reassigned": { + "to": "Firmante reasignado por {{fromName}} <{{fromEmail}}> a {{toName}} <{{toEmail}}>", + "complex": "{{personName}} <{{personEmail}}> fue reasignado por {{fromName}} <{{fromEmail}}> a {{toName}} <{{toEmail}}>" + }, + "inperson": { + "started": "Transacción en persona iniciada por {{userName}} <{{userEmail}}>", + "verification": "Verificación de firma en persona aceptada por {{userName}} <{{userEmail}}>" + }, + "facilitator": { + "accepted": "Proceso de Facilitador aceptado por {{userName}} <{{userEmail}}>" + } + }, + "signatureModal": { + "title": { + "signature": "Firma", + "initial": "Inicial", + "edit": "Editar", + "styleSelection": "Selección de Estilo" + }, + "subtitle": "Crea tus firmas digitales", + "tabs": { + "select": "Seleccionar", + "draw": "Dibujar", + "upload": "Subir" + }, + "selectTab": { + "description": "Confirma tu nombre y elige un estilo de firma.", + "requiredFields": "Campos requeridos.", + "fullName": { + "label": "Nombre Completo", + "required": "*", + "placeholder": "Ingresa el nombre completo" + }, + "initials": { + "label": "Iniciales", + "required": "*", + "placeholder": "Ingresa las iniciales" + } + }, + "drawTab": { + "description": "Dibuje su firma.", + "required": "*", + "requiredFields": "Son campos obligatorios.", + "signature": "Firma", + "initials": "Iniciales", + "clearSignature": "Borrar firma", + "fullNameBox": { + "label": "Firma completa", + "required": "*" + }, + "initialsBox": { + "label": "Iniciales", + "required": "*", + "placeholder": "Ingrese las iniciales" + } + }, + "uploadTab": { + "requiredMessage": "Tanto la firma como las iniciales son requeridas.", + "requirements": "Usa imágenes de 300×100px para firmas y 100×100px para iniciales. Máx. 300KB. Compatible: .png, .jpg.", + "signature": { + "uploadLabel": "Subir Firma", + "uploadHint": "JPG, PNG (300×100px, máx. 300KB)", + "browseButton": "Examinar", + "uploadedLabel": "Firma ✓", + "changeButton": "Cambiar Firma", + "altText": "Imagen de firma subida" + }, + "initials": { + "uploadLabel": "Subir Iniciales", + "uploadHint": "JPG, PNG (100×100px, máx. 300KB)", + "browseButton": "Examinar", + "uploadedLabel": "Iniciales ✓", + "changeButton": "Cambiar Iniciales", + "altText": "Imagen de iniciales subida" + } + }, + "footer": { + "agreementText": "Entiendo que estoy firmando este documento.", + "cancelButton": "Cancelar", + "adoptButton": "Adoptar Firma y Firmar" + }, + "errors": { + "requiredField": "Este campo es requerido", + "fileTooLarge": "El tamaño del archivo debe ser menor a 300KB", + "invalidFileType": "Solo se admiten archivos .png, .jpg y .jpeg", + "signatureRequired": "Por favor agrega una firma", + "initialsRequired": "Por favor agrega iniciales" + } + }, + "stampModal": { + "title": { + "add": "Agregar Sello", + "edit": "Editar Sello" + }, + "closeButton": "Cerrar modal", + "fileRequirements": "Tamaño máximo = 400Kb | Tipos de archivo admitidos = .png, .jpg, .jpeg", + "dragDropLabel": "Arrastra y suelta una imagen, o haz clic para subir", + "previewAltText": "Vista Previa del Sello", + "changeImageButton": "Cambiar imagen", + "clearButton": "Cerrar", + "saveButton": "Guardar", + "updateButton": "Actualizar", + "errors": { + "fileTooLarge": "El tamaño del archivo excede el límite de 400KB", + "invalidFileType": "Solo se admiten archivos .png, .jpg y .jpeg", + "uploadFailed": "Error al subir la imagen. Por favor, inténtalo de nuevo." + } + }, + "attachmentModal": { + "title": "Adjunto", + "subtitle": { + "hasFile": "Gestionar tu adjunto", + "noFile": "Subir adjunto" + }, + "uploading": { + "status": "Subiendo archivo...", + "shimmerText": "Subiendo archivo..." + }, + "uploadArea": { + "dragging": "Suelta tu archivo aquí", + "default": "Subir o arrastrar y soltar archivo", + "fileTypes": "PDF, DOCX, JPG, PNG, TXT (máx. 10MB)", + "browseButton": "Examinar Archivos" + }, + "uploadedFile": { + "status": "Subido exitosamente", + "deleteButton": "Eliminar archivo" + }, + "buttons": { + "close": "Cerrar", + "uploading": "Subiendo...", + "deleting": "Eliminando...", + "saved": "¡Archivo Guardado!", + "done": "Hecho", + "uploadFile": "Subir Archivo" + }, + "errors": { + "fileTooLarge": "El tamaño del archivo excede el límite de 10MB", + "invalidFileType": "Solo se admiten archivos PDF, DOCX, JPG, PNG y TXT", + "uploadFailed": "Error al subir el archivo. Por favor, inténtalo de nuevo.", + "deleteFailed": "Error al eliminar el archivo. Por favor, inténtalo de nuevo.", + "noFileSelected": "Por favor selecciona un archivo antes de continuar" + }, + "accessibility": { + "fileUpload": "Subida de archivo", + "deleteFile": "Eliminar archivo" + } + }, + "languages": { + "zh_CN": "Chino (Simplificado)", + "zh_TW": "Chino (Tradicional)", + "da": "Danés", + "nl_NL": "Neerlandés", + "en": "Inglés", + "fi": "Finlandés", + "fr": "Francés", + "de": "Alemán", + "it": "Italiano", + "ja": "Japonés", + "ko": "Coreano", + "no": "Noruego", + "pt_BR": "Portugués (Brasil)", + "ru": "Ruso", + "es": "Español", + "es_MX": "Español (México)", + "sv": "Sueco", + "th": "Tailandés", + "he": "Hebreo" + }, + "session-expired": { + "title": "Sesión expirada", + "description": "Este enlace de firma de documento ha expirado debido a inactividad o tiempo de espera de la sesión. Vuelva a su correo electrónico y haga clic en el enlace nuevamente para continuar firmando." + }, + "inPersonComplete": { + "title": "🎉 ¡Firma completada!", + "subtitle": "El documento ha sido firmado exitosamente", + "thankYou": "¡Gracias por firmar!", + "message": "Recibirá un correo electrónico de confirmación una vez que el documento haya sido firmado por todas las partes.", + "passDevice": "Ahora puede devolver el dispositivo a {{senderName}}", + "continueButton": "Continuar" + } +} \ No newline at end of file diff --git a/public/locales/es_MX/translation.json b/public/locales/es_MX/translation.json new file mode 100644 index 0000000..e5bc487 --- /dev/null +++ b/public/locales/es_MX/translation.json @@ -0,0 +1,380 @@ +{ + "terms": { + "agreementText": "Al hacer clic en <0>Acepto, confirma que ha revisado la <1>Divulgación de registros electrónicos y firmas y da su consentimiento para el uso de registros y firmas electrónicas en la revisión y ejecución de este documento.", + "note": "Nota:", + "noteText": "Aceptar esto no significa que esté firmando el documento de inmediato. Solo le permite revisarlo electrónicamente. Tendrá la oportunidad de revisar el documento completo antes de firmar." + }, + "buttons": { + "agree": "Acepto", + "processing": "Procesando...", + "close": "Cerrar", + "downloadPdf": "Descargar PDF", + "downloading": "Descargando..." + }, + "header": { + "aiSummary": "Resumen de IA", + "completeSign": "Completar firma", + "sign": "Firmar", + "processing": "Procesando...", + "options": "Descargar" + }, + "menu": { + "downloadPdf": "Descargar PDF", + "auditTrail": "Pista de auditoría", + "reassignSigner": "Reasignar firmante", + "cancelTransaction": "Cancelar transacción", + "viewTerms": "Ver términos y condiciones", + "helpSupport": "Ayuda y soporte", + "about": "Acerca de SME" + }, + "sidebar": { + "documents": "Documentos", + "pages": "Páginas: {{count}}", + "noDocuments": "No hay documentos disponibles." + }, + "footer": { + "readyTitle": "¿Listo para finalizar?", + "readyDesc": "Ha completado los campos obligatorios. Revise su trabajo y luego seleccione Finalizar.", + "finish": "Finalizar", + "submitting": "Enviando...", + "start": "Comenzar", + "next": "Siguiente", + "agreementText": "Al firmar, acepto los <0>Términos y condiciones de Sign Made Easy." + }, + "completion": { + "complete": { + "hit": "¡Todo listo!", + "title": "Gracias por firmar", + "message": "Su documento ahora está completo y almacenado de forma segura. Le hemos enviado una copia por correo electrónico." + }, + "declined": { + "hit": "¡Acción cancelada!", + "title": "¡Quizás la próxima vez!", + "message": "Su solicitud ha sido rechazada exitosamente." + }, + "cancelled": { + "hit": "¡Acción cancelada!", + "title": "¡Quizás la próxima vez!", + "message": "Su solicitud ha sido cancelada exitosamente." + }, + "download": "Descargar", + "downloading": "Descargando...", + "downloadSuccess": "Archivo descargado exitosamente.", + "downloadOptions": { + "pdf": "Documento PDF", + "audit": "Pistas de auditoría", + "selectFormat": "Seleccionar formato" + }, + "downloadError": "Error al descargar el archivo. Por favor, inténtelo de nuevo.", + "appsTitle": "Aumente la eficiencia con nuestras aplicaciones", + "formsTitle": "Genere formularios con facilidad", + "docsTitle": "Genere documentos (facturas, informes, cotizaciones)", + "tryNow": "Probar ahora", + "footerText": "Derechos de autor 2026 Sign Made Easy. Todos los derechos reservados.<0>Política de privacidad | <1>Política de uso razonable" + }, + "reassign": { + "title": "Reasignar firmante", + "successSubtitle": "El documento ha sido reasignado exitosamente", + "successTitle": "¡Gracias!", + "successMessage": "El documento ha sido reasignado exitosamente al nuevo firmante.", + "fields": { + "firstName": "Nombre", + "lastName": "Apellido", + "email": "Correo electrónico", + "language": "Idioma", + "message": "Mensaje opcional" + }, + "placeholders": { + "firstName": "Ingrese su nombre", + "lastName": "Ingrese su apellido", + "email": "your.email@example.com", + "message": "Escriba su mensaje aquí..." + }, + "buttons": { + "submit": "Enviar", + "submitting": "Enviando...", + "cancel": "Cancelar" + }, + "errors": { + "firstNameRequired": "El nombre es obligatorio", + "firstNameMin": "El nombre debe tener al menos 2 caracteres", + "lastNameRequired": "El apellido es obligatorio", + "lastNameMin": "El apellido debe tener al menos 2 caracteres", + "emailRequired": "El correo electrónico es obligatorio", + "emailInvalid": "Dirección de correo electrónico inválida" + } + }, + "cancelModal": { + "title": "Cancelar transacción", + "description": "¿Está seguro de que desea cancelar esta transacción? Proporcione el motivo de cancelación a continuación.", + "placeholder": "Por favor, proporcione el motivo de cancelación...", + "buttons": { + "no": "No, no cancelar", + "yes": "Sí, cancelarla" + }, + "errors": { + "reasonRequired": "El motivo de cancelación es obligatorio" + }, + "inPersonSuccess": { + "title": "Cancelar Transacción", + "message": "La transacción se canceló correctamente. Se enviaron correos de confirmación.", + "passBackDevice": "Ahora puede devolver el dispositivo a {{senderName}}.", + "continueButton": "Continuar" + } + }, + "enTranslations": { + "app.name": "Sign Made Easy", + "app.subtitle": "Auditoría de transacciones", + "meta.transaction_id": "ID de transacción", + "meta.transaction_status": "Estado de la transacción", + "meta.files": "Archivos", + "audit.title": "Pista de auditoría completa", + "audit.description": "Actualice el Asunto y el Mensaje a continuación para un mensaje personalizado.", + "table.header.actions": "Acciones", + "table.header.language": "Idioma", + "table.header.ip_address": "Dirección IP", + "table.header.date": "Fecha", + "status.completed": "Completado", + "status.pending": "Pendiente", + "status.failed": "Fallido", + "action.created": "Creado", + "action.updated": "Actualizado", + "action.deleted": "Eliminado", + "action.viewed": "Visto", + "action.signed": "Firmado", + "action.uploaded": "Cargado", + "action.downloaded": "Descargado", + "placeholder.not_available": "—" + }, + "auditPage": { + "appName": "Sign Made Easy", + "subtitle": "Auditoría de transacciones", + "meta": { + "transactionId": "ID de transacción", + "transactionStatus": "Estado de la transacción", + "files": "Archivos" + }, + "audit": { + "title": "Pista de auditoría completa", + "description": "Actualice el Asunto y el Mensaje a continuación para un mensaje personalizado." + }, + "table": { + "actions": "Acciones", + "language": "Idioma", + "ipAddress": "Dirección IP", + "date": "Fecha" + }, + "status": { + "completed": "Completado", + "pending": "Pendiente", + "failed": "Fallido" + }, + "fallback": { + "notAvailable": "—" + } + }, + "audit": { + "transaction": { + "created": "Transacción creada por {{userName}} <{{userEmail}}>", + "sent": "Transacción enviada por {{userName}} <{{userEmail}}>", + "cancelled": "Transacción cancelada por {{userName}} <{{userEmail}}>", + "edited": "Transacción editada por {{userName}} <{{userEmail}}>", + "viewed": "Transacción vista por {{userName}} <{{userEmail}}>", + "signed": "Transacción firmada por {{userName}} <{{userEmail}}>" + }, + "signature": { + "declined": "Firma de transacción rechazada por {{userName}} <{{userEmail}}>" + }, + "ers": { + "accepted": "Divulgación de Registro Electrónico y Firma aceptada por {{userName}} <{{userEmail}}>" + }, + "language": { + "updated": "{{userName}} <{{userEmail}}> actualizó su idioma a {{language}}" + }, + "invitation": { + "sent": "Invitación por correo enviada a {{userName}} <{{userEmail}}>", + "view": "La invitación para ver el documento se envió a {{userName}} <{{userEmail}}>", + "resent": "Invitación reenviada a {{recipientName}} <{{recipientEmail}}> por {{senderName}} <{{senderEmail}}>" + }, + "reassigned": { + "to": "Firmante reasignado por {{fromName}} <{{fromEmail}}> a {{toName}} <{{toEmail}}>", + "complex": "{{personName}} <{{personEmail}}> fue reasignado por {{fromName}} <{{fromEmail}}> a {{toName}} <{{toEmail}}>" + }, + "inperson": { + "started": "Transacción en persona iniciada por {{userName}} <{{userEmail}}>", + "verification": "Verificación de firma en persona aceptada por {{userName}} <{{userEmail}}>" + }, + "facilitator": { + "accepted": "Proceso de Facilitador aceptado por {{userName}} <{{userEmail}}>" + } + }, + "signatureModal": { + "title": { + "signature": "Firma", + "initial": "Inicial", + "edit": "Editar", + "styleSelection": "Selección de estilo" + }, + "subtitle": "Cree sus firmas digitales", + "tabs": { + "select": "Seleccionar", + "draw": "Dibujar", + "upload": "Subir" + }, + "selectTab": { + "description": "Confirme su nombre y elija un estilo de firma.", + "requiredFields": "Campos obligatorios.", + "fullName": { + "label": "Nombre completo", + "required": "*", + "placeholder": "Ingrese el nombre completo" + }, + "initials": { + "label": "Iniciales", + "required": "*", + "placeholder": "Ingrese las iniciales" + } + }, + "drawTab": { + "description": "Dibuje su firma.", + "required": "*", + "requiredFields": "Son campos obligatorios.", + "signature": "Firma", + "initials": "Iniciales", + "clearSignature": "Borrar firma", + "fullNameBox": { + "label": "Firma completa", + "required": "*" + }, + "initialsBox": { + "label": "Iniciales", + "required": "*", + "placeholder": "Ingrese las iniciales" + } + }, + "uploadTab": { + "requiredMessage": "Tanto la firma como las iniciales son obligatorias.", + "requirements": "Use imágenes de 300×100px para firmas y de 100×100px para iniciales. Máx. 300KB. Compatibles: .png, .jpg.", + "signature": { + "uploadLabel": "Subir firma", + "uploadHint": "JPG, PNG (300×100px, máx. 300KB)", + "browseButton": "Examinar", + "uploadedLabel": "Firma ✓", + "changeButton": "Cambiar firma", + "altText": "Imagen de firma subida" + }, + "initials": { + "uploadLabel": "Subir iniciales", + "uploadHint": "JPG, PNG (100×100px, máx. 300KB)", + "browseButton": "Examinar", + "uploadedLabel": "Iniciales ✓", + "changeButton": "Cambiar iniciales", + "altText": "Imagen de iniciales subida" + } + }, + "footer": { + "agreementText": "Entiendo que estoy firmando este documento.", + "cancelButton": "Cancelar", + "adoptButton": "Adoptar firma y firmar" + }, + "errors": { + "requiredField": "Este campo es obligatorio", + "fileTooLarge": "El tamaño del archivo debe ser menor a 300KB", + "invalidFileType": "Solo se admiten archivos .png, .jpg y .jpeg", + "signatureRequired": "Por favor agregue una firma", + "initialsRequired": "Por favor agregue las iniciales" + } + }, + "stampModal": { + "title": { + "add": "Agregar sello", + "edit": "Editar sello" + }, + "closeButton": "Cerrar modal", + "fileRequirements": "Tamaño máximo = 400KB | Tipos de archivo compatibles = .png, .jpg, .jpeg", + "dragDropLabel": "Arrastre y suelte una imagen, o haga clic para subir", + "previewAltText": "Vista previa del sello", + "changeImageButton": "Cambiar imagen", + "clearButton": "Cerrar", + "saveButton": "Guardar", + "updateButton": "Actualizar", + "errors": { + "fileTooLarge": "El tamaño del archivo excede el límite de 400KB", + "invalidFileType": "Solo se admiten archivos .png, .jpg y .jpeg", + "uploadFailed": "Error al subir la imagen. Intente de nuevo." + } + }, + "attachmentModal": { + "title": "Adjunto", + "subtitle": { + "hasFile": "Administre su adjunto", + "noFile": "Subir adjunto" + }, + "uploading": { + "status": "Subiendo archivo...", + "shimmerText": "Subiendo archivo..." + }, + "uploadArea": { + "dragging": "Suelte su archivo aquí", + "default": "Subir o arrastrar y soltar archivo", + "fileTypes": "PDF, DOCX, JPG, PNG, TXT (máx. 10MB)", + "browseButton": "Examinar archivos" + }, + "uploadedFile": { + "status": "Subido exitosamente", + "deleteButton": "Eliminar archivo" + }, + "buttons": { + "close": "Cerrar", + "uploading": "Subiendo...", + "deleting": "Eliminando...", + "saved": "¡Archivo guardado!", + "done": "Listo", + "uploadFile": "Subir archivo" + }, + "errors": { + "fileTooLarge": "El tamaño del archivo excede el límite de 10MB", + "invalidFileType": "Solo se admiten archivos PDF, DOCX, JPG, PNG y TXT", + "uploadFailed": "Error al subir el archivo. Intente de nuevo.", + "deleteFailed": "Error al eliminar el archivo. Intente de nuevo.", + "noFileSelected": "Por favor seleccione un archivo antes de continuar" + }, + "accessibility": { + "fileUpload": "Subida de archivo", + "deleteFile": "Eliminar archivo" + } + }, + "languages": { + "zh_CN": "Chino (Simplificado)", + "zh_TW": "Chino (Tradicional)", + "da": "Danés", + "nl_NL": "Neerlandés", + "en": "Inglés", + "fi": "Finlandés", + "fr": "Francés", + "de": "Alemán", + "it": "Italiano", + "ja": "Japonés", + "ko": "Coreano", + "no": "Noruego", + "pt_BR": "Portugués (Brasil)", + "ru": "Ruso", + "es": "Español", + "es_MX": "Español (México)", + "sv": "Sueco", + "th": "Tailandés", + "he": "Hebreo" + }, + "session-expired": { + "title": "Sesión expirada", + "description": "Este enlace de firma de documento ha expirado debido a inactividad o tiempo de espera de la sesión. Regrese a su correo electrónico y haga clic en el enlace nuevamente para continuar firmando." + }, + "inPersonComplete": { + "title": "🎉 ¡Firma completada!", + "subtitle": "El documento ha sido firmado exitosamente", + "thankYou": "¡Gracias por firmar!", + "message": "Recibirá un correo electrónico de confirmación una vez que el documento haya sido firmado por todas las partes.", + "passDevice": "Ahora puede devolver el dispositivo a {{senderName}}", + "continueButton": "Continuar" + } +} \ No newline at end of file diff --git a/public/locales/fi/translation.json b/public/locales/fi/translation.json new file mode 100644 index 0000000..025f610 --- /dev/null +++ b/public/locales/fi/translation.json @@ -0,0 +1,380 @@ +{ + "terms": { + "agreementText": "Napsauttamalla <0>Hyväksyn vahvistat, että olet tarkistanut <1>Sähköinen tallennus- ja allekirjoitusilmoitus -asiakirjan ja annat suostumuksesi sähköisten tallenteiden ja allekirjoitusten käyttöön tämän asiakirjan tarkastelussa ja allekirjoittamisessa.", + "note": "Huomautus:", + "noteText": "Tämän hyväksyminen ei tarkoita, että allekirjoitat asiakirjan välittömästi. Se sallii sinun vain tarkastella sitä sähköisesti. Sinulla on mahdollisuus tarkastella asiakirjaa kokonaisuudessaan ennen allekirjoittamista." + }, + "buttons": { + "agree": "Hyväksyn", + "processing": "Käsitellään...", + "close": "Sulje", + "downloadPdf": "Lataa PDF", + "downloading": "Ladataan..." + }, + "header": { + "aiSummary": "AI-yhteenveto", + "completeSign": "Suorita allekirjoitus", + "sign": "Allekirjoita", + "processing": "Käsitellään...", + "options": "Lataa" + }, + "menu": { + "downloadPdf": "Lataa PDF", + "auditTrail": "Tarkastusjälki", + "reassignSigner": "Määritä allekirjoittaja uudelleen", + "cancelTransaction": "Peruuta tapahtuma", + "viewTerms": "Näytä ehdot", + "helpSupport": "Apua ja tuki", + "about": "Tietoja SME:stä" + }, + "sidebar": { + "documents": "Asiakirjat", + "pages": "Sivut: {{count}}", + "noDocuments": "Ei asiakirjoja saatavilla." + }, + "footer": { + "readyTitle": "Valmis viimeistelemään?", + "readyDesc": "Olet täyttänyt vaaditut kentät. Tarkista työsi ja valitse sitten Viimeistele.", + "finish": "Viimeistele", + "submitting": "Lähetetään...", + "start": "Aloita", + "next": "Seuraava", + "agreementText": "Allekirjoittamalla hyväksyn Sign Made Easyn <0>käyttöehdot." + }, + "completion": { + "complete": { + "hit": "Kaikki valmista!", + "title": "Kiitos allekirjoituksesta", + "message": "Asiakirjasi on nyt valmis ja tallennettu turvallisesti. Olemme lähettäneet sinulle kopion sähköpostitse." + }, + "declined": { + "hit": "Toiminto peruttu!", + "title": "Ehkä ensi kerralla!", + "message": "Pyyntösi on hylätty." + }, + "cancelled": { + "hit": "Toiminto peruttu!", + "title": "Ehkä ensi kerralla!", + "message": "Pyyntösi on peruttu." + }, + "download": "Lataa", + "downloading": "Ladataan...", + "downloadSuccess": "Tiedosto ladattu onnistuneesti.", + "downloadOptions": { + "pdf": "PDF-asiakirja", + "audit": "Tarkastusjälki", + "selectFormat": "Valitse muoto" + }, + "downloadError": "Tiedoston lataus epäonnistui. Yritä uudelleen.", + "appsTitle": "Tehosta toimintaamme sovelluksillamme", + "formsTitle": "Luo lomakkeita helposti", + "docsTitle": "Luo asiakirjoja (laskut, raportit, tarjoukset)", + "tryNow": "Kokeile nyt", + "footerText": "Tekijänoikeus 2026 Sign Made Easy. Kaikki oikeudet pidätetään.<0>Tietosuojakäytäntö | <1>Kohtuullisen käytön käytäntö" + }, + "reassign": { + "title": "Määritä allekirjoittaja uudelleen", + "successSubtitle": "Asiakirja on määritetty uudelleen", + "successTitle": "Kiitos!", + "successMessage": "Asiakirja on määritetty uudelleen uudelle allekirjoittajalle.", + "fields": { + "firstName": "Etunimi", + "lastName": "Sukunimi", + "email": "Sähköposti", + "language": "Kieli", + "message": "Valinnainen viesti" + }, + "placeholders": { + "firstName": "Syötä etunimesi", + "lastName": "Syötä sukunimesi", + "email": "your.email@example.com", + "message": "Kirjoita viestisi tähän..." + }, + "buttons": { + "submit": "Lähetä", + "submitting": "Lähetetään...", + "cancel": "Peruuta" + }, + "errors": { + "firstNameRequired": "Etunimi vaaditaan", + "firstNameMin": "Etunimen on oltava vähintään 2 merkkiä", + "lastNameRequired": "Sukunimi vaaditaan", + "lastNameMin": "Sukunimen on oltava vähintään 2 merkkiä", + "emailRequired": "Sähköposti vaaditaan", + "emailInvalid": "Virheellinen sähköpostiosoite" + } + }, + "cancelModal": { + "title": "Peruuta tapahtuma", + "description": "Oletko varma, että haluat peruuttaa tämän tapahtuman? Anna peruutuksen syy alla.", + "placeholder": "Anna peruutuksen syy...", + "buttons": { + "no": "Ei, älä peruuta", + "yes": "Kyllä, peruuta se" + }, + "errors": { + "reasonRequired": "Peruutuksen syy vaaditaan" + }, + "inPersonSuccess": { + "title": "Peruuta tapahtuma", + "message": "Tapahtuma peruutettiin onnistuneesti. Vahvistussähköpostit on lähetetty.", + "passBackDevice": "Voit nyt antaa laitteen takaisin {{senderName}}.", + "continueButton": "Jatka" + } + }, + "enTranslations": { + "app.name": "Sign Made Easy", + "app.subtitle": "Tapahtuman tarkastus", + "meta.transaction_id": "Tapahtumatunnus", + "meta.transaction_status": "Tapahtuman tila", + "meta.files": "Tiedostot", + "audit.title": "Täysi tarkastusjälki", + "audit.description": "Päivitä alla oleva aihe ja viesti mukautettua viestiä varten.", + "table.header.actions": "Toiminnot", + "table.header.language": "Kieli", + "table.header.ip_address": "IP-osoite", + "table.header.date": "Päivämäärä", + "status.completed": "Valmis", + "status.pending": "Odottaa", + "status.failed": "Epäonnistui", + "action.created": "Luotu", + "action.updated": "Päivitetty", + "action.deleted": "Poistettu", + "action.viewed": "Näytetty", + "action.signed": "Allekirjoitettu", + "action.uploaded": "Ladattu", + "action.downloaded": "Ladattu", + "placeholder.not_available": "—" + }, + "auditPage": { + "appName": "Sign Made Easy", + "subtitle": "Tapahtuman tarkastus", + "meta": { + "transactionId": "Tapahtumatunnus", + "transactionStatus": "Tapahtuman tila", + "files": "Tiedostot" + }, + "audit": { + "title": "Täysi tarkastusjälki", + "description": "Päivitä alla oleva aihe ja viesti mukautettua viestiä varten." + }, + "table": { + "actions": "Toiminnot", + "language": "Kieli", + "ipAddress": "IP-osoite", + "date": "Päivämäärä" + }, + "status": { + "completed": "Valmis", + "pending": "Odottaa", + "failed": "Epäonnistui" + }, + "fallback": { + "notAvailable": "—" + } + }, + "audit": { + "transaction": { + "created": "Tapahtuman loi {{userName}} <{{userEmail}}>", + "sent": "Tapahtuman lähetti {{userName}} <{{userEmail}}>", + "cancelled": "Tapahtuman peruutti {{userName}} <{{userEmail}}>", + "edited": "Tapahtumaa muokkasi {{userName}} <{{userEmail}}>", + "viewed": "Tapahtuman katsoi {{userName}} <{{userEmail}}>", + "signed": "Tapahtuman allekirjoitti {{userName}} <{{userEmail}}>" + }, + "signature": { + "declined": "Tapahtuman allekirjoitus hylättiin käyttäjällä {{userName}} <{{userEmail}}>" + }, + "ers": { + "accepted": "Sähköinen tietue- ja allekirjoitusilmoitus hyväksyttiin käyttäjällä {{userName}} <{{userEmail}}>" + }, + "language": { + "updated": "{{userName}} <{{userEmail}}> päivitti kielensä muotoon {{language}}" + }, + "invitation": { + "sent": "Kutsusähköposti lähetettiin käyttäjälle {{userName}} <{{userEmail}}>", + "view": "Kutsu asiakirjan tarkasteluun on lähetetty käyttäjälle {{userName}} <{{userEmail}}>", + "resent": "Kutsusähköposti lähetettiin uudelleen käyttäjälle {{recipientName}} <{{recipientEmail}}> käyttäjän {{senderName}} <{{senderEmail}}> toimesta" + }, + "reassigned": { + "to": "Allekirjoittaja siirrettiin käyttäjältä {{fromName}} <{{fromEmail}}> käyttäjälle {{toName}} <{{toEmail}}>", + "complex": "{{personName}} <{{personEmail}}> siirrettiin käyttäjältä {{fromName}} <{{fromEmail}}> käyttäjälle {{toName}} <{{toEmail}}>" + }, + "inperson": { + "started": "Henkilökohtainen tapahtuma aloitettiin käyttäjällä {{userName}} <{{userEmail}}>", + "verification": "Henkilökohtainen allekirjoituksen vahvistus hyväksyttiin käyttäjällä {{userName}} <{{userEmail}}>" + }, + "facilitator": { + "accepted": "Fasilitaattoriprosessi hyväksyttiin käyttäjällä {{userName}} <{{userEmail}}>" + } + }, + "signatureModal": { + "title": { + "signature": "Allekirjoitus", + "initial": "Alkukirjaimet", + "edit": "Muokkaa", + "styleSelection": "Tyylin valinta" + }, + "subtitle": "Luo digitaaliset allekirjoituksesi", + "tabs": { + "select": "Valitse", + "draw": "Piirrä", + "upload": "Lataa" + }, + "selectTab": { + "description": "Vahvista nimesi ja valitse allekirjoitustyyli.", + "requiredFields": "Pakolliset kentät.", + "fullName": { + "label": "Koko nimi", + "required": "*", + "placeholder": "Kirjoita koko nimi" + }, + "initials": { + "label": "Alkukirjaimet", + "required": "*", + "placeholder": "Kirjoita alkukirjaimet" + } + }, + "drawTab": { + "description": "Piirrä allekirjoituksesi.", + "required": "*", + "requiredFields": "Ovat pakollisia kenttiä.", + "signature": "Allekirjoitus", + "initials": "Alkukirjaimet", + "clearSignature": "Tyhjennä allekirjoitus", + "fullNameBox": { + "label": "Koko allekirjoitus", + "required": "*" + }, + "initialsBox": { + "label": "Alkukirjaimet", + "required": "*", + "placeholder": "Syötä alkukirjaimet" + } + }, + "uploadTab": { + "requiredMessage": "Sekä allekirjoitus että alkukirjaimet vaaditaan.", + "requirements": "Käytä 300×100px kuvia allekirjoituksiin ja 100×100px kuvia alkukirjaimiin. Max 300KB. Tuetut: .png, .jpg.", + "signature": { + "uploadLabel": "Lataa allekirjoitus", + "uploadHint": "JPG, PNG (300×100px, max 300KB)", + "browseButton": "Selaa", + "uploadedLabel": "Allekirjoitus ✓", + "changeButton": "Vaihda allekirjoitus", + "altText": "Ladattu allekirjoituskuva" + }, + "initials": { + "uploadLabel": "Lataa alkukirjaimet", + "uploadHint": "JPG, PNG (100×100px, max 300KB)", + "browseButton": "Selaa", + "uploadedLabel": "Alkukirjaimet ✓", + "changeButton": "Vaihda alkukirjaimet", + "altText": "Ladattu alkukirjainkuva" + } + }, + "footer": { + "agreementText": "Ymmärrän, että allekirjoitan tämän asiakirjan.", + "cancelButton": "Peruuta", + "adoptButton": "Käytä allekirjoitusta ja allekirjoita" + }, + "errors": { + "requiredField": "Tämä kenttä on pakollinen", + "fileTooLarge": "Tiedostokoon on oltava alle 300KB", + "invalidFileType": "Vain .png, .jpg ja .jpeg tiedostot tuetaan", + "signatureRequired": "Lisää allekirjoitus", + "initialsRequired": "Lisää alkukirjaimet" + } + }, + "stampModal": { + "title": { + "add": "Lisää leima", + "edit": "Muokkaa leimaa" + }, + "closeButton": "Sulje modaali", + "fileRequirements": "Maksimikoko = 400Kb | Tuetut tiedostotyypit = .png, .jpg, .jpeg", + "dragDropLabel": "Vedä ja pudota kuva, tai klikkaa ladataksesi", + "previewAltText": "Leiman esikatselu", + "changeImageButton": "Vaihda kuva", + "clearButton": "Sulje", + "saveButton": "Tallenna", + "updateButton": "Päivitä", + "errors": { + "fileTooLarge": "Tiedostokoko ylittää 400KB rajan", + "invalidFileType": "Vain .png, .jpg ja .jpeg tiedostot tuetaan", + "uploadFailed": "Kuvan lataus epäonnistui. Yritä uudelleen." + } + }, + "attachmentModal": { + "title": "Liite", + "subtitle": { + "hasFile": "Hallitse liitettäsi", + "noFile": "Lataa liite" + }, + "uploading": { + "status": "Ladataan tiedostoa...", + "shimmerText": "Ladataan tiedostoa..." + }, + "uploadArea": { + "dragging": "Pudota tiedosto tähän", + "default": "Lataa tai vedä ja pudota tiedosto", + "fileTypes": "PDF, DOCX, JPG, PNG, TXT (max 10MB)", + "browseButton": "Selaa tiedostoja" + }, + "uploadedFile": { + "status": "Ladattu onnistuneesti", + "deleteButton": "Poista tiedosto" + }, + "buttons": { + "close": "Sulje", + "uploading": "Ladataan...", + "deleting": "Poistetaan...", + "saved": "Tiedosto tallennettu!", + "done": "Valmis", + "uploadFile": "Lataa tiedosto" + }, + "errors": { + "fileTooLarge": "Tiedostokoko ylittää 10MB rajan", + "invalidFileType": "Vain PDF, DOCX, JPG, PNG ja TXT tiedostot tuetaan", + "uploadFailed": "Tiedoston lataus epäonnistui. Yritä uudelleen.", + "deleteFailed": "Tiedoston poisto epäonnistui. Yritä uudelleen.", + "noFileSelected": "Valitse tiedosto ennen jatkamista" + }, + "accessibility": { + "fileUpload": "Tiedoston lataus", + "deleteFile": "Poista tiedosto" + } + }, + "languages": { + "zh_CN": "Kiina (yksinkertaistettu)", + "zh_TW": "Kiina (perinteinen)", + "da": "Tanska", + "nl_NL": "Hollanti", + "en": "Englanti", + "fi": "Suomi", + "fr": "Ranska", + "de": "Saksa", + "it": "Italia", + "ja": "Japani", + "ko": "Korea", + "no": "Norja", + "pt_BR": "Portugali (Brasilia)", + "ru": "Venäjä", + "es": "Espanja", + "es_MX": "Espanja (Meksiko)", + "sv": "Ruotsi", + "th": "Thai", + "he": "Heprea" + }, + "session-expired": { + "title": "Istunto vanhentunut", + "description": "Tämä asiakirjan allekirjoituslinkki on vanhentunut käyttämättömyyden tai istunnon aikakatkaisun vuoksi. Palaa sähköpostiisi ja napsauta linkkiä uudelleen jatkaaksesi allekirjoittamista." + }, + "inPersonComplete": { + "title": "🎉 Allekirjoitus valmis!", + "subtitle": "Asiakirja on allekirjoitettu onnistuneesti", + "thankYou": "Kiitos allekirjoituksesta!", + "message": "Saat vahvistusviestin sähköpostiisi, kun kaikki osapuolet ovat allekirjoittaneet asiakirjan.", + "passDevice": "Voit nyt palauttaa laitteen {{senderName}}:lle", + "continueButton": "Jatka" + } +} \ No newline at end of file diff --git a/public/locales/fr/translation.json b/public/locales/fr/translation.json new file mode 100644 index 0000000..635012e --- /dev/null +++ b/public/locales/fr/translation.json @@ -0,0 +1,380 @@ +{ + "terms": { + "agreementText": "En cliquant sur <0>J'accepte, vous confirmez avoir examiné la <1>Divulgation des registres électroniques et des signatures et consentez à l'utilisation de registres et signatures électroniques pour l'examen et l'exécution de ce document.", + "note": "Remarque :", + "noteText": "Accepter cela ne signifie pas que vous signez le document immédiatement. Cela vous permet uniquement de le consulter électroniquement. Vous aurez la possibilité d'examiner le document dans son intégralité avant de signer." + }, + "buttons": { + "agree": "J'accepte", + "processing": "Traitement en cours...", + "close": "Fermer", + "downloadPdf": "Télécharger le PDF", + "downloading": "Téléchargement..." + }, + "header": { + "aiSummary": "Résumé IA", + "completeSign": "Signer complètement", + "sign": "Signer", + "processing": "Traitement en cours...", + "options": "Télécharger" + }, + "menu": { + "downloadPdf": "Télécharger le PDF", + "auditTrail": "Piste d'audit", + "reassignSigner": "Réattribuer le signataire", + "cancelTransaction": "Annuler la transaction", + "viewTerms": "Voir les conditions générales", + "helpSupport": "Aide et assistance", + "about": "À propos de SME" + }, + "sidebar": { + "documents": "Documents", + "pages": "Pages : {{count}}", + "noDocuments": "Aucun document disponible." + }, + "footer": { + "readyTitle": "Prêt à finaliser ?", + "readyDesc": "Vous avez rempli les champs requis. Vérifiez votre travail, puis sélectionnez Terminer.", + "finish": "Terminer", + "submitting": "Soumission...", + "start": "Commencer", + "next": "Suivant", + "agreementText": "En signant, j'accepte les <0>conditions générales de Sign Made Easy." + }, + "completion": { + "complete": { + "hit": "Terminé !", + "title": "Merci d'avoir signé", + "message": "Votre document est maintenant complété et stocké en toute sécurité. Nous vous en avons envoyé une copie par e-mail." + }, + "declined": { + "hit": "Action annulée !", + "title": "La prochaine fois peut-être !", + "message": "Votre demande a été refusée." + }, + "cancelled": { + "hit": "Action annulée !", + "title": "La prochaine fois peut-être !", + "message": "Votre demande a été annulée." + }, + "download": "Télécharger", + "downloading": "Téléchargement...", + "downloadSuccess": "Fichier téléchargé avec succès.", + "downloadOptions": { + "pdf": "Document PDF", + "audit": "Piste d'audit", + "selectFormat": "Sélectionner le format" + }, + "downloadError": "Le téléchargement du fichier a échoué. Veuillez réessayer.", + "appsTitle": "Améliorez votre efficacité avec nos applications", + "formsTitle": "Générez facilement des formulaires", + "docsTitle": "Générez des documents (factures, rapports, devis)", + "tryNow": "Essayer maintenant", + "footerText": "Droits d'auteur 2026 Sign Made Easy. Tous droits réservés.<0>Politique de confidentialité | <1>Politique d'utilisation raisonnable" + }, + "reassign": { + "title": "Réattribuer le signataire", + "successSubtitle": "Le document a été réattribué avec succès", + "successTitle": "Merci !", + "successMessage": "Le document a été réattribué avec succès au nouveau signataire.", + "fields": { + "firstName": "Prénom", + "lastName": "Nom", + "email": "E-mail", + "language": "Langue", + "message": "Message optionnel" + }, + "placeholders": { + "firstName": "Entrez votre prénom", + "lastName": "Entrez votre nom", + "email": "your.email@example.com", + "message": "Écrivez votre message ici..." + }, + "buttons": { + "submit": "Soumettre", + "submitting": "Soumission...", + "cancel": "Annuler" + }, + "errors": { + "firstNameRequired": "Le prénom est requis", + "firstNameMin": "Le prénom doit contenir au moins 2 caractères", + "lastNameRequired": "Le nom est requis", + "lastNameMin": "Le nom doit contenir au moins 2 caractères", + "emailRequired": "L'e-mail est requis", + "emailInvalid": "Adresse e-mail invalide" + } + }, + "cancelModal": { + "title": "Annuler la transaction", + "description": "Êtes-vous sûr de vouloir annuler cette transaction ? Fournissez votre raison d'annulation ci-dessous.", + "placeholder": "Veuillez indiquer votre raison d'annulation...", + "buttons": { + "no": "Non, ne pas annuler", + "yes": "Oui, annuler" + }, + "errors": { + "reasonRequired": "La raison de l'annulation est requise" + }, + "inPersonSuccess": { + "title": "Annuler la transaction", + "message": "La transaction a été annulée avec succès. Des e-mails de confirmation ont été envoyés.", + "passBackDevice": "Vous pouvez maintenant remettre l'appareil à {{senderName}}.", + "continueButton": "Continuer" + } + }, + "enTranslations": { + "app.name": "Sign Made Easy", + "app.subtitle": "Audit de transaction", + "meta.transaction_id": "ID de transaction", + "meta.transaction_status": "Statut de la transaction", + "meta.files": "Fichiers", + "audit.title": "Piste d'audit complète", + "audit.description": "Veuillez mettre à jour le sujet et le message ci-dessous pour un message personnalisé.", + "table.header.actions": "Actions", + "table.header.language": "Langue", + "table.header.ip_address": "Adresse IP", + "table.header.date": "Date", + "status.completed": "Terminé", + "status.pending": "En attente", + "status.failed": "Échoué", + "action.created": "Créé", + "action.updated": "Mis à jour", + "action.deleted": "Supprimé", + "action.viewed": "Consulté", + "action.signed": "Signé", + "action.uploaded": "Téléchargé", + "action.downloaded": "Téléchargé", + "placeholder.not_available": "—" + }, + "auditPage": { + "appName": "Sign Made Easy", + "subtitle": "Audit de transaction", + "meta": { + "transactionId": "ID de transaction", + "transactionStatus": "Statut de la transaction", + "files": "Fichiers" + }, + "audit": { + "title": "Piste d'audit complète", + "description": "Veuillez mettre à jour le sujet et le message ci-dessous pour un message personnalisé." + }, + "table": { + "actions": "Actions", + "language": "Langue", + "ipAddress": "Adresse IP", + "date": "Date" + }, + "status": { + "completed": "Terminé", + "pending": "En attente", + "failed": "Échoué" + }, + "fallback": { + "notAvailable": "—" + } + }, + "audit": { + "transaction": { + "created": "La transaction a été créée par {{userName}} <{{userEmail}}>", + "sent": "La transaction a été envoyée par {{userName}} <{{userEmail}}>", + "cancelled": "La transaction a été annulée par {{userName}} <{{userEmail}}>", + "edited": "La transaction a été modifiée par {{userName}} <{{userEmail}}>", + "viewed": "La transaction a été consultée par {{userName}} <{{userEmail}}>", + "signed": "La transaction a été signée par {{userName}} <{{userEmail}}>" + }, + "signature": { + "declined": "La signature de la transaction a été refusée par {{userName}} <{{userEmail}}>" + }, + "ers": { + "accepted": "La divulgation de l'enregistrement électronique et de la signature a été acceptée par {{userName}} <{{userEmail}}>" + }, + "language": { + "updated": "{{userName}} <{{userEmail}}> a mis à jour sa langue vers {{language}}" + }, + "invitation": { + "sent": "E-mail d'invitation envoyé à {{userName}} <{{userEmail}}>", + "view": "L'invitation à consulter le document a été envoyée à {{userName}} <{{userEmail}}>", + "resent": "E-mail d'invitation renvoyé à {{recipientName}} <{{recipientEmail}}> par {{senderName}} <{{senderEmail}}>" + }, + "reassigned": { + "to": "Le signataire a été réaffecté par {{fromName}} <{{fromEmail}}> à {{toName}} <{{toEmail}}>", + "complex": "{{personName}} <{{personEmail}}> a été réaffecté par {{fromName}} <{{fromEmail}}> à {{toName}} <{{toEmail}}>" + }, + "inperson": { + "started": "La transaction en personne a été démarrée par {{userName}} <{{userEmail}}>", + "verification": "La vérification de signature en personne a été acceptée par {{userName}} <{{userEmail}}>" + }, + "facilitator": { + "accepted": "Le processus de facilitateur a été accepté par {{userName}} <{{userEmail}}>" + } + }, + "signatureModal": { + "title": { + "signature": "Signature", + "initial": "Initiale", + "edit": "Modifier", + "styleSelection": "Sélection du Style" + }, + "subtitle": "Créez vos signatures numériques", + "tabs": { + "select": "Sélectionner", + "draw": "Dessiner", + "upload": "Télécharger" + }, + "selectTab": { + "description": "Confirmez votre nom et choisissez un style de signature.", + "requiredFields": "Champs obligatoires.", + "fullName": { + "label": "Nom Complet", + "required": "*", + "placeholder": "Entrez le nom complet" + }, + "initials": { + "label": "Initiales", + "required": "*", + "placeholder": "Entrez les initiales" + } + }, + "drawTab": { + "description": "Dessinez votre signature.", + "required": "*", + "requiredFields": "Sont des champs obligatoires.", + "signature": "Signature", + "initials": "Initiales", + "clearSignature": "Effacer la signature", + "fullNameBox": { + "label": "Signature complète", + "required": "*" + }, + "initialsBox": { + "label": "Initiales", + "required": "*", + "placeholder": "Entrez les initiales" + } + }, + "uploadTab": { + "requiredMessage": "La signature et les initiales sont obligatoires.", + "requirements": "Utilisez des images de 300×100px pour les signatures et 100×100px pour les initiales. Max 300KB. Formats supportés : .png, .jpg.", + "signature": { + "uploadLabel": "Télécharger la Signature", + "uploadHint": "JPG, PNG (300×100px, max 300KB)", + "browseButton": "Parcourir", + "uploadedLabel": "Signature ✓", + "changeButton": "Changer la Signature", + "altText": "Image de signature téléchargée" + }, + "initials": { + "uploadLabel": "Télécharger les Initiales", + "uploadHint": "JPG, PNG (100×100px, max 300KB)", + "browseButton": "Parcourir", + "uploadedLabel": "Initiales ✓", + "changeButton": "Changer les Initiales", + "altText": "Image des initiales téléchargée" + } + }, + "footer": { + "agreementText": "Je comprends que je signe ce document.", + "cancelButton": "Annuler", + "adoptButton": "Adopter la Signature et Signer" + }, + "errors": { + "requiredField": "Ce champ est obligatoire", + "fileTooLarge": "La taille du fichier doit être inférieure à 300KB", + "invalidFileType": "Seuls les fichiers .png, .jpg et .jpeg sont supportés", + "signatureRequired": "Veuillez ajouter une signature", + "initialsRequired": "Veuillez ajouter des initiales" + } + }, + "stampModal": { + "title": { + "add": "Ajouter un Tampon", + "edit": "Modifier le Tampon" + }, + "closeButton": "Fermer la modale", + "fileRequirements": "Taille maximale = 400Kb | Types de fichiers supportés = .png, .jpg, .jpeg", + "dragDropLabel": "Glissez-déposez une image, ou cliquez pour télécharger", + "previewAltText": "Aperçu du Tampon", + "changeImageButton": "Changer l'image", + "clearButton": "Fermer", + "saveButton": "Enregistrer", + "updateButton": "Mettre à jour", + "errors": { + "fileTooLarge": "La taille du fichier dépasse la limite de 400KB", + "invalidFileType": "Seuls les fichiers .png, .jpg et .jpeg sont supportés", + "uploadFailed": "Échec du téléchargement de l'image. Veuillez réessayer." + } + }, + "attachmentModal": { + "title": "Pièce jointe", + "subtitle": { + "hasFile": "Gérer votre pièce jointe", + "noFile": "Télécharger une pièce jointe" + }, + "uploading": { + "status": "Téléchargement du fichier...", + "shimmerText": "Téléchargement du fichier..." + }, + "uploadArea": { + "dragging": "Déposez votre fichier ici", + "default": "Télécharger ou glisser-déposer un fichier", + "fileTypes": "PDF, DOCX, JPG, PNG, TXT (max 10MB)", + "browseButton": "Parcourir les fichiers" + }, + "uploadedFile": { + "status": "Téléchargé avec succès", + "deleteButton": "Supprimer le fichier" + }, + "buttons": { + "close": "Fermer", + "uploading": "Téléchargement...", + "deleting": "Suppression...", + "saved": "Fichier Enregistré !", + "done": "Terminé", + "uploadFile": "Télécharger le fichier" + }, + "errors": { + "fileTooLarge": "La taille du fichier dépasse la limite de 10MB", + "invalidFileType": "Seuls les fichiers PDF, DOCX, JPG, PNG et TXT sont supportés", + "uploadFailed": "Échec du téléchargement du fichier. Veuillez réessayer.", + "deleteFailed": "Échec de la suppression du fichier. Veuillez réessayer.", + "noFileSelected": "Veuillez sélectionner un fichier avant de continuer" + }, + "accessibility": { + "fileUpload": "Téléchargement de fichier", + "deleteFile": "Supprimer le fichier" + } + }, + "languages": { + "zh_CN": "Chinois (Simplifié)", + "zh_TW": "Chinois (Traditionnel)", + "da": "Danois", + "nl_NL": "Néerlandais", + "en": "Anglais", + "fi": "Finnois", + "fr": "Français", + "de": "Allemand", + "it": "Italien", + "ja": "Japonais", + "ko": "Coréen", + "no": "Norvégien", + "pt_BR": "Portugais (Brésil)", + "ru": "Russe", + "es": "Espagnol", + "es_MX": "Espagnol (Mexique)", + "sv": "Suédois", + "th": "Thaïlandais", + "he": "Hébreu" + }, + "session-expired": { + "title": "Session expirée", + "description": "Ce lien de signature de document a expiré en raison d'une inactivité ou d'un délai d'attente de session. Veuillez retourner dans votre courrier électronique et cliquer à nouveau sur le lien pour continuer à signer." + }, + "inPersonComplete": { + "title": "🎉 Signature terminée !", + "subtitle": "Le document a été signé avec succès", + "thankYou": "Merci d'avoir signé !", + "message": "Vous recevrez un e-mail de confirmation une fois que le document aura été signé par toutes les parties.", + "passDevice": "Vous pouvez maintenant rendre l'appareil à {{senderName}}", + "continueButton": "Continuer" + } +} \ No newline at end of file diff --git a/public/locales/he/translation.json b/public/locales/he/translation.json new file mode 100644 index 0000000..3370e44 --- /dev/null +++ b/public/locales/he/translation.json @@ -0,0 +1,380 @@ +{ + "terms": { + "agreementText": "בלחיצה על <0>אני מסכים, אתה מאשר כי עיינת ב-<1>הצהרת רשומה אלקטרונית וחתימה, ונותן את הסכמתך לשימוש ברשומות ובחתימות אלקטרוניות בעת עיון וחתימה על מסמך זה.", + "note": "הערה:", + "noteText": "הסכמה לכך אינה משמעה שאתה חותם על המסמך באופן מיידי. זה רק מאפשר לך לעיין בו באופן אלקטרוני. תהיה לך הזדמנות לעיין במסמך במלואו לפני החתימה." + }, + "buttons": { + "agree": "אני מסכים", + "processing": "מעבד...", + "close": "סגור", + "downloadPdf": "הורד PDF", + "downloading": "מוריד..." + }, + "header": { + "aiSummary": "סיכום AI", + "completeSign": "השלם חתימה", + "sign": "חתום", + "processing": "מעבד...", + "options": "הורד" + }, + "menu": { + "downloadPdf": "הורד PDF", + "auditTrail": "מסלול ביקורת", + "reassignSigner": "הקצה חותם מחדש", + "cancelTransaction": "בטל עסקה", + "viewTerms": "צפה בתנאים והגבלות", + "helpSupport": "עזרה ותמיכה", + "about": "אודות SME" + }, + "sidebar": { + "documents": "מסמכים", + "pages": "עמודים: {{count}}", + "noDocuments": "אין מסמכים זמינים." + }, + "footer": { + "readyTitle": "הכל מוכן לסיום?", + "readyDesc": "מילאת את כל השדות הנדרשים. עיין בעבודתך, ולאחר מכן בחר סיום.", + "finish": "סיים", + "submitting": "שולח...", + "start": "התחל", + "next": "הבא", + "agreementText": "בחתימתי, אני מסכים ל-<0>תנאים והגבלות של Sign Made Easy." + }, + "completion": { + "complete": { + "hit": "הכל הושלם!", + "title": "תודה על החתימה", + "message": "המסמך שלך הושלם ומאוחסן בצורה מאובטחת. שלחנו לך עותק במייל." + }, + "declined": { + "hit": "הפעולה בוטלה!", + "title": "אולי בפעם הבאה!", + "message": "בקשתך נדחתה בהצלחה." + }, + "cancelled": { + "hit": "הפעולה בוטלה!", + "title": "אולי בפעם הבאה!", + "message": "בקשתך בוטלה בהצלחה." + }, + "download": "הורד", + "downloading": "מוריד...", + "downloadSuccess": "הקובץ הורד בהצלחה.", + "downloadOptions": { + "pdf": "מסמך PDF", + "audit": "מסלולי ביקורת", + "selectFormat": "בחר פורמט" + }, + "downloadError": "הורדת הקובץ נכשלה. אנא נסה שוב.", + "appsTitle": "הגבר יעילות עם האפליקציות שלנו", + "formsTitle": "צור טפסים בקלות", + "docsTitle": "צור מסמכים (חשבוניות, דוחות, הצעות מחיר)", + "tryNow": "נסה עכשיו", + "footerText": "כל הזכויות שמורות 2026 Sign Made Easy. <0>מדיניות פרטיות | <1>מדיניות שימוש סביר" + }, + "reassign": { + "title": "הקצאת חותם מחדש", + "successSubtitle": "המסמך הוקצה מחדש בהצלחה", + "successTitle": "תודה רבה!", + "successMessage": "המסמך הוקצה מחדש לחתום החדש בהצלחה.", + "fields": { + "firstName": "שם פרטי", + "lastName": "שם משפחה", + "email": "דוא\"ל", + "language": "שפה", + "message": "הודעה אופציונלית" + }, + "placeholders": { + "firstName": "הכנס את שמך הפרטי", + "lastName": "הכנס את שם משפחתך", + "email": "your.email@example.com", + "message": "כתוב את הודעתך כאן..." + }, + "buttons": { + "submit": "שלח", + "submitting": "שולח...", + "cancel": "בטל" + }, + "errors": { + "firstNameRequired": "שם פרטי הוא שדה חובה", + "firstNameMin": "שם פרטי חייב להכיל לפחות 2 תווים", + "lastNameRequired": "שם משפחה הוא שדה חובה", + "lastNameMin": "שם משפחה חייב להכיל לפחות 2 תווים", + "emailRequired": "דוא\"ל הוא שדה חובה", + "emailInvalid": "כתובת דוא\"ל לא תקינה" + } + }, + "cancelModal": { + "title": "בטל עסקה", + "description": "האם אתה בטוח שברצונך לבטל עסקה זו? ספק את סיבת הביטול להלן.", + "placeholder": "אנא ספק את סיבת הביטול שלך...", + "buttons": { + "no": "לא, אל תבטל", + "yes": "כן, בטל אותה" + }, + "errors": { + "reasonRequired": "סיבת ביטול היא שדה חובה" + }, + "inPersonSuccess": { + "title": "בטל עסקה", + "message": "העסקה בוטלה בהצלחה. מיילי אישור נשלחו.", + "passBackDevice": "כעת תוכל להעביר את המכשיר בחזרה ל-{{senderName}}.", + "continueButton": "המשך" + } + }, + "enTranslations": { + "app.name": "Sign Made Easy", + "app.subtitle": "ביקורת עסקה", + "meta.transaction_id": "מזהה עסקה", + "meta.transaction_status": "סטטוס עסקה", + "meta.files": "קבצים", + "audit.title": "מסלול ביקורת מלא", + "audit.description": "אנא עדכן את הנושא וההודעה להלן להודעה מותאמת אישית.", + "table.header.actions": "פעולות", + "table.header.language": "שפה", + "table.header.ip_address": "כתובת IP", + "table.header.date": "תאריך", + "status.completed": "הושלם", + "status.pending": "ממתין", + "status.failed": "נכשל", + "action.created": "נוצר", + "action.updated": "עודכן", + "action.deleted": "נמחק", + "action.viewed": "נצפה", + "action.signed": "נחתם", + "action.uploaded": "הועלה", + "action.downloaded": "הורד", + "placeholder.not_available": "—" + }, + "auditPage": { + "appName": "Sign Made Easy", + "subtitle": "ביקורת עסקה", + "meta": { + "transactionId": "מזהה עסקה", + "transactionStatus": "סטטוס עסקה", + "files": "קבצים" + }, + "audit": { + "title": "מסלול ביקורת מלא", + "description": "אנא עדכן את הנושא וההודעה להלן להודעה מותאמת אישית." + }, + "table": { + "actions": "פעולות", + "language": "שפה", + "ipAddress": "כתובת IP", + "date": "תאריך" + }, + "status": { + "completed": "הושלם", + "pending": "ממתין", + "failed": "נכשל" + }, + "fallback": { + "notAvailable": "—" + } + }, + "audit": { + "transaction": { + "created": "העסקה נוצרה על ידי {{userName}} <{{userEmail}}>", + "sent": "העסקה נשלחה על ידי {{userName}} <{{userEmail}}>", + "cancelled": "העסקה בוטלה על ידי {{userName}} <{{userEmail}}>", + "edited": "העסקה נערכה על ידי {{userName}} <{{userEmail}}>", + "viewed": "העסקה נצפתה על ידי {{userName}} <{{userEmail}}>", + "signed": "העסקה נחתמה על ידי {{userName}} <{{userEmail}}>" + }, + "signature": { + "declined": "חתימת העסקה נדחתה על ידי {{userName}} <{{userEmail}}>" + }, + "ers": { + "accepted": "הצהרת רשומה אלקטרונית וחתימה התקבלה על ידי {{userName}} <{{userEmail}}>" + }, + "language": { + "updated": "{{userName}} <{{userEmail}}> עדכן את השפה שלו ל-{{language}}" + }, + "invitation": { + "sent": "מייל הזמנה נשלח ל-{{userName}} <{{userEmail}}>", + "view": "הזמנה לעיון במסמך נשלחה ל-{{userName}} <{{userEmail}}>", + "resent": "מייל הזמנה נשלח שוב ל-{{recipientName}} <{{recipientEmail}}> על ידי {{senderName}} <{{senderEmail}}>" + }, + "reassigned": { + "to": "החותם הוקצה מחדש על ידי {{fromName}} <{{fromEmail}}> ל-{{toName}} <{{toEmail}}>", + "complex": "{{personName}} <{{personEmail}}> הוקצה מחדש על ידי {{fromName}} <{{fromEmail}}> ל-{{toName}} <{{toEmail}}>" + }, + "inperson": { + "started": "עסקה אישית החלה על ידי {{userName}} <{{userEmail}}>", + "verification": "אימות חתימה אישית התקבל על ידי {{userName}} <{{userEmail}}>" + }, + "facilitator": { + "accepted": "תהליך המנחה התקבל על ידי {{userName}} <{{userEmail}}>" + } + }, + "signatureModal": { + "title": { + "signature": "חתימה", + "initial": "ראשי תיבות", + "edit": "עריכה", + "styleSelection": "בחירת סגנון" + }, + "subtitle": "צור את החתימות הדיגיטליות שלך", + "tabs": { + "select": "בחירה", + "draw": "ציור", + "upload": "העלאה" + }, + "selectTab": { + "description": "אשר את שמך ובחר סגנון חתימה.", + "requiredFields": "שדות חובה.", + "fullName": { + "label": "שם מלא", + "required": "*", + "placeholder": "הזן שם מלא" + }, + "initials": { + "label": "ראשי תיבות", + "required": "*", + "placeholder": "הזן ראשי תיבות" + } + }, + "drawTab": { + "description": "צייר את החתימה שלך.", + "required": "*", + "requiredFields": "הם שדות חובה.", + "signature": "חתימה", + "initials": "ראשי תיבות", + "clearSignature": "נקה חתימה", + "fullNameBox": { + "label": "חתימה מלאה", + "required": "*" + }, + "initialsBox": { + "label": "ראשי תיבות", + "required": "*", + "placeholder": "הזן ראשי תיבות" + } + }, + "uploadTab": { + "requiredMessage": "נדרשים גם חתימה וגם ראשי תיבות.", + "requirements": "השתמש בתמונות בגודל 300×100px לחתימות ו-100×100px לראשי תיבות. מקסימום 300KB. נתמך: .png, .jpg.", + "signature": { + "uploadLabel": "העלאת חתימה", + "uploadHint": "JPG, PNG (300×100px, מקסימום 300KB)", + "browseButton": "עיון", + "uploadedLabel": "חתימה ✓", + "changeButton": "שינוי חתימה", + "altText": "תמונת חתימה שהועלתה" + }, + "initials": { + "uploadLabel": "העלאת ראשי תיבות", + "uploadHint": "JPG, PNG (100×100px, מקסימום 300KB)", + "browseButton": "עיון", + "uploadedLabel": "ראשי תיבות ✓", + "changeButton": "שינוי ראשי תיבות", + "altText": "תמונת ראשי תיבות שהועלתה" + } + }, + "footer": { + "agreementText": "אני מבין שאני חותם על מסמך זה.", + "cancelButton": "ביטול", + "adoptButton": "אימוץ חתימה וחתימה" + }, + "errors": { + "requiredField": "שדה זה הוא חובה", + "fileTooLarge": "גודל הקובץ חייב להיות פחות מ-300KB", + "invalidFileType": "נתמכים רק קבצי .png, .jpg ו-.jpeg", + "signatureRequired": "נא להוסיף חתימה", + "initialsRequired": "נא להוסיף ראשי תיבות" + } + }, + "stampModal": { + "title": { + "add": "הוספת חותמת", + "edit": "עריכת חותמת" + }, + "closeButton": "סגירת חלון", + "fileRequirements": "גודל מקסימלי = 400Kb | סוגי קבצים נתמכים = .png, .jpg, .jpeg", + "dragDropLabel": "גרור ושחרר תמונה, או לחץ להעלאה", + "previewAltText": "תצוגה מקדימה של החותמת", + "changeImageButton": "שינוי תמונה", + "clearButton": "סגור", + "saveButton": "שמור", + "updateButton": "עדכן", + "errors": { + "fileTooLarge": "גודל הקובץ חורג ממגבלת 400KB", + "invalidFileType": "נתמכים רק קבצי .png, .jpg ו-.jpeg", + "uploadFailed": "העלאת התמונה נכשלה. אנא נסה שוב." + } + }, + "attachmentModal": { + "title": "קובץ מצורף", + "subtitle": { + "hasFile": "ניהול הקובץ המצורף שלך", + "noFile": "העלאת קובץ מצורף" + }, + "uploading": { + "status": "מעלה קובץ...", + "shimmerText": "מעלה קובץ..." + }, + "uploadArea": { + "dragging": "שחרר את הקובץ שלך כאן", + "default": "העלה או גרור ושחרר קובץ", + "fileTypes": "PDF, DOCX, JPG, PNG, TXT (מקסימום 10MB)", + "browseButton": "עיון בקבצים" + }, + "uploadedFile": { + "status": "הועלה בהצלחה", + "deleteButton": "מחיקת קובץ" + }, + "buttons": { + "close": "סגור", + "uploading": "מעלה...", + "deleting": "מוחק...", + "saved": "הקובץ נשמר!", + "done": "בוצע", + "uploadFile": "העלאת קובץ" + }, + "errors": { + "fileTooLarge": "גודל הקובץ חורג ממגבלת 10MB", + "invalidFileType": "נתמכים רק קבצי PDF, DOCX, JPG, PNG ו-TXT", + "uploadFailed": "העלאת הקובץ נכשלה. אנא נסה שוב.", + "deleteFailed": "מחיקת הקובץ נכשלה. אנא נסה שוב.", + "noFileSelected": "אנא בחר קובץ לפני ההמשך" + }, + "accessibility": { + "fileUpload": "העלאת קובץ", + "deleteFile": "מחיקת קובץ" + } + }, + "languages": { + "he": "עברית", + "zh_CN": "סינית (פשוטה)", + "zh_TW": "סינית (מסורתית)", + "da": "דנית", + "nl_NL": "הולנדית", + "en": "אנגלית", + "fi": "פינית", + "fr": "צרפתית", + "de": "גרמנית", + "it": "איטלקית", + "ja": "יפנית", + "ko": "קוריאנית", + "no": "נורווגית", + "pt_BR": "פורטוגזית (ברזיל)", + "ru": "רוסית", + "es": "ספרדית", + "es_MX": "ספרדית (מקסיקו)", + "sv": "שוודית", + "th": "תאית" + }, + "session-expired": { + "title": "הפגישה פגה", + "description": "קישור החתימה על מסמך זה פג עקב חוסר פעילות או פקיעת זמן פגישה. אנא חזור לדוא\"ל שלך ולחץ שוב על הקישור כדי להמשיך בחתימה." + }, + "inPersonComplete": { + "title": "🎉 ההחתמה הושלמה!", + "subtitle": "המסמך נחתם בהצלחה", + "thankYou": "תודה על החתימה!", + "message": "תקבל אישור בדוא\"ל לאחר שהמסמך ייחתם על ידי כל הצדדים.", + "passDevice": "כעת תוכל להחזיר את המכשיר ל{{senderName}}", + "continueButton": "המשך" + } +} \ No newline at end of file diff --git a/public/locales/hi/translation.json b/public/locales/hi/translation.json new file mode 100644 index 0000000..e7407c0 --- /dev/null +++ b/public/locales/hi/translation.json @@ -0,0 +1,109 @@ +{ + "terms": { + "agreementText": "<0>\"मैं सहमत हूँ\" पर क्लिक करके, आप पुष्टि करते हैं कि आपने <1>इलेक्ट्रॉनिक रिकॉर्ड और हस्ताक्षर प्रकटीकरण की समीक्षा कर ली है, और इस दस्तावेज़ की समीक्षा और निष्पादन के लिए इलेक्ट्रॉनिक रिकॉर्ड और हस्ताक्षरों के उपयोग के लिए अपनी सहमति देते हैं।", + "note": "नोट:", + "noteText": "इससे सहमत होने का मतलब यह नहीं है कि आप तुरंत दस्तावेज़ पर हस्ताक्षर कर रहे हैं। यह केवल आपको इसे इलेक्ट्रॉनिक रूप से देखने की अनुमति देता है। हस्ताक्षर करने से पहले आपको दस्तावेज़ को पूरी तरह से समीक्षा करने का अवसर मिलेगा।" + }, + "buttons": { + "agree": "मैं सहमत हूँ", + "processing": "प्रोसेस हो रहा है...", + "close": "बंद करें", + "downloadPdf": "PDF डाउनलोड करें", + "downloading": "डाउनलोड हो रहा है..." + }, + "header": { + "aiSummary": "AI सारांश", + "completeSign": "साइन पूरा करें", + "sign": "साइन करें", + "processing": "प्रोसेस हो रहा है..." + }, + "menu": { + "downloadPdf": "PDF डाउनलोड करें", + "reassignSigner": "साइनर पुनः असाइन करें", + "cancelTransaction": "लेनदेन रद्द करें", + "viewTerms": "नियम और शर्तें देखें", + "helpSupport": "सहायता और समर्थन", + "about": "SME के बारे में" + }, + "sidebar": { + "documents": "दस्तावेज़", + "pages": "पेज: {{count}}", + "noDocuments": "कोई दस्तावेज़ उपलब्ध नहीं है।" + }, + "footer": { + "readyTitle": "क्या आप इसे पूरा करने के लिए तैयार हैं?", + "readyDesc": "आपने आवश्यक फ़ील्ड भर लिए हैं। अपने काम की समीक्षा करें, फिर समाप्त करें चुनें।", + "finish": "समाप्त करें", + "submitting": "सबमिट हो रहा है...", + "start": "शुरू करें", + "next": "अगला", + "agreementText": "हस्ताक्षर करके, मैं Sign Made Easy के <0>नियम और शर्तों से सहमत हूँ।" + }, + "completion": { + "complete": { + "hit": "सब पूरा हो गया!", + "title": "साइन करने के लिए धन्यवाद", + "message": "आपका दस्तावेज़ अब पूरा हो चुका है और सुरक्षित रूप से संग्रहीत है। हमने आपको इसकी एक कॉपी ईमेल कर दी है।" + }, + "declined": { + "hit": "कार्रवाई रद्द की गई!", + "title": "शायद अगली बार!", + "message": "आपका अनुरोध सफलतापूर्वक अस्वीकार कर दिया गया है।" + }, + "cancelled": { + "hit": "कार्रवाई रद्द की गई!", + "title": "शायद अगली बार!", + "message": "आपका अनुरोध सफलतापूर्वक अस्वीकार कर दिया गया है।" + }, + "download": "डाउनलोड करें", + "downloading": "डाउनलोड हो रहा है...", + "downloadSuccess": "फ़ाइल सफलतापूर्वक डाउनलोड हो गई।", + "downloadError": "फ़ाइल डाउनलोड नहीं हो सकी। कृपया पुनः प्रयास करें।", + "appsTitle": "हमारे ऐप्स के साथ अपनी कार्यक्षमता बढ़ाएँ", + "formsTitle": "आसानी से फॉर्म बनाएं", + "docsTitle": "दस्तावेज़ बनाएं (इनवॉइस, रिपोर्ट, कोट्स)", + "tryNow": "अभी आज़माएं", + "footerText": "कॉपीराइट 2026 Sign Made Easy। सर्वाधिकार सुरक्षित। <0>गोपनीयता नीति | <1>उचित उपयोग नीति" + }, + "reassign": { + "title": "हस्ताक्षरकर्ता पुनः असाइन करें", + "fields": { + "firstName": "पहला नाम", + "lastName": "अंतिम नाम", + "email": "ईमेल", + "language": "भाषा", + "message": "वैकल्पिक संदेश" + }, + "placeholders": { + "firstName": "अपना पहला नाम दर्ज करें", + "lastName": "अपना अंतिम नाम दर्ज करें", + "email": "your.email@example.com", + "message": "अपना संदेश यहाँ लिखें..." + }, + "buttons": { + "submit": "सबमिट करें", + "submitting": "सबमिट किया जा रहा है...", + "cancel": "रद्द करें" + }, + "errors": { + "firstNameRequired": "पहला नाम आवश्यक है", + "firstNameMin": "पहला नाम कम से कम 2 अक्षरों का होना चाहिए", + "lastNameRequired": "अंतिम नाम आवश्यक है", + "lastNameMin": "अंतिम नाम कम से कम 2 अक्षरों का होना चाहिए", + "emailRequired": "ईमेल आवश्यक है", + "emailInvalid": "अमान्य ईमेल पता" + } + }, + "cancelModal": { + "title": "लेनदेन रद्द करें", + "description": "क्या आप वाकई इस लेनदेन को रद्द करना चाहते हैं? कृपया नीचे रद्द करने का कारण बताएं।", + "placeholder": "कृपया रद्द करने का कारण लिखें...", + "buttons": { + "no": "नहीं, रद्द न करें", + "yes": "हाँ, इसे रद्द करें" + }, + "errors": { + "reasonRequired": "रद्द करने का कारण आवश्यक है" + } + } +} \ No newline at end of file diff --git a/public/locales/it/translation.json b/public/locales/it/translation.json new file mode 100644 index 0000000..b82733d --- /dev/null +++ b/public/locales/it/translation.json @@ -0,0 +1,380 @@ +{ + "terms": { + "agreementText": "Facendo clic su <0>Accetto, confermi di aver letto l'<1>Informativa sui registri elettronici e le firme e acconsenti all'uso di registri e firme elettronici per la revisione e l'esecuzione di questo documento.", + "note": "Nota:", + "noteText": "Accettare questo non significa che firmi immediatamente il documento. Ti permette solo di visualizzarlo elettronicamente. Avrai la possibilità di rivedere il documento per intero prima di firmare." + }, + "buttons": { + "agree": "Accetto", + "processing": "Elaborazione in corso...", + "close": "Chiudi", + "downloadPdf": "Scarica PDF", + "downloading": "Download in corso..." + }, + "header": { + "aiSummary": "Riepilogo AI", + "completeSign": "Completa firma", + "sign": "Firma", + "processing": "Elaborazione in corso...", + "options": "Scarica" + }, + "menu": { + "downloadPdf": "Scarica PDF", + "auditTrail": "Traccia di audit", + "reassignSigner": "Riassegna firmatario", + "cancelTransaction": "Annulla transazione", + "viewTerms": "Visualizza termini e condizioni", + "helpSupport": "Aiuto e supporto", + "about": "Informazioni su SME" + }, + "sidebar": { + "documents": "Documenti", + "pages": "Pagine: {{count}}", + "noDocuments": "Nessun documento disponibile." + }, + "footer": { + "readyTitle": "Pronto per concludere?", + "readyDesc": "Hai compilato i campi richiesti. Rivedi il tuo lavoro, quindi seleziona Fine.", + "finish": "Fine", + "submitting": "Invio in corso...", + "start": "Inizia", + "next": "Avanti", + "agreementText": "Firmando, accetto i <0>Termini e condizioni di Sign Made Easy." + }, + "completion": { + "complete": { + "hit": "Tutto fatto!", + "title": "Grazie per la firma", + "message": "Il tuo documento è ora completo e archiviato in modo sicuro. Ti abbiamo inviato una copia via email." + }, + "declined": { + "hit": "Azione annullata!", + "title": "Forse la prossima volta!", + "message": "La tua richiesta è stata rifiutata." + }, + "cancelled": { + "hit": "Azione annullata!", + "title": "Forse la prossima volta!", + "message": "La tua richiesta è stata annullata." + }, + "download": "Scarica", + "downloading": "Download in corso...", + "downloadSuccess": "File scaricato con successo.", + "downloadOptions": { + "pdf": "Documento PDF", + "audit": "Traccia di audit", + "selectFormat": "Seleziona formato" + }, + "downloadError": "Download del file fallito. Riprova.", + "appsTitle": "Aumenta l'efficienza con le nostre app", + "formsTitle": "Genera moduli facilmente", + "docsTitle": "Genera documenti (fatture, report, preventivi)", + "tryNow": "Prova ora", + "footerText": "Copyright 2026 Sign Made Easy. Tutti i diritti riservati.<0>Informativa sulla privacy | <1>Politica di uso ragionevole" + }, + "reassign": { + "title": "Riassegna firmatario", + "successSubtitle": "Il documento è stato riassegnato con successo", + "successTitle": "Grazie!", + "successMessage": "Il documento è stato riassegnato con successo al nuovo firmatario.", + "fields": { + "firstName": "Nome", + "lastName": "Cognome", + "email": "Email", + "language": "Lingua", + "message": "Messaggio opzionale" + }, + "placeholders": { + "firstName": "Inserisci il tuo nome", + "lastName": "Inserisci il tuo cognome", + "email": "your.email@example.com", + "message": "Scrivi il tuo messaggio qui..." + }, + "buttons": { + "submit": "Invia", + "submitting": "Invio in corso...", + "cancel": "Annulla" + }, + "errors": { + "firstNameRequired": "Il nome è obbligatorio", + "firstNameMin": "Il nome deve contenere almeno 2 caratteri", + "lastNameRequired": "Il cognome è obbligatorio", + "lastNameMin": "Il cognome deve contenere almeno 2 caratteri", + "emailRequired": "L'email è obbligatoria", + "emailInvalid": "Indirizzo email non valido" + } + }, + "cancelModal": { + "title": "Annulla transazione", + "description": "Sei sicuro di voler annullare questa transazione? Fornisci il motivo dell'annullamento qui sotto.", + "placeholder": "Fornisci il motivo dell'annullamento...", + "buttons": { + "no": "No, non annullare", + "yes": "Sì, annulla" + }, + "errors": { + "reasonRequired": "Il motivo dell'annullamento è obbligatorio" + }, + "inPersonSuccess": { + "title": "Annulla transazione", + "message": "Transazione annullata con successo. Email di conferma inviate.", + "passBackDevice": "Ora puoi restituire il dispositivo a {{senderName}}.", + "continueButton": "Continua" + } + }, + "enTranslations": { + "app.name": "Sign Made Easy", + "app.subtitle": "Audit di transazione", + "meta.transaction_id": "ID transazione", + "meta.transaction_status": "Stato transazione", + "meta.files": "File", + "audit.title": "Traccia di audit completa", + "audit.description": "Aggiorna l'oggetto e il messaggio qui sotto per un messaggio personalizzato.", + "table.header.actions": "Azioni", + "table.header.language": "Lingua", + "table.header.ip_address": "Indirizzo IP", + "table.header.date": "Data", + "status.completed": "Completato", + "status.pending": "In sospeso", + "status.failed": "Fallito", + "action.created": "Creato", + "action.updated": "Aggiornato", + "action.deleted": "Eliminato", + "action.viewed": "Visualizzato", + "action.signed": "Firmato", + "action.uploaded": "Caricato", + "action.downloaded": "Scaricato", + "placeholder.not_available": "—" + }, + "auditPage": { + "appName": "Sign Made Easy", + "subtitle": "Audit di transazione", + "meta": { + "transactionId": "ID transazione", + "transactionStatus": "Stato transazione", + "files": "File" + }, + "audit": { + "title": "Traccia di audit completa", + "description": "Aggiorna l'oggetto e il messaggio qui sotto per un messaggio personalizzato." + }, + "table": { + "actions": "Azioni", + "language": "Lingua", + "ipAddress": "Indirizzo IP", + "date": "Data" + }, + "status": { + "completed": "Completato", + "pending": "In sospeso", + "failed": "Fallito" + }, + "fallback": { + "notAvailable": "—" + } + }, + "audit": { + "transaction": { + "created": "Transazione creata da {{userName}} <{{userEmail}}>", + "sent": "Transazione inviata da {{userName}} <{{userEmail}}>", + "cancelled": "Transazione annullata da {{userName}} <{{userEmail}}>", + "edited": "Transazione modificata da {{userName}} <{{userEmail}}>", + "viewed": "Transazione visualizzata da {{userName}} <{{userEmail}}>", + "signed": "Transazione firmata da {{userName}} <{{userEmail}}>" + }, + "signature": { + "declined": "Firma della transazione rifiutata da {{userName}} <{{userEmail}}>" + }, + "ers": { + "accepted": "Divulgazione di registro elettronico e firma accettata da {{userName}} <{{userEmail}}>" + }, + "language": { + "updated": "{{userName}} <{{userEmail}}> ha aggiornato la lingua a {{language}}" + }, + "invitation": { + "sent": "Email di invito inviata a {{userName}} <{{userEmail}}>", + "view": "Invito a visualizzare il documento inviato a {{userName}} <{{userEmail}}>", + "resent": "Email di invito reinviata a {{recipientName}} <{{recipientEmail}}> da {{senderName}} <{{senderEmail}}>" + }, + "reassigned": { + "to": "Firmatario riassegnato da {{fromName}} <{{fromEmail}}> a {{toName}} <{{toEmail}}>", + "complex": "{{personName}} <{{personEmail}}> è stato riassegnato da {{fromName}} <{{fromEmail}}> a {{toName}} <{{toEmail}}>" + }, + "inperson": { + "started": "Transazione di persona avviata da {{userName}} <{{userEmail}}>", + "verification": "Verifica firma di persona accettata da {{userName}} <{{userEmail}}>" + }, + "facilitator": { + "accepted": "Processo del facilitatore accettato da {{userName}} <{{userEmail}}>" + } + }, + "signatureModal": { + "title": { + "signature": "Firma", + "initial": "Iniziale", + "edit": "Modifica", + "styleSelection": "Selezione Stile" + }, + "subtitle": "Crea le tue firme digitali", + "tabs": { + "select": "Seleziona", + "draw": "Disegna", + "upload": "Carica" + }, + "selectTab": { + "description": "Conferma il tuo nome e scegli uno stile di firma.", + "requiredFields": "Campi obbligatori.", + "fullName": { + "label": "Nome Completo", + "required": "*", + "placeholder": "Inserisci il nome completo" + }, + "initials": { + "label": "Iniziali", + "required": "*", + "placeholder": "Inserisci le iniziali" + } + }, + "drawTab": { + "description": "Disegna la tua firma.", + "required": "*", + "requiredFields": "Sono campi obbligatori.", + "signature": "Firma", + "initials": "Iniziali", + "clearSignature": "Cancella firma", + "fullNameBox": { + "label": "Firma completa", + "required": "*" + }, + "initialsBox": { + "label": "Iniziali", + "required": "*", + "placeholder": "Inserisci le iniziali" + } + }, + "uploadTab": { + "requiredMessage": "Sia la firma che le iniziali sono obbligatorie.", + "requirements": "Utilizza immagini di 300×100px per le firme e 100×100px per le iniziali. Max 300KB. Supportati: .png, .jpg.", + "signature": { + "uploadLabel": "Carica Firma", + "uploadHint": "JPG, PNG (300×100px, max 300KB)", + "browseButton": "Sfoglia", + "uploadedLabel": "Firma ✓", + "changeButton": "Cambia Firma", + "altText": "Immagine firma caricata" + }, + "initials": { + "uploadLabel": "Carica Iniziali", + "uploadHint": "JPG, PNG (100×100px, max 300KB)", + "browseButton": "Sfoglia", + "uploadedLabel": "Iniziali ✓", + "changeButton": "Cambia Iniziali", + "altText": "Immagine iniziali caricata" + } + }, + "footer": { + "agreementText": "Comprendo che sto firmando questo documento.", + "cancelButton": "Annulla", + "adoptButton": "Adotta Firma e Firma" + }, + "errors": { + "requiredField": "Questo campo è obbligatorio", + "fileTooLarge": "La dimensione del file deve essere inferiore a 300KB", + "invalidFileType": "Sono supportati solo file .png, .jpg e .jpeg", + "signatureRequired": "Si prega di aggiungere una firma", + "initialsRequired": "Si prega di aggiungere le iniziali" + } + }, + "stampModal": { + "title": { + "add": "Aggiungi Timbro", + "edit": "Modifica Timbro" + }, + "closeButton": "Chiudi modale", + "fileRequirements": "Dimensione massima = 400Kb | Tipi di file supportati = .png, .jpg, .jpeg", + "dragDropLabel": "Trascina e rilascia un'immagine, o clicca per caricare", + "previewAltText": "Anteprima Timbro", + "changeImageButton": "Cambia immagine", + "clearButton": "Chiudi", + "saveButton": "Salva", + "updateButton": "Aggiorna", + "errors": { + "fileTooLarge": "La dimensione del file supera il limite di 400KB", + "invalidFileType": "Sono supportati solo file .png, .jpg e .jpeg", + "uploadFailed": "Caricamento dell'immagine fallito. Si prega di riprovare." + } + }, + "attachmentModal": { + "title": "Allegato", + "subtitle": { + "hasFile": "Gestisci il tuo allegato", + "noFile": "Carica allegato" + }, + "uploading": { + "status": "Caricamento file...", + "shimmerText": "Caricamento file..." + }, + "uploadArea": { + "dragging": "Rilascia il file qui", + "default": "Carica o trascina e rilascia il file", + "fileTypes": "PDF, DOCX, JPG, PNG, TXT (max 10MB)", + "browseButton": "Sfoglia File" + }, + "uploadedFile": { + "status": "Caricato con successo", + "deleteButton": "Elimina file" + }, + "buttons": { + "close": "Chiudi", + "uploading": "Caricamento...", + "deleting": "Eliminazione...", + "saved": "File Salvato!", + "done": "Fatto", + "uploadFile": "Carica File" + }, + "errors": { + "fileTooLarge": "La dimensione del file supera il limite di 10MB", + "invalidFileType": "Sono supportati solo file PDF, DOCX, JPG, PNG e TXT", + "uploadFailed": "Caricamento del file fallito. Si prega di riprovare.", + "deleteFailed": "Eliminazione del file fallita. Si prega di riprovare.", + "noFileSelected": "Si prega di selezionare un file prima di procedere" + }, + "accessibility": { + "fileUpload": "Caricamento file", + "deleteFile": "Elimina file" + } + }, + "languages": { + "zh_CN": "Cinese (Semplificato)", + "zh_TW": "Cinese (Tradizionale)", + "da": "Danese", + "nl_NL": "Olandese", + "en": "Inglese", + "fi": "Finlandese", + "fr": "Francese", + "de": "Tedesco", + "it": "Italiano", + "ja": "Giapponese", + "ko": "Coreano", + "no": "Norvegese", + "pt_BR": "Portoghese (Brasile)", + "ru": "Russo", + "es": "Spagnolo", + "es_MX": "Spagnolo (Messico)", + "sv": "Svedese", + "th": "Tailandese", + "he": "Ebraico" + }, + "session-expired": { + "title": "Sessione scaduta", + "description": "Questo link per la firma del documento è scaduto a causa di inattività o timeout della sessione. Torna alla tua email e fai di nuovo clic sul link per continuare a firmare." + }, + "inPersonComplete": { + "title": "🎉 Firma completata!", + "subtitle": "Il documento è stato firmato con successo", + "thankYou": "Grazie per aver firmato!", + "message": "Riceverai un'email di conferma una volta che il documento sarà stato firmato da tutte le parti.", + "passDevice": "Ora puoi restituire il dispositivo a {{senderName}}", + "continueButton": "Continua" + } +} \ No newline at end of file diff --git a/public/locales/ja/translation.json b/public/locales/ja/translation.json new file mode 100644 index 0000000..873efdb --- /dev/null +++ b/public/locales/ja/translation.json @@ -0,0 +1,380 @@ +{ + "terms": { + "agreementText": "<0>同意するをクリックすると、<1>電子記録および署名の開示を確認し、この文書の確認および実行における電子記録および署名の使用に同意することを確認します。", + "note": "注:", + "noteText": "これに同意しても、すぐに文書に署名するわけではありません。電子的に確認できるようになるだけです。署名する前に文書全体を確認する機会があります。" + }, + "buttons": { + "agree": "同意する", + "processing": "処理中...", + "close": "閉じる", + "downloadPdf": "PDFをダウンロード", + "downloading": "ダウンロード中..." + }, + "header": { + "aiSummary": "AIサマリー", + "completeSign": "署名完了", + "sign": "署名", + "processing": "処理中...", + "options": "ダウンロード" + }, + "menu": { + "downloadPdf": "PDFをダウンロード", + "auditTrail": "監査証跡", + "reassignSigner": "署名者の再割り当て", + "cancelTransaction": "トランザクションをキャンセル", + "viewTerms": "利用規約を表示", + "helpSupport": "ヘルプとサポート", + "about": "SMEについて" + }, + "sidebar": { + "documents": "ドキュメント", + "pages": "ページ:{{count}}", + "noDocuments": "利用可能なドキュメントはありません。" + }, + "footer": { + "readyTitle": "完了する準備はできましたか?", + "readyDesc": "必須フィールドに入力しました。作業内容を確認し、「完了」を選択してください。", + "finish": "完了", + "submitting": "送信中...", + "start": "開始", + "next": "次へ", + "agreementText": "署名することにより、Sign Made Easyの<0>利用規約に同意します。" + }, + "completion": { + "complete": { + "hit": "すべて完了!", + "title": "ご署名ありがとうございます", + "message": "文書は完了し、安全に保管されました。コピーをメールで送信しました。" + }, + "declined": { + "hit": "アクションがキャンセルされました!", + "title": "また次回!", + "message": "リクエストは拒否されました。" + }, + "cancelled": { + "hit": "アクションがキャンセルされました!", + "title": "また次回!", + "message": "リクエストはキャンセルされました。" + }, + "download": "ダウンロード", + "downloading": "ダウンロード中...", + "downloadSuccess": "ファイルのダウンロードに成功しました。", + "downloadOptions": { + "pdf": "PDFドキュメント", + "audit": "監査証跡", + "selectFormat": "形式を選択" + }, + "downloadError": "ファイルのダウンロードに失敗しました。再試行してください。", + "appsTitle": "アプリで効率アップ", + "formsTitle": "フォームを簡単に生成", + "docsTitle": "ドキュメントを生成(請求書、レポート、見積書)", + "tryNow": "今すぐ試す", + "footerText": "Copyright 2026 Sign Made Easy. All Rights Reserved.<0>プライバシーポリシー | <1>合理的利用ポリシー" + }, + "reassign": { + "title": "署名者の再割り当て", + "successSubtitle": "ドキュメントは正常に再割り当てされました", + "successTitle": "ありがとうございます!", + "successMessage": "ドキュメントは新しい署名者に正常に再割り当てされました。", + "fields": { + "firstName": "名", + "lastName": "姓", + "email": "メール", + "language": "言語", + "message": "オプションメッセージ" + }, + "placeholders": { + "firstName": "名を入力してください", + "lastName": "姓を入力してください", + "email": "your.email@example.com", + "message": "ここにメッセージを書いてください..." + }, + "buttons": { + "submit": "送信", + "submitting": "送信中...", + "cancel": "キャンセル" + }, + "errors": { + "firstNameRequired": "名は必須です", + "firstNameMin": "名は2文字以上である必要があります", + "lastNameRequired": "姓は必須です", + "lastNameMin": "姓は2文字以上である必要があります", + "emailRequired": "メールは必須です", + "emailInvalid": "無効なメールアドレスです" + } + }, + "cancelModal": { + "title": "トランザクションをキャンセル", + "description": "このトランザクションをキャンセルしてもよろしいですか?以下にキャンセル理由を記入してください。", + "placeholder": "キャンセル理由を記入してください...", + "buttons": { + "no": "いいえ、キャンセルしない", + "yes": "はい、キャンセルする" + }, + "errors": { + "reasonRequired": "キャンセル理由は必須です" + }, + "inPersonSuccess": { + "title": "取引をキャンセル", + "message": "取引は正常にキャンセルされました。確認メールが送信されました。", + "passBackDevice": "デバイスを{{senderName}}に戻すことができます。", + "continueButton": "続行" + } + }, + "enTranslations": { + "app.name": "Sign Made Easy", + "app.subtitle": "トランザクション監査", + "meta.transaction_id": "トランザクションID", + "meta.transaction_status": "トランザクションステータス", + "meta.files": "ファイル", + "audit.title": "完全な監査証跡", + "audit.description": "カスタムメッセージについては、以下の件名とメッセージを更新してください。", + "table.header.actions": "アクション", + "table.header.language": "言語", + "table.header.ip_address": "IPアドレス", + "table.header.date": "日付", + "status.completed": "完了", + "status.pending": "保留中", + "status.failed": "失敗", + "action.created": "作成済み", + "action.updated": "更新済み", + "action.deleted": "削除済み", + "action.viewed": "表示済み", + "action.signed": "署名済み", + "action.uploaded": "アップロード済み", + "action.downloaded": "ダウンロード済み", + "placeholder.not_available": "—" + }, + "auditPage": { + "appName": "Sign Made Easy", + "subtitle": "トランザクション監査", + "meta": { + "transactionId": "トランザクションID", + "transactionStatus": "トランザクションステータス", + "files": "ファイル" + }, + "audit": { + "title": "完全な監査証跡", + "description": "カスタムメッセージについては、以下の件名とメッセージを更新してください。" + }, + "table": { + "actions": "アクション", + "language": "言語", + "ipAddress": "IPアドレス", + "date": "日付" + }, + "status": { + "completed": "完了", + "pending": "保留中", + "failed": "失敗" + }, + "fallback": { + "notAvailable": "—" + } + }, + "audit": { + "transaction": { + "created": "トランザクションが {{userName}} <{{userEmail}}> によって作成されました", + "sent": "トランザクションが {{userName}} <{{userEmail}}> によって送信されました", + "cancelled": "トランザクションが {{userName}} <{{userEmail}}> によってキャンセルされました", + "edited": "トランザクションが {{userName}} <{{userEmail}}> によって編集されました", + "viewed": "トランザクションが {{userName}} <{{userEmail}}> によって閲覧されました", + "signed": "トランザクションが {{userName}} <{{userEmail}}> によって署名されました" + }, + "signature": { + "declined": "トランザクションの署名が {{userName}} <{{userEmail}}> によって拒否されました" + }, + "ers": { + "accepted": "電子記録および署名開示が {{userName}} <{{userEmail}}> によって受け入れられました" + }, + "language": { + "updated": "{{userName}} <{{userEmail}}> が言語を {{language}} に更新しました" + }, + "invitation": { + "sent": "招待メールが {{userName}} <{{userEmail}}> に送信されました", + "view": "ドキュメントを表示するための招待が {{userName}} <{{userEmail}}> に送信されました", + "resent": "招待メールが {{senderName}} <{{senderEmail}}> によって {{recipientName}} <{{recipientEmail}}> に再送信されました" + }, + "reassigned": { + "to": "署名者が {{fromName}} <{{fromEmail}}> から {{toName}} <{{toEmail}}> に再割り当てされました", + "complex": "{{personName}} <{{personEmail}}> が {{fromName}} <{{fromEmail}}> から {{toName}} <{{toEmail}}> に再割り当てされました" + }, + "inperson": { + "started": "対面トランザクションが {{userName}} <{{userEmail}}> によって開始されました", + "verification": "対面署名検証が {{userName}} <{{userEmail}}> によって受け入れられました" + }, + "facilitator": { + "accepted": "ファシリテータープロセスが {{userName}} <{{userEmail}}> によって受け入れられました" + } + }, + "signatureModal": { + "title": { + "signature": "署名", + "initial": "イニシャル", + "edit": "編集", + "styleSelection": "スタイル選択" + }, + "subtitle": "デジタル署名を作成", + "tabs": { + "select": "選択", + "draw": "描画", + "upload": "アップロード" + }, + "selectTab": { + "description": "名前を確認し、署名スタイルを選択してください。", + "requiredFields": "必須項目。", + "fullName": { + "label": "フルネーム", + "required": "*", + "placeholder": "フルネームを入力" + }, + "initials": { + "label": "イニシャル", + "required": "*", + "placeholder": "イニシャルを入力" + } + }, + "drawTab": { + "description": "署名を描いてください。", + "required": "*", + "requiredFields": "必須フィールドです。", + "signature": "署名", + "initials": "イニシャル", + "clearSignature": "署名をクリア", + "fullNameBox": { + "label": "完全な署名", + "required": "*" + }, + "initialsBox": { + "label": "イニシャル", + "required": "*", + "placeholder": "イニシャルを入力" + } + }, + "uploadTab": { + "requiredMessage": "署名とイニシャルの両方が必要です。", + "requirements": "署名には300×100px、イニシャルには100×100pxの画像を使用してください。最大300KB。対応形式:.png、.jpg。", + "signature": { + "uploadLabel": "署名をアップロード", + "uploadHint": "JPG、PNG(300×100px、最大300KB)", + "browseButton": "参照", + "uploadedLabel": "署名 ✓", + "changeButton": "署名を変更", + "altText": "アップロードされた署名画像" + }, + "initials": { + "uploadLabel": "イニシャルをアップロード", + "uploadHint": "JPG、PNG(100×100px、最大300KB)", + "browseButton": "参照", + "uploadedLabel": "イニシャル ✓", + "changeButton": "イニシャルを変更", + "altText": "アップロードされたイニシャル画像" + } + }, + "footer": { + "agreementText": "この文書に署名することを理解しています。", + "cancelButton": "キャンセル", + "adoptButton": "署名を採用して署名" + }, + "errors": { + "requiredField": "この項目は必須です", + "fileTooLarge": "ファイルサイズは300KB未満である必要があります", + "invalidFileType": ".png、.jpg、.jpegファイルのみ対応しています", + "signatureRequired": "署名を追加してください", + "initialsRequired": "イニシャルを追加してください" + } + }, + "stampModal": { + "title": { + "add": "スタンプを追加", + "edit": "スタンプを編集" + }, + "closeButton": "モーダルを閉じる", + "fileRequirements": "最大サイズ = 400Kb | 対応ファイル形式 = .png、.jpg、.jpeg", + "dragDropLabel": "画像をドラッグ&ドロップするか、クリックしてアップロード", + "previewAltText": "スタンププレビュー", + "changeImageButton": "画像を変更", + "clearButton": "閉じる", + "saveButton": "保存", + "updateButton": "更新", + "errors": { + "fileTooLarge": "ファイルサイズが400KBの制限を超えています", + "invalidFileType": ".png、.jpg、.jpegファイルのみ対応しています", + "uploadFailed": "画像のアップロードに失敗しました。もう一度お試しください。" + } + }, + "attachmentModal": { + "title": "添付ファイル", + "subtitle": { + "hasFile": "添付ファイルを管理", + "noFile": "添付ファイルをアップロード" + }, + "uploading": { + "status": "ファイルをアップロード中...", + "shimmerText": "ファイルをアップロード中..." + }, + "uploadArea": { + "dragging": "ファイルをここにドロップ", + "default": "ファイルをアップロードまたはドラッグ&ドロップ", + "fileTypes": "PDF、DOCX、JPG、PNG、TXT(最大10MB)", + "browseButton": "ファイルを参照" + }, + "uploadedFile": { + "status": "アップロード成功", + "deleteButton": "ファイルを削除" + }, + "buttons": { + "close": "閉じる", + "uploading": "アップロード中...", + "deleting": "削除中...", + "saved": "ファイル保存完了!", + "done": "完了", + "uploadFile": "ファイルをアップロード" + }, + "errors": { + "fileTooLarge": "ファイルサイズが10MBの制限を超えています", + "invalidFileType": "PDF、DOCX、JPG、PNG、TXTファイルのみ対応しています", + "uploadFailed": "ファイルのアップロードに失敗しました。もう一度お試しください。", + "deleteFailed": "ファイルの削除に失敗しました。もう一度お試しください。", + "noFileSelected": "続行する前にファイルを選択してください" + }, + "accessibility": { + "fileUpload": "ファイルアップロード", + "deleteFile": "ファイルを削除" + } + }, + "languages": { + "zh_CN": "中国語(簡体字)", + "zh_TW": "中国語(繁体字)", + "da": "デンマーク語", + "nl_NL": "オランダ語", + "en": "英語", + "fi": "フィンランド語", + "fr": "フランス語", + "de": "ドイツ語", + "it": "イタリア語", + "ja": "日本語", + "ko": "韓国語", + "no": "ノルウェー語", + "pt_BR": "ポルトガル語(ブラジル)", + "ru": "ロシア語", + "es": "スペイン語", + "es_MX": "スペイン語(メキシコ)", + "sv": "スウェーデン語", + "th": "タイ語", + "he": "ヘブライ語" + }, + "session-expired": { + "title": "セッションの有効期限が切れました", + "description": "この文書署名リンクは、操作がないかセッションタイムアウトにより期限切れになりました。メールに戻り、リンクをもう一度クリックして署名を続けてください。" + }, + "inPersonComplete": { + "title": "🎉 署名が完了しました!", + "subtitle": "文書は正常に署名されました", + "thankYou": "ご署名ありがとうございます!", + "message": "すべての関係者が文書に署名すると、確認メールが届きます。", + "passDevice": "デバイスを {{senderName}} に戻すことができます", + "continueButton": "続行" + } +} \ No newline at end of file diff --git a/public/locales/ko/translation.json b/public/locales/ko/translation.json new file mode 100644 index 0000000..17d0378 --- /dev/null +++ b/public/locales/ko/translation.json @@ -0,0 +1,380 @@ +{ + "terms": { + "agreementText": "<0>동의함을 클릭하면 <1>전자 기록 및 서명 공개를 검토했음을 확인하고 이 문서 검토 및 실행에 전자 기록 및 서명 사용에 동의합니다.", + "note": "참고:", + "noteText": "이에 동의한다고 해서 즉시 문서에 서명하는 것은 아닙니다. 전자적으로 검토할 수만 있습니다. 서명하기 전에 문서 전체를 검토할 기회가 있습니다." + }, + "buttons": { + "agree": "동의함", + "processing": "처리 중...", + "close": "닫기", + "downloadPdf": "PDF 다운로드", + "downloading": "다운로드 중..." + }, + "header": { + "aiSummary": "AI 요약", + "completeSign": "서명 완료", + "sign": "서명", + "processing": "처리 중...", + "options": "다운로드" + }, + "menu": { + "downloadPdf": "PDF 다운로드", + "auditTrail": "감사 추적", + "reassignSigner": "서명자 재할당", + "cancelTransaction": "거래 취소", + "viewTerms": "이용약관 보기", + "helpSupport": "도움말 및 지원", + "about": "SME 정보" + }, + "sidebar": { + "documents": "문서", + "pages": "페이지: {{count}}", + "noDocuments": "사용 가능한 문서가 없습니다." + }, + "footer": { + "readyTitle": "완료할 준비가 되셨나요?", + "readyDesc": "필수 필드를 작성했습니다. 작업을 검토한 후 완료를 선택하세요.", + "finish": "완료", + "submitting": "제출 중...", + "start": "시작", + "next": "다음", + "agreementText": "서명함으로써 Sign Made Easy의 <0>이용약관에 동의합니다." + }, + "completion": { + "complete": { + "hit": "모두 완료!", + "title": "서명해 주셔서 감사합니다", + "message": "문서가 완료되어 안전하게 저장되었습니다. 사본을 이메일로 보내드렸습니다." + }, + "declined": { + "hit": "작업이 취소되었습니다!", + "title": "다음에 다시 만나요!", + "message": "요청이 거부되었습니다." + }, + "cancelled": { + "hit": "작업이 취소되었습니다!", + "title": "다음에 다시 만나요!", + "message": "요청이 취소되었습니다." + }, + "download": "다운로드", + "downloading": "다운로드 중...", + "downloadSuccess": "파일이 성공적으로 다운로드되었습니다.", + "downloadOptions": { + "pdf": "PDF 문서", + "audit": "감사 추적", + "selectFormat": "형식 선택" + }, + "downloadError": "파일 다운로드에 실패했습니다. 다시 시도하세요.", + "appsTitle": "앱으로 효율성 향상", + "formsTitle": "양식을 쉽게 생성", + "docsTitle": "문서 생성(송장, 보고서, 견적서)", + "tryNow": "지금 사용해보기", + "footerText": "Copyright 2026 Sign Made Easy. All Rights Reserved.<0>개인정보처리방침 | <1>합리적 이용 정책" + }, + "reassign": { + "title": "서명자 재할당", + "successSubtitle": "문서가 성공적으로 재할당되었습니다", + "successTitle": "감사합니다!", + "successMessage": "문서가 새 서명자에게 성공적으로 재할당되었습니다.", + "fields": { + "firstName": "이름", + "lastName": "성", + "email": "이메일", + "language": "언어", + "message": "선택 메시지" + }, + "placeholders": { + "firstName": "이름을 입력하세요", + "lastName": "성을 입력하세요", + "email": "your.email@example.com", + "message": "여기에 메시지를 작성하세요..." + }, + "buttons": { + "submit": "제출", + "submitting": "제출 중...", + "cancel": "취소" + }, + "errors": { + "firstNameRequired": "이름은 필수입니다", + "firstNameMin": "이름은 최소 2자 이상이어야 합니다", + "lastNameRequired": "성은 필수입니다", + "lastNameMin": "성은 최소 2자 이상이어야 합니다", + "emailRequired": "이메일은 필수입니다", + "emailInvalid": "유효하지 않은 이메일 주소입니다" + } + }, + "cancelModal": { + "title": "거래 취소", + "description": "이 거래를 취소하시겠습니까? 아래에 취소 사유를 제공하세요.", + "placeholder": "취소 사유를 제공하세요...", + "buttons": { + "no": "아니요, 취소하지 않음", + "yes": "예, 취소함" + }, + "errors": { + "reasonRequired": "취소 사유는 필수입니다" + }, + "inPersonSuccess": { + "title": "거래 취소", + "message": "거래가 성공적으로 취소되었습니다. 확인 이메일이 발송되었습니다.", + "passBackDevice": "이제 {{senderName}}에게 기기를 돌려줄 수 있습니다.", + "continueButton": "계속" + } + }, + "enTranslations": { + "app.name": "Sign Made Easy", + "app.subtitle": "거래 감사", + "meta.transaction_id": "거래 ID", + "meta.transaction_status": "거래 상태", + "meta.files": "파일", + "audit.title": "전체 감사 추적", + "audit.description": "사용자 정의 메시지를 위해 아래 제목과 메시지를 업데이트하세요.", + "table.header.actions": "작업", + "table.header.language": "언어", + "table.header.ip_address": "IP 주소", + "table.header.date": "날짜", + "status.completed": "완료됨", + "status.pending": "보류 중", + "status.failed": "실패함", + "action.created": "생성됨", + "action.updated": "업데이트됨", + "action.deleted": "삭제됨", + "action.viewed": "조회됨", + "action.signed": "서명됨", + "action.uploaded": "업로드됨", + "action.downloaded": "다운로드됨", + "placeholder.not_available": "—" + }, + "auditPage": { + "appName": "Sign Made Easy", + "subtitle": "거래 감사", + "meta": { + "transactionId": "거래 ID", + "transactionStatus": "거래 상태", + "files": "파일" + }, + "audit": { + "title": "전체 감사 추적", + "description": "사용자 정의 메시지를 위해 아래 제목과 메시지를 업데이트하세요." + }, + "table": { + "actions": "작업", + "language": "언어", + "ipAddress": "IP 주소", + "date": "날짜" + }, + "status": { + "completed": "완료됨", + "pending": "보류 중", + "failed": "실패함" + }, + "fallback": { + "notAvailable": "—" + } + }, + "audit": { + "transaction": { + "created": "트랜잭션이 {{userName}} <{{userEmail}}>에 의해 생성되었습니다", + "sent": "트랜잭션이 {{userName}} <{{userEmail}}>에 의해 전송되었습니다", + "cancelled": "트랜잭션이 {{userName}} <{{userEmail}}>에 의해 취소되었습니다", + "edited": "트랜잭션이 {{userName}} <{{userEmail}}>에 의해 편집되었습니다", + "viewed": "트랜잭션이 {{userName}} <{{userEmail}}>에 의해 조회되었습니다", + "signed": "트랜잭션이 {{userName}} <{{userEmail}}>에 의해 서명되었습니다" + }, + "signature": { + "declined": "트랜잭션 서명이 {{userName}} <{{userEmail}}>에 의해 거부되었습니다" + }, + "ers": { + "accepted": "전자 기록 및 서명 공개가 {{userName}} <{{userEmail}}>에 의해 수락되었습니다" + }, + "language": { + "updated": "{{userName}} <{{userEmail}}>님이 언어를 {{language}}(으)로 업데이트했습니다" + }, + "invitation": { + "sent": "초대 이메일이 {{userName}} <{{userEmail}}>에게 전송되었습니다", + "view": "문서 보기 초대장이 {{userName}} <{{userEmail}}>(으)로 발송되었습니다", + "resent": "초대 이메일이 {{senderName}} <{{senderEmail}}>에 의해 {{recipientName}} <{{recipientEmail}}>에게 재전송되었습니다" + }, + "reassigned": { + "to": "서명자가 {{fromName}} <{{fromEmail}}>에서 {{toName}} <{{toEmail}}>(으)로 재할당되었습니다", + "complex": "{{personName}} <{{personEmail}}>이(가) {{fromName}} <{{fromEmail}}>에서 {{toName}} <{{toEmail}}>(으)로 재할당되었습니다" + }, + "inperson": { + "started": "대면 트랜잭션이 {{userName}} <{{userEmail}}>에 의해 시작되었습니다", + "verification": "대면 서명 확인이 {{userName}} <{{userEmail}}>에 의해 수락되었습니다" + }, + "facilitator": { + "accepted": "조정자 프로세스가 {{userName}} <{{userEmail}}>에 의해 수락되었습니다" + } + }, + "signatureModal": { + "title": { + "signature": "서명", + "initial": "이니셜", + "edit": "편집", + "styleSelection": "스타일 선택" + }, + "subtitle": "디지털 서명 만들기", + "tabs": { + "select": "선택", + "draw": "그리기", + "upload": "업로드" + }, + "selectTab": { + "description": "이름을 확인하고 서명 스타일을 선택하세요.", + "requiredFields": "필수 항목.", + "fullName": { + "label": "전체 이름", + "required": "*", + "placeholder": "전체 이름 입력" + }, + "initials": { + "label": "이니셜", + "required": "*", + "placeholder": "이니셜 입력" + } + }, + "drawTab": { + "description": "서명을 그려주세요.", + "required": "*", + "requiredFields": "필수 입력 필드입니다.", + "signature": "서명", + "initials": "이니셜", + "clearSignature": "서명 지우기", + "fullNameBox": { + "label": "전체 서명", + "required": "*" + }, + "initialsBox": { + "label": "이니셜", + "required": "*", + "placeholder": "이니셜 입력" + } + }, + "uploadTab": { + "requiredMessage": "서명과 이니셜이 모두 필요합니다.", + "requirements": "서명은 300×100px, 이니셜은 100×100px 이미지를 사용하세요. 최대 300KB. 지원: .png, .jpg.", + "signature": { + "uploadLabel": "서명 업로드", + "uploadHint": "JPG, PNG (300×100px, 최대 300KB)", + "browseButton": "찾아보기", + "uploadedLabel": "서명 ✓", + "changeButton": "서명 변경", + "altText": "업로드된 서명 이미지" + }, + "initials": { + "uploadLabel": "이니셜 업로드", + "uploadHint": "JPG, PNG (100×100px, 최대 300KB)", + "browseButton": "찾아보기", + "uploadedLabel": "이니셜 ✓", + "changeButton": "이니셜 변경", + "altText": "업로드된 이니셜 이미지" + } + }, + "footer": { + "agreementText": "이 문서에 서명하고 있음을 이해합니다.", + "cancelButton": "취소", + "adoptButton": "서명 채택 및 서명" + }, + "errors": { + "requiredField": "이 필드는 필수입니다", + "fileTooLarge": "파일 크기는 300KB 미만이어야 합니다", + "invalidFileType": ".png, .jpg, .jpeg 파일만 지원됩니다", + "signatureRequired": "서명을 추가해주세요", + "initialsRequired": "이니셜을 추가해주세요" + } + }, + "stampModal": { + "title": { + "add": "스탬프 추가", + "edit": "스탬프 편집" + }, + "closeButton": "모달 닫기", + "fileRequirements": "최대 크기 = 400Kb | 지원 파일 형식 = .png, .jpg, .jpeg", + "dragDropLabel": "이미지를 드래그 앤 드롭하거나 클릭하여 업로드", + "previewAltText": "스탬프 미리보기", + "changeImageButton": "이미지 변경", + "clearButton": "닫기", + "saveButton": "저장", + "updateButton": "업데이트", + "errors": { + "fileTooLarge": "파일 크기가 400KB 제한을 초과했습니다", + "invalidFileType": ".png, .jpg, .jpeg 파일만 지원됩니다", + "uploadFailed": "이미지 업로드에 실패했습니다. 다시 시도해주세요." + } + }, + "attachmentModal": { + "title": "첨부파일", + "subtitle": { + "hasFile": "첨부파일 관리", + "noFile": "첨부파일 업로드" + }, + "uploading": { + "status": "파일 업로드 중...", + "shimmerText": "파일 업로드 중..." + }, + "uploadArea": { + "dragging": "파일을 여기에 드롭하세요", + "default": "파일 업로드 또는 드래그 앤 드롭", + "fileTypes": "PDF, DOCX, JPG, PNG, TXT (최대 10MB)", + "browseButton": "파일 찾아보기" + }, + "uploadedFile": { + "status": "업로드 성공", + "deleteButton": "파일 삭제" + }, + "buttons": { + "close": "닫기", + "uploading": "업로드 중...", + "deleting": "삭제 중...", + "saved": "파일 저장 완료!", + "done": "완료", + "uploadFile": "파일 업로드" + }, + "errors": { + "fileTooLarge": "파일 크기가 10MB 제한을 초과했습니다", + "invalidFileType": "PDF, DOCX, JPG, PNG, TXT 파일만 지원됩니다", + "uploadFailed": "파일 업로드에 실패했습니다. 다시 시도해주세요.", + "deleteFailed": "파일 삭제에 실패했습니다. 다시 시도해주세요.", + "noFileSelected": "진행하기 전에 파일을 선택해주세요" + }, + "accessibility": { + "fileUpload": "파일 업로드", + "deleteFile": "파일 삭제" + } + }, + "languages": { + "zh_CN": "중국어(간체)", + "zh_TW": "중국어(번체)", + "da": "덴마크어", + "nl_NL": "네덜란드어", + "en": "영어", + "fi": "핀란드어", + "fr": "프랑스어", + "de": "독일어", + "it": "이탈리아어", + "ja": "일본어", + "ko": "한국어", + "no": "노르웨이어", + "pt_BR": "포르투갈어(브라질)", + "ru": "러시아어", + "es": "스페인어", + "es_MX": "스페인어(멕시코)", + "sv": "스웨덴어", + "th": "태국어", + "he": "히브리어" + }, + "session-expired": { + "title": "세션이 만료되었습니다", + "description": "이 문서 서명 링크는 비활성 또는 세션 시간 초과로 인해 만료되었습니다. 이메일로 돌아가서 링크를 다시 클릭하여 서명을 계속하십시오." + }, + "inPersonComplete": { + "title": "🎉 서명 완료!", + "subtitle": "문서가 성공적으로 서명되었습니다", + "thankYou": "서명해 주셔서 감사합니다!", + "message": "모든 당사자가 문서에 서명하면 확인 이메일을 받게 됩니다.", + "passDevice": "이제 기기를 {{senderName}}에게 다시 전달할 수 있습니다", + "continueButton": "계속" + } +} \ No newline at end of file diff --git a/public/locales/nl_NL/translation.json b/public/locales/nl_NL/translation.json new file mode 100644 index 0000000..cd3277b --- /dev/null +++ b/public/locales/nl_NL/translation.json @@ -0,0 +1,380 @@ +{ + "terms": { + "agreementText": "Door op <0>Ik ga akkoord te klikken, bevestigt u dat u de <1>Disclosure van elektronische registratie en handtekening hebt bekeken en instemt met het gebruik van elektronische registraties en handtekeningen bij het bekijken en ondertekenen van dit document.", + "note": "Opmerking:", + "noteText": "Akkoord gaan hiermee betekent niet dat u het document onmiddellijk ondertekent. Het stelt u alleen in staat het elektronisch te bekijken. U krijgt de kans het document volledig te bekijken voordat u ondertekent." + }, + "buttons": { + "agree": "Ik ga akkoord", + "processing": "Verwerken...", + "close": "Sluiten", + "downloadPdf": "PDF downloaden", + "downloading": "Downloaden..." + }, + "header": { + "aiSummary": "AI-samenvatting", + "completeSign": "Ondertekening voltooien", + "sign": "Ondertekenen", + "processing": "Verwerken...", + "options": "Downloaden" + }, + "menu": { + "downloadPdf": "PDF downloaden", + "auditTrail": "Audit trail", + "reassignSigner": "Ondertekenaar opnieuw toewijzen", + "cancelTransaction": "Transactie annuleren", + "viewTerms": "Algemene voorwaarden bekijken", + "helpSupport": "Help & ondersteuning", + "about": "Over SME" + }, + "sidebar": { + "documents": "Documenten", + "pages": "Pagina's: {{count}}", + "noDocuments": "Geen documenten beschikbaar." + }, + "footer": { + "readyTitle": "Klaar om af te ronden?", + "readyDesc": "U hebt de vereiste velden ingevuld. Bekijk uw werk en selecteer vervolgens Voltooien.", + "finish": "Voltooien", + "submitting": "Verzenden...", + "start": "Start", + "next": "Volgende", + "agreementText": "Door te ondertekenen ga ik akkoord met de <0>algemene voorwaarden van Sign Made Easy." + }, + "completion": { + "complete": { + "hit": "Helemaal klaar!", + "title": "Bedankt voor het ondertekenen", + "message": "Uw document is nu voltooid en veilig opgeslagen. We hebben u een kopie gemaild." + }, + "declined": { + "hit": "Actie geannuleerd!", + "title": "Misschien volgende keer!", + "message": "Uw verzoek is succesvol afgewezen." + }, + "cancelled": { + "hit": "Actie geannuleerd!", + "title": "Misschien volgende keer!", + "message": "Uw verzoek is succesvol geannuleerd." + }, + "download": "Downloaden", + "downloading": "Downloaden...", + "downloadSuccess": "Bestand succesvol gedownload.", + "downloadOptions": { + "pdf": "PDF-document", + "audit": "Audit trail", + "selectFormat": "Selecteer formaat" + }, + "downloadError": "Download mislukt. Probeer het opnieuw.", + "appsTitle": "Verhoog de efficiëntie met onze apps", + "formsTitle": "Genereer eenvoudig formulieren", + "docsTitle": "Genereer documenten (facturen, rapporten, offertes)", + "tryNow": "Probeer nu", + "footerText": "Auteursrecht 2026 Sign Made Easy. Alle rechten voorbehouden.<0>Privacybeleid | <1>Beleid voor redelijk gebruik" + }, + "reassign": { + "title": "Ondertekenaar opnieuw toewijzen", + "successSubtitle": "Document is succesvol opnieuw toegewezen", + "successTitle": "Dank u!", + "successMessage": "Het document is succesvol opnieuw toegewezen aan de nieuwe ondertekenaar.", + "fields": { + "firstName": "Voornaam", + "lastName": "Achternaam", + "email": "E-mail", + "language": "Taal", + "message": "Optioneel bericht" + }, + "placeholders": { + "firstName": "Voer uw voornaam in", + "lastName": "Voer uw achternaam in", + "email": "your.email@example.com", + "message": "Schrijf uw bericht hier..." + }, + "buttons": { + "submit": "Verzenden", + "submitting": "Verzenden...", + "cancel": "Annuleren" + }, + "errors": { + "firstNameRequired": "Voornaam is verplicht", + "firstNameMin": "Voornaam moet minimaal 2 tekens bevatten", + "lastNameRequired": "Achternaam is verplicht", + "lastNameMin": "Achternaam moet minimaal 2 tekens bevatten", + "emailRequired": "E-mail is verplicht", + "emailInvalid": "Ongeldig e-mailadres" + } + }, + "cancelModal": { + "title": "Transactie annuleren", + "description": "Weet u zeker dat u deze transactie wilt annuleren? Geef hieronder uw reden voor annulering op.", + "placeholder": "Geef uw reden voor annulering...", + "buttons": { + "no": "Nee, niet annuleren", + "yes": "Ja, annuleer het" + }, + "errors": { + "reasonRequired": "Annuleringsreden is verplicht" + }, + "inPersonSuccess": { + "title": "Annuleer transactie", + "message": "De transactie is succesvol geannuleerd. Bevestigingsmails zijn verzonden.", + "passBackDevice": "U kunt het apparaat nu teruggeven aan {{senderName}}.", + "continueButton": "Doorgaan" + } + }, + "enTranslations": { + "app.name": "Sign Made Easy", + "app.subtitle": "Transactie-audit", + "meta.transaction_id": "Transactie-ID", + "meta.transaction_status": "Transactiestatus", + "meta.files": "Bestanden", + "audit.title": "Volledige audit trail", + "audit.description": "Werk het onderwerp en bericht hieronder bij voor een aangepast bericht.", + "table.header.actions": "Acties", + "table.header.language": "Taal", + "table.header.ip_address": "IP-adres", + "table.header.date": "Datum", + "status.completed": "Voltooid", + "status.pending": "In behandeling", + "status.failed": "Mislukt", + "action.created": "Aangemaakt", + "action.updated": "Bijgewerkt", + "action.deleted": "Verwijderd", + "action.viewed": "Bekeken", + "action.signed": "Ondertekend", + "action.uploaded": "Geüpload", + "action.downloaded": "Gedownload", + "placeholder.not_available": "—" + }, + "auditPage": { + "appName": "Sign Made Easy", + "subtitle": "Transactie-audit", + "meta": { + "transactionId": "Transactie-ID", + "transactionStatus": "Transactiestatus", + "files": "Bestanden" + }, + "audit": { + "title": "Volledige audit trail", + "description": "Werk het onderwerp en bericht hieronder bij voor een aangepast bericht." + }, + "table": { + "actions": "Acties", + "language": "Taal", + "ipAddress": "IP-adres", + "date": "Datum" + }, + "status": { + "completed": "Voltooid", + "pending": "In behandeling", + "failed": "Mislukt" + }, + "fallback": { + "notAvailable": "—" + } + }, + "audit": { + "transaction": { + "created": "Transactie is gemaakt door {{userName}} <{{userEmail}}>", + "sent": "Transactie is verzonden door {{userName}} <{{userEmail}}>", + "cancelled": "Transactie is geannuleerd door {{userName}} <{{userEmail}}>", + "edited": "Transactie is bewerkt door {{userName}} <{{userEmail}}>", + "viewed": "Transactie is bekeken door {{userName}} <{{userEmail}}>", + "signed": "Transactie is ondertekend door {{userName}} <{{userEmail}}>" + }, + "signature": { + "declined": "Transactiehandtekening is geweigerd door {{userName}} <{{userEmail}}>" + }, + "ers": { + "accepted": "Elektronische registratie en handtekeningopenbaarmaking is geaccepteerd door {{userName}} <{{userEmail}}>" + }, + "language": { + "updated": "{{userName}} <{{userEmail}}> heeft hun taal bijgewerkt naar {{language}}" + }, + "invitation": { + "sent": "Uitnodigingsmail verzonden naar {{userName}} <{{userEmail}}>", + "view": "Uitnodiging om het document te bekijken is verzonden naar {{userName}} <{{userEmail}}>", + "resent": "Uitnodigingsmail opnieuw verzonden naar {{recipientName}} <{{recipientEmail}}> door {{senderName}} <{{senderEmail}}>" + }, + "reassigned": { + "to": "Ondertekenaar is opnieuw toegewezen door {{fromName}} <{{fromEmail}}> aan {{toName}} <{{toEmail}}>", + "complex": "{{personName}} <{{personEmail}}> is opnieuw toegewezen door {{fromName}} <{{fromEmail}}> aan {{toName}} <{{toEmail}}>" + }, + "inperson": { + "started": "Persoonlijke transactie is gestart door {{userName}} <{{userEmail}}>", + "verification": "Persoonlijke handtekeningverificatie is geaccepteerd door {{userName}} <{{userEmail}}>" + }, + "facilitator": { + "accepted": "Facilitatorproces is geaccepteerd door {{userName}} <{{userEmail}}>" + } + }, + "signatureModal": { + "title": { + "signature": "Handtekening", + "initial": "Initialen", + "edit": "Bewerken", + "styleSelection": "Stijlselectie" + }, + "subtitle": "Maak uw digitale handtekeningen", + "tabs": { + "select": "Selecteren", + "draw": "Tekenen", + "upload": "Uploaden" + }, + "selectTab": { + "description": "Bevestig uw naam en kies een handtekeningstijl.", + "requiredFields": "Verplichte velden.", + "fullName": { + "label": "Volledige naam", + "required": "*", + "placeholder": "Voer volledige naam in" + }, + "initials": { + "label": "Initialen", + "required": "*", + "placeholder": "Voer initialen in" + } + }, + "drawTab": { + "description": "Teken uw handtekening.", + "required": "*", + "requiredFields": "Zijn verplichte velden.", + "signature": "Handtekening", + "initials": "Initialen", + "clearSignature": "Wis handtekening", + "fullNameBox": { + "label": "Volledige handtekening", + "required": "*" + }, + "initialsBox": { + "label": "Initialen", + "required": "*", + "placeholder": "Voer initialen in" + } + }, + "uploadTab": { + "requiredMessage": "Zowel handtekening als initialen zijn vereist.", + "requirements": "Gebruik afbeeldingen van 300×100px voor handtekeningen en 100×100px voor initialen. Max. 300KB. Ondersteund: .png, .jpg.", + "signature": { + "uploadLabel": "Handtekening uploaden", + "uploadHint": "JPG, PNG (300×100px, max. 300KB)", + "browseButton": "Bladeren", + "uploadedLabel": "Handtekening ✓", + "changeButton": "Handtekening wijzigen", + "altText": "Geüploade handtekeningafbeelding" + }, + "initials": { + "uploadLabel": "Initialen uploaden", + "uploadHint": "JPG, PNG (100×100px, max. 300KB)", + "browseButton": "Bladeren", + "uploadedLabel": "Initialen ✓", + "changeButton": "Initialen wijzigen", + "altText": "Geüploade initialenafbeelding" + } + }, + "footer": { + "agreementText": "Ik begrijp dat ik dit document onderteken.", + "cancelButton": "Annuleren", + "adoptButton": "Handtekening overnemen en ondertekenen" + }, + "errors": { + "requiredField": "Dit veld is verplicht", + "fileTooLarge": "Bestandsgrootte moet onder 300KB zijn", + "invalidFileType": "Alleen .png, .jpg en .jpeg bestanden worden ondersteund", + "signatureRequired": "Voeg een handtekening toe", + "initialsRequired": "Voeg initialen toe" + } + }, + "stampModal": { + "title": { + "add": "Stempel toevoegen", + "edit": "Stempel bewerken" + }, + "closeButton": "Modal sluiten", + "fileRequirements": "Maximale grootte = 400Kb | Ondersteunde bestandstypen = .png, .jpg, .jpeg", + "dragDropLabel": "Sleep een afbeelding, of klik om te uploaden", + "previewAltText": "Stempelvoorbeeld", + "changeImageButton": "Afbeelding wijzigen", + "clearButton": "Sluiten", + "saveButton": "Opslaan", + "updateButton": "Bijwerken", + "errors": { + "fileTooLarge": "Bestandsgrootte overschrijdt de limiet van 400KB", + "invalidFileType": "Alleen .png, .jpg en .jpeg bestanden worden ondersteund", + "uploadFailed": "Afbeelding uploaden mislukt. Probeer het opnieuw." + } + }, + "attachmentModal": { + "title": "Bijlage", + "subtitle": { + "hasFile": "Uw bijlage beheren", + "noFile": "Bijlage uploaden" + }, + "uploading": { + "status": "Bestand uploaden...", + "shimmerText": "Bestand uploaden..." + }, + "uploadArea": { + "dragging": "Zet uw bestand hier neer", + "default": "Upload of sleep een bestand", + "fileTypes": "PDF, DOCX, JPG, PNG, TXT (max. 10MB)", + "browseButton": "Bladeren door bestanden" + }, + "uploadedFile": { + "status": "Succesvol geüpload", + "deleteButton": "Bestand verwijderen" + }, + "buttons": { + "close": "Sluiten", + "uploading": "Uploaden...", + "deleting": "Verwijderen...", + "saved": "Bestand opgeslagen!", + "done": "Gereed", + "uploadFile": "Bestand uploaden" + }, + "errors": { + "fileTooLarge": "Bestandsgrootte overschrijdt de limiet van 10MB", + "invalidFileType": "Alleen PDF, DOCX, JPG, PNG en TXT bestanden worden ondersteund", + "uploadFailed": "Bestand uploaden mislukt. Probeer het opnieuw.", + "deleteFailed": "Bestand verwijderen mislukt. Probeer het opnieuw.", + "noFileSelected": "Selecteer een bestand voordat u doorgaat" + }, + "accessibility": { + "fileUpload": "Bestand uploaden", + "deleteFile": "Bestand verwijderen" + } + }, + "languages": { + "zh_CN": "Chinees (Vereenvoudigd)", + "zh_TW": "Chinees (Traditioneel)", + "da": "Deens", + "nl_NL": "Nederlands", + "en": "Engels", + "fi": "Fins", + "fr": "Frans", + "de": "Duits", + "it": "Italiaans", + "ja": "Japans", + "ko": "Koreaans", + "no": "Noors", + "pt_BR": "Portugees (Brazilië)", + "ru": "Russisch", + "es": "Spaans", + "es_MX": "Spaans (Mexico)", + "sv": "Zweeds", + "th": "Thais", + "he": "Hebreeuws" + }, + "session-expired": { + "title": "Sessie verlopen", + "description": "Deze link voor het ondertekenen van documenten is verlopen vanwege inactiviteit of een time-out van de sessie. Ga terug naar uw e-mail en klik opnieuw op de link om verder te gaan met ondertekenen." + }, + "inPersonComplete": { + "title": "🎉 Ondertekening voltooid!", + "subtitle": "Document is succesvol ondertekend", + "thankYou": "Bedankt voor het ondertekenen!", + "message": "U ontvangt een bevestigingsmail zodra het document door alle partijen is ondertekend.", + "passDevice": "U kunt het apparaat nu teruggeven aan {{senderName}}", + "continueButton": "Doorgaan" + } +} \ No newline at end of file diff --git a/public/locales/no/translation.json b/public/locales/no/translation.json new file mode 100644 index 0000000..1a92f26 --- /dev/null +++ b/public/locales/no/translation.json @@ -0,0 +1,380 @@ +{ + "terms": { + "agreementText": "Ved å klikke på <0>Jeg godtar bekrefter du at du har gjennomgått <1>Opplysning om elektronisk registrering og signatur, og samtykker til bruk av elektroniske registreringer og signaturer ved gjennomgang og utførelse av dette dokumentet.", + "note": "Merk:", + "noteText": "Å godta dette betyr ikke at du signerer dokumentet umiddelbart. Det tillater deg bare å gjennomgå det elektronisk. Du vil få muligheten til å gjennomgå dokumentet fullstendig før du signerer." + }, + "buttons": { + "agree": "Jeg godtar", + "processing": "Behandler...", + "close": "Lukk", + "downloadPdf": "Last ned PDF", + "downloading": "Laster ned..." + }, + "header": { + "aiSummary": "AI-sammendrag", + "completeSign": "Fullfør signering", + "sign": "Signer", + "processing": "Behandler...", + "options": "Last ned" + }, + "menu": { + "downloadPdf": "Last ned PDF", + "auditTrail": "Revisjonsspor", + "reassignSigner": "Tilordne signatar på nytt", + "cancelTransaction": "Avbryt transaksjon", + "viewTerms": "Se vilkår og betingelser", + "helpSupport": "Hjelp og støtte", + "about": "Om SME" + }, + "sidebar": { + "documents": "Dokumenter", + "pages": "Sider: {{count}}", + "noDocuments": "Ingen tilgjengelige dokumenter." + }, + "footer": { + "readyTitle": "Klar til å fullføre?", + "readyDesc": "Du har fylt ut de obligatoriske feltene. Gå gjennom arbeidet ditt, og velg deretter Fullfør.", + "finish": "Fullfør", + "submitting": "Sender inn...", + "start": "Start", + "next": "Neste", + "agreementText": "Ved å signere godtar jeg Sign Made Easy's <0>vilkår og betingelser." + }, + "completion": { + "complete": { + "hit": "Helt ferdig!", + "title": "Takk for at du signerte", + "message": "Dokumentet ditt er nå fullført og sikkert lagret. Vi har sendt deg en kopi på e-post." + }, + "declined": { + "hit": "Handling avbrutt!", + "title": "Kanskje neste gang!", + "message": "Forespørselen din er avvist." + }, + "cancelled": { + "hit": "Handling avbrutt!", + "title": "Kanskje neste gang!", + "message": "Forespørselen din er avbrutt." + }, + "download": "Last ned", + "downloading": "Laster ned...", + "downloadSuccess": "Fil lastet ned.", + "downloadOptions": { + "pdf": "PDF-dokument", + "audit": "Revisjonsspor", + "selectFormat": "Velg format" + }, + "downloadError": "Nedlasting mislyktes. Prøv igjen.", + "appsTitle": "Øk effektiviteten med appene våre", + "formsTitle": "Generer skjemaer enkelt", + "docsTitle": "Generer dokumenter (fakturaer, rapporter, tilbud)", + "tryNow": "Prøv nå", + "footerText": "Opphavsrett 2026 Sign Made Easy. Alle rettigheter forbeholdt.<0>Personvernerklæring | <1>Retningslinjer for rimelig bruk" + }, + "reassign": { + "title": "Tilordne signatar på nytt", + "successSubtitle": "Dokumentet er blitt tilordnet på nytt", + "successTitle": "Takk!", + "successMessage": "Dokumentet er blitt tilordnet den nye signataren.", + "fields": { + "firstName": "Fornavn", + "lastName": "Etternavn", + "email": "E-post", + "language": "Språk", + "message": "Valgfri melding" + }, + "placeholders": { + "firstName": "Skriv inn fornavnet ditt", + "lastName": "Skriv inn etternavnet ditt", + "email": "your.email@example.com", + "message": "Skriv meldingen din her..." + }, + "buttons": { + "submit": "Send inn", + "submitting": "Sender inn...", + "cancel": "Avbryt" + }, + "errors": { + "firstNameRequired": "Fornavn er påkrevd", + "firstNameMin": "Fornavn må være minst 2 tegn", + "lastNameRequired": "Etternavn er påkrevd", + "lastNameMin": "Etternavn må være minst 2 tegn", + "emailRequired": "E-post er påkrevd", + "emailInvalid": "Ugyldig e-postadresse" + } + }, + "cancelModal": { + "title": "Avbryt transaksjon", + "description": "Er du sikker på at du vil avbryte denne transaksjonen? Oppgi årsaken til avbruddet nedenfor.", + "placeholder": "Vennligst oppgi årsaken til avbruddet...", + "buttons": { + "no": "Nei, ikke avbryt", + "yes": "Ja, avbryt den" + }, + "errors": { + "reasonRequired": "Årsak til avbrudd er påkrevd" + }, + "inPersonSuccess": { + "title": "Avbryt transaksjon", + "message": "Transaksjonen ble kansellert. Bekreftelses-e-poster ble sendt.", + "passBackDevice": "Du kan nå gi enheten tilbake til {{senderName}}.", + "continueButton": "Fortsett" + } + }, + "enTranslations": { + "app.name": "Sign Made Easy", + "app.subtitle": "Transaksjonsrevisjon", + "meta.transaction_id": "Transaksjons-ID", + "meta.transaction_status": "Transaksjonsstatus", + "meta.files": "Filer", + "audit.title": "Fullt revisjonsspor", + "audit.description": "Oppdater emne og melding nedenfor for en egendefinert melding.", + "table.header.actions": "Handlinger", + "table.header.language": "Språk", + "table.header.ip_address": "IP-adresse", + "table.header.date": "Dato", + "status.completed": "Fullført", + "status.pending": "Venter", + "status.failed": "Mislyktes", + "action.created": "Opprettet", + "action.updated": "Oppdatert", + "action.deleted": "Slettet", + "action.viewed": "Vist", + "action.signed": "Signert", + "action.uploaded": "Lastet opp", + "action.downloaded": "Lastet ned", + "placeholder.not_available": "—" + }, + "auditPage": { + "appName": "Sign Made Easy", + "subtitle": "Transaksjonsrevisjon", + "meta": { + "transactionId": "Transaksjons-ID", + "transactionStatus": "Transaksjonsstatus", + "files": "Filer" + }, + "audit": { + "title": "Fullt revisjonsspor", + "description": "Oppdater emne og melding nedenfor for en egendefinert melding." + }, + "table": { + "actions": "Handlinger", + "language": "Språk", + "ipAddress": "IP-adresse", + "date": "Dato" + }, + "status": { + "completed": "Fullført", + "pending": "Venter", + "failed": "Mislyktes" + }, + "fallback": { + "notAvailable": "—" + } + }, + "audit": { + "transaction": { + "created": "Transaksjon ble opprettet av {{userName}} <{{userEmail}}>", + "sent": "Transaksjon ble sendt av {{userName}} <{{userEmail}}>", + "cancelled": "Transaksjon ble kansellert av {{userName}} <{{userEmail}}>", + "edited": "Transaksjon ble redigert av {{userName}} <{{userEmail}}>", + "viewed": "Transaksjon ble sett av {{userName}} <{{userEmail}}>", + "signed": "Transaksjon ble signert av {{userName}} <{{userEmail}}>" + }, + "signature": { + "declined": "Transaksjonssignatur ble avvist av {{userName}} <{{userEmail}}>" + }, + "ers": { + "accepted": "Elektronisk opptak og signaturavsløring ble akseptert av {{userName}} <{{userEmail}}>" + }, + "language": { + "updated": "{{userName}} <{{userEmail}}> oppdaterte språket sitt til {{language}}" + }, + "invitation": { + "sent": "Invitasjons-e-post sendt til {{userName}} <{{userEmail}}>", + "view": "Invitasjon til å vise dokumentet er sendt til {{userName}} <{{userEmail}}>", + "resent": "Invitasjons-e-post sendt på nytt til {{recipientName}} <{{recipientEmail}}> av {{senderName}} <{{senderEmail}}>" + }, + "reassigned": { + "to": "Signatar ble tildelt på nytt av {{fromName}} <{{fromEmail}}> til {{toName}} <{{toEmail}}>", + "complex": "{{personName}} <{{personEmail}}> ble tildelt på nytt av {{fromName}} <{{fromEmail}}> til {{toName}} <{{toEmail}}>" + }, + "inperson": { + "started": "Personlig transaksjon ble startet av {{userName}} <{{userEmail}}>", + "verification": "Personlig signaturverifisering ble akseptert av {{userName}} <{{userEmail}}>" + }, + "facilitator": { + "accepted": "Fasilitatorprosess ble akseptert av {{userName}} <{{userEmail}}>" + } + }, + "signatureModal": { + "title": { + "signature": "Signatur", + "initial": "Initialer", + "edit": "Rediger", + "styleSelection": "Stilvalg" + }, + "subtitle": "Opprett dine digitale signaturer", + "tabs": { + "select": "Velg", + "draw": "Tegn", + "upload": "Last opp" + }, + "selectTab": { + "description": "Bekreft navnet ditt og velg en signaturstil.", + "requiredFields": "Obligatoriske felt.", + "fullName": { + "label": "Fullt navn", + "required": "*", + "placeholder": "Skriv inn fullt navn" + }, + "initials": { + "label": "Initialer", + "required": "*", + "placeholder": "Skriv inn initialer" + } + }, + "drawTab": { + "description": "Tegn signaturen din.", + "required": "*", + "requiredFields": "Er obligatoriske felt.", + "signature": "Signatur", + "initials": "Initialer", + "clearSignature": "Tøm signatur", + "fullNameBox": { + "label": "Full signatur", + "required": "*" + }, + "initialsBox": { + "label": "Initialer", + "required": "*", + "placeholder": "Skriv inn initialer" + } + }, + "uploadTab": { + "requiredMessage": "Både signatur og initialer er påkrevd.", + "requirements": "Bruk bilder på 300×100px for signaturer og 100×100px for initialer. Maks 300KB. Støttet: .png, .jpg.", + "signature": { + "uploadLabel": "Last opp signatur", + "uploadHint": "JPG, PNG (300×100px, maks 300KB)", + "browseButton": "Bla gjennom", + "uploadedLabel": "Signatur ✓", + "changeButton": "Endre signatur", + "altText": "Opplastet signaturbilde" + }, + "initials": { + "uploadLabel": "Last opp initialer", + "uploadHint": "JPG, PNG (100×100px, maks 300KB)", + "browseButton": "Bla gjennom", + "uploadedLabel": "Initialer ✓", + "changeButton": "Endre initialer", + "altText": "Opplastet initialbilde" + } + }, + "footer": { + "agreementText": "Jeg forstår at jeg signerer dette dokumentet.", + "cancelButton": "Avbryt", + "adoptButton": "Adopter signatur og signer" + }, + "errors": { + "requiredField": "Dette feltet er påkrevd", + "fileTooLarge": "Filstørrelsen må være under 300KB", + "invalidFileType": "Kun .png, .jpg og .jpeg filer støttes", + "signatureRequired": "Vennligst legg til en signatur", + "initialsRequired": "Vennligst legg til initialer" + } + }, + "stampModal": { + "title": { + "add": "Legg til stempel", + "edit": "Rediger stempel" + }, + "closeButton": "Lukk modal", + "fileRequirements": "Maksimal størrelse = 400Kb | Støttede filtyper = .png, .jpg, .jpeg", + "dragDropLabel": "Dra og slipp et bilde, eller klikk for å laste opp", + "previewAltText": "Stempelforvisning", + "changeImageButton": "Endre bilde", + "clearButton": "Lukk", + "saveButton": "Lagre", + "updateButton": "Oppdater", + "errors": { + "fileTooLarge": "Filstørrelsen overstiger grensen på 400KB", + "invalidFileType": "Kun .png, .jpg og .jpeg filer støttes", + "uploadFailed": "Kunne ikke laste opp bildet. Prøv igjen." + } + }, + "attachmentModal": { + "title": "Vedlegg", + "subtitle": { + "hasFile": "Administrer vedlegget ditt", + "noFile": "Last opp vedlegg" + }, + "uploading": { + "status": "Laster opp fil...", + "shimmerText": "Laster opp fil..." + }, + "uploadArea": { + "dragging": "Slipp filen her", + "default": "Last opp eller dra og slipp fil", + "fileTypes": "PDF, DOCX, JPG, PNG, TXT (maks 10MB)", + "browseButton": "Bla gjennom filer" + }, + "uploadedFile": { + "status": "Opplastet vellykket", + "deleteButton": "Slett fil" + }, + "buttons": { + "close": "Lukk", + "uploading": "Laster opp...", + "deleting": "Sletter...", + "saved": "Fil lagret!", + "done": "Ferdig", + "uploadFile": "Last opp fil" + }, + "errors": { + "fileTooLarge": "Filstørrelsen overstiger grensen på 10MB", + "invalidFileType": "Kun PDF, DOCX, JPG, PNG og TXT filer støttes", + "uploadFailed": "Kunne ikke laste opp filen. Prøv igjen.", + "deleteFailed": "Kunne ikke slette filen. Prøv igjen.", + "noFileSelected": "Vennligst velg en fil før du fortsetter" + }, + "accessibility": { + "fileUpload": "Filopplasting", + "deleteFile": "Slett fil" + } + }, + "languages": { + "zh_CN": "Kinesisk (Forenklet)", + "zh_TW": "Kinesisk (Tradisjonell)", + "da": "Dansk", + "nl_NL": "Nederlandsk", + "en": "Engelsk", + "fi": "Finsk", + "fr": "Fransk", + "de": "Tysk", + "it": "Italiensk", + "ja": "Japansk", + "ko": "Koreansk", + "no": "Norsk", + "pt_BR": "Portugisisk (Brasil)", + "ru": "Russisk", + "es": "Spansk", + "es_MX": "Spansk (Mexico)", + "sv": "Svensk", + "th": "Thai", + "he": "Hebraisk" + }, + "session-expired": { + "title": "Økten har utløpt", + "description": "Denne dokumentunderskriftslenken har utløpt på grunn av inaktivitet eller tidsavbrudd for økten. Vennligst gå tilbake til e-posten din og klikk på lenken igjen for å fortsette å underskrive." + }, + "inPersonComplete": { + "title": "🎉 Signering fullført!", + "subtitle": "Dokumentet er signert", + "thankYou": "Takk for at du signerte!", + "message": "Du vil motta en bekreftelses-e-post når dokumentet er signert av alle parter.", + "passDevice": "Du kan nå gi enheten tilbake til {{senderName}}", + "continueButton": "Fortsett" + } +} \ No newline at end of file diff --git a/public/locales/pt_BR/translation.json b/public/locales/pt_BR/translation.json new file mode 100644 index 0000000..2987af3 --- /dev/null +++ b/public/locales/pt_BR/translation.json @@ -0,0 +1,380 @@ +{ + "terms": { + "agreementText": "Ao clicar em <0>Eu concordo, você confirma que revisou a <1>Divulgação de Registro Eletrônico e Assinatura e consente com o uso de registros e assinaturas eletrônicas na revisão e execução deste documento.", + "note": "Observação:", + "noteText": "Concordar com isso não significa que você está assinando o documento imediatamente. Apenas permite que você o revise eletronicamente. Você terá a chance de revisar o documento por completo antes de assinar." + }, + "buttons": { + "agree": "Eu concordo", + "processing": "Processando...", + "close": "Fechar", + "downloadPdf": "Baixar PDF", + "downloading": "Baixando..." + }, + "header": { + "aiSummary": "Resumo de IA", + "completeSign": "Assinar completamente", + "sign": "Assinar", + "processing": "Processando...", + "options": "Baixar" + }, + "menu": { + "downloadPdf": "Baixar PDF", + "auditTrail": "Trilha de Auditoria", + "reassignSigner": "Reatribuir Signatário", + "cancelTransaction": "Cancelar Transação", + "viewTerms": "Ver Termos e Condições", + "helpSupport": "Ajuda e Suporte", + "about": "Sobre a SME" + }, + "sidebar": { + "documents": "Documentos", + "pages": "Páginas: {{count}}", + "noDocuments": "Nenhum documento disponível." + }, + "footer": { + "readyTitle": "Pronto para finalizar?", + "readyDesc": "Você preencheu os campos obrigatórios. Revise seu trabalho e selecione Finalizar.", + "finish": "Finalizar", + "submitting": "Enviando...", + "start": "Iniciar", + "next": "Próximo", + "agreementText": "Ao assinar, concordo com os <0>Termos e Condições do Sign Made Easy." + }, + "completion": { + "complete": { + "hit": "Tudo pronto!", + "title": "Obrigado por assinar", + "message": "Seu documento agora está completo e armazenado com segurança. Enviamos uma cópia para seu e-mail." + }, + "declined": { + "hit": "Ação cancelada!", + "title": "Talvez na próxima!", + "message": "Sua solicitação foi recusada." + }, + "cancelled": { + "hit": "Ação cancelada!", + "title": "Talvez na próxima!", + "message": "Sua solicitação foi cancelada." + }, + "download": "Baixar", + "downloading": "Baixando...", + "downloadSuccess": "Arquivo baixado com sucesso.", + "downloadOptions": { + "pdf": "Documento PDF", + "audit": "Trilhas de Auditoria", + "selectFormat": "Selecionar formato" + }, + "downloadError": "Falha no download do arquivo. Tente novamente.", + "appsTitle": "Aumente a eficiência com nossos aplicativos", + "formsTitle": "Gere formulários com facilidade", + "docsTitle": "Gere documentos (faturas, relatórios, cotações)", + "tryNow": "Experimente agora", + "footerText": "Copyright 2026 Sign Made Easy. Todos os direitos reservados.<0>Política de Privacidade | <1>Política de Uso Razoável" + }, + "reassign": { + "title": "Reatribuir Signatário", + "successSubtitle": "Documento foi reatribuído com sucesso", + "successTitle": "Obrigado!", + "successMessage": "O documento foi reatribuído com sucesso ao novo signatário.", + "fields": { + "firstName": "Nome", + "lastName": "Sobrenome", + "email": "E-mail", + "language": "Idioma", + "message": "Mensagem Opcional" + }, + "placeholders": { + "firstName": "Digite seu nome", + "lastName": "Digite seu sobrenome", + "email": "your.email@example.com", + "message": "Escreva sua mensagem aqui..." + }, + "buttons": { + "submit": "Enviar", + "submitting": "Enviando...", + "cancel": "Cancelar" + }, + "errors": { + "firstNameRequired": "O nome é obrigatório", + "firstNameMin": "O nome deve ter pelo menos 2 caracteres", + "lastNameRequired": "O sobrenome é obrigatório", + "lastNameMin": "O sobrenome deve ter pelo menos 2 caracteres", + "emailRequired": "O e-mail é obrigatório", + "emailInvalid": "Endereço de e-mail inválido" + } + }, + "cancelModal": { + "title": "Cancelar Transação", + "description": "Tem certeza de que deseja cancelar esta transação? Forneça o motivo do cancelamento abaixo.", + "placeholder": "Forneça o motivo do cancelamento...", + "buttons": { + "no": "Não, não cancelar", + "yes": "Sim, cancelar" + }, + "errors": { + "reasonRequired": "O motivo do cancelamento é obrigatório" + }, + "inPersonSuccess": { + "title": "Cancelar Transação", + "message": "A transação foi cancelada com sucesso. E-mails de confirmação foram enviados.", + "passBackDevice": "Agora você pode devolver o dispositivo para {{senderName}}.", + "continueButton": "Continuar" + } + }, + "enTranslations": { + "app.name": "Sign Made Easy", + "app.subtitle": "Auditoria de Transação", + "meta.transaction_id": "ID da Transação", + "meta.transaction_status": "Status da Transação", + "meta.files": "Arquivos", + "audit.title": "Trilha de Auditoria Completa", + "audit.description": "Atualize o Assunto e a Mensagem abaixo para uma mensagem personalizada.", + "table.header.actions": "Ações", + "table.header.language": "Idioma", + "table.header.ip_address": "Endereço IP", + "table.header.date": "Data", + "status.completed": "Concluído", + "status.pending": "Pendente", + "status.failed": "Falhou", + "action.created": "Criado", + "action.updated": "Atualizado", + "action.deleted": "Excluído", + "action.viewed": "Visualizado", + "action.signed": "Assinado", + "action.uploaded": "Enviado", + "action.downloaded": "Baixado", + "placeholder.not_available": "—" + }, + "auditPage": { + "appName": "Sign Made Easy", + "subtitle": "Auditoria de Transação", + "meta": { + "transactionId": "ID da Transação", + "transactionStatus": "Status da Transação", + "files": "Arquivos" + }, + "audit": { + "title": "Trilha de Auditoria Completa", + "description": "Atualize o Assunto e a Mensagem abaixo para uma mensagem personalizada." + }, + "table": { + "actions": "Ações", + "language": "Idioma", + "ipAddress": "Endereço IP", + "date": "Data" + }, + "status": { + "completed": "Concluído", + "pending": "Pendente", + "failed": "Falhou" + }, + "fallback": { + "notAvailable": "—" + } + }, + "audit": { + "transaction": { + "created": "Transação foi criada por {{userName}} <{{userEmail}}>", + "sent": "Transação foi enviada por {{userName}} <{{userEmail}}>", + "cancelled": "Transação foi cancelada por {{userName}} <{{userEmail}}>", + "edited": "Transação foi editada por {{userName}} <{{userEmail}}>", + "viewed": "Transação foi visualizada por {{userName}} <{{userEmail}}>", + "signed": "Transação foi assinada por {{userName}} <{{userEmail}}>" + }, + "signature": { + "declined": "Assinatura da transação foi recusada por {{userName}} <{{userEmail}}>" + }, + "ers": { + "accepted": "Divulgação de Registro Eletrônico e Assinatura foi aceita por {{userName}} <{{userEmail}}>" + }, + "language": { + "updated": "{{userName}} <{{userEmail}}> atualizou seu idioma para {{language}}" + }, + "invitation": { + "sent": "E-mail de convite enviado para {{userName}} <{{userEmail}}>", + "view": "Convite para visualizar o documento enviado para {{userName}} <{{userEmail}}>", + "resent": "E-mail de convite reenviado para {{recipientName}} <{{recipientEmail}}> por {{senderName}} <{{senderEmail}}>" + }, + "reassigned": { + "to": "Signatário foi reatribuído por {{fromName}} <{{fromEmail}}> para {{toName}} <{{toEmail}}>", + "complex": "{{personName}} <{{personEmail}}> foi reatribuído por {{fromName}} <{{fromEmail}}> para {{toName}} <{{toEmail}}>" + }, + "inperson": { + "started": "Transação presencial foi iniciada por {{userName}} <{{userEmail}}>", + "verification": "Verificação de assinatura presencial foi aceita por {{userName}} <{{userEmail}}>" + }, + "facilitator": { + "accepted": "Processo do Facilitador foi aceito por {{userName}} <{{userEmail}}>" + } + }, + "signatureModal": { + "title": { + "signature": "Assinatura", + "initial": "Inicial", + "edit": "Editar", + "styleSelection": "Seleção de Estilo" + }, + "subtitle": "Crie suas assinaturas digitais", + "tabs": { + "select": "Selecionar", + "draw": "Desenhar", + "upload": "Enviar" + }, + "selectTab": { + "description": "Confirme seu nome e escolha um estilo de assinatura.", + "requiredFields": "Campos obrigatórios.", + "fullName": { + "label": "Nome Completo", + "required": "*", + "placeholder": "Digite o nome completo" + }, + "initials": { + "label": "Iniciais", + "required": "*", + "placeholder": "Digite as iniciais" + } + }, + "drawTab": { + "description": "Desenhe sua assinatura.", + "required": "*", + "requiredFields": "São campos obrigatórios.", + "signature": "Assinatura", + "initials": "Iniciais", + "clearSignature": "Limpar assinatura", + "fullNameBox": { + "label": "Assinatura completa", + "required": "*" + }, + "initialsBox": { + "label": "Iniciais", + "required": "*", + "placeholder": "Digite as iniciais" + } + }, + "uploadTab": { + "requiredMessage": "Tanto a assinatura quanto as iniciais são obrigatórias.", + "requirements": "Use imagens de 300×100px para assinaturas e 100×100px para iniciais. Máx. 300KB. Suportado: .png, .jpg.", + "signature": { + "uploadLabel": "Enviar Assinatura", + "uploadHint": "JPG, PNG (300×100px, máx. 300KB)", + "browseButton": "Procurar", + "uploadedLabel": "Assinatura ✓", + "changeButton": "Alterar Assinatura", + "altText": "Imagem de assinatura enviada" + }, + "initials": { + "uploadLabel": "Enviar Iniciais", + "uploadHint": "JPG, PNG (100×100px, máx. 300KB)", + "browseButton": "Procurar", + "uploadedLabel": "Iniciais ✓", + "changeButton": "Alterar Iniciais", + "altText": "Imagem de iniciais enviada" + } + }, + "footer": { + "agreementText": "Entendo que estou assinando este documento.", + "cancelButton": "Cancelar", + "adoptButton": "Adotar Assinatura e Assinar" + }, + "errors": { + "requiredField": "Este campo é obrigatório", + "fileTooLarge": "O tamanho do arquivo deve ser inferior a 300KB", + "invalidFileType": "Apenas arquivos .png, .jpg e .jpeg são suportados", + "signatureRequired": "Por favor, adicione uma assinatura", + "initialsRequired": "Por favor, adicione iniciais" + } + }, + "stampModal": { + "title": { + "add": "Adicionar Carimbo", + "edit": "Editar Carimbo" + }, + "closeButton": "Fechar modal", + "fileRequirements": "Tamanho máximo = 400Kb | Tipos de arquivo suportados = .png, .jpg, .jpeg", + "dragDropLabel": "Arraste e solte uma imagem, ou clique para enviar", + "previewAltText": "Prévia do Carimbo", + "changeImageButton": "Alterar imagem", + "clearButton": "Fechar", + "saveButton": "Salvar", + "updateButton": "Atualizar", + "errors": { + "fileTooLarge": "O tamanho do arquivo excede o limite de 400KB", + "invalidFileType": "Apenas arquivos .png, .jpg e .jpeg são suportados", + "uploadFailed": "Falha ao enviar a imagem. Por favor, tente novamente." + } + }, + "attachmentModal": { + "title": "Anexo", + "subtitle": { + "hasFile": "Gerenciar seu anexo", + "noFile": "Enviar anexo" + }, + "uploading": { + "status": "Enviando arquivo...", + "shimmerText": "Enviando arquivo..." + }, + "uploadArea": { + "dragging": "Solte seu arquivo aqui", + "default": "Enviar ou arrastar e soltar arquivo", + "fileTypes": "PDF, DOCX, JPG, PNG, TXT (máx. 10MB)", + "browseButton": "Procurar Arquivos" + }, + "uploadedFile": { + "status": "Enviado com sucesso", + "deleteButton": "Excluir arquivo" + }, + "buttons": { + "close": "Fechar", + "uploading": "Enviando...", + "deleting": "Excluindo...", + "saved": "Arquivo Salvo!", + "done": "Concluído", + "uploadFile": "Enviar Arquivo" + }, + "errors": { + "fileTooLarge": "O tamanho do arquivo excede o limite de 10MB", + "invalidFileType": "Apenas arquivos PDF, DOCX, JPG, PNG e TXT são suportados", + "uploadFailed": "Falha ao enviar o arquivo. Por favor, tente novamente.", + "deleteFailed": "Falha ao excluir o arquivo. Por favor, tente novamente.", + "noFileSelected": "Por favor, selecione um arquivo antes de prosseguir" + }, + "accessibility": { + "fileUpload": "Envio de arquivo", + "deleteFile": "Excluir arquivo" + } + }, + "languages": { + "zh_CN": "Chinês (Simplificado)", + "zh_TW": "Chinês (Tradicional)", + "da": "Dinamarquês", + "nl_NL": "Holandês", + "en": "Inglês", + "fi": "Finlandês", + "fr": "Francês", + "de": "Alemão", + "it": "Italiano", + "ja": "Japonês", + "ko": "Coreano", + "no": "Norueguês", + "pt_BR": "Português (Brasil)", + "ru": "Russo", + "es": "Espanhol", + "es_MX": "Espanhol (México)", + "sv": "Sueco", + "th": "Tailandês", + "he": "Hebraico" + }, + "session-expired": { + "title": "Sessão expirada", + "description": "Este link de assinatura de documento expirou devido à inatividade ou tempo limite da sessão. Por favor, volte ao seu e-mail e clique no link novamente para continuar assinando." + }, + "inPersonComplete": { + "title": "🎉 Assinatura concluída!", + "subtitle": "Documento foi assinado com sucesso", + "thankYou": "Obrigado por assinar!", + "message": "Você receberá um e-mail de confirmação assim que o documento for assinado por todas as partes.", + "passDevice": "Agora você pode devolver o dispositivo para {{senderName}}", + "continueButton": "Continuar" + } +} \ No newline at end of file diff --git a/public/locales/ru/translation.json b/public/locales/ru/translation.json new file mode 100644 index 0000000..3dd896a --- /dev/null +++ b/public/locales/ru/translation.json @@ -0,0 +1,380 @@ +{ + "terms": { + "agreementText": "Нажимая <0>Я соглашаюсь, вы подтверждаете, что ознакомились с <1>Раскрытием информации об электронных записях и подписях и соглашаетесь на использование электронных записей и подписей при просмотре и подписании этого документа.", + "note": "Примечание:", + "noteText": "Согласие с этим не означает, что вы немедленно подписываете документ. Это позволяет вам только просмотреть его в электронном виде. У вас будет возможность полностью ознакомиться с документом перед подписанием." + }, + "buttons": { + "agree": "Я соглашаюсь", + "processing": "Обработка...", + "close": "Закрыть", + "downloadPdf": "Скачать PDF", + "downloading": "Загрузка..." + }, + "header": { + "aiSummary": "Резюме ИИ", + "completeSign": "Завершить подписание", + "sign": "Подписать", + "processing": "Обработка...", + "options": "Скачать" + }, + "menu": { + "downloadPdf": "Скачать PDF", + "auditTrail": "Журнал аудита", + "reassignSigner": "Переназначить подписанта", + "cancelTransaction": "Отменить транзакцию", + "viewTerms": "Просмотреть условия", + "helpSupport": "Помощь и поддержка", + "about": "О SME" + }, + "sidebar": { + "documents": "Документы", + "pages": "Страниц: {{count}}", + "noDocuments": "Нет доступных документов." + }, + "footer": { + "readyTitle": "Готовы завершить?", + "readyDesc": "Вы заполнили обязательные поля. Проверьте свою работу и выберите Завершить.", + "finish": "Завершить", + "submitting": "Отправка...", + "start": "Начать", + "next": "Далее", + "agreementText": "Подписывая, я соглашаюсь с <0>Условиями Sign Made Easy." + }, + "completion": { + "complete": { + "hit": "Готово!", + "title": "Спасибо за подписание", + "message": "Ваш документ теперь завершен и надежно сохранен. Мы отправили вам копию по электронной почте." + }, + "declined": { + "hit": "Действие отменено!", + "title": "Может быть, в следующий раз!", + "message": "Ваш запрос был отклонен." + }, + "cancelled": { + "hit": "Действие отменено!", + "title": "Может быть, в следующий раз!", + "message": "Ваш запрос был отменен." + }, + "download": "Скачать", + "downloading": "Загрузка...", + "downloadSuccess": "Файл успешно загружен.", + "downloadOptions": { + "pdf": "PDF документ", + "audit": "Журналы аудита", + "selectFormat": "Выбрать формат" + }, + "downloadError": "Не удалось загрузить файл. Пожалуйста, попробуйте снова.", + "appsTitle": "Повысьте эффективность с нашими приложениями", + "formsTitle": "Легко создавайте формы", + "docsTitle": "Создавайте документы (счета, отчеты, предложения)", + "tryNow": "Попробовать сейчас", + "footerText": "Авторские права 2026 Sign Made Easy. Все права защищены.<0>Политика конфиденциальности | <1>Политика добросовестного использования" + }, + "reassign": { + "title": "Переназначить подписанта", + "successSubtitle": "Документ успешно переназначен", + "successTitle": "Спасибо!", + "successMessage": "Документ успешно переназначен новому подписанту.", + "fields": { + "firstName": "Имя", + "lastName": "Фамилия", + "email": "Электронная почта", + "language": "Язык", + "message": "Дополнительное сообщение" + }, + "placeholders": { + "firstName": "Введите ваше имя", + "lastName": "Введите вашу фамилию", + "email": "your.email@example.com", + "message": "Напишите ваше сообщение здесь..." + }, + "buttons": { + "submit": "Отправить", + "submitting": "Отправка...", + "cancel": "Отмена" + }, + "errors": { + "firstNameRequired": "Имя обязательно", + "firstNameMin": "Имя должно содержать не менее 2 символов", + "lastNameRequired": "Фамилия обязательна", + "lastNameMin": "Фамилия должна содержать не менее 2 символов", + "emailRequired": "Электронная почта обязательна", + "emailInvalid": "Неверный адрес электронной почты" + } + }, + "cancelModal": { + "title": "Отменить транзакцию", + "description": "Вы уверены, что хотите отменить эту транзакцию? Укажите причину отмены ниже.", + "placeholder": "Пожалуйста, укажите причину отмены...", + "buttons": { + "no": "Нет, не отменять", + "yes": "Да, отменить" + }, + "errors": { + "reasonRequired": "Необходимо указать причину отмены" + }, + "inPersonSuccess": { + "title": "Отменить транзакцию", + "message": "Транзакция успешно отменена. Письма с подтверждением отправлены.", + "passBackDevice": "Теперь вы можете вернуть устройство {{senderName}}.", + "continueButton": "Продолжить" + } + }, + "enTranslations": { + "app.name": "Sign Made Easy", + "app.subtitle": "Аудит транзакций", + "meta.transaction_id": "ID транзакции", + "meta.transaction_status": "Статус транзакции", + "meta.files": "Файлы", + "audit.title": "Полный журнал аудита", + "audit.description": "Обновите тему и сообщение ниже для настраиваемого сообщения.", + "table.header.actions": "Действия", + "table.header.language": "Язык", + "table.header.ip_address": "IP-адрес", + "table.header.date": "Дата", + "status.completed": "Завершено", + "status.pending": "Ожидает", + "status.failed": "Ошибка", + "action.created": "Создано", + "action.updated": "Обновлено", + "action.deleted": "Удалено", + "action.viewed": "Просмотрено", + "action.signed": "Подписано", + "action.uploaded": "Загружено", + "action.downloaded": "Скачано", + "placeholder.not_available": "—" + }, + "auditPage": { + "appName": "Sign Made Easy", + "subtitle": "Аудит транзакций", + "meta": { + "transactionId": "ID транзакции", + "transactionStatus": "Статус транзакции", + "files": "Файлы" + }, + "audit": { + "title": "Полный журнал аудита", + "description": "Обновите тему и сообщение ниже для настраиваемого сообщения." + }, + "table": { + "actions": "Действия", + "language": "Язык", + "ipAddress": "IP-адрес", + "date": "Дата" + }, + "status": { + "completed": "Завершено", + "pending": "Ожидает", + "failed": "Ошибка" + }, + "fallback": { + "notAvailable": "—" + } + }, + "audit": { + "transaction": { + "created": "Транзакция создана {{userName}} <{{userEmail}}>", + "sent": "Транзакция отправлена {{userName}} <{{userEmail}}>", + "cancelled": "Транзакция отменена {{userName}} <{{userEmail}}>", + "edited": "Транзакция отредактирована {{userName}} <{{userEmail}}>", + "viewed": "Транзакция просмотрена {{userName}} <{{userEmail}}>", + "signed": "Транзакция подписана {{userName}} <{{userEmail}}>" + }, + "signature": { + "declined": "Подпись транзакции отклонена {{userName}} <{{userEmail}}>" + }, + "ers": { + "accepted": "Раскрытие электронной записи и подписи принято {{userName}} <{{userEmail}}>" + }, + "language": { + "updated": "{{userName}} <{{userEmail}}> обновил язык на {{language}}" + }, + "invitation": { + "sent": "Приглашение по электронной почте отправлено {{userName}} <{{userEmail}}>", + "view": "Приглашение просмотреть документ отправлено {{userName}} <{{userEmail}}>", + "resent": "Приглашение по электронной почте повторно отправлено {{recipientName}} <{{recipientEmail}}> от {{senderName}} <{{senderEmail}}>" + }, + "reassigned": { + "to": "Подписывающий переназначен {{fromName}} <{{fromEmail}}> на {{toName}} <{{toEmail}}>", + "complex": "{{personName}} <{{personEmail}}> был переназначен {{fromName}} <{{fromEmail}}> на {{toName}} <{{toEmail}}>" + }, + "inperson": { + "started": "Личная транзакция начата {{userName}} <{{userEmail}}>", + "verification": "Проверка личной подписи принята {{userName}} <{{userEmail}}>" + }, + "facilitator": { + "accepted": "Процесс фасилитатора принят {{userName}} <{{userEmail}}>" + } + }, + "signatureModal": { + "title": { + "signature": "Подпись", + "initial": "Инициалы", + "edit": "Редактировать", + "styleSelection": "Выбор стиля" + }, + "subtitle": "Создайте свои цифровые подписи", + "tabs": { + "select": "Выбрать", + "draw": "Рисовать", + "upload": "Загрузить" + }, + "selectTab": { + "description": "Подтвердите свое имя и выберите стиль подписи.", + "requiredFields": "Обязательные поля.", + "fullName": { + "label": "Полное имя", + "required": "*", + "placeholder": "Введите полное имя" + }, + "initials": { + "label": "Инициалы", + "required": "*", + "placeholder": "Введите инициалы" + } + }, + "drawTab": { + "description": "Нарисуйте свою подпись.", + "required": "*", + "requiredFields": "Являются обязательными полями.", + "signature": "Подпись", + "initials": "Инициалы", + "clearSignature": "Очистить подпись", + "fullNameBox": { + "label": "Полная подпись", + "required": "*" + }, + "initialsBox": { + "label": "Инициалы", + "required": "*", + "placeholder": "Введите инициалы" + } + }, + "uploadTab": { + "requiredMessage": "Требуются как подпись, так и инициалы.", + "requirements": "Используйте изображения 300×100px для подписей и 100×100px для инициалов. Макс. 300KB. Поддерживается: .png, .jpg.", + "signature": { + "uploadLabel": "Загрузить подпись", + "uploadHint": "JPG, PNG (300×100px, макс. 300KB)", + "browseButton": "Обзор", + "uploadedLabel": "Подпись ✓", + "changeButton": "Изменить подпись", + "altText": "Загруженное изображение подписи" + }, + "initials": { + "uploadLabel": "Загрузить инициалы", + "uploadHint": "JPG, PNG (100×100px, макс. 300KB)", + "browseButton": "Обзор", + "uploadedLabel": "Инициалы ✓", + "changeButton": "Изменить инициалы", + "altText": "Загруженное изображение инициалов" + } + }, + "footer": { + "agreementText": "Я понимаю, что подписываю этот документ.", + "cancelButton": "Отмена", + "adoptButton": "Принять подпись и подписать" + }, + "errors": { + "requiredField": "Это поле обязательно", + "fileTooLarge": "Размер файла должен быть менее 300KB", + "invalidFileType": "Поддерживаются только файлы .png, .jpg и .jpeg", + "signatureRequired": "Пожалуйста, добавьте подпись", + "initialsRequired": "Пожалуйста, добавьте инициалы" + } + }, + "stampModal": { + "title": { + "add": "Добавить штамп", + "edit": "Редактировать штамп" + }, + "closeButton": "Закрыть модальное окно", + "fileRequirements": "Максимальный размер = 400Kb | Поддерживаемые типы файлов = .png, .jpg, .jpeg", + "dragDropLabel": "Перетащите изображение или нажмите для загрузки", + "previewAltText": "Предпросмотр штампа", + "changeImageButton": "Изменить изображение", + "clearButton": "Закрыть", + "saveButton": "Сохранить", + "updateButton": "Обновить", + "errors": { + "fileTooLarge": "Размер файла превышает лимит 400KB", + "invalidFileType": "Поддерживаются только файлы .png, .jpg и .jpeg", + "uploadFailed": "Не удалось загрузить изображение. Пожалуйста, попробуйте снова." + } + }, + "attachmentModal": { + "title": "Вложение", + "subtitle": { + "hasFile": "Управление вложением", + "noFile": "Загрузить вложение" + }, + "uploading": { + "status": "Загрузка файла...", + "shimmerText": "Загрузка файла..." + }, + "uploadArea": { + "dragging": "Перетащите файл сюда", + "default": "Загрузить или перетащить файл", + "fileTypes": "PDF, DOCX, JPG, PNG, TXT (макс. 10MB)", + "browseButton": "Обзор файлов" + }, + "uploadedFile": { + "status": "Загружено успешно", + "deleteButton": "Удалить файл" + }, + "buttons": { + "close": "Закрыть", + "uploading": "Загрузка...", + "deleting": "Удаление...", + "saved": "Файл сохранен!", + "done": "Готово", + "uploadFile": "Загрузить файл" + }, + "errors": { + "fileTooLarge": "Размер файла превышает лимит 10MB", + "invalidFileType": "Поддерживаются только файлы PDF, DOCX, JPG, PNG и TXT", + "uploadFailed": "Не удалось загрузить файл. Пожалуйста, попробуйте снова.", + "deleteFailed": "Не удалось удалить файл. Пожалуйста, попробуйте снова.", + "noFileSelected": "Пожалуйста, выберите файл перед продолжением" + }, + "accessibility": { + "fileUpload": "Загрузка файла", + "deleteFile": "Удалить файл" + } + }, + "languages": { + "zh_CN": "Китайский (упрощенный)", + "zh_TW": "Китайский (традиционный)", + "da": "Датский", + "nl_NL": "Голландский", + "en": "Английский", + "fi": "Финский", + "fr": "Французский", + "de": "Немецкий", + "it": "Итальянский", + "ja": "Японский", + "ko": "Корейский", + "no": "Норвежский", + "pt_BR": "Португальский (Бразилия)", + "ru": "Русский", + "es": "Испанский", + "es_MX": "Испанский (Мексика)", + "sv": "Шведский", + "th": "Тайский", + "he": "Иврит" + }, + "session-expired": { + "title": "Сессия истекла", + "description": "Срок действия ссылки для подписания документа истек из-за бездействия или тайм-аута сеанса. Пожалуйста, вернитесь к своему электронному письму и нажмите на ссылку еще раз, чтобы продолжить подписание." + }, + "inPersonComplete": { + "title": "🎉 Подписание завершено!", + "subtitle": "Документ успешно подписан", + "thankYou": "Спасибо за подписание!", + "message": "Вы получите подтверждение по электронной почте, когда документ будет подписан всеми сторонами.", + "passDevice": "Теперь вы можете передать устройство обратно {{senderName}}", + "continueButton": "Продолжить" + } +} \ No newline at end of file diff --git a/public/locales/sv/translation.json b/public/locales/sv/translation.json new file mode 100644 index 0000000..2ce82c4 --- /dev/null +++ b/public/locales/sv/translation.json @@ -0,0 +1,380 @@ +{ + "terms": { + "agreementText": "Genom att klicka på <0>Jag godkänner bekräftar du att du har granskat <1>Information om elektroniska register och signaturer och samtycker till användningen av elektroniska register och signaturer vid granskning och utförande av detta dokument.", + "note": "Observera:", + "noteText": "Att godkänna detta innebär inte att du omedelbart undertecknar dokumentet. Det tillåter dig bara att granska det elektroniskt. Du kommer att ha möjlighet att granska dokumentet fullständigt innan du undertecknar." + }, + "buttons": { + "agree": "Jag godkänner", + "processing": "Bearbetar...", + "close": "Stäng", + "downloadPdf": "Ladda ner PDF", + "downloading": "Laddar ner..." + }, + "header": { + "aiSummary": "AI-sammanfattning", + "completeSign": "Slutför signering", + "sign": "Signera", + "processing": "Bearbetar...", + "options": "Ladda ner" + }, + "menu": { + "downloadPdf": "Ladda ner PDF", + "auditTrail": "Revisionsspår", + "reassignSigner": "Omfördelad undertecknare", + "cancelTransaction": "Avbryt transaktion", + "viewTerms": "Visa villkor", + "helpSupport": "Hjälp och support", + "about": "Om SME" + }, + "sidebar": { + "documents": "Dokument", + "pages": "Sidor: {{count}}", + "noDocuments": "Inga dokument tillgängliga." + }, + "footer": { + "readyTitle": "Redo att avsluta?", + "readyDesc": "Du har fyllt i de obligatoriska fälten. Granska ditt arbete och välj sedan Slutför.", + "finish": "Slutför", + "submitting": "Skickar...", + "start": "Starta", + "next": "Nästa", + "agreementText": "Genom att underteckna godkänner jag Sign Made Easy's <0>villkor." + }, + "completion": { + "complete": { + "hit": "Helt klart!", + "title": "Tack för din underskrift", + "message": "Ditt dokument är nu slutfört och säkert lagrat. Vi har skickat en kopia till dig via e-post." + }, + "declined": { + "hit": "Åtgärd avbruten!", + "title": "Kanske nästa gång!", + "message": "Din begäran har avvisats." + }, + "cancelled": { + "hit": "Åtgärd avbruten!", + "title": "Kanske nästa gång!", + "message": "Din begäran har avbrutits." + }, + "download": "Ladda ner", + "downloading": "Laddar ner...", + "downloadSuccess": "Fil nedladdad.", + "downloadOptions": { + "pdf": "PDF-dokument", + "audit": "Revisionsspår", + "selectFormat": "Välj format" + }, + "downloadError": "Nedladdning misslyckades. Försök igen.", + "appsTitle": "Öka effektiviteten med våra appar", + "formsTitle": "Skapa formulär enkelt", + "docsTitle": "Skapa dokument (fakturor, rapporter, offerter)", + "tryNow": "Prova nu", + "footerText": "Upphovsrätt 2026 Sign Made Easy. Alla rättigheter förbehållna.<0>Sekretesspolicy | <1>Policy för rimlig användning" + }, + "reassign": { + "title": "Omfördelad undertecknare", + "successSubtitle": "Dokumentet har omfördelats", + "successTitle": "Tack!", + "successMessage": "Dokumentet har omfördelats till den nya undertecknaren.", + "fields": { + "firstName": "Förnamn", + "lastName": "Efternamn", + "email": "E-post", + "language": "Språk", + "message": "Valfritt meddelande" + }, + "placeholders": { + "firstName": "Ange ditt förnamn", + "lastName": "Ange ditt efternamn", + "email": "your.email@example.com", + "message": "Skriv ditt meddelande här..." + }, + "buttons": { + "submit": "Skicka", + "submitting": "Skickar...", + "cancel": "Avbryt" + }, + "errors": { + "firstNameRequired": "Förnamn krävs", + "firstNameMin": "Förnamn måste vara minst 2 tecken", + "lastNameRequired": "Efternamn krävs", + "lastNameMin": "Efternamn måste vara minst 2 tecken", + "emailRequired": "E-post krävs", + "emailInvalid": "Ogiltig e-postadress" + } + }, + "cancelModal": { + "title": "Avbryt transaktion", + "description": "Är du säker på att du vill avbryta denna transaktion? Ange din anledning till avbokning nedan.", + "placeholder": "Vänligen ange din anledning till avbokning...", + "buttons": { + "no": "Nej, avbryt inte", + "yes": "Ja, avbryt den" + }, + "errors": { + "reasonRequired": "Avbokningsorsak krävs" + }, + "inPersonSuccess": { + "title": "Avbryt transaktion", + "message": "Transaktionen avbröts. Bekräftelsemeddelanden skickades.", + "passBackDevice": "Du kan nu lämna tillbaka enheten till {{senderName}}.", + "continueButton": "Fortsätt" + } + }, + "enTranslations": { + "app.name": "Sign Made Easy", + "app.subtitle": "Transaktionsrevision", + "meta.transaction_id": "Transaktions-ID", + "meta.transaction_status": "Transaktionsstatus", + "meta.files": "Filer", + "audit.title": "Fullt revisionsspår", + "audit.description": "Uppdatera ämne och meddelande nedan för ett anpassat meddelande.", + "table.header.actions": "Åtgärder", + "table.header.language": "Språk", + "table.header.ip_address": "IP-adress", + "table.header.date": "Datum", + "status.completed": "Slutförd", + "status.pending": "Väntande", + "status.failed": "Misslyckades", + "action.created": "Skapad", + "action.updated": "Uppdaterad", + "action.deleted": "Raderad", + "action.viewed": "Visad", + "action.signed": "Signerad", + "action.uploaded": "Uppladdad", + "action.downloaded": "Nerladdad", + "placeholder.not_available": "—" + }, + "auditPage": { + "appName": "Sign Made Easy", + "subtitle": "Transaktionsrevision", + "meta": { + "transactionId": "Transaktions-ID", + "transactionStatus": "Transaktionsstatus", + "files": "Filer" + }, + "audit": { + "title": "Fullt revisionsspår", + "description": "Uppdatera ämne och meddelande nedan för ett anpassat meddelande." + }, + "table": { + "actions": "Åtgärder", + "language": "Språk", + "ipAddress": "IP-adress", + "date": "Datum" + }, + "status": { + "completed": "Slutförd", + "pending": "Väntande", + "failed": "Misslyckades" + }, + "fallback": { + "notAvailable": "—" + } + }, + "audit": { + "transaction": { + "created": "Transaktion skapades av {{userName}} <{{userEmail}}>", + "sent": "Transaktion skickades av {{userName}} <{{userEmail}}>", + "cancelled": "Transaktion avbröts av {{userName}} <{{userEmail}}>", + "edited": "Transaktion redigerades av {{userName}} <{{userEmail}}>", + "viewed": "Transaktion visades av {{userName}} <{{userEmail}}>", + "signed": "Transaktion signerades av {{userName}} <{{userEmail}}>" + }, + "signature": { + "declined": "Transaktionssignatur avvisades av {{userName}} <{{userEmail}}>" + }, + "ers": { + "accepted": "Elektronisk registrering och signaturavsöjning accepterades av {{userName}} <{{userEmail}}>" + }, + "language": { + "updated": "{{userName}} <{{userEmail}}> uppdaterade sitt språk till {{language}}" + }, + "invitation": { + "sent": "Inbjudningsmejl skickat till {{userName}} <{{userEmail}}>", + "view": "Inbjudan att visa dokumentet har skickats till {{userName}} <{{userEmail}}>", + "resent": "Inbjudningsmejl skickades igen till {{recipientName}} <{{recipientEmail}}> av {{senderName}} <{{senderEmail}}>" + }, + "reassigned": { + "to": "Undertecknare omtilldelades av {{fromName}} <{{fromEmail}}> till {{toName}} <{{toEmail}}>", + "complex": "{{personName}} <{{personEmail}}> omtilldelades av {{fromName}} <{{fromEmail}}> till {{toName}} <{{toEmail}}>" + }, + "inperson": { + "started": "Personlig transaktion startades av {{userName}} <{{userEmail}}>", + "verification": "Personlig signaturverifiering accepterades av {{userName}} <{{userEmail}}>" + }, + "facilitator": { + "accepted": "Facilitatorprocess accepterades av {{userName}} <{{userEmail}}>" + } + }, + "signatureModal": { + "title": { + "signature": "Signatur", + "initial": "Initialer", + "edit": "Redigera", + "styleSelection": "Stilval" + }, + "subtitle": "Skapa dina digitala signaturer", + "tabs": { + "select": "Välj", + "draw": "Rita", + "upload": "Ladda upp" + }, + "selectTab": { + "description": "Bekräfta ditt namn och välj en signaturstil.", + "requiredFields": "Obligatoriska fält.", + "fullName": { + "label": "Fullständigt namn", + "required": "*", + "placeholder": "Ange fullständigt namn" + }, + "initials": { + "label": "Initialer", + "required": "*", + "placeholder": "Ange initialer" + } + }, + "drawTab": { + "description": "Rita din signatur.", + "required": "*", + "requiredFields": "Är obligatoriska fält.", + "signature": "Signatur", + "initials": "Initialer", + "clearSignature": "Rensa signatur", + "fullNameBox": { + "label": "Fullständig signatur", + "required": "*" + }, + "initialsBox": { + "label": "Initialer", + "required": "*", + "placeholder": "Ange initialer" + } + }, + "uploadTab": { + "requiredMessage": "Både signatur och initialer krävs.", + "requirements": "Använd bilder på 300×100px för signaturer och 100×100px för initialer. Max 300KB. Stödjer: .png, .jpg.", + "signature": { + "uploadLabel": "Ladda upp signatur", + "uploadHint": "JPG, PNG (300×100px, max 300KB)", + "browseButton": "Bläddra", + "uploadedLabel": "Signatur ✓", + "changeButton": "Ändra signatur", + "altText": "Uppladdad signaturbild" + }, + "initials": { + "uploadLabel": "Ladda upp initialer", + "uploadHint": "JPG, PNG (100×100px, max 300KB)", + "browseButton": "Bläddra", + "uploadedLabel": "Initialer ✓", + "changeButton": "Ändra initialer", + "altText": "Uppladdad initialbild" + } + }, + "footer": { + "agreementText": "Jag förstår att jag signerar detta dokument.", + "cancelButton": "Avbryt", + "adoptButton": "Adoptera signatur och signera" + }, + "errors": { + "requiredField": "Detta fält är obligatoriskt", + "fileTooLarge": "Filstorleken måste vara under 300KB", + "invalidFileType": "Endast .png, .jpg och .jpeg filer stöds", + "signatureRequired": "Lägg till en signatur", + "initialsRequired": "Lägg till initialer" + } + }, + "stampModal": { + "title": { + "add": "Lägg till stämpel", + "edit": "Redigera stämpel" + }, + "closeButton": "Stäng modal", + "fileRequirements": "Maximal storlek = 400Kb | Filtyper som stöds = .png, .jpg, .jpeg", + "dragDropLabel": "Dra och släpp en bild, eller klicka för att ladda upp", + "previewAltText": "Förhandsgranskning av stämpel", + "changeImageButton": "Ändra bild", + "clearButton": "Stäng", + "saveButton": "Spara", + "updateButton": "Uppdatera", + "errors": { + "fileTooLarge": "Filstorleken överstiger gränsen på 400KB", + "invalidFileType": "Endast .png, .jpg och .jpeg filer stöds", + "uploadFailed": "Misslyckades att ladda upp bilden. Försök igen." + } + }, + "attachmentModal": { + "title": "Bilaga", + "subtitle": { + "hasFile": "Hantera din bilaga", + "noFile": "Ladda upp bilaga" + }, + "uploading": { + "status": "Laddar upp fil...", + "shimmerText": "Laddar upp fil..." + }, + "uploadArea": { + "dragging": "Släpp din fil här", + "default": "Ladda upp eller dra och släpp fil", + "fileTypes": "PDF, DOCX, JPG, PNG, TXT (max 10MB)", + "browseButton": "Bläddra bland filer" + }, + "uploadedFile": { + "status": "Uppladdad framgångsrikt", + "deleteButton": "Ta bort fil" + }, + "buttons": { + "close": "Stäng", + "uploading": "Laddar upp...", + "deleting": "Tar bort...", + "saved": "Fil sparad!", + "done": "Klart", + "uploadFile": "Ladda upp fil" + }, + "errors": { + "fileTooLarge": "Filstorleken överstiger gränsen på 10MB", + "invalidFileType": "Endast PDF, DOCX, JPG, PNG och TXT filer stöds", + "uploadFailed": "Misslyckades att ladda upp filen. Försök igen.", + "deleteFailed": "Misslyckades att ta bort filen. Försök igen.", + "noFileSelected": "Välj en fil innan du fortsätter" + }, + "accessibility": { + "fileUpload": "Filuppladdning", + "deleteFile": "Ta bort fil" + } + }, + "languages": { + "zh_CN": "Kinesiska (Förenklad)", + "zh_TW": "Kinesiska (Traditionell)", + "da": "Danska", + "nl_NL": "Holländska", + "en": "Engelska", + "fi": "Finska", + "fr": "Franska", + "de": "Tyska", + "it": "Italienska", + "ja": "Japanska", + "ko": "Koreanska", + "no": "Norska", + "pt_BR": "Portugisiska (Brasilien)", + "ru": "Ryska", + "es": "Spanska", + "es_MX": "Spanska (Mexiko)", + "sv": "Svenska", + "th": "Thai", + "he": "Hebreiska" + }, + "session-expired": { + "title": "Sessionen har upphört", + "description": "Denna dokumentunderskriftslänk har upphört på grund av inaktivitet eller tidsgräns för sessionen. Gå tillbaka till din e-post och klicka på länken igen för att fortsätta skriva under." + }, + "inPersonComplete": { + "title": "🎉 Signering slutförd!", + "subtitle": "Dokumentet har signerats", + "thankYou": "Tack för din underskrift!", + "message": "Du kommer att få ett bekräftelsemail när dokumentet har signerats av alla parter.", + "passDevice": "Du kan nu lämna tillbaka enheten till {{senderName}}", + "continueButton": "Fortsätt" + } +} \ No newline at end of file diff --git a/public/locales/th/translation.json b/public/locales/th/translation.json new file mode 100644 index 0000000..75131c7 --- /dev/null +++ b/public/locales/th/translation.json @@ -0,0 +1,380 @@ +{ + "terms": { + "agreementText": "การคลิก <0>ฉันยอมรับ แสดงว่าคุณยืนยันว่าได้ตรวจสอบ <1>การเปิดเผยบันทึกอิเล็กทรอนิกส์และลายมือชื่อ แล้ว และยินยอมให้ใช้บันทึกอิเล็กทรอนิกส์และลายมือชื่อในการตรวจสอบและดำเนินการตามเอกสารนี้", + "note": "หมายเหตุ:", + "noteText": "การยอมรับนี้ไม่ได้หมายความว่าคุณกำลังลงนามในเอกสารทันที เป็นเพียงการอนุญาตให้คุณตรวจสอบด้วยวิธีอิเล็กทรอนิกส์เท่านั้น คุณจะมีโอกาสตรวจสอบเอกสารทั้งหมดก่อนลงนาม" + }, + "buttons": { + "agree": "ฉันยอมรับ", + "processing": "กำลังดำเนินการ...", + "close": "ปิด", + "downloadPdf": "ดาวน์โหลด PDF", + "downloading": "กำลังดาวน์โหลด..." + }, + "header": { + "aiSummary": "สรุปผลจาก AI", + "completeSign": "ลงนามเสร็จสมบูรณ์", + "sign": "ลงนาม", + "processing": "กำลังดำเนินการ...", + "options": "ดาวน์โหลด" + }, + "menu": { + "downloadPdf": "ดาวน์โหลด PDF", + "auditTrail": "เส้นทางการตรวจสอบ", + "reassignSigner": "กำหนดผู้ลงนามใหม่", + "cancelTransaction": "ยกเลิกรายการ", + "viewTerms": "ดูข้อกำหนดและเงื่อนไข", + "helpSupport": "ความช่วยเหลือและการสนับสนุน", + "about": "เกี่ยวกับ SME" + }, + "sidebar": { + "documents": "เอกสาร", + "pages": "หน้า: {{count}}", + "noDocuments": "ไม่มีเอกสาร" + }, + "footer": { + "readyTitle": "พร้อมที่จะเสร็จสิ้นหรือยัง?", + "readyDesc": "คุณกรอกข้อมูลในช่องที่จำเป็นเรียบร้อยแล้ว ตรวจสอบงานของคุณ จากนั้นเลือกเสร็จสิ้น", + "finish": "เสร็จสิ้น", + "submitting": "กำลังส่ง...", + "start": "เริ่มต้น", + "next": "ถัดไป", + "agreementText": "การลงนามแสดงว่าฉันยอมรับ <0>ข้อกำหนดและเงื่อนไข ของ Sign Made Easy" + }, + "completion": { + "complete": { + "hit": "เสร็จเรียบร้อย!", + "title": "ขอบคุณที่ลงนาม", + "message": "เอกสารของคุณเสร็จสมบูรณ์และถูกจัดเก็บอย่างปลอดภัยแล้ว เราได้ส่งสำเนาทางอีเมลถึงคุณแล้ว" + }, + "declined": { + "hit": "ยกเลิกการดำเนินการ!", + "title": "โอกาสหน้า!", + "message": "คำขอของคุณถูกปฏิเสธเรียบร้อยแล้ว" + }, + "cancelled": { + "hit": "ยกเลิกการดำเนินการ!", + "title": "โอกาสหน้า!", + "message": "คำขอของคุณถูกยกเลิกเรียบร้อยแล้ว" + }, + "download": "ดาวน์โหลด", + "downloading": "กำลังดาวน์โหลด...", + "downloadSuccess": "ดาวน์โหลดไฟล์สำเร็จ", + "downloadOptions": { + "pdf": "เอกสาร PDF", + "audit": "เส้นทางการตรวจสอบ", + "selectFormat": "เลือกรูปแบบ" + }, + "downloadError": "การดาวน์โหลดไฟล์ล้มเหลว กรุณาลองอีกครั้ง", + "appsTitle": "เพิ่มประสิทธิภาพด้วยแอปของเรา", + "formsTitle": "สร้างแบบฟอร์มได้อย่างง่ายดาย", + "docsTitle": "สร้างเอกสาร (ใบแจ้งหนี้ รายงาน ใบเสนอราคา)", + "tryNow": "ลองใช้เลย", + "footerText": "ลิขสิทธิ์ 2026 Sign Made Easy สงวนลิขสิทธิ์ <0>นโยบายความเป็นส่วนตัว | <1>นโยบายการใช้งานที่เหมาะสม" + }, + "reassign": { + "title": "กำหนดผู้ลงนามใหม่", + "successSubtitle": "เอกสารถูกกำหนดใหม่เรียบร้อยแล้ว", + "successTitle": "ขอบคุณ!", + "successMessage": "เอกสารถูกกำหนดให้กับผู้ลงนามใหม่เรียบร้อยแล้ว", + "fields": { + "firstName": "ชื่อ", + "lastName": "นามสกุล", + "email": "อีเมล", + "language": "ภาษา", + "message": "ข้อความเพิ่มเติม" + }, + "placeholders": { + "firstName": "ป้อนชื่อของคุณ", + "lastName": "ป้อนนามสกุลของคุณ", + "email": "your.email@example.com", + "message": "เขียนข้อความของคุณที่นี่..." + }, + "buttons": { + "submit": "ส่ง", + "submitting": "กำลังส่ง...", + "cancel": "ยกเลิก" + }, + "errors": { + "firstNameRequired": "ต้องระบุชื่อ", + "firstNameMin": "ชื่อต้องมีอย่างน้อย 2 ตัวอักษร", + "lastNameRequired": "ต้องระบุนามสกุล", + "lastNameMin": "นามสกุลต้องมีอย่างน้อย 2 ตัวอักษร", + "emailRequired": "ต้องระบุอีเมล", + "emailInvalid": "ที่อยู่อีเมลไม่ถูกต้อง" + } + }, + "cancelModal": { + "title": "ยกเลิกรายการ", + "description": "คุณแน่ใจหรือว่าต้องการยกเลิกรายการนี้? กรุณาระบุเหตุผลในการยกเลิกด้านล่าง", + "placeholder": "กรุณาระบุเหตุผลในการยกเลิก...", + "buttons": { + "no": "ไม่ ไม่ยกเลิก", + "yes": "ใช่ ยกเลิก" + }, + "errors": { + "reasonRequired": "ต้องระบุเหตุผลในการยกเลิก" + }, + "inPersonSuccess": { + "title": "ยกเลิกธุรกรรม", + "message": "ยกเลิกธุรกรรมเรียบร้อยแล้ว มีการส่งอีเมลยืนยันแล้ว", + "passBackDevice": "คุณสามารถส่งคืนอุปกรณ์ให้ {{senderName}} ได้แล้ว", + "continueButton": "ดำเนินการต่อ" + } + }, + "enTranslations": { + "app.name": "Sign Made Easy", + "app.subtitle": "การตรวจสอบรายการ", + "meta.transaction_id": "รหัสรายการ", + "meta.transaction_status": "สถานะรายการ", + "meta.files": "ไฟล์", + "audit.title": "เส้นทางการตรวจสอบแบบเต็ม", + "audit.description": "กรุณาอัปเดตหัวข้อและข้อความด้านล่างสำหรับข้อความที่กำหนดเอง", + "table.header.actions": "การดำเนินการ", + "table.header.language": "ภาษา", + "table.header.ip_address": "ที่อยู่ IP", + "table.header.date": "วันที่", + "status.completed": "เสร็จสมบูรณ์", + "status.pending": "รอดำเนินการ", + "status.failed": "ล้มเหลว", + "action.created": "สร้างแล้ว", + "action.updated": "อัปเดตแล้ว", + "action.deleted": "ลบแล้ว", + "action.viewed": "ดูแล้ว", + "action.signed": "ลงนามแล้ว", + "action.uploaded": "อัปโหลดแล้ว", + "action.downloaded": "ดาวน์โหลดแล้ว", + "placeholder.not_available": "—" + }, + "auditPage": { + "appName": "Sign Made Easy", + "subtitle": "การตรวจสอบรายการ", + "meta": { + "transactionId": "รหัสรายการ", + "transactionStatus": "สถานะรายการ", + "files": "ไฟล์" + }, + "audit": { + "title": "เส้นทางการตรวจสอบแบบเต็ม", + "description": "กรุณาอัปเดตหัวข้อและข้อความด้านล่างสำหรับข้อความที่กำหนดเอง" + }, + "table": { + "actions": "การดำเนินการ", + "language": "ภาษา", + "ipAddress": "ที่อยู่ IP", + "date": "วันที่" + }, + "status": { + "completed": "เสร็จสมบูรณ์", + "pending": "รอดำเนินการ", + "failed": "ล้มเหลว" + }, + "fallback": { + "notAvailable": "—" + } + }, + "audit": { + "transaction": { + "created": "ธุรกรรมถูกสร้างโดย {{userName}} <{{userEmail}}>", + "sent": "ธุรกรรมถูกส่งโดย {{userName}} <{{userEmail}}>", + "cancelled": "ธุรกรรมถูกยกเลิกโดย {{userName}} <{{userEmail}}>", + "edited": "ธุรกรรมถูกแก้ไขโดย {{userName}} <{{userEmail}}>", + "viewed": "ธุรกรรมถูกดูโดย {{userName}} <{{userEmail}}>", + "signed": "ธุรกรรมถูกลงนามโดย {{userName}} <{{userEmail}}>" + }, + "signature": { + "declined": "ลายเซ็นธุรกรรมถูกปฏิเสธโดย {{userName}} <{{userEmail}}>" + }, + "ers": { + "accepted": "การเปิดเผยบันทึกอิเล็กทรอนิกส์และลายเซ็นถูกยอมรับโดย {{userName}} <{{userEmail}}>" + }, + "language": { + "updated": "{{userName}} <{{userEmail}}> อัปเดตภาษาเป็น {{language}}" + }, + "invitation": { + "sent": "ส่งอีเมลเชิญไปยัง {{userName}} <{{userEmail}}>", + "view": "คำเชิญให้ดูเอกสารถูกส่งไปยัง {{userName}} <{{userEmail}}> แล้ว", + "resent": "ส่งอีเมลเชิญอีกครั้งไปยัง {{recipientName}} <{{recipientEmail}}> โดย {{senderName}} <{{senderEmail}}>" + }, + "reassigned": { + "to": "ผู้ลงนามถูกมอบหมายใหม่โดย {{fromName}} <{{fromEmail}}> ไปยัง {{toName}} <{{toEmail}}>", + "complex": "{{personName}} <{{personEmail}}> ถูกมอบหมายใหม่โดย {{fromName}} <{{fromEmail}}> ไปยัง {{toName}} <{{toEmail}}>" + }, + "inperson": { + "started": "ธุรกรรมแบบเผชิญหน้าเริ่มต้นโดย {{userName}} <{{userEmail}}>", + "verification": "การยืนยันลายเซ็นแบบเผชิญหน้าถูกยอมรับโดย {{userName}} <{{userEmail}}>" + }, + "facilitator": { + "accepted": "กระบวนการผู้ช่วยถูกยอมรับโดย {{userName}} <{{userEmail}}>" + } + }, + "signatureModal": { + "title": { + "signature": "ลายเซ็น", + "initial": "อักษรย่อ", + "edit": "แก้ไข", + "styleSelection": "เลือกรูปแบบ" + }, + "subtitle": "สร้างลายเซ็นดิจิทัลของคุณ", + "tabs": { + "select": "เลือก", + "draw": "วาด", + "upload": "อัปโหลด" + }, + "selectTab": { + "description": "ยืนยันชื่อของคุณและเลือกรูปแบบลายเซ็น", + "requiredFields": "กรุณากรอกข้อมูล", + "fullName": { + "label": "ชื่อเต็ม", + "required": "*", + "placeholder": "กรอกชื่อเต็ม" + }, + "initials": { + "label": "อักษรย่อ", + "required": "*", + "placeholder": "กรอกอักษรย่อ" + } + }, + "drawTab": { + "description": "วาดลายเซ็นของคุณ", + "required": "*", + "requiredFields": "เป็นช่องที่ต้องกรอก", + "signature": "ลายเซ็น", + "initials": "อักษรย่อ", + "clearSignature": "ล้างลายเซ็น", + "fullNameBox": { + "label": "ลายเซ็นเต็ม", + "required": "*" + }, + "initialsBox": { + "label": "อักษรย่อ", + "required": "*", + "placeholder": "ป้อนอักษรย่อ" + } + }, + "uploadTab": { + "requiredMessage": "ต้องมีทั้งลายเซ็นและอักษรย่อ", + "requirements": "ใช้รูปภาพขนาด 300×100px สำหรับลายเซ็น และ 100×100px สำหรับอักษรย่อ สูงสุด 300KB รองรับ: .png, .jpg", + "signature": { + "uploadLabel": "อัปโหลดลายเซ็น", + "uploadHint": "JPG, PNG (300×100px, สูงสุด 300KB)", + "browseButton": "เรียกดู", + "uploadedLabel": "ลายเซ็น ✓", + "changeButton": "เปลี่ยนลายเซ็น", + "altText": "รูปภาพลายเซ็นที่อัปโหลด" + }, + "initials": { + "uploadLabel": "อัปโหลดอักษรย่อ", + "uploadHint": "JPG, PNG (100×100px, สูงสุด 300KB)", + "browseButton": "เรียกดู", + "uploadedLabel": "อักษรย่อ ✓", + "changeButton": "เปลี่ยนอักษรย่อ", + "altText": "รูปภาพอักษรย่อที่อัปโหลด" + } + }, + "footer": { + "agreementText": "ฉันเข้าใจว่าฉันกำลังลงนามในเอกสารนี้", + "cancelButton": "ยกเลิก", + "adoptButton": "ใช้ลายเซ็นและลงนาม" + }, + "errors": { + "requiredField": "กรุณากรอกข้อมูลในช่องนี้", + "fileTooLarge": "ขนาดไฟล์ต้องน้อยกว่า 300KB", + "invalidFileType": "รองรับเฉพาะไฟล์ .png, .jpg และ .jpeg", + "signatureRequired": "กรุณาเพิ่มลายเซ็น", + "initialsRequired": "กรุณาเพิ่มอักษรย่อ" + } + }, + "stampModal": { + "title": { + "add": "เพิ่มตราประทับ", + "edit": "แก้ไขตราประทับ" + }, + "closeButton": "ปิดหน้าต่าง", + "fileRequirements": "ขนาดสูงสุด = 400Kb | ประเภทไฟล์ที่รองรับ = .png, .jpg, .jpeg", + "dragDropLabel": "ลากและวางรูปภาพ หรือคลิกเพื่ออัปโหลด", + "previewAltText": "ตัวอย่างตราประทับ", + "changeImageButton": "เปลี่ยนรูปภาพ", + "clearButton": "ปิด", + "saveButton": "บันทึก", + "updateButton": "อัปเดต", + "errors": { + "fileTooLarge": "ขนาดไฟล์เกินขีดจำกัด 400KB", + "invalidFileType": "รองรับเฉพาะไฟล์ .png, .jpg และ .jpeg", + "uploadFailed": "อัปโหลดรูปภาพไม่สำเร็จ กรุณาลองอีกครั้ง" + } + }, + "attachmentModal": { + "title": "ไฟล์แนบ", + "subtitle": { + "hasFile": "จัดการไฟล์แนบของคุณ", + "noFile": "อัปโหลดไฟล์แนบ" + }, + "uploading": { + "status": "กำลังอัปโหลดไฟล์...", + "shimmerText": "กำลังอัปโหลดไฟล์..." + }, + "uploadArea": { + "dragging": "วางไฟล์ของคุณที่นี่", + "default": "อัปโหลดหรือลากและวางไฟล์", + "fileTypes": "PDF, DOCX, JPG, PNG, TXT (สูงสุด 10MB)", + "browseButton": "เรียกดูไฟล์" + }, + "uploadedFile": { + "status": "อัปโหลดสำเร็จ", + "deleteButton": "ลบไฟล์" + }, + "buttons": { + "close": "ปิด", + "uploading": "กำลังอัปโหลด...", + "deleting": "กำลังลบ...", + "saved": "บันทึกไฟล์แล้ว!", + "done": "เสร็จสิ้น", + "uploadFile": "อัปโหลดไฟล์" + }, + "errors": { + "fileTooLarge": "ขนาดไฟล์เกินขีดจำกัด 10MB", + "invalidFileType": "รองรับเฉพาะไฟล์ PDF, DOCX, JPG, PNG และ TXT", + "uploadFailed": "อัปโหลดไฟล์ไม่สำเร็จ กรุณาลองอีกครั้ง", + "deleteFailed": "ลบไฟล์ไม่สำเร็จ กรุณาลองอีกครั้ง", + "noFileSelected": "กรุณาเลือกไฟล์ก่อนดำเนินการต่อ" + }, + "accessibility": { + "fileUpload": "การอัปโหลดไฟล์", + "deleteFile": "ลบไฟล์" + } + }, + "languages": { + "zh_CN": "จีน (ตัวย่อ)", + "zh_TW": "จีน (ตัวเต็ม)", + "da": "เดนมาร์ก", + "nl_NL": "ดัตช์", + "en": "อังกฤษ", + "fi": "ฟินแลนด์", + "fr": "ฝรั่งเศส", + "de": "เยอรมัน", + "it": "อิตาลี", + "ja": "ญี่ปุ่น", + "ko": "เกาหลี", + "no": "นอร์เวย์", + "pt_BR": "โปรตุเกส (บราซิล)", + "ru": "รัสเซีย", + "es": "สเปน", + "es_MX": "สเปน (เม็กซิโก)", + "sv": "สวีเดน", + "th": "ไทย", + "he": "ฮีบรู" + }, + "session-expired": { + "title": "เซสชันหมดอายุ", + "description": "ลิงก์เซ็นเอกสารนี้หมดอายุเนื่องจากการไม่มีการใช้งานหรือเซสชันหมดเวลา กรุณากลับไปที่อีเมลของคุณและคลิกลิงก์อีกครั้งเพื่อดำเนินการเซ็นชื่อต่อ" + }, + "inPersonComplete": { + "title": "🎉 การลงนามเสร็จสมบูรณ์!", + "subtitle": "เอกสารได้รับการลงนามเรียบร้อยแล้ว", + "thankYou": "ขอบคุณที่ลงนาม!", + "message": "คุณจะได้รับอีเมลยืนยันเมื่อเอกสารได้รับการลงนามโดยทุกฝ่าย", + "passDevice": "ตอนนี้คุณสามารถส่งคืนอุปกรณ์ให้ {{senderName}}", + "continueButton": "ดำเนินการต่อ" + } +} \ No newline at end of file diff --git a/public/locales/zh_CN/translation.json b/public/locales/zh_CN/translation.json new file mode 100644 index 0000000..acf0d77 --- /dev/null +++ b/public/locales/zh_CN/translation.json @@ -0,0 +1,380 @@ +{ + "terms": { + "agreementText": "点击<0>我同意,即表示您确认已阅读 <1>电子记录和签名披露,并同意在审查和执行本文档时使用电子记录和签名。", + "note": "注意:", + "noteText": "同意此条款并不意味着您立即签署文档。仅允许您以电子方式审阅文档。在签署之前,您将有机会完整审阅文档。" + }, + "buttons": { + "agree": "我同意", + "processing": "处理中...", + "close": "关闭", + "downloadPdf": "下载 PDF", + "downloading": "下载中..." + }, + "header": { + "aiSummary": "AI 摘要", + "completeSign": "完成签署", + "sign": "签署", + "processing": "处理中...", + "options": "下载" + }, + "menu": { + "downloadPdf": "下载 PDF", + "auditTrail": "审计跟踪", + "reassignSigner": "重新分配签署人", + "cancelTransaction": "取消交易", + "viewTerms": "查看条款和条件", + "helpSupport": "帮助与支持", + "about": "关于 SME" + }, + "sidebar": { + "documents": "文档", + "pages": "页数:{{count}}", + "noDocuments": "没有可用文档。" + }, + "footer": { + "readyTitle": "准备好完成了吗?", + "readyDesc": "您已完成必填字段。请检查您的工作,然后选择完成。", + "finish": "完成", + "submitting": "提交中...", + "start": "开始", + "next": "下一步", + "agreementText": "签署即表示我同意 Sign Made Easy <0>条款和条件。" + }, + "completion": { + "complete": { + "hit": "全部完成!", + "title": "感谢您的签署", + "message": "您的文档现已完成并安全存储。我们已通过电子邮件发送了一份副本给您。" + }, + "declined": { + "hit": "操作已取消!", + "title": "下次吧!", + "message": "您的请求已成功取消。" + }, + "cancelled": { + "hit": "操作已取消!", + "title": "下次吧!", + "message": "您的请求已成功取消。" + }, + "download": "下载", + "downloading": "下载中...", + "downloadSuccess": "文件下载成功。", + "downloadOptions": { + "pdf": "PDF 文档", + "audit": "审计跟踪", + "selectFormat": "选择格式" + }, + "downloadError": "文件下载失败,请重试。", + "appsTitle": "使用我们的应用提高效率", + "formsTitle": "轻松生成表单", + "docsTitle": "生成文档(发票、报告、报价)", + "tryNow": "立即试用", + "footerText": "版权所有 2026 Sign Made Easy。保留所有权利。<0>隐私政策 | <1>合理使用政策" + }, + "reassign": { + "title": "重新分配签署人", + "successSubtitle": "文档已成功重新分配", + "successTitle": "谢谢您!", + "successMessage": "文档已成功重新分配给新的签署人。", + "fields": { + "firstName": "名字", + "lastName": "姓氏", + "email": "电子邮件", + "language": "语言", + "message": "可选消息" + }, + "placeholders": { + "firstName": "请输入您的名字", + "lastName": "请输入您的姓氏", + "email": "your.email@example.com", + "message": "在此处撰写您的消息..." + }, + "buttons": { + "submit": "提交", + "submitting": "提交中...", + "cancel": "取消" + }, + "errors": { + "firstNameRequired": "名字为必填项", + "firstNameMin": "名字至少需要2个字符", + "lastNameRequired": "姓氏为必填项", + "lastNameMin": "姓氏至少需要2个字符", + "emailRequired": "电子邮件为必填项", + "emailInvalid": "电子邮件地址无效" + } + }, + "cancelModal": { + "title": "取消交易", + "description": "您确定要取消此交易吗?请在下方提供取消原因。", + "placeholder": "请提供取消原因...", + "buttons": { + "no": "不,不要取消", + "yes": "是的,取消它" + }, + "errors": { + "reasonRequired": "取消原因为必填项" + }, + "inPersonSuccess": { + "title": "取消交易", + "message": "交易已成功取消。确认邮件已发送。", + "passBackDevice": "您现在可以将设备交还给{{senderName}}。", + "continueButton": "继续" + } + }, + "enTranslations": { + "app.name": "Sign Made Easy", + "app.subtitle": "交易审计", + "meta.transaction_id": "交易 ID", + "meta.transaction_status": "交易状态", + "meta.files": "文件", + "audit.title": "完整审计跟踪", + "audit.description": "请更新以下主题和消息以获得自定义消息。", + "table.header.actions": "操作", + "table.header.language": "语言", + "table.header.ip_address": "IP 地址", + "table.header.date": "日期", + "status.completed": "已完成", + "status.pending": "待处理", + "status.failed": "失败", + "action.created": "已创建", + "action.updated": "已更新", + "action.deleted": "已删除", + "action.viewed": "已查看", + "action.signed": "已签署", + "action.uploaded": "已上传", + "action.downloaded": "已下载", + "placeholder.not_available": "—" + }, + "auditPage": { + "appName": "Sign Made Easy", + "subtitle": "交易审计", + "meta": { + "transactionId": "交易 ID", + "transactionStatus": "交易状态", + "files": "文件" + }, + "audit": { + "title": "完整审计跟踪", + "description": "请更新以下主题和消息以获得自定义消息。" + }, + "table": { + "actions": "操作", + "language": "语言", + "ipAddress": "IP 地址", + "date": "日期" + }, + "status": { + "completed": "已完成", + "pending": "待处理", + "failed": "失败" + }, + "fallback": { + "notAvailable": "—" + } + }, + "audit": { + "transaction": { + "created": "交易由 {{userName}} <{{userEmail}}> 创建", + "sent": "交易由 {{userName}} <{{userEmail}}> 发送", + "cancelled": "交易由 {{userName}} <{{userEmail}}> 取消", + "edited": "交易由 {{userName}} <{{userEmail}}> 编辑", + "viewed": "交易由 {{userName}} <{{userEmail}}> 查看", + "signed": "交易由 {{userName}} <{{userEmail}}> 签署" + }, + "signature": { + "declined": "交易签名被 {{userName}} <{{userEmail}}> 拒绝" + }, + "ers": { + "accepted": "电子记录和签名披露已被 {{userName}} <{{userEmail}}> 接受" + }, + "language": { + "updated": "{{userName}} <{{userEmail}}> 将语言更新为 {{language}}" + }, + "invitation": { + "sent": "邀请邮件已发送至 {{userName}} <{{userEmail}}>", + "view": "查看文档的邀请已发送给 {{userName}} <{{userEmail}}>", + "resent": "邀请邮件由 {{senderName}} <{{senderEmail}}> 重新发送至 {{recipientName}} <{{recipientEmail}}>" + }, + "reassigned": { + "to": "签署人由 {{fromName}} <{{fromEmail}}> 重新分配给 {{toName}} <{{toEmail}}>", + "complex": "{{personName}} <{{personEmail}}> 被 {{fromName}} <{{fromEmail}}> 重新分配给 {{toName}} <{{toEmail}}>" + }, + "inperson": { + "started": "面对面交易由 {{userName}} <{{userEmail}}> 启动", + "verification": "面对面签名验证已被 {{userName}} <{{userEmail}}> 接受" + }, + "facilitator": { + "accepted": "协调员流程已被 {{userName}} <{{userEmail}}> 接受" + } + }, + "signatureModal": { + "title": { + "signature": "签名", + "initial": "首字母", + "edit": "编辑", + "styleSelection": "样式选择" + }, + "subtitle": "创建您的数字签名", + "tabs": { + "select": "选择", + "draw": "绘制", + "upload": "上传" + }, + "selectTab": { + "description": "确认您的姓名并选择签名样式。", + "requiredFields": "必填字段。", + "fullName": { + "label": "全名", + "required": "*", + "placeholder": "输入全名" + }, + "initials": { + "label": "首字母缩写", + "required": "*", + "placeholder": "输入首字母缩写" + } + }, + "drawTab": { + "description": "绘制您的签名。", + "required": "*", + "requiredFields": "为必填字段。", + "signature": "签名", + "initials": "首字母缩写", + "clearSignature": "清除签名", + "fullNameBox": { + "label": "完整签名", + "required": "*" + }, + "initialsBox": { + "label": "首字母缩写", + "required": "*", + "placeholder": "输入首字母缩写" + } + }, + "uploadTab": { + "requiredMessage": "签名和首字母缩写均为必填。", + "requirements": "签名使用300×100px图片,首字母缩写使用100×100px图片。最大300KB。支持:.png、.jpg。", + "signature": { + "uploadLabel": "上传签名", + "uploadHint": "JPG、PNG(300×100px,最大300KB)", + "browseButton": "浏览", + "uploadedLabel": "签名 ✓", + "changeButton": "更换签名", + "altText": "已上传的签名图片" + }, + "initials": { + "uploadLabel": "上传首字母缩写", + "uploadHint": "JPG、PNG(100×100px,最大300KB)", + "browseButton": "浏览", + "uploadedLabel": "首字母缩写 ✓", + "changeButton": "更换首字母缩写", + "altText": "已上传的首字母缩写图片" + } + }, + "footer": { + "agreementText": "我理解,我正在签署此文件。", + "cancelButton": "取消", + "adoptButton": "采用签名并签署" + }, + "errors": { + "requiredField": "此字段为必填", + "fileTooLarge": "文件大小必须小于300KB", + "invalidFileType": "仅支持.png、.jpg和.jpeg文件", + "signatureRequired": "请添加签名", + "initialsRequired": "请添加首字母缩写" + } + }, + "stampModal": { + "title": { + "add": "添加印章", + "edit": "编辑印章" + }, + "closeButton": "关闭弹窗", + "fileRequirements": "最大尺寸 = 400KB | 支持的文件类型 = .png、.jpg、.jpeg", + "dragDropLabel": "拖放图片,或点击上传", + "previewAltText": "印章预览", + "changeImageButton": "更换图片", + "clearButton": "关闭", + "saveButton": "保存", + "updateButton": "更新", + "errors": { + "fileTooLarge": "文件大小超过400KB限制", + "invalidFileType": "仅支持.png、.jpg和.jpeg文件", + "uploadFailed": "上传图片失败,请重试。" + } + }, + "attachmentModal": { + "title": "附件", + "subtitle": { + "hasFile": "管理您的附件", + "noFile": "上传附件" + }, + "uploading": { + "status": "正在上传文件...", + "shimmerText": "正在上传文件..." + }, + "uploadArea": { + "dragging": "将文件拖放到此处", + "default": "上传或拖放文件", + "fileTypes": "PDF、DOCX、JPG、PNG、TXT(最大10MB)", + "browseButton": "浏览文件" + }, + "uploadedFile": { + "status": "上传成功", + "deleteButton": "删除文件" + }, + "buttons": { + "close": "关闭", + "uploading": "上传中...", + "deleting": "删除中...", + "saved": "文件已保存!", + "done": "完成", + "uploadFile": "上传文件" + }, + "errors": { + "fileTooLarge": "文件大小超过10MB限制", + "invalidFileType": "仅支持PDF、DOCX、JPG、PNG和TXT文件", + "uploadFailed": "上传文件失败,请重试。", + "deleteFailed": "删除文件失败,请重试。", + "noFileSelected": "请先选择文件" + }, + "accessibility": { + "fileUpload": "文件上传", + "deleteFile": "删除文件" + } + }, + "languages": { + "zh_CN": "中文(简体)", + "zh_TW": "中文(繁体)", + "da": "丹麦语", + "nl_NL": "荷兰语", + "en": "英语", + "fi": "芬兰语", + "fr": "法语", + "de": "德语", + "it": "意大利语", + "ja": "日语", + "ko": "韩语", + "no": "挪威语", + "pt_BR": "葡萄牙语(巴西)", + "ru": "俄语", + "es": "西班牙语", + "es_MX": "西班牙语(墨西哥)", + "sv": "瑞典语", + "th": "泰语", + "he": "希伯来语" + }, + "session-expired": { + "title": "会话已过期", + "description": "由于不活动或会话超时,此文档签署链接已过期。请返回您的电子邮件,再次点击链接以继续签署。" + }, + "inPersonComplete": { + "title": "🎉 签署完成!", + "subtitle": "文档已成功签署", + "thankYou": "感谢您的签署!", + "message": "文档经所有相关方签署后,您将收到一封确认电子邮件。", + "passDevice": "您现在可以将设备交还给 {{senderName}}", + "continueButton": "继续" + } +} \ No newline at end of file diff --git a/public/locales/zh_TW/translation.json b/public/locales/zh_TW/translation.json new file mode 100644 index 0000000..1c8971b --- /dev/null +++ b/public/locales/zh_TW/translation.json @@ -0,0 +1,380 @@ +{ + "terms": { + "agreementText": "點擊<0>我同意,即表示您確認已閱讀 <1>電子記錄和簽名披露,並同意在審查和執行本文檔時使用電子記錄和簽名。", + "note": "注意:", + "noteText": "同意此條款並不意味著您立即簽署文檔。僅允許您以電子方式審閱文檔。在簽署之前,您將有機會完整審閱文檔。" + }, + "buttons": { + "agree": "我同意", + "processing": "處理中...", + "close": "關閉", + "downloadPdf": "下載 PDF", + "downloading": "下載中..." + }, + "header": { + "aiSummary": "AI 摘要", + "completeSign": "完成簽署", + "sign": "簽署", + "processing": "處理中...", + "options": "下載" + }, + "menu": { + "downloadPdf": "下載 PDF", + "auditTrail": "審計追蹤", + "reassignSigner": "重新分配簽署人", + "cancelTransaction": "取消交易", + "viewTerms": "查看條款和條件", + "helpSupport": "幫助與支援", + "about": "關於 SME" + }, + "sidebar": { + "documents": "文件", + "pages": "頁數:{{count}}", + "noDocuments": "沒有可用文件。" + }, + "footer": { + "readyTitle": "準備好完成了嗎?", + "readyDesc": "您已完成必填欄位。請檢查您的工作,然後選擇完成。", + "finish": "完成", + "submitting": "提交中...", + "start": "開始", + "next": "下一步", + "agreementText": "簽署即表示我同意 Sign Made Easy <0>條款和條件。" + }, + "completion": { + "complete": { + "hit": "全部完成!", + "title": "感謝您的簽署", + "message": "您的文件現已完成並安全存儲。我們已通過電子郵件發送了一份副本給您。" + }, + "declined": { + "hit": "操作已取消!", + "title": "下次吧!", + "message": "您的請求已成功取消。" + }, + "cancelled": { + "hit": "操作已取消!", + "title": "下次吧!", + "message": "您的請求已成功取消。" + }, + "download": "下載", + "downloading": "下載中...", + "downloadSuccess": "文件下載成功。", + "downloadOptions": { + "pdf": "PDF 文件", + "audit": "審計追蹤", + "selectFormat": "選擇格式" + }, + "downloadError": "文件下載失敗,請重試。", + "appsTitle": "使用我們的應用提高效率", + "formsTitle": "輕鬆生成表單", + "docsTitle": "生成文件(發票、報告、報價)", + "tryNow": "立即試用", + "footerText": "版權所有 2026 Sign Made Easy。保留所有權利。<0>隱私政策 | <1>合理使用政策" + }, + "reassign": { + "title": "重新分配簽署人", + "successSubtitle": "文件已成功重新分配", + "successTitle": "謝謝您!", + "successMessage": "文件已成功重新分配給新的簽署人。", + "fields": { + "firstName": "名字", + "lastName": "姓氏", + "email": "電子郵件", + "language": "語言", + "message": "可選訊息" + }, + "placeholders": { + "firstName": "請輸入您的名字", + "lastName": "請輸入您的姓氏", + "email": "your.email@example.com", + "message": "在此處撰寫您的訊息..." + }, + "buttons": { + "submit": "提交", + "submitting": "提交中...", + "cancel": "取消" + }, + "errors": { + "firstNameRequired": "名字為必填項", + "firstNameMin": "名字至少需要2個字符", + "lastNameRequired": "姓氏為必填項", + "lastNameMin": "姓氏至少需要2個字符", + "emailRequired": "電子郵件為必填項", + "emailInvalid": "電子郵件地址無效" + } + }, + "cancelModal": { + "title": "取消交易", + "description": "您確定要取消此交易嗎?請在下方提供取消原因。", + "placeholder": "請提供取消原因...", + "buttons": { + "no": "不,不要取消", + "yes": "是的,取消它" + }, + "errors": { + "reasonRequired": "取消原因為必填項" + }, + "inPersonSuccess": { + "title": "取消交易", + "message": "交易已成功取消。確認郵件已發送。", + "passBackDevice": "您現在可以將設備交還給{{senderName}}。", + "continueButton": "繼續" + } + }, + "enTranslations": { + "app.name": "Sign Made Easy", + "app.subtitle": "交易審計", + "meta.transaction_id": "交易 ID", + "meta.transaction_status": "交易狀態", + "meta.files": "文件", + "audit.title": "完整審計追蹤", + "audit.description": "請更新以下主題和訊息以獲得自定義訊息。", + "table.header.actions": "操作", + "table.header.language": "語言", + "table.header.ip_address": "IP 地址", + "table.header.date": "日期", + "status.completed": "已完成", + "status.pending": "待處理", + "status.failed": "失敗", + "action.created": "已創建", + "action.updated": "已更新", + "action.deleted": "已刪除", + "action.viewed": "已查看", + "action.signed": "已簽署", + "action.uploaded": "已上傳", + "action.downloaded": "已下載", + "placeholder.not_available": "—" + }, + "auditPage": { + "appName": "Sign Made Easy", + "subtitle": "交易審計", + "meta": { + "transactionId": "交易 ID", + "transactionStatus": "交易狀態", + "files": "文件" + }, + "audit": { + "title": "完整審計追蹤", + "description": "請更新以下主題和訊息以獲得自定義訊息。" + }, + "table": { + "actions": "操作", + "language": "語言", + "ipAddress": "IP 地址", + "date": "日期" + }, + "status": { + "completed": "已完成", + "pending": "待處理", + "failed": "失敗" + }, + "fallback": { + "notAvailable": "—" + } + }, + "audit": { + "transaction": { + "created": "交易由 {{userName}} <{{userEmail}}> 建立", + "sent": "交易由 {{userName}} <{{userEmail}}> 發送", + "cancelled": "交易由 {{userName}} <{{userEmail}}> 取消", + "edited": "交易由 {{userName}} <{{userEmail}}> 編輯", + "viewed": "交易由 {{userName}} <{{userEmail}}> 檢視", + "signed": "交易由 {{userName}} <{{userEmail}}> 簽署" + }, + "signature": { + "declined": "交易簽名被 {{userName}} <{{userEmail}}> 拒絕" + }, + "ers": { + "accepted": "電子記錄和簽名披露已被 {{userName}} <{{userEmail}}> 接受" + }, + "language": { + "updated": "{{userName}} <{{userEmail}}> 將語言更新為 {{language}}" + }, + "invitation": { + "sent": "邀請郵件已發送至 {{userName}} <{{userEmail}}>", + "view": "檢視文件的邀請已發送給 {{userName}} <{{userEmail}}>", + "resent": "邀請郵件由 {{senderName}} <{{senderEmail}}> 重新發送至 {{recipientName}} <{{recipientEmail}}>" + }, + "reassigned": { + "to": "簽署人由 {{fromName}} <{{fromEmail}}> 重新分配給 {{toName}} <{{toEmail}}>", + "complex": "{{personName}} <{{personEmail}}> 被 {{fromName}} <{{fromEmail}}> 重新分配給 {{toName}} <{{toEmail}}>" + }, + "inperson": { + "started": "面對面交易由 {{userName}} <{{userEmail}}> 啟動", + "verification": "面對面簽名驗證已被 {{userName}} <{{userEmail}}> 接受" + }, + "facilitator": { + "accepted": "協調員流程已被 {{userName}} <{{userEmail}}> 接受" + } + }, + "signatureModal": { + "title": { + "signature": "簽名", + "initial": "縮寫", + "edit": "編輯", + "styleSelection": "樣式選擇" + }, + "subtitle": "創建您的數位簽名", + "tabs": { + "select": "選擇", + "draw": "繪製", + "upload": "上傳" + }, + "selectTab": { + "description": "確認您的姓名並選擇簽名樣式。", + "requiredFields": "必填欄位。", + "fullName": { + "label": "全名", + "required": "*", + "placeholder": "輸入全名" + }, + "initials": { + "label": "縮寫", + "required": "*", + "placeholder": "輸入縮寫" + } + }, + "drawTab": { + "description": "繪製您的簽名。", + "required": "*", + "requiredFields": "為必填欄位。", + "signature": "簽名", + "initials": "姓名縮寫", + "clearSignature": "清除簽名", + "fullNameBox": { + "label": "完整簽名", + "required": "*" + }, + "initialsBox": { + "label": "姓名縮寫", + "required": "*", + "placeholder": "輸入姓名縮寫" + } + }, + "uploadTab": { + "requiredMessage": "簽名和縮寫均為必填。", + "requirements": "簽名使用300×100px圖片,縮寫使用100×100px圖片。最大300KB。支援格式:.png、.jpg。", + "signature": { + "uploadLabel": "上傳簽名", + "uploadHint": "JPG、PNG(300×100px,最大300KB)", + "browseButton": "瀏覽", + "uploadedLabel": "簽名 ✓", + "changeButton": "更改簽名", + "altText": "已上傳的簽名圖片" + }, + "initials": { + "uploadLabel": "上傳縮寫", + "uploadHint": "JPG、PNG(100×100px,最大300KB)", + "browseButton": "瀏覽", + "uploadedLabel": "縮寫 ✓", + "changeButton": "更改縮寫", + "altText": "已上傳的縮寫圖片" + } + }, + "footer": { + "agreementText": "我理解我正在簽署此文件。", + "cancelButton": "取消", + "adoptButton": "採用簽名並簽署" + }, + "errors": { + "requiredField": "此欄位為必填", + "fileTooLarge": "檔案大小必須小於300KB", + "invalidFileType": "僅支援.png、.jpg和.jpeg檔案", + "signatureRequired": "請添加簽名", + "initialsRequired": "請添加縮寫" + } + }, + "stampModal": { + "title": { + "add": "添加印章", + "edit": "編輯印章" + }, + "closeButton": "關閉模態框", + "fileRequirements": "最大尺寸 = 400Kb | 支援的檔案類型 = .png、.jpg、.jpeg", + "dragDropLabel": "拖放圖片,或點擊上傳", + "previewAltText": "印章預覽", + "changeImageButton": "更改圖片", + "clearButton": "關閉", + "saveButton": "儲存", + "updateButton": "更新", + "errors": { + "fileTooLarge": "檔案大小超過400KB限制", + "invalidFileType": "僅支援.png、.jpg和.jpeg檔案", + "uploadFailed": "上傳圖片失敗。請重試。" + } + }, + "attachmentModal": { + "title": "附件", + "subtitle": { + "hasFile": "管理您的附件", + "noFile": "上傳附件" + }, + "uploading": { + "status": "正在上傳檔案...", + "shimmerText": "正在上傳檔案..." + }, + "uploadArea": { + "dragging": "將檔案拖放到此處", + "default": "上傳或拖放檔案", + "fileTypes": "PDF、DOCX、JPG、PNG、TXT(最大10MB)", + "browseButton": "瀏覽檔案" + }, + "uploadedFile": { + "status": "上傳成功", + "deleteButton": "刪除檔案" + }, + "buttons": { + "close": "關閉", + "uploading": "上傳中...", + "deleting": "刪除中...", + "saved": "檔案已儲存!", + "done": "完成", + "uploadFile": "上傳檔案" + }, + "errors": { + "fileTooLarge": "檔案大小超過10MB限制", + "invalidFileType": "僅支援PDF、DOCX、JPG、PNG和TXT檔案", + "uploadFailed": "上傳檔案失敗。請重試。", + "deleteFailed": "刪除檔案失敗。請重試。", + "noFileSelected": "請先選擇檔案再繼續" + }, + "accessibility": { + "fileUpload": "檔案上傳", + "deleteFile": "刪除檔案" + } + }, + "languages": { + "zh_CN": "中文(簡體)", + "zh_TW": "中文(繁體)", + "da": "丹麥語", + "nl_NL": "荷蘭語", + "en": "英語", + "fi": "芬蘭語", + "fr": "法語", + "de": "德語", + "it": "義大利語", + "ja": "日語", + "ko": "韓語", + "no": "挪威語", + "pt_BR": "葡萄牙語(巴西)", + "ru": "俄語", + "es": "西班牙語", + "es_MX": "西班牙語(墨西哥)", + "sv": "瑞典語", + "th": "泰語", + "he": "希伯來語" + }, + "session-expired": { + "title": "會話已過期", + "description": "由於不活動或會話超時,此文件簽署連結已過期。請返回您的電子郵件,再次點擊連結以繼續簽署。" + }, + "inPersonComplete": { + "title": "🎉 簽署完成!", + "subtitle": "文件已成功簽署", + "thankYou": "感謝您的簽署!", + "message": "文件經所有相關方簽署後,您將收到一封確認電子郵件。", + "passDevice": "您現在可以將設備交還給 {{senderName}}", + "continueButton": "繼續" + } +} \ No newline at end of file diff --git a/public/vite.svg b/public/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/App.css b/src/App.css new file mode 100644 index 0000000..e69de29 diff --git a/src/App.jsx b/src/App.jsx new file mode 100644 index 0000000..8665a0f --- /dev/null +++ b/src/App.jsx @@ -0,0 +1,73 @@ + +import { BrowserRouter, Navigate, Route, Routes, useLocation } from "react-router-dom"; +import { Suspense, lazy, useEffect } from "react"; + +import Loader from "./helper/Loader.jsx"; +import AppLayout from "./layout/AppLayout"; + +// Lazy loaded pages +const Home = lazy(() => import("./pages/Home")); +const ErrorPage = lazy(() => import("./pages/ErrorPage")); +const AccessDenied = lazy(() => import("./pages/AccessDenied")); +const CompletionScreen = lazy(() => import("./pages/CompletionScreen")); +const ReassignPage = lazy(() => import("./pages/ReassignPage")); +const ReassignInfoPage = lazy(() => import("./pages/ReassignInfoPage.jsx")) +const AuditTrails = lazy(() => import("./pages/AuditTrails.jsx")) +const SessionExpired = lazy(() => import("./pages/SessionExpired.jsx")) +const ExpiredPage = lazy(() => import("./pages/ExpiredPage.jsx")) +const EmailTemplateEditorPage = lazy(() => import("./pages/EmailTemplateEditorPage.jsx")); + +const titles = { + '/': 'Sign', + '/sign': 'Sign', + '/preview': 'Preview', + '/error': 'Error', + '/expired': "Sign", + '/access-denied': 'Access Denied', + '/session-expired': 'Session Expired', + '/status': 'Sign', + '/reassign': 'Reassign', + '/reassign-info': 'Reassign', + '/audit-trails-info': 'Audit Trails' +}; + + +const AppRoutes = () => { + const location = useLocation(); + + useEffect(() => { + document.title = titles[location.pathname] || 'Sign'; + }, [location.pathname]); + + return ( + + }> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + + } /> + + ); +}; + +const App = () => { + return ( + + }> + + + + ); +}; + +export default App; \ No newline at end of file diff --git a/src/ShimmerUI/CompletionScreenShimmerUI.jsx b/src/ShimmerUI/CompletionScreenShimmerUI.jsx new file mode 100644 index 0000000..c8bc811 --- /dev/null +++ b/src/ShimmerUI/CompletionScreenShimmerUI.jsx @@ -0,0 +1,38 @@ +import React from 'react' + +const CompletionScreenShimmerUI = () => { + return ( +
+ {/* Header Skeleton */} +
+
+
+ + {/* Main Content Skeleton */} +
+
+
+
+ + {/* Image Placeholder */} +
+ + {/* Apps Section Skeleton */} +
+
+
+
+
+
+
+
+ + {/* Footer Skeleton */} +
+
+
+
+ ); +} + +export default CompletionScreenShimmerUI \ No newline at end of file diff --git a/src/ShimmerUI/DocFormOverlayShimmerUI.jsx b/src/ShimmerUI/DocFormOverlayShimmerUI.jsx new file mode 100644 index 0000000..623704d --- /dev/null +++ b/src/ShimmerUI/DocFormOverlayShimmerUI.jsx @@ -0,0 +1,99 @@ +const DocFormOverlayShimmerUI = () => { + return ( + <> +
+
+
+ {/* Sidebar - Documents List with Skeleton */} +
+
+ {/* Documents Header */} +
+ +
+ + {/* Skeleton Document Items */} + {Array.from({ length: 3 }).map((_, index) => ( +
+
+ {/* Document Name Skeleton */} +
+ {/* Pages Count Skeleton */} +
+
+ +
+
+ {/* Thumbnail Skeletons */} + {Array.from({ length: 2 }).map((_, pageIndex) => ( +
+
+
+ ))} +
+
+
+ ))} +
+
+ + {/* Main Document Viewer Area with Skeleton */} +
+
+
+
+ {Array.from({ length: 2 }).map((_, docIndex) => ( +
+ {/* Document Title Skeleton */} +
+ +
+ {Array.from({ length: 3 }).map((_, pageIndex) => ( +
+
+ {/* Full Page Skeleton - A4-like aspect ratio */} +
+
+
+ ))} +
+
+ ))} +
+
+
+
+
+ + {/* Skeleton Footer */} +
+
+ {/* Mobile: Start/Next Button Skeleton */} +
+
+
+ + {/* Desktop: Terms & Conditions Skeleton */} +
+
+
+
+
+
+ + ) +} + +export default DocFormOverlayShimmerUI \ No newline at end of file diff --git a/src/ShimmerUI/ExpiredPageShimmerUI.jsx b/src/ShimmerUI/ExpiredPageShimmerUI.jsx new file mode 100644 index 0000000..4863ed2 --- /dev/null +++ b/src/ShimmerUI/ExpiredPageShimmerUI.jsx @@ -0,0 +1,33 @@ +import bgComplete from "../assets/bgComplete.png"; + +export default function ExpiredPageShimmerUI() { + return ( +
+ {/* Header */} +
+
+
+ + {/* Main */} +
+
+ +
+ +
+
+
+
+
+
+
+ ); +} \ No newline at end of file diff --git a/src/api/Axios.jsx b/src/api/Axios.jsx new file mode 100644 index 0000000..7613825 --- /dev/null +++ b/src/api/Axios.jsx @@ -0,0 +1,50 @@ +import axios from "axios"; +import { navigateTo } from "../helper/navigator"; + +const api = axios.create({ + baseURL: import.meta.env.VITE_BASE_API_URL, + headers: { + "X-AUTH-TYPE": "TRANSACTIONAL", + "ngrok-skip-browser-warning": "69420", + }, +}); + +// Request Interceptor — auto attach uuid from URL +api.interceptors.request.use( + (config) => { + const uuid = new URLSearchParams(window.location.search).get("uuid"); + if (uuid) { + config.headers.Authorization = `${uuid}`; + // config.headers.Authorization = `Bearer ${uuid}`; + } + return config; + }, + (error) => Promise.reject(error) +); + +// Response Interceptor — global error routing +api.interceptors.response.use( + (response) => response, + (error) => { + const status = error?.response?.status; + const message = error?.response?.data?.message || "Something went wrong."; + const errorCode = error?.response?.data?.errorCode || null; + const uuid = new URLSearchParams(window.location.search).get("uuid"); + + if (status === 401) { + navigateTo("/session-expired", { + replace: true, + state: { status, message, errorCode, uuid }, + }); + } else { + navigateTo("/error", { + replace: true, + state: { status, message, errorCode }, + }); + } + + return Promise.reject(error); + } +); + +export default api; \ No newline at end of file diff --git a/src/assets/AccessDeniedGif.gif b/src/assets/AccessDeniedGif.gif new file mode 100644 index 0000000..eef5581 Binary files /dev/null and b/src/assets/AccessDeniedGif.gif differ diff --git a/src/assets/AiIcon.png b/src/assets/AiIcon.png new file mode 100644 index 0000000..3de28e4 Binary files /dev/null and b/src/assets/AiIcon.png differ diff --git a/src/assets/CompleteGif.gif b/src/assets/CompleteGif.gif new file mode 100644 index 0000000..813996f Binary files /dev/null and b/src/assets/CompleteGif.gif differ diff --git a/src/assets/DMELogo.png b/src/assets/DMELogo.png new file mode 100644 index 0000000..4f4fdc9 Binary files /dev/null and b/src/assets/DMELogo.png differ diff --git a/src/assets/DeniedGif.gif b/src/assets/DeniedGif.gif new file mode 100644 index 0000000..3ec5930 Binary files /dev/null and b/src/assets/DeniedGif.gif differ diff --git a/src/assets/FMELogo.png b/src/assets/FMELogo.png new file mode 100644 index 0000000..235237a Binary files /dev/null and b/src/assets/FMELogo.png differ diff --git a/src/assets/Options.png b/src/assets/Options.png new file mode 100644 index 0000000..e6ddaa6 Binary files /dev/null and b/src/assets/Options.png differ diff --git a/src/assets/Print.png b/src/assets/Print.png new file mode 100644 index 0000000..ea2b18b Binary files /dev/null and b/src/assets/Print.png differ diff --git a/src/assets/SMELoader.gif b/src/assets/SMELoader.gif new file mode 100644 index 0000000..ebf79a9 Binary files /dev/null and b/src/assets/SMELoader.gif differ diff --git a/src/assets/SMELogo.png b/src/assets/SMELogo.png new file mode 100644 index 0000000..e6ddc10 Binary files /dev/null and b/src/assets/SMELogo.png differ diff --git a/src/assets/SMELogoCompScreens.png b/src/assets/SMELogoCompScreens.png new file mode 100644 index 0000000..4904121 Binary files /dev/null and b/src/assets/SMELogoCompScreens.png differ diff --git a/src/assets/bgComplete.png b/src/assets/bgComplete.png new file mode 100644 index 0000000..95eba66 Binary files /dev/null and b/src/assets/bgComplete.png differ diff --git a/src/assets/icons/attachment.svg b/src/assets/icons/attachment.svg new file mode 100644 index 0000000..1311c14 --- /dev/null +++ b/src/assets/icons/attachment.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/icons/company.svg b/src/assets/icons/company.svg new file mode 100644 index 0000000..c8b6951 --- /dev/null +++ b/src/assets/icons/company.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/custom-tag.svg b/src/assets/icons/custom-tag.svg new file mode 100644 index 0000000..f06c703 --- /dev/null +++ b/src/assets/icons/custom-tag.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/icons/dropdown.svg b/src/assets/icons/dropdown.svg new file mode 100644 index 0000000..da08821 --- /dev/null +++ b/src/assets/icons/dropdown.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/icons/icons.js b/src/assets/icons/icons.js new file mode 100644 index 0000000..1cd954b --- /dev/null +++ b/src/assets/icons/icons.js @@ -0,0 +1,29 @@ +import SignatureIcon from "/src/assets/icons/signature.svg?react"; +import InitialIcon from "/src/assets/icons/initial.svg?react"; +import NameIcon from "/src/assets/icons/name.svg?react"; +import StampIcon from "/src/assets/icons/stamp.svg?react"; +import AttachmentIcon from "/src/assets/icons/attachment.svg?react"; +import CompanyIcon from "/src/assets/icons/company.svg?react"; +import TitleIcon from "/src/assets/icons/title.svg?react"; +import TextareaIcon from "/src/assets/icons/textarea.svg?react"; +import NumberIcon from "/src/assets/icons/number.svg?react"; +import TextIcon from "/src/assets/icons/text.svg?react"; +import CustomTagIcon from "/src/assets/icons/custom-tag.svg?react" +import DropDownIcon from "/src/assets/icons/dropdown.svg?react" +import WritebackIcon from "/src/assets/icons/writeback.svg?react" + +export const FieldIcons = { + signature: SignatureIcon, + initial: InitialIcon, + names: NameIcon, + stamp: StampIcon, + attachment: AttachmentIcon, + company: CompanyIcon, + titles: TitleIcon, + textarea: TextareaIcon, + number: NumberIcon, + text: TextIcon, + customtag: CustomTagIcon, + dropdown: DropDownIcon, + writeback: WritebackIcon, +}; diff --git a/src/assets/icons/initial.svg b/src/assets/icons/initial.svg new file mode 100644 index 0000000..52601cf --- /dev/null +++ b/src/assets/icons/initial.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/icons/name.svg b/src/assets/icons/name.svg new file mode 100644 index 0000000..0346577 --- /dev/null +++ b/src/assets/icons/name.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/icons/number.svg b/src/assets/icons/number.svg new file mode 100644 index 0000000..07d4381 --- /dev/null +++ b/src/assets/icons/number.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/assets/icons/signature.svg b/src/assets/icons/signature.svg new file mode 100644 index 0000000..f8cefb5 --- /dev/null +++ b/src/assets/icons/signature.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/icons/stamp.svg b/src/assets/icons/stamp.svg new file mode 100644 index 0000000..611a5d4 --- /dev/null +++ b/src/assets/icons/stamp.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/text.svg b/src/assets/icons/text.svg new file mode 100644 index 0000000..ba4650e --- /dev/null +++ b/src/assets/icons/text.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/icons/textarea.svg b/src/assets/icons/textarea.svg new file mode 100644 index 0000000..ece0934 --- /dev/null +++ b/src/assets/icons/textarea.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/icons/title.svg b/src/assets/icons/title.svg new file mode 100644 index 0000000..791879d --- /dev/null +++ b/src/assets/icons/title.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/writeback.svg b/src/assets/icons/writeback.svg new file mode 100644 index 0000000..d2dba03 --- /dev/null +++ b/src/assets/icons/writeback.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/react.svg b/src/assets/react.svg new file mode 100644 index 0000000..6c87de9 --- /dev/null +++ b/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/server-down-image.svg b/src/assets/server-down-image.svg new file mode 100644 index 0000000..bef5a96 --- /dev/null +++ b/src/assets/server-down-image.svg @@ -0,0 +1,1816 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/sme-logo.png b/src/assets/sme-logo.png new file mode 100644 index 0000000..59d59cb Binary files /dev/null and b/src/assets/sme-logo.png differ diff --git a/src/assets/t&cHeader.png b/src/assets/t&cHeader.png new file mode 100644 index 0000000..33a9cd9 Binary files /dev/null and b/src/assets/t&cHeader.png differ diff --git a/src/assets/upload-filled.png b/src/assets/upload-filled.png new file mode 100644 index 0000000..4933552 Binary files /dev/null and b/src/assets/upload-filled.png differ diff --git a/src/components/AIDrawersidebar.jsx b/src/components/AIDrawersidebar.jsx new file mode 100644 index 0000000..3b83aa8 --- /dev/null +++ b/src/components/AIDrawersidebar.jsx @@ -0,0 +1,274 @@ +import { useState, useEffect } from "react"; +import { FileText, ChevronDown, X, FolderOpen, AlertCircle } from "lucide-react"; +import { useDocStore } from "../store"; +import AiIcon from '../assets/AiIcon.png' + +// -------------------- Shimmer -------------------- +const ShimmerSkeleton = () => ( +
+
+
+
+
+ + {[100, 92, 78, 95, 60].map((w, i) => ( +
+ ))} +
+); + +// -------------------- Main -------------------- +const AIDrawerSidebar = ({ isOpen, onClose, uuid }) => { + const [selectedId, setSelectedId] = useState(""); + const [error, setError] = useState(null); + + const { + aiSummaryList, + aiLoading, + setAiSummaryList, + setAiLoading, + documents, + } = useDocStore(); + + + console.log("documents33", documents) + + + // ✅ Find selected summary + const selectedSummary = aiSummaryList.find( + (item) => item.documentId === selectedId + ); + + const summaryText = selectedSummary?.summary || null; + + // -------------------- API CALL -------------------- + const fetchDocumentSummary = async () => { + if (aiSummaryList.length > 0) return; + + try { + setError(null); + setAiLoading(true); + + const res = await fetch( + `${import.meta.env.VITE_BASE_API_URL}/sign/summarize`, + { + method: "GET", + headers: { + "X-AUTH-TYPE": "TRANSACTIONAL", + "Content-Type": "application/json", + Authorization: `${uuid}`, + }, + } + ); + + if (!res.ok) throw new Error("API failed"); + + const data = await res.json(); + + setAiSummaryList(data); + } catch (err) { + setError("Failed to load summary"); + } finally { + setAiLoading(false); + } + }; + + // -------------------- Effects -------------------- + + // Call API + useEffect(() => { + if (uuid && isOpen && aiSummaryList.length === 0) { + fetchDocumentSummary(); + } + }, [uuid, isOpen]); + + // Auto select first doc + useEffect(() => { + if (documents.length > 0 && !selectedId) { + setSelectedId(documents[0].contentDocumentId); + } + }, [documents]); + + // -------------------- Render -------------------- + const renderContent = () => { + // ✅ 1. Shimmer FIRST + if (aiLoading) { + return ; + } + + // ✅ 2. Empty + if (!selectedId) { + return ( +
+ +

+ Select a document to view summary +

+
+ ); + } + + // ✅ 3. Error + if (error) { + return ( +
+ +

{error}

+
+ ); + } + + // ✅ 4. Content + if (summaryText) { + return ( +
+
+ +

+ Document Summary +

+
+ + {/* 🔥 THIS IS WHERE YOU ADD dangerouslySetInnerHTML */} +
+ +
+ ID: {selectedId} +
+
+ ); + } + + return ( +
+ No summary found +
+ ); + }; + + // -------------------- JSX -------------------- + return ( + <> + {isOpen && ( +
+ )} + +
+
+ + {/* Header */} +
+ + {/* Left side */} +
+ + {/* Gradient Icon Wrapper */} +
+ AI +
+ + {/* Title */} +

+ Document Summary +

+ +
+ + {/* Close Button */} + +
+ + {/* Dropdown Section */} +
+ + + + {/* Trigger Button */} + + + {/* Dropdown Menu */} + +
+ + {/* Content Area */} +
+ + {/* Card */} +
+ + {/* 🔥 Shimmer */} + {aiLoading ? ( + + ) : summaryText ? ( +
+ ) : ( +

+ No summary available +

+ )} +
+
+
+
+ + ); +}; + +export default AIDrawerSidebar; \ No newline at end of file diff --git a/src/components/AuditTrailsModules/AuditTrailsBody.jsx b/src/components/AuditTrailsModules/AuditTrailsBody.jsx new file mode 100644 index 0000000..da7f4d2 --- /dev/null +++ b/src/components/AuditTrailsModules/AuditTrailsBody.jsx @@ -0,0 +1,523 @@ +import { useState, useEffect, useRef } from "react"; +import { + PlusCircle, Send, Mail, Eye, ShieldCheck, FileEdit, + Hash, Activity, FileText, FilePen, ClipboardList, Copy, Check, +} from "lucide-react"; +import SMELogo from "../../assets/SMELogo.png"; +import { useDocStore } from "../../store"; +import { useTranslation } from "react-i18next"; +import LanguageDropdown from "../LanguageDropdown"; +// import { getCachedTranslation, setCachedTranslation } from "../../services/auditTranslationCache"; +import { translateAuditAction } from "../../services/auditTranslator"; +import i18n from "../../i18n"; +import { languageSupport } from "../../constant/language"; +import { useLocalizedLabel } from "../../hooks/useLocalizedLabel"; + + +// ── TYPE → icon/color config ────────────────────────────────────────────────── +const TYPE_CONFIG = { + CREATE: { + icon: PlusCircle, + iconColor: "text-blue-500", + iconBg: "bg-blue-50", + badgeClass: "badge-info badge-outline", + }, + SENT: { + icon: Send, + iconColor: "text-green-500", + iconBg: "bg-green-50", + badgeClass: "badge-success badge-outline", + }, + EMAIL: { + icon: Mail, + iconColor: "text-amber-500", + iconBg: "bg-amber-50", + badgeClass: "badge-warning badge-outline", + }, + VIEWED: { + icon: Eye, + iconColor: "text-sky-500", + iconBg: "bg-sky-50", + badgeClass: "badge-info badge-outline", + }, + ACCEPT: { + icon: ShieldCheck, + iconColor: "text-violet-500", + iconBg: "bg-violet-50", + badgeClass: "badge-secondary badge-outline", + }, + DEFAULT: { + icon: FileEdit, + iconColor: "text-gray-400", + iconBg: "bg-gray-50", + badgeClass: "badge-ghost badge-outline", + }, +}; + +/** + * Derives icon config from type; falls back to DEFAULT. + * Special case: SENT + "Invitation email" → EMAIL style. + */ +function getConfig(type, action = "") { + if (type === "SENT" && action.toLowerCase().includes("invitation email")) { + return TYPE_CONFIG.EMAIL; + } + return TYPE_CONFIG[type] || TYPE_CONFIG.DEFAULT; +} + +/** + * Splits "04/13/2026 03:34:28 America/Los_Angeles" + * into { datetime: "04/13/2026 03:34:28", tz: "America/Los_Angeles" } + */ +function parseDate(raw = "") { + const parts = raw.trim().split(" "); + const tz = parts.length >= 3 ? parts[parts.length - 1] : ""; + const datetime = parts.slice(0, parts.length - 1).join(" "); + return { datetime, tz }; +} + +// ── SHIMMER COMPONENTS ──────────────────────────────────────────────────────── + +function ShimmerBlock({ className = "" }) { + return ( +
+ ); +} + +function MetaCardShimmer() { + return ( +
+
+ + +
+
+ ); +} + +function TableRowShimmer({ delay = 0 }) { + return ( + + + + + +
+ +
+ + +
+
+ + + + + + + + +
+ + +
+ + + ); +} + +function ShimmerLayout() { + return ( +
+ {/* Navbar shimmer */} +
+
+ + +
+
+ +
+ {/* Meta cards shimmer */} +
+ + + +
+ + {/* Table card shimmer */} +
+
+ {/* Header */} +
+
+ + + +
+
+ + {/* Table skeleton */} +
+ + + + {["w-12 pl-5", "", "w-28", "w-36", "w-52"].map((cls, i) => ( + + ))} + + + + {Array.from({ length: 5 }).map((_, i) => ( + + ))} + +
+ +
+
+ + {/* Footer shimmer */} +
+ +
+
+
+
+ + +
+ ); +} + +// ── MAIN COMPONENT ──────────────────────────────────────────────────────────── + +export default function AuditTrailsBody() { + const { t } = useTranslation(); + const [copied, setCopied] = useState(false); + const [visible, setVisible] = useState([]); + const [translatedActions, setTranslatedActions] = useState({}); + const [isTranslating, setIsTranslating] = useState(false); + const previousLanguageRef = useRef(null); + const { getLocalizedLabel } = useLocalizedLabel(); + + const { formJson } = useDocStore(); + const uid = useDocStore((s) => s.uid); + const status = useDocStore((s) => s.status); + const docs = useDocStore((s) => s.docs); + const audit = useDocStore((s) => s.audit); + const isLoaded = useDocStore((s) => s.isLoaded); + const setAuditLoading = useDocStore((s) => s.setAuditLoading); + const isProUser = useDocStore((s) => s.isProUser) + const currentLanguage = useDocStore((s) => s.currentLanguage); + + + // ── Translate all audit actions when language changes ── + useEffect(() => { + if (!audit?.length) return; + const newLang = currentLanguage?.value || 'en'; + const languageChanged = previousLanguageRef.current !== newLang; + if (!languageChanged) return; + + previousLanguageRef.current = newLang; + setAuditLoading(true); + setTranslatedActions({}); + setVisible([]); + + // Await the language change FIRST, then translate + i18n.reloadResources(newLang, 'translation').then(() => { //reloadResources forces a fresh HTTP fetch regardless + return i18n.changeLanguage(newLang); + }).then(() => { + const translations = {}; + for (let i = 0; i < audit.length; i++) { + translations[i] = translateAuditAction(audit[i].action, i18n.t.bind(i18n)); + } + setTranslatedActions(translations); + setAuditLoading(false); + audit.forEach((_, idx) => { + setTimeout(() => setVisible(prev => [...prev, idx]), idx * 80); + }); + }); + + }, [currentLanguage?.value, audit]); + + // Staggered row reveal after data loads + useEffect(() => { + if (!isLoaded || !audit?.length) return; + // Don't re-run if we're mid-language-change (translations will trigger their own reveal) + if (previousLanguageRef.current === null) return; + setVisible([]); + audit.forEach((_, i) => { + setTimeout(() => setVisible(v => [...v, i]), i * 120 + 200); + }); + }, [isLoaded, audit]); + + const handleCopy = () => { + navigator.clipboard.writeText(uid); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + }; + + + + + // ── Show shimmer while data is not ready ── + if (!isLoaded || !audit) return ; + + return ( +
+ + {/* ── NAVBAR ── */} +
+ + {/* LEFT SIDE */} +
+
+ + {/* Logo */} +
+ logo +
+ + {/* Text */} +
+ + Sign Made Easy + + + {t("auditPage.subtitle")} + +
+
+
+ + {/* RIGHT SIDE */} +
+ {isProUser && } +
+ +
+ + {/* ── PAGE BODY ── */} +
+ + {/* ── META CARDS ── */} +
+ + {/* Transaction ID */} +
+
+
+

+ {t("auditPage.meta.transactionId")} +

+
+
+ + {uid || "—"} + +
+
+
+ + {/* Status */} +
+
+
+

+ {t("auditPage.meta.transactionStatus")} +

+
+
+ + + {status || "—"} + +
+
+
+ + {/* File Name */} +
+
+
+

+ {t("auditPage.meta.files")} +

+
+
+ {docs.map((item, index) => ( + + {item.title} + + ))} +
+
+
+
+ + {/* ── AUDIT TRAIL CARD ── */} +
+
+ + {/* Card header */} +
+
+ + {t("auditPage.audit.title")} + + + {/* {t("auditPage.audit.description")} */} + +
+
+ + {/* Scrollable table - Horizontal scroll on mobile */} +
+
+ + + + + + + + + + + {audit.map((row, i) => { + const config = getConfig(row.type, row.action); + const RowIcon = config.icon; + const { datetime, tz } = parseDate(row.date); + // const lang = row.language || "—"; + const translatedAction = translatedActions[i] || row.action; + const isTranslationLoading = isTranslating; + + return ( + + {/* Action */} + + + {/* Language */} + + + {/* IP Address */} + + + {/* Date */} + + + ); + })} + +
+ {t("auditPage.table.actions")} + + {t("auditPage.table.language")} + + {t("auditPage.table.ipAddress")} + + {t("auditPage.table.date")} +
+
+
+ +
+
+ {isTranslationLoading ? ( +
+
+ Loading translation... +
+ ) : ( + <> +

+ {translatedAction} +

+ + )} +
+
+
+ + {getLocalizedLabel(row.language)} + + + + {row.ip} + + +

+ {datetime} +

+

+ {tz} +

+
+
+
+
+
+
+ + +
+ ); +} \ No newline at end of file diff --git a/src/components/DocFormOverlay.jsx b/src/components/DocFormOverlay.jsx new file mode 100644 index 0000000..f4ae37e --- /dev/null +++ b/src/components/DocFormOverlay.jsx @@ -0,0 +1,2050 @@ +import React, { + useState, + useCallback, + useEffect, + useRef, + useMemo, +} from "react"; + +import { useNavigate, useSearchParams } from "react-router-dom"; + + +import TermsAndConditionsModal from "../modals/TermsAndConditionsModal" +import { + SelectInputField, + DefaultInputField, + RadioInputField, + CheckboxInputField, + DropDownInputField, + CustomTagInputField, + TextareaInputField, + TextInputField, + SignatureInputField, +} from "./inputFields"; + +import { parsePixelValue, getCheckboxScale, getFontScaleFactor, getMinSize, getRadioScale, } from './inputFields/utils' +import InitialInputField from "./inputFields/InitialInputField"; +import StampInputField from "./inputFields/StampInputField"; +import NameInputField from "./inputFields/NameInputField"; +import EmailInputField from "./inputFields/EmailInputField"; +import NumberInputField from "./inputFields/NumberInputField"; +import SignDateInputField from "./inputFields/SignDateInputField"; +import TimeInputField from "./inputFields/TimeInputField"; +import TitlesInputField from "./inputFields/TitlesInputField"; +import AttachmentInputField from "./inputFields/AttachmentInputField"; +import CompanyInputField from "./inputFields/CompanyInputField"; +import ImageBadges from "./inputFields/ImageBadges"; +import WritebackInputField from "./WritebackFields/WritebackInputField"; +import Header from "./DocFormOverlayModules/Header"; +import { useDocStore } from "../store"; +import CancelTransactionModal from "../modals/CancelTransactionModal"; +import api from "../api/Axios"; +import AIDrawersidebar from "./AIDrawersidebar"; +import { Trans, useTranslation } from "react-i18next"; +import MessageInPersonSignerModal from "../modals/MessageInPersonSignerModal"; +import Loader from "../helper/Loader"; + + +// ResponsiveImageWithFields component +const ResponsiveImageWithFields = React.memo(({ + src, + alt, + maxHeight, + maxWidth, + documentIndex, + pageIndex, + signatureValue, + setSignatureValue, + initialValue, + setInitialValue, + stampValue, + setStampValue, + handleFieldClick, + getFieldsForPage, + fieldState, + lastActiveTab, + setLastActiveTab, + documents, + currentActiveFieldId, + allRequiredFilled, + handleSubmitClick, + handleNextClick, + currentFieldIndex, + totalFields, + goToField, + inputFields, + transaction, + setSignatureRequest, + // recipientInfo, + // setRecipientInfo, + allFieldsFilled, + hasStarted, + setHasStarted, + parseLocation, + + radioFocusedOptionIndex, + setRadioFocusedOptionIndex, + visibilityMap +}) => { + const containerRef = useRef(null); + const [imageLoaded, setImageLoaded] = useState(false); + // Track width/height separately so we only re-render when values actually change + const containerSizeRef = useRef({ width: 0, height: 0 }); + const [, forceResize] = useState(0); + + const pageFields = useMemo( + () => getFieldsForPage(documentIndex, pageIndex), + [getFieldsForPage, documentIndex, pageIndex] + ); + + const getLatestFilledValue = (type) => { + const filledField = inputFields + .filter((f) => f.type === type) + .find((f) => { + const fs = fieldState[f.id]; + if (!fs || !fs.update) return false; + const v = fs.value; + return v && (typeof v === "string" ? v.trim() : v?.text); + }); + return filledField ? fieldState[filledField.id].value : ""; + }; + + const derivedSignatureValue = getLatestFilledValue("signature"); + const derivedInitialValue = getLatestFilledValue("initial"); + + // Stable style calculator — no deps needed because helpers are module-level + const getResponsiveStyle = useCallback( + (field) => { + if (!containerRef.current) return {}; + const containerRect = containerRef.current.getBoundingClientRect(); + // console.log("containerRect", containerRect, "maxWidthOfPDF", maxWidth) + + const fieldTop = parsePixelValue(field.top); + const fieldLeft = parsePixelValue(field.left); + const fieldWidth = parsePixelValue(field.width); + const fieldHeight = parsePixelValue(field.height); + + const scaleX = containerRect.width / maxWidth; + const scaleY = containerRect.height / maxHeight; + const scale = Math.min(scaleX, scaleY); + + const baseFontSize = parsePixelValue(field.fontSize || "13px"); + const scaledHeight = fieldHeight * scale; + + const FONT_BOOST = 1.15; // ← tweak this: 1.2 = 20% bigger, 1.5 = 50% bigger + + // Font scales exactly like the field — capped at 85% of field height + const responsiveFontSize = Math.max(8, Math.min( + baseFontSize * scale * FONT_BOOST, // boosted display size + scaledHeight * 0.85 // never overflow the field + )); + + return { + position: "absolute", + top: `${fieldTop * scaleY}px`, + left: `${fieldLeft * scaleX}px`, + width: `${fieldWidth * scaleX}px`, + height: `${fieldHeight * scaleY}px`, + fontSize: `${responsiveFontSize}px`, + zIndex: 10, + boxSizing: "border-box", + }; + }, + [maxWidth, maxHeight] // only recalc when document dimensions change + ); + + + const renderField = useCallback((field) => { + const responsiveStyle = getResponsiveStyle(field); + const fieldStateValue = fieldState[field.id]; + const fontSize = parseFloat(responsiveStyle.fontSize) || 12; + + const commonProps = { + field, + value: fieldStateValue?.value || "", + fieldState: fieldStateValue, // FULL STATE + handleFieldClick, + responsiveStyle, + fontSize, + lastActiveTab, + setLastActiveTab, + goToField, + inputFields, + transaction, + setSignatureRequest, + // recipientInfo, + // setRecipientInfo, + visibilityMap + }; + + switch (field.type) { + case "select": return ; + case "checkbox": return ; + case "dropdown": return ; + case "custom-tag": return ; + case "textarea": return ; + case "text": return ; + case "email": return ; + case "number": return ; + case "signdate": return ; + case "time": return ; + case "company": return ; + case "titles": return ; + case "attachment": return ; + case "radio": { + // Filter options that belong to THIS document/page context + const filteredOptions = field.options?.filter(opt => { + const match = opt.location?.match(/container-(\d+)-page-(\d+)/); + if (!match) return false; + const optContainerIndex = parseInt(match[1]); + const optPageNumber = parseInt(match[2]); + return optContainerIndex === documentIndex && optPageNumber === pageIndex; + }); + + // Don't render if no options belong to this page + if (!filteredOptions || filteredOptions.length === 0) return null; + + return ( + + ); + } + case "names": return ; + case "signature": + return ( + + ); + case "initial": + return ( + + ); + case "stamp": + return ( + + ); + case "writeback": + return ; + default: + return ; + } + }, [getResponsiveStyle, + maxHeight, maxWidth, + fieldState]); + + // Resize observer — only triggers a re-render when dimensions actually change + useEffect(() => { + const el = containerRef.current; + if (!el) return; + + const ro = new ResizeObserver(([entry]) => { + const { width, height } = entry.contentRect; + const prev = containerSizeRef.current; + + if ( + Math.abs(prev.width - width) > 1 || + Math.abs(prev.height - height) > 1 + ) { + containerSizeRef.current = { width, height }; + forceResize(v => v + 1); // trigger re-render + } + }); + + ro.observe(el); + return () => ro.disconnect(); + }, []); + + + const handleImageLoad = () => { + setImageLoaded(true); + }; + + return ( + <> + +
+ {alt} { + e.target.src = `https://via.placeholder.com/${maxWidth}x${maxHeight}/f0f0f0/999?text=Image+Loading+Error`; + }} + /> + {imageLoaded && pageFields.map(field => renderField(field))} +
+ +
+ +
+ + ); +}); + +export default function DocFormOverlay({ + inputFields, + documents, + uuid, + onSubmit, + submitting, + transaction, + // recipientInfo, + // setRecipientInfo, + showInPersonSignerModal, + setShowInPersonSignerModal +}) { + + // console.log("recipientInfo" , recipientInfo) + const { formJson, recipientInfo, + setRecipientInfo, } = useDocStore(); + const setToast = useDocStore((state) => state.setToast); + const updateFormJson = useDocStore((state) => state.updateFormJson) + const setRedirectUrl = useDocStore((state) => state.setRedirectUrl) + const { t } = useTranslation(); + // console.log("formJson", formJson) + const [downloadOpen, setDownloadOpen] = useState(false); + const [signInOpen, setSignInOpen] = useState(false); + const [languageOpen, setLanguageOpen] = useState(false); + const [signatureValue, setSignatureValue] = useState(""); + const [signatureRequest, setSignatureRequest] = useState(null); + const [initialValue, setInitialValue] = useState(""); + const [stampValue, setStampValue] = useState(""); + const [fieldState, setFieldState] = useState({}); + const [lastActiveTab, setLastActiveTab] = useState(""); + const [currentFieldIndex, setCurrentFieldIndex] = useState(0); + // const [currentActiveFieldId, setCurrentActiveFieldId] = useState(null); + const [allRequiredFilled, setAllRequiredFilled] = useState(false); + const [progressPercent, setProgressPercent] = useState(0); + const [currentActiveFieldId, setCurrentActiveFieldId] = useState(null); + const [allFieldsFilled, setAllFieldsFilled] = useState(false); + const [showCancelTransaction, setShowCancelTransaction] = useState(false); + const [showLanguageBasedTermsAndConditions, setShowLanguageBasedTermsAndConditions] = useState(false) + const navigate = useNavigate() + const [radioFocusedOptionIndex, setRadioFocusedOptionIndex] = useState(0); + const [showInPersonScreenCancelTransaction, setShowInPersonScreenCancelTransaction] = useState(false); + + // ✅ Reset to 0 whenever the active field changes to a new radio cluster + useEffect(() => { + setRadioFocusedOptionIndex(0); + }, [currentActiveFieldId]); + + const [hasStarted, setHasStarted] = useState(false); // when user start via badges or sm screen start then handle the auto scroll to required fields only + const [openDrawer, setOpenDrawer] = useState(false); // Ai Drawer + const [cancelTransactionModalLoader, setCancelTransactionModalLoader] = useState(false) + + console.log("fieldState", fieldState); + + // console.log("signatureValue", signatureValue, "recipientInfo", recipientInfo) + + const [openIndex, setOpenIndex] = useState(null); + const [searchParams, setSearchParams] = useSearchParams(); + const containerRef = useRef(null); + + // Refs for all images + const imageRefs = useRef({}); + + // Get selected doc and page from URL + const selectedDocId = searchParams.get("doc"); + const selectedPageIndex = parseInt(searchParams.get("page")); + + useEffect(() => { + if (lastActiveTab === "select" && !recipientInfo?.fullName?.trim()) { + setSignatureValue(""); + setInitialValue(""); + } + }, [recipientInfo?.fullName, lastActiveTab]); + + useEffect(() => { + if (documents.length > 0 && openIndex === null) { + setOpenIndex(0); // Open the first document by default + } + }, [documents]); + + // Update accordion openIndex and scroll to image when URL changes + useEffect(() => { + if (selectedDocId && !isNaN(selectedPageIndex)) { + const refKey = `${selectedDocId}-${selectedPageIndex}`; + const imgEl = imageRefs.current[refKey]; + const container = containerRef.current; + if (imgEl && container) { + const headerEl = document.querySelector("header"); + const headerHeight = headerEl ? headerEl.offsetHeight : 0; + container.scrollTo({ + top: imgEl.offsetTop - container.offsetTop - headerHeight - 10, + behavior: "smooth", + }); + } + } + }, [selectedDocId, selectedPageIndex]); + + // Handle click on image + const handleClick = (docId, pageIndex) => { + const currentParams = new URLSearchParams(searchParams); + currentParams.set("doc", docId); + currentParams.set("page", pageIndex); + setSearchParams(currentParams); + }; + + // Initialize fieldState for all inputFields + useEffect(() => { + setFieldState((prev) => { + const updated = { ...prev }; + const seenClusters = new Set(); + + inputFields.forEach((field) => { + if (field.type === "radio") { + if (seenClusters.has(field.id)) return; + seenClusters.add(field.id); + + // field.id IS clusterId + if (!updated[field.id]) { + const preSelected = field.options?.find(o => o.selected)?.id ?? null; + updated[field.id] = { + documentId: field.documentId, + pageNumber: field.pageNumber ?? 0, + type: "radio", + update: false, + value: preSelected, // null if nothing pre-selected + activeTab: "", + }; + } + return; + } + // If field not initialized yet + if (!updated[field.id]) { + // Handle attachment fields separately + if (field.type === "attachment") { + updated[field.id] = { + documentId: field.documentId, + pageNumber: field.pageNumber ?? 0, + type: field.type, + update: field.uploadedFileName && field.uploadedDocumentId ? true : false, + value: field.uploadedFileName || "", // Preloaded file name + link: field.uploadedDocumentId || "", // Preloaded ContentDocumentId + activeTab: lastActiveTab, + }; + } else if (field.type === "writeback") { + // ✅ use wbtFieldValue as the real value, not field.value (which is SF API name) + const wbtVal = field.wbtFieldValue ?? ""; + updated[field.id] = { + documentId: field.documentId, + pageNumber: field.pageNumber ?? 0, + type: field.type, + update: wbtVal !== "", + value: wbtVal, + activeTab: lastActiveTab, + } + } else { + // Default initialization for other types + updated[field.id] = { + documentId: field.documentId, + pageNumber: field.pageNumber ?? 0, + type: field.type, + update: field.type === 'email' && (field.defaultValue || field.value) ? true : false, + value: field.type === 'checkbox' ? field.selected : field.defaultValue || field.value || "", + // value: field.type === field.defaultValue || field.value || "", + activeTab: lastActiveTab, + }; + } + } + }); + + return updated; + }); + }, [inputFields, lastActiveTab]); + + const parseLocation = useCallback((locationStr) => { + if (typeof locationStr !== "string") { + // console.warn("Invalid input: not a string"); + return { containerIndex: 0, pageNumber: 1 }; + } + const match = locationStr.match(/container-(\d+)-page-(\d+)/); + if (match) { + return { + containerIndex: parseInt(match[1], 10), + pageNumber: parseInt(match[2], 10), + }; + } + return { containerIndex: 0, pageNumber: 1 }; + }, []); + + // ── Compute which fields are currently visible based on rules ── + const visibilityMap = useMemo(() => { + const map = {}; + + // Step 1: every field starts visible + inputFields.forEach((field) => { + map[field.id] = true; + if (field.type === "radio") { + (field.options || []).forEach((opt) => { + map[opt.id] = true; + }); + } + }); + + // Step 2: collect all rules + const allRules = []; + + inputFields.forEach((field) => { + (field.rule || []).forEach((rule) => { + allRules.push({ rule, triggerFieldId: field.id, isRadioOption: false }); + }); + + if (field.type === "radio") { + (field.options || []).forEach((opt) => { + (opt.rule || []).forEach((rule) => { + allRules.push({ rule, triggerFieldId: opt.id, parentField: field, isRadioOption: true }); + }); + }); + } + }); + + // Step 2.5: set defaults + allRules.forEach(({ rule, isRadioOption }) => { + if (!["show", "hide"].includes(rule.action)) return; + + (rule.target || []).forEach((targetId) => { + if (isRadioOption) { + map[targetId] = false; + } else if (rule.action === "show" && rule.condition.type === "equals") { + map[targetId] = false; + } else if (rule.action === "hide" && rule.condition.type === "not") { + map[targetId] = false; + } else if (rule.action === "show" && rule.condition.type === "not") { + map[targetId] = false; + } + }); + }); + + // Step 3: collect all rule results — show wins over hide + const pendingResults = {}; // targetId → { show: bool, hide: bool } + + allRules.forEach(({ rule, triggerFieldId, parentField, isRadioOption }) => { + if (!["show", "hide"].includes(rule.action)) return; + + let currentValue = ""; + let noOptionSelected = false; + + if (isRadioOption) { + const freshParent = inputFields.find( + (f) => f.type === "radio" && f.options?.some((o) => o.id === triggerFieldId) + ); + if (!freshParent) return; + + const selectedOptionId = fieldState[freshParent.id]?.value ?? ""; + noOptionSelected = !selectedOptionId; + currentValue = selectedOptionId === triggerFieldId ? "selected" : ""; + } else { + currentValue = fieldState[triggerFieldId]?.value ?? ""; + } + + // Skip radio rules when nothing selected — keep Step 2.5 default + if (isRadioOption && noOptionSelected) return; + + let conditionMet = false; + const { type, value: condValue } = rule.condition; + + if (type === "equals") { + if (typeof condValue === "boolean") { + const rawVal = fieldState[triggerFieldId]?.value; + conditionMet = rawVal === condValue || rawVal === String(condValue); + } else { + conditionMet = + typeof currentValue === "string" + ? currentValue.trim() === condValue + : currentValue === condValue; + } + } else if (type === "not") { + if (typeof condValue === "boolean") { + const rawVal = fieldState[triggerFieldId]?.value; + conditionMet = rawVal !== condValue && rawVal !== String(condValue); + } else { + conditionMet = + typeof currentValue === "string" + ? currentValue.trim() !== condValue + : currentValue !== condValue; + } + } + + (rule.target || []).forEach((targetId) => { + if (!pendingResults[targetId]) { + pendingResults[targetId] = { show: false, hide: false }; + } + if (rule.action === "show" && conditionMet) { + pendingResults[targetId].show = true; + } + if (rule.action === "hide" && conditionMet) { + pendingResults[targetId].hide = true; + } + // ── Track when a hide rule exists but condition is NOT met ── + if (rule.action === "hide" && !conditionMet) { + pendingResults[targetId].notHiding = true; + } + if (rule.action === "show" && !conditionMet) { // ← ADD THIS + pendingResults[targetId].notShowing = true; + } + }); + }); + + // Step 4: apply results — show always beats hide + Object.entries(pendingResults).forEach(([targetId, { show, hide, notHiding, notShowing }]) => { + if (show) { + map[targetId] = true; // ← show wins regardless of hide + } else if (notShowing) { // ← ADD THIS (before hide check) + map[targetId] = false; + } else if (hide) { + map[targetId] = false; + } + else if (notHiding) { + map[targetId] = true; // hide rule exists but condition not met → visible + } + // neither fired → keep Step 2.5 default + }); + + return map; // ← must be last + }, [fieldState, inputFields]); + + const getFieldsForPage = useCallback( + (documentIndex, pageIndex) => { + const seenClusters = new Set(); + + return inputFields + .flatMap((field) => { + if (field.type === "radio" && field.options) { + if (seenClusters.has(field.id)) return []; + seenClusters.add(field.id); + + const pageKeys = new Set(); + const entries = []; + + // ── Filter options by visibilityMap ── + const visibleOptions = field.options.filter( + (opt) => visibilityMap[opt.id] !== false + ); + + visibleOptions.forEach((opt) => { + const { containerIndex, pageNumber } = parseLocation(opt.location); + const key = `${containerIndex}-${pageNumber}`; + if (!pageKeys.has(key)) { + pageKeys.add(key); + entries.push({ + ...field, + options: visibleOptions, // pass only visible options down + _renderContainerIndex: containerIndex, + _renderPageNumber: pageNumber, + location: opt.location, + }); + } + }); + + return entries; + } + return [field]; + }) + .filter((field) => { + const { containerIndex, pageNumber } = parseLocation(field.location); + return containerIndex === documentIndex && pageNumber === pageIndex; + }); + }, + [inputFields, parseLocation, visibilityMap] // ← add visibilityMap to deps + ); + + const sortedAllFields = useMemo(() => { + const required = inputFields.filter((f) => f.required); + const optional = inputFields.filter((f) => !f.required); + + const sortByPosition = (a, b) => { + // ── Radio: use options[0] for location/top/left ── + const aLocation = a.type === "radio" ? (a.options?.[0]?.location ?? a.location) : a.location; + const bLocation = b.type === "radio" ? (b.options?.[0]?.location ?? b.location) : b.location; + + const { containerIndex: aDoc, pageNumber: aPage } = parseLocation(aLocation); + const { containerIndex: bDoc, pageNumber: bPage } = parseLocation(bLocation); + + const aTop = a.type === "radio" ? parseFloat(a.options?.[0]?.top) || 0 : parseFloat(a.top) || 0; + const bTop = b.type === "radio" ? parseFloat(b.options?.[0]?.top) || 0 : parseFloat(b.top) || 0; + const aLeft = a.type === "radio" ? parseFloat(a.options?.[0]?.left) || 0 : parseFloat(a.left) || 0; + const bLeft = b.type === "radio" ? parseFloat(b.options?.[0]?.left) || 0 : parseFloat(b.left) || 0; + + if (aDoc !== bDoc) return aDoc - bDoc; + if (aPage !== bPage) return aPage - bPage; + if (Math.abs(aTop - bTop) > 5) return aTop - bTop; + return aLeft - bLeft; + }; + + return [...required.sort(sortByPosition), ...optional.sort(sortByPosition)]; + }, [inputFields, parseLocation]); + + const visibleSortedAllFields = useMemo(() => { + return sortedAllFields.filter((f) => { + // Always filter out fields hidden by visibilityMap + if (visibilityMap[f.id] === false) return false; + + // For radio: also exclude if the cluster itself has no visible options + // (all options are hidden by rules) + if (f.type === "radio") { + const hasVisibleOptions = (f.options || []).some( + (opt) => visibilityMap[opt.id] !== false + ); + if (!hasVisibleOptions) return false; + } + + return true; + }); + }, [sortedAllFields, visibilityMap]); + + useEffect(() => { + if (!currentActiveFieldId) return; + + // Check if current active field should be skipped + const shouldSkip = (() => { + if (visibilityMap[currentActiveFieldId] === false) return true; + + // Radio cluster: skip if all options are hidden + const activeField = inputFields.find(f => f.id === currentActiveFieldId); + if (activeField?.type === "radio") { + const hasVisibleOptions = (activeField.options || []).some( + (opt) => visibilityMap[opt.id] !== false + ); + if (!hasVisibleOptions) return true; + } + + return false; + })(); + + if (!shouldSkip) return; + + // Find next visible unfilled required field + const next = visibleSortedAllFields.find((f) => { + if (!f.required || ["signdate", "time"].includes(f.type)) return false; + const v = fieldState[f.id]?.value; + if (v === null || v === undefined) return true; // unfilled + if (typeof v === "boolean") return v === false; // ← add this for checkbox + if (v === "") return true; + if (typeof v === "string") return v.trim() === ""; + if (typeof v === "object") return Object.keys(v).length === 0; + return false; + }); + + if (next) { + const idx = visibleSortedAllFields.findIndex(f => f.id === next.id); + setCurrentFieldIndex(idx); + setCurrentActiveFieldId(next.id); + } else { + setCurrentActiveFieldId(null); + } + }, [visibilityMap, currentActiveFieldId, visibleSortedAllFields, fieldState, inputFields]); + + + useEffect(() => { + // Find first visible unfilled required field + const firstVisible = visibleSortedAllFields.find( + f => f.required && !["signdate", "time"].includes(f.type) + ); + + if (firstVisible) { + // Only set if currentActiveFieldId is null or currently hidden + const currentIsHidden = !currentActiveFieldId || + visibilityMap[currentActiveFieldId] === false; + + if (currentIsHidden) { + const idx = visibleSortedAllFields.findIndex(f => f.id === firstVisible.id); + setCurrentFieldIndex(idx); + setCurrentActiveFieldId(firstVisible.id); + } + } else { + // No visible required fields — clear active field so badge hides + if (currentActiveFieldId && visibilityMap[currentActiveFieldId] === false) { + setCurrentActiveFieldId(null); + } + } + }, [visibleSortedAllFields, visibilityMap]); // ← runs whenever visibility changes + + const goToField = useCallback( + (fieldId) => { + console.log('[GO_TO_FIELD] Called with fieldId:', fieldId); + console.log('[GO_TO_FIELD] Is field visible?', visibilityMap[fieldId] !== false); + + if (visibilityMap[fieldId] === false) { + console.log('[GO_TO_FIELD] Field is HIDDEN, aborting navigation'); + return; + } + + const targetField = visibleSortedAllFields.find(f => f.id === fieldId); + if (!targetField) { + console.log('[GO_TO_FIELD] Field not found in visibleSortedAllFields'); + return; + } + + console.log('[GO_TO_FIELD] Target field found:', targetField.id, targetField.type, 'required:', targetField.required); + + // Only block navigation to optional fields if required aren't all done + if (!targetField.required) { + const visibleRequiredFields = visibleSortedAllFields.filter(f => f.required); + console.log('[GO_TO_FIELD] Checking required fields completion. Required count:', visibleRequiredFields.length); + + const allRequiredDone = visibleRequiredFields.every(f => { + const fs = fieldState[f.id]; + if (!fs) return false; + const v = fs.value; + if (v === null || v === undefined) return false; + if (typeof v === "boolean") return v === true; // ← add this + if (v === "") return false; + if (typeof v === "string") return v.trim() !== ""; + if (typeof v === "object") return Object.keys(v).length > 0; + return true; + }); + + if (!allRequiredDone) { + console.log('[GO_TO_FIELD] Not all required fields are filled, blocking navigation to optional field'); + return; + } + } + + const fieldIndex = visibleSortedAllFields.findIndex(f => f.id === fieldId); + if (fieldIndex !== -1) { + console.log('[GO_TO_FIELD] Setting currentFieldIndex to:', fieldIndex); + console.log('[GO_TO_FIELD] Setting currentActiveFieldId to:', fieldId); + setCurrentFieldIndex(fieldIndex); + setCurrentActiveFieldId(fieldId); + } + }, + [visibleSortedAllFields, fieldState, visibilityMap] + ); + + + const handleNextClick = useCallback(() => { + console.log('[NEXT_CLICK] ========================================='); + console.log('[NEXT_CLICK] Current Field Index:', currentFieldIndex); + console.log('[NEXT_CLICK] Current Active Field ID:', currentActiveFieldId); + console.log('[NEXT_CLICK] Total visible fields:', visibleSortedAllFields.length); + + // Get ONLY visible required fields (not hidden by rules) + const requiredFields = visibleSortedAllFields.filter( + f => f.required && !["signdate", "time"].includes(f.type) + ); + + console.log('[NEXT_CLICK] Required visible fields count:', requiredFields.length); + console.log('[NEXT_CLICK] Required visible fields:', requiredFields.map(f => ({ + id: f.id, + type: f.type, + required: f.required, + visible: visibilityMap[f.id] !== false + }))); + + const isFieldFilled = (field) => { + const fs = fieldState[field.id]; + if (!fs) return false; + const v = fs.value; + if (v === null || v === undefined) return false; + if (typeof v === "boolean") return v === true; // ← add this for checkbox + if (v === "") return false; + if (typeof v === "string") return v.trim() !== ""; + if (typeof v === "object") return Object.keys(v).length > 0; + return true; // ← add fallback true for any other non-empty value + }; + + // Check if all required fields are filled + const allFilled = requiredFields.every(isFieldFilled); + console.log('[NEXT_CLICK] All required fields filled?', allFilled); + + if (allFilled) { + console.log('[NEXT_CLICK] All filled - showing submit badge'); + return; + } + + // Find current index in visible fields + const currentVisibleIndex = visibleSortedAllFields.findIndex(f => f.id === currentActiveFieldId); + console.log('[NEXT_CLICK] Current field index in visible fields:', currentVisibleIndex); + console.log('[NEXT_CLICK] Current field details:', visibleSortedAllFields[currentVisibleIndex]); + + // Find next UNFILLED required field AFTER current position + let nextUnfilled = null; + let nextIndex = -1; + + console.log('[NEXT_CLICK] Searching for next unfilled required field after index:', currentVisibleIndex); + + for (let i = currentVisibleIndex + 1; i < visibleSortedAllFields.length; i++) { + const field = visibleSortedAllFields[i]; + const isRequired = field.required && !["signdate", "time"].includes(field.type); + const isNotFilled = !isFieldFilled(field); + + console.log(`[NEXT_CLICK] Checking field at index ${i}:`, field.id, + 'required:', isRequired, + 'filled:', !isNotFilled, + 'candidate:', isRequired && isNotFilled); + + if (isRequired && isNotFilled) { + nextUnfilled = field; + nextIndex = i; + console.log('[NEXT_CLICK] ✅ Found next unfilled field:', field.id, 'at index:', i); + break; + } + } + + // If not found after, search from beginning (wrap around) + if (!nextUnfilled) { + console.log('[NEXT_CLICK] No unfilled found after current, searching from beginning'); + for (let i = 0; i < currentVisibleIndex; i++) { + const field = visibleSortedAllFields[i]; + const isRequired = field.required && !["signdate", "time"].includes(field.type); + const isNotFilled = !isFieldFilled(field); + + console.log(`[NEXT_CLICK] Checking field at index ${i}:`, field.id, + 'required:', isRequired, + 'filled:', !isNotFilled, + 'candidate:', isRequired && isNotFilled); + + if (isRequired && isNotFilled) { + nextUnfilled = field; + nextIndex = i; + console.log('[NEXT_CLICK] ✅ Found wrapped unfilled field:', field.id, 'at index:', i); + break; + } + } + } + + if (nextUnfilled) { + console.log('[NEXT_CLICK] 🎯 Navigating to next field:', nextUnfilled.id, 'type:', nextUnfilled.type); + console.log('[NEXT_CLICK] Setting index to:', nextIndex); + setCurrentFieldIndex(nextIndex); + setCurrentActiveFieldId(nextUnfilled.id); + } else { + console.log('[NEXT_CLICK] ❌ No unfilled required fields found!'); + // Double check - maybe all required are actually filled? + const recheckFilled = requiredFields.every(isFieldFilled); + console.log('[NEXT_CLICK] Recheck all required filled?', recheckFilled); + } + }, [currentFieldIndex, currentActiveFieldId, visibleSortedAllFields, fieldState, visibilityMap]); + + // Add debug for visibilityMap changes + // useEffect(() => { + // console.log('[VISIBILITY_MAP] ========================================='); + // console.log('[VISIBILITY_MAP] visibilityMap updated'); + // const hiddenFields = Object.entries(visibilityMap) + // .filter(([_, visible]) => visible === false) + // .map(([id]) => id); + // console.log('[VISIBILITY_MAP] Hidden fields:', hiddenFields); + + // // Find fields that are required but hidden + // const requiredButHidden = inputFields.filter(f => + // f.required && visibilityMap[f.id] === false && !["signdate", "time"].includes(f.type) + // ); + // if (requiredButHidden.length > 0) { + // console.warn('[VISIBILITY_MAP] ⚠️ Required but HIDDEN fields:', requiredButHidden.map(f => ({ id: f.id, type: f.type }))); + // } + // }, [visibilityMap, inputFields]); + + // Add debug for currentActiveFieldId changes + + useEffect(() => { + if (currentActiveFieldId) { + console.log('[ACTIVE_FIELD] ========================================='); + console.log('[ACTIVE_FIELD] Current active field changed to:', currentActiveFieldId); + const isVisible = visibilityMap[currentActiveFieldId] !== false; + console.log('[ACTIVE_FIELD] Is field visible?', isVisible); + + if (!isVisible) { + console.warn('[ACTIVE_FIELD] ⚠️ Active field is HIDDEN! This should not happen!'); + // Find next visible field + const nextVisible = visibleSortedAllFields.find(f => f.id !== currentActiveFieldId); + if (nextVisible) { + console.log('[ACTIVE_FIELD] Attempting to move to next visible field:', nextVisible.id); + setCurrentActiveFieldId(nextVisible.id); + } + } + + const fieldDetails = inputFields.find(f => f.id === currentActiveFieldId); + console.log('[ACTIVE_FIELD] Field details:', { + id: currentActiveFieldId, + type: fieldDetails?.type, + required: fieldDetails?.required, + location: fieldDetails?.location + }); + } + }, [currentActiveFieldId, visibilityMap, visibleSortedAllFields, inputFields]); + + const handleFieldClick = useCallback( + ( + fieldId, + documentId, + pageNumber, + fieldType, + fieldValue, + activeTab, + sigValue, + initValue, + newStamp, + isBadgeClick = false, + contentDocumentId, + isValid = true, + ) => { + + const stampFields = inputFields.filter(f => f.type === "stamp"); + + setFieldState((prev) => { + const updated = { ...prev }; + + console.log("handleFieldClick triggered for field:", fieldId, + documentId, + pageNumber, + fieldType, + fieldValue, + activeTab, + sigValue, + initValue, + newStamp, + isBadgeClick = false, + contentDocumentId, + isValid); + + // RADIO GROUP HANDLING + if (fieldType === "radio") { + const parentField = inputFields.find( + (f) => f.type === "radio" && + f.options?.some((opt) => opt.id === fieldId) + ); + + if (!parentField) { + console.warn("Radio parent field not found for option:", fieldId); + return prev; + } + + // field.id IS clusterId + const storeKey = parentField.id; + + updated[storeKey] = { + ...(prev[storeKey] || {}), + documentId: parentField.documentId, + pageNumber: parentField.options?.find(o => o.id === fieldId)?.pageNumber ?? 0, + type: "radio", + update: true, + value: fieldId, // selected option id + activeTab: activeTab ?? prev[storeKey]?.activeTab ?? lastActiveTab, + }; + + return updated; // early return — skip the bottom "Track click source" block + } + + // ATTACHMENT FIELD HANDLING + if (fieldType === "attachment") { + updated[fieldId] = { + ...prev[fieldId], + documentId, + pageNumber, + type: "attachment", + update: true, + value: fieldValue, + link: contentDocumentId || "", + activeTab: activeTab ?? prev[fieldId]?.activeTab, + }; + return updated; + } + + // Stamp Condition + const effectiveStamp = fieldValue; + + if (fieldType === "stamp" && effectiveStamp) { + console.log("🔥 Running stamp sync", effectiveStamp); + + stampFields.forEach((field) => { + updated[field.id] = { + ...prev[field.id], + documentId: field.documentId, + pageNumber: field.pageNumber ?? 0, + type: "stamp", + value: effectiveStamp, + update: true, + isValid, + activeTab: activeTab ?? prev[field.id]?.activeTab ?? lastActiveTab, + }; + }); + + return updated; // 🚀 MUST STOP HERE + } + + + // SYNC LOGIC FOR GLOBAL FIELD TYPES + const syncFieldTypes = { + // ✅ FIXED: names now also syncs signature and initial fields + names: () => { + const nameValue = fieldValue ?? ""; // preserve spaces for display + const trimmedName = nameValue.trim(); // for initials / signature text + + // 1️⃣ Always sync every "names" field (same as before) + inputFields + .filter((f) => f.type === "names") + .forEach((f) => { + updated[f.id] = { + ...prev[f.id], + documentId: f.documentId, + pageNumber: f.pageNumber ?? 0, + type: f.type, + update: true, + value: nameValue, + activeTab: activeTab ?? prev[f.id]?.activeTab ?? lastActiveTab, + }; + }); + + // 2️⃣ Name cleared while on "select" tab → wipe only already-shown fields + if (lastActiveTab === "select" && !trimmedName) { + inputFields + .filter((f) => ["signature", "initial"].includes(f.type)) + .forEach((f) => { + // Only clear fields the user had already filled in + if (prev[f.id]?.update === true) { + updated[f.id] = { + ...prev[f.id], + value: "", + activeTab: "", + update: false, + }; + } + }); + return; + } + + // 3️⃣ Name present while on "select" tab → sync only already-clicked fields + if (lastActiveTab === "select" && trimmedName) { + const newSig = { + text: trimmedName, + fontFamily: '"Great Vibes", cursive', + fontSize: "23px", + }; + + setSignatureValue(newSig) + + const newInit = { + text: trimmedName + .split(" ") + .filter(Boolean) + .map((w) => w[0].toUpperCase()) + .join(""), + fontFamily: '"Great Vibes", cursive', + fontSize: "23px", + }; + + setInitialValue(newInit) + + inputFields + .filter((f) => f.type === "signature") + .forEach((f) => { + // ✅ Only update fields the user has already interacted with + if (prev[f.id]?.update === true) { + updated[f.id] = { + ...prev[f.id], + value: newSig, + activeTab: "select", + update: true, + }; + } + }); + + inputFields + .filter((f) => f.type === "initial") + .forEach((f) => { + // ✅ Only update fields the user has already interacted with + if (prev[f.id]?.update === true) { + updated[f.id] = { + ...prev[f.id], + value: newInit, + activeTab: "select", + update: true, + }; + } + }); + } + + // 4️⃣ If lastActiveTab is "draw" or "upload", name changes don't + // affect signature/initial content (user drew/uploaded manually). + // Nothing extra needed — just leave those fields as-is. + }, + + titles: () => + inputFields + .filter((field) => field.type === "titles") + .forEach((field) => { + updated[field.id] = { + ...prev[field.id], + documentId: field.documentId, + pageNumber: field.pageNumber ?? 0, + type: field.type, + update: true, + value: fieldValue, + isValid, + activeTab: + activeTab ?? prev[field.id]?.activeTab ?? lastActiveTab, + }; + }), + + company: () => + inputFields + .filter((field) => field.type === "company") + .forEach((field) => { + updated[field.id] = { + ...prev[field.id], + documentId: field.documentId, + pageNumber: field.pageNumber ?? 0, + type: field.type, + update: true, + value: fieldValue, + isValid: fieldValue.trim() === "" ? false : true, + activeTab: + activeTab ?? prev[field.id]?.activeTab ?? lastActiveTab, + }; + }), + + signdate: () => + inputFields + .filter((field) => field.type === "signdate") + .forEach((field) => { + updated[field.id] = { + ...prev[field.id], + documentId: field.documentId, + pageNumber: field.pageNumber ?? 0, + type: field.type, + update: true, + value: fieldValue, + activeTab: + activeTab ?? prev[field.id]?.activeTab ?? lastActiveTab, + }; + }), + + // time: () => + // inputFields + // .filter((field) => field.type === "time") + // .forEach((field) => { + // updated[field.id] = { + // ...prev[field.id], + // documentId: field.documentId, + // pageNumber: field.pageNumber ?? 0, + // type: field.type, + // update: true, + // value: fieldValue, + // activeTab: + // activeTab ?? prev[field.id]?.activeTab ?? lastActiveTab, + // }; + // }), + + writeback: () => { + const currentField = inputFields.find((f) => f.id === fieldId); + if (!currentField) return; + + const sfApiName = currentField.value; // e.g. "BillingCity" + + inputFields + .filter( + (f) => + f.type === "writeback" && + f.value === sfApiName // ✅ match all fields with same SF API name + ) + .forEach((f) => { + updated[f.id] = { + ...(prev[f.id] || {}), + documentId: f.documentId, + pageNumber: f.pageNumber, + type: "writeback", + update: fieldValue !== "", + value: fieldValue, + activeTab: activeTab ?? prev[f.id]?.activeTab ?? lastActiveTab, + isValid, + }; + }); + }, + }; + + // Execute sync if field type has sync logic + if (syncFieldTypes[fieldType]) { + syncFieldTypes[fieldType](); + } else { + // Single field update (for non-syncing field types) + updated[fieldId] = { + documentId, + pageNumber, + type: fieldType, + update: true, + value: fieldValue, + activeTab: activeTab ?? prev[fieldId]?.activeTab ?? lastActiveTab, + isValid, + }; + } + + console.log(`Updated field ${fieldId} with value ${fieldValue}`); + + // ✅ writeback early return — sync already handled all matching fields above + if (fieldType === "writeback") { + updated[fieldId] = { + ...updated[fieldId], + clickedViaBadge: isBadgeClick, + lastClicked: new Date().toISOString(), + }; + return updated; + } + + + // Without this guard, the block below would overwrite with stale global values. + if (fieldType !== "names") { + // ── Determine the correct sync values ────────────────────────────────────── + // If the user just clicked a signature field, `fieldValue` IS the new + // signature; use it directly so we never read stale useState. + // Same logic for initial fields. + // For all other field types fall back to the useState values (unchanged). + const updateSig = + fieldType === "signature" + ? fieldValue // ← fresh value from this click + : sigValue !== undefined ? sigValue : signatureValue; // ← existing behaviour + + const updateInit = + fieldType === "initial" + ? fieldValue // ← fresh value from this click + : initValue !== undefined ? initValue : initialValue; // ← existing behaviour + + const updateStamp = + newStamp !== undefined ? newStamp : stampValue; + + inputFields + .filter( + (field) => + ["signature", "initial", "stamp"].includes(field.type) && + field.id !== fieldId // don't touch the field that was just clicked + ) + .forEach((field) => { + if (field.type === "signature" && prev[field.id]?.update === true) { + // Only sync if the value would actually change (avoids noisy updates) + if (prev[field.id]?.value !== updateSig) { + updated[field.id] = { + ...prev[field.id], + value: updateSig, + activeTab: + activeTab ?? prev[field.id]?.activeTab ?? lastActiveTab, + }; + } + } else if (field.type === "initial" && prev[field.id]?.update === true) { + if (prev[field.id]?.value !== updateInit) { + updated[field.id] = { + ...prev[field.id], + value: updateInit, + activeTab: + activeTab ?? prev[field.id]?.activeTab ?? lastActiveTab, + }; + } + } + // stamp sync unchanged — handled separately earlier in the function + }); + } + + + // Track click source + updated[fieldId] = { + ...updated[fieldId], + clickedViaBadge: isBadgeClick, + lastClicked: new Date().toISOString(), + }; + + return updated; + }); + }, + [ + lastActiveTab, + inputFields, + currentActiveFieldId, + handleNextClick, + ] + ); + + // Initialize current field + // useEffect(() => { + // if (visibleSortedAllFields.length > 0 && currentFieldIndex < visibleSortedAllFields.length) { + // setCurrentActiveFieldId(visibleSortedAllFields[currentFieldIndex].id); // ← here + // } + // }, [currentFieldIndex, visibleSortedAllFields]); + + useEffect(() => { + const valueOnlyTypes = new Set([ + "signature", "initial", "stamp", "attachment", + "signdate", "time", "checkbox", "radio", + "select", "dropdown", "names", "custom-tag" + ]); + + // Helper: is a field actually visible (shown in UI)? + const isFieldVisible = (field) => { + if (visibilityMap[field.id] === false) return false; + if (field.type === "radio") { + return (field.options || []).some( + (opt) => visibilityMap[opt.id] !== false + ); + } + return true; + }; + + // ── Only visible required fields count ── + const visibleRequiredFields = inputFields.filter( + (f) => f.required && !["signdate", "time"].includes(f.type) && isFieldVisible(f) + ); + const totalRequired = visibleRequiredFields.length; + const totalAll = inputFields.filter(isFieldVisible).length; + + let filledRequiredCount = 0; + let filledAllCount = 0; + let hasError = false; + + for (const field of inputFields) { + // ── Skip if not visible in UI ── + if (!isFieldVisible(field)) continue; + + const state = fieldState?.[field.id] || { value: "", isValid: false }; + const rawValue = state.value; + + const hasValue = (() => { + if (rawValue === null || rawValue === undefined || rawValue === "") return false; + if (typeof rawValue === "boolean") return rawValue === true; + if (typeof rawValue === "string") return rawValue.trim() !== ""; + if (typeof rawValue === "object") return Object.keys(rawValue).length > 0; + return true; + })(); + + const isPrefilledDefault = !!field.defaultValue; + + const effectiveValid = (() => { + if (["signdate", "time"].includes(field.type)) return true; + if (isPrefilledDefault) return true; + if (valueOnlyTypes.has(field.type)) return hasValue; + if (state.update && state.isValid === false) return false; + return hasValue; + })(); + + if ( + field.required && + !["signdate", "time"].includes(field.type) && + !isPrefilledDefault && + !valueOnlyTypes.has(field.type) && + state.update && + state.isValid === false + ) { + hasError = true; + } + + const isFilled = hasValue && effectiveValid; + + if (isFilled) { + filledAllCount++; + if (field.required && !["signdate", "time"].includes(field.type)) { + filledRequiredCount++; + } + } + } + + const progress = + totalRequired === 0 + ? 100 + : Math.round((filledRequiredCount / totalRequired) * 100); + + setProgressPercent(progress); + setAllRequiredFilled(!hasError && filledRequiredCount === totalRequired); + setAllFieldsFilled(!hasError && filledAllCount === totalAll); + }, [fieldState, inputFields, visibilityMap]); + + // Auto-scroll to the current active field + useEffect(() => { + if (!hasStarted) return; + if (!currentActiveFieldId || sortedAllFields.length === 0) return; + + const activeField = visibleSortedAllFields.find((f) => f.id === currentActiveFieldId); + if (!activeField) return; + + // Get the correct location and top value based on field type + let fieldLocation; + let fieldTop; + + if (activeField.type === "radio") { + // For radio, use the focused option's location and top + const options = activeField.options || []; + const focusedOption = options[radioFocusedOptionIndex ?? 0]; + if (!focusedOption) return; + + fieldLocation = focusedOption.location; + fieldTop = parseFloat(focusedOption.top) || 0; + } else { + // For all other field types (checkbox, text, signature, etc.) + fieldLocation = activeField.location; + fieldTop = parseFloat(activeField.top) || 0; + } + + const { containerIndex, pageNumber } = parseLocation(fieldLocation); + const targetDoc = documents[containerIndex]; + if (!targetDoc) return; + + const refKey = `${targetDoc.contentDocumentId}-${pageNumber}`; + const targetElement = imageRefs.current[refKey]; + const container = containerRef.current; + + if (!targetElement || !container) return; + + setTimeout(() => { + const containerRect = container.getBoundingClientRect(); + const targetRect = targetElement.getBoundingClientRect(); + const imageHeight = targetDoc?.images?.[pageNumber]?.height || 1000; + const currentScroll = container.scrollTop; + + const targetImageElement = targetElement.querySelector("img"); + const scaleFactor = targetImageElement + ? targetImageElement.getBoundingClientRect().height / imageHeight + : 1; + + const targetTopInContainer = targetRect.top - containerRect.top + currentScroll; + const fieldOffsetInImage = fieldTop * scaleFactor; + const containerVisibleHeight = container.clientHeight; + + const finalScrollTop = targetTopInContainer + fieldOffsetInImage - containerVisibleHeight / 2; + + container.scrollTo({ + top: Math.max(0, finalScrollTop), + behavior: "smooth", + }); + }, 200); + + }, [currentActiveFieldId, radioFocusedOptionIndex, sortedAllFields, documents, parseLocation, hasStarted]); + + // Fires whenever badge changes active field — no re-render of children needed + useEffect(() => { + if (!currentActiveFieldId) return; + if (!hasStarted) return; + + // Clear data-active from every field wrapper in the document + document.querySelectorAll(".field-wrapper[data-active='true']").forEach((el) => { + el.removeAttribute("data-active"); + }); + + // Find the active field definition so we can detect radio clusters + const activeField = inputFields.find(f => f.id === currentActiveFieldId); + + if (activeField?.type === "radio") { + // Radio: activate only the single option the badge is currently scrolled to. + // radioFocusedOptionIndex tracks which option within the cluster is focused. + const options = activeField.options || []; + const focusedOption = options[radioFocusedOptionIndex ?? 0]; + + if (focusedOption) { + // Target by data-option-id so only that one option wrapper gets the border + const target = document.querySelector( + `.field-wrapper[data-option-id="${focusedOption.id}"]` + ); + if (target) target.setAttribute("data-active", "true"); + } + } else { + // All other field types: activate by data-field-id (unchanged behaviour) + const target = document.querySelector( + `.field-wrapper[data-field-id="${currentActiveFieldId}"]` + ); + if (target) target.setAttribute("data-active", "true"); + } + + }, [currentActiveFieldId, radioFocusedOptionIndex, hasStarted, inputFields]); + + + const handleSubmitClick = () => { + if (formJson.status === 'DRAFT') { + setToast("Document Preview!", "info"); + return; + } + + // ── Shared visibility helper (same logic as progress useEffect) ── + const isFieldVisible = (field) => { + if (visibilityMap[field.id] === false) return false; + if (field.type === "radio") { + // Radio cluster visible only if at least one option is visible + return (field.options || []).some( + (opt) => visibilityMap[opt.id] !== false + ); + } + return true; + }; + + // Find all required fields that are empty AND visible + const emptyRequiredFields = inputFields.filter((field) => { + // ── Skip hidden fields using consistent visibility check ── + if (!isFieldVisible(field)) return false; + if (["signdate", "time"].includes(field.type)) return false; + if (!field.required) return false; + + const fs = fieldState[field.id]; + if (!fs) return true; + + const v = fs.value; + + // For writeback fields, also check the fieldState value + if (field.type === "writeback") { + return v === null || v === undefined || v === ""; + } + + // Handle radio fields specially + if (field?.type === "radio") { + return v === null || v === undefined || v === ""; + } + + // Handle checkbox/boolean fields + if (field?.type === "checkbox" || field?.wbtType === "BOOLEAN") { + return v !== true && v !== "true"; + } + + // Handle picklist/dropdown fields + if (field?.type === "dropdown" || field?.wbtType === "PICKLIST") { + return !v || v === "" || v === "none"; + } + + // Handle other field types + if (v === null || v === undefined || v === "") return true; + if (typeof v === "boolean") return v === false; + if (typeof v === "string") return v.trim() === ""; + if (typeof v === "object") return Object.keys(v).length === 0; + return false; + }); + + if (emptyRequiredFields.length > 0) { + document.querySelectorAll(".field-wrapper[data-error='true']").forEach((el) => { + el.removeAttribute("data-error"); + }); + + emptyRequiredFields.forEach((field) => { + const el = document.querySelector(`.field-wrapper[data-field-id="${field.id}"]`); + if (el) { + el.setAttribute("data-error", "true"); + + // Also trigger a visual update for writeback fields + if (field.type === "writeback") { + // Force a re-render or trigger validation + const event = new CustomEvent('field-validation', { detail: { fieldId: field.id, hasError: true } }); + document.dispatchEvent(event); + } + } + }); + + const first = emptyRequiredFields[0]; + const firstIndex = visibleSortedAllFields.findIndex(f => f.id === first.id); + if (firstIndex !== -1) { + setCurrentFieldIndex(firstIndex); + setCurrentActiveFieldId(first.id); + + // Scroll to the field + const element = document.querySelector(`.field-wrapper[data-field-id="${first.id}"]`); + if (element) { + element.scrollIntoView({ behavior: 'smooth', block: 'center' }); + } + } + + setToast( + `${emptyRequiredFields.length} required field${emptyRequiredFields.length > 1 ? 's' : ''} need attention`, + "error" + ); + return; + } + + document.querySelectorAll(".field-wrapper[data-error='true']").forEach((el) => { + el.removeAttribute("data-error"); + }); + + onSubmit(fieldState, visibilityMap); + }; + + const handleCancelClose = () => { + setShowCancelTransaction(false); + }; + + const handleCancelConfirm = async (reason) => { + setCancelTransactionModalLoader(true) + try { + let res = await api.put(`/sign/decline`, { reason }, { + headers: { Authorization: `${uuid}` } + }); + // console.log(res) + if (res.status === 202) { + setToast("Action Canceled successfully!", "success"); + if (formJson?.role === 'InPersonSigner') { + // Close the loader and show InPerson screen + setCancelTransactionModalLoader(false); + setShowInPersonScreenCancelTransaction(true) + } else { + updateFormJson({ + status: "DECLINED", + }); + } + } + + } catch (error) { + console.log(error); + } finally { + if (formJson?.role !== 'InPersonSigner') { + setCancelTransactionModalLoader(false); + } + } + }; + + return ( + <> + {submitting && } +
+ + +
+ + {/* --------------------------------------------------------HeaderTop ----------------------------------------------------------------*/} +
+
+ + {/* --------------------------------------------------------TermsAndConditionsModal ----------------------------------------------------------------*/} + {(formJson.term_and_condition_accepted === false && formJson.status !== 'DRAFT' && formJson.role !== 'CC' || showLanguageBasedTermsAndConditions) && } + + +
+
+ + {/* ---------------------------------------------------Fixed Header-----------------------------------------------------------*/} +
+
+ {t("sidebar.documents")} +
+
+ + {/* Scrollable Area */} +
+
+ {documents.length > 0 ? ( + documents.map((doc, index) => ( +
+
setOpenIndex(openIndex === index ? null : index)} + className="collapse-title font-semibold flex flex-col cursor-pointer" + > + + {doc?.name} + + + {t("sidebar.pages", { count: doc?.images?.length })} + +
+ +
+
+ {doc?.images?.map((imageData, pageIndex) => { + const refKey = `${doc.contentDocumentId}-${pageIndex}`; + return ( + +
(imageRefs.current[refKey] = el)} + className={`relative border rounded-lg p-1 bg-white shadow-sm ${selectedDocId === doc.contentDocumentId && + selectedPageIndex === pageIndex + ? "border-blue-500" + : "border-gray-300" + }`} + + > + {`Page + handleClick(doc.contentDocumentId, pageIndex) + } + /> +
+ + {pageIndex + 1} + +
+
+ + ); + })} +
+
+
+ )) + ) : ( +

+ {t("sidebar.noDocuments")} +

+ )} +
+
+
+ +
+
+
+
+ {documents.length > 0 ? ( + documents.map((item, documentIndex) => ( +
+

+ {item?.name} +

+
+ {item?.images?.map((imageData, pageIndex) => { + const refKey = `${item.contentDocumentId}-${pageIndex}`; + + return ( + (imageRefs.current[refKey] = el)} + className="block w-full max-w-full relative" + > +
+ +
+
+ ); + })} +
+
+ )) + ) : ( +

+ No documents available. +

+ )} +
+
+
+
+
+ + {/* Bottom Submit Pop-up Bar */} + {allRequiredFilled && formJson.role !== 'CC' && + ( +
+ +
+ + {/* Text Section */} +
+

+ {t("footer.readyTitle")} +

+

+ {t("footer.readyDesc")} +

+
+ + {/* Button */} + {formJson.status !== 'DRAFT' && } + +
+
+ )} + +
+
+ + {/* Mobile: current field pill + next button */} +
+ + {!hasStarted ? ( + + ) : ( + + )} +
+ + {/* Desktop: terms text */} +
setShowLanguageBasedTermsAndConditions(!showLanguageBasedTermsAndConditions)}> + + ]} + /> +
+ +
+
+ +
+ {/* ---------------------------------------------------------Cancel Transactional Modal----------------------------------------------- */} + + + {/* ----------------------------------------------------------Ai Drawer sidebar---------------------------------------------------------*/} + setOpenDrawer(false)} + uuid={uuid} + /> + + {/* --------------------------------------------------------InPersonSignerModal When Complete Tra.---------------------------------------------------------------- */} + + + {/* */} + + + + ); +} diff --git a/src/components/DocFormOverlayModules/Header.jsx b/src/components/DocFormOverlayModules/Header.jsx new file mode 100644 index 0000000..dcc11a0 --- /dev/null +++ b/src/components/DocFormOverlayModules/Header.jsx @@ -0,0 +1,368 @@ +import { ChevronDown, HelpCircle, Info, XCircle, RefreshCw, FileText, ArrowDownToLine, Download, History } from "lucide-react"; +import SMELogo from "../../assets/sme-logo.png"; +import { useEffect, useRef, useState } from "react"; +import { useDocStore } from "../../store"; +import { useNavigate } from "react-router-dom"; +import LanguageDropdown from "../LanguageDropdown"; +import AiIcon from '../../assets/AiIcon.png'; +import SMELogoIcon from '../../assets/SMELogo.png'; +import { downloadPdfApi } from "../../services/downloadDocument"; +import { useTranslation } from "react-i18next"; +import { fetchReassignData } from "../../services/reassignService"; +import { isRtlLanguage } from "../../i18n"; + +const Header = ({ progressPercent, uuid, setShowCancelTransaction, setShowLanguageBasedTermsAndConditions, handleSubmitClick, setOpenDrawer }) => { + const docFormJson = useDocStore((state) => state.formJson); + console.log("docFormJson123", docFormJson) + const { t, i18n } = useTranslation(); + const [open, setOpen] = useState(false); + const [userMenuOpen, setUserMenuOpen] = useState(false); + const dropdownRef = useRef(null); + const userMenuRef = useRef(null); + const navigate = useNavigate(); + const [loadingItem, setLoadingItem] = useState(null); + // Determine RTL based on current i18n language + const isRtl = isRtlLanguage(i18n.language); + + console.log(isRtl, "Drop Down ") + + const isCCRole = docFormJson?.role === 'CC'; + const isInPersonSigner = docFormJson?.role === 'InPersonSigner'; + const isDraft = docFormJson?.status === 'DRAFT'; + const isProUser = docFormJson?.isProUser + + // Menu configuration for regular signers + const signerMenuItems = [ + { + id: "download-pdf", + labelKey: "menu.downloadPdf", + icon: , + action: async () => { + await downloadPdfApi('pdf'); + }, + danger: false, + divider: false, + visible: true + }, + { + id: "audit-trail", + labelKey: "menu.auditTrail", + icon: , + action: async () => { + await downloadPdfApi('audit'); + }, + danger: false, + divider: false, + visible: !docFormJson?.hide_audit_trail + }, + { + id: "reassign", + labelKey: "menu.reassignSigner", + icon: , + action: async () => { + try { + await fetchReassignData(); + navigate(`/reassign?uuid=${uuid}`, { state: { fromSign: true } }, { replace: true }); + } catch (error) { + console.error("Failed to fetch reassign data", error); + } + }, + danger: false, + divider: false, + visible: docFormJson?.re_assignable && !isInPersonSigner + }, + { + id: "cancel", + labelKey: "menu.cancelTransaction", + icon: , + action: () => setShowCancelTransaction(true), + danger: true, + divider: false, + visible: true + }, + { + id: "terms", + labelKey: "menu.viewTerms", + icon: , + action: () => setShowLanguageBasedTermsAndConditions(true), + danger: false, + divider: true, + visible: true + }, + { + id: "help", + labelKey: "menu.helpSupport", + icon: , + action: () => console.log("Help & Support"), + danger: false, + href: "https://support.signmadeasy.com", + divider: false, + visible: true + }, + { + id: "about", + labelKey: "menu.about", + icon: , + action: () => console.log("About SME"), + danger: false, + href: "https://signmadeasy.com", + divider: false, + visible: true + } + ]; + + // Menu configuration for CC role (only PDF and Audit Trail) + const ccMenuItems = [ + { + id: "download-pdf", + labelKey: "menu.downloadPdf", + icon: , + action: async () => { + await downloadPdfApi('pdf'); + }, + danger: false, + divider: false, + visible: true + }, + { + id: "audit-trail", + labelKey: "menu.auditTrail", + icon: , + action: async () => { + await downloadPdfApi('audit'); + }, + danger: false, + divider: false, + visible: !docFormJson?.hide_audit_trail + } + ]; + + // Select menu items based on role + const userMenuItems = isCCRole ? ccMenuItems : signerMenuItems; + + // Close dropdowns on outside click + useEffect(() => { + function handleClickOutside(e) { + if (loadingItem) return; + + if (dropdownRef.current && !dropdownRef.current.contains(e.target)) { + setOpen(false); + } + if (userMenuRef.current && !userMenuRef.current.contains(e.target)) { + setUserMenuOpen(false); + } + } + + document.addEventListener("mousedown", handleClickOutside); + return () => document.removeEventListener("mousedown", handleClickOutside); + }, [loadingItem]); + + const handleMenuItemClick = async (item) => { + if (!item.action) return; + + try { + setLoadingItem(item.id); + await item.action(); + } catch (err) { + console.error(err); + } finally { + setLoadingItem(null); + + // Don't close dropdown for download items + if (item.id !== "download-pdf" && item.id !== "audit-trail") { + setUserMenuOpen(false); + setOpen(false); + } + } + }; + + return ( +
+ {/* Top Bar */} +
+ {/* Responsive Logo - Mobile vs Tablet/Desktop */} + {/* Mobile */} + SME Logo + + {/* Desktop */} + SME Logo + +
+ {isProUser && } + + {!isDraft && ( +
+ {/* AI Summary Button - Only show for non-CC roles */} + {docFormJson?.ai_enabled && !isCCRole && ( + + )} + +
+ {/* CC Role: Show single "Options" button instead of split button */} + {isCCRole ? ( + <> + + + + + ) : ( + /* Regular Signer: Show split button with Complete Sign */ + <> + + + + + )} + + {/* Dropdown Menu */} + {open && ( +
+ {userMenuItems.map((item, index) => { + const commonClass = `w-full text-left px-4 py-2.5 text-xs sm:text-sm transition-all duration-200 cursor-pointer + flex items-center gap-3 group + ${item.danger + ? "text-red-600 hover:bg-red-50 hover:text-red-700" + : "text-gray-700 hover:bg-blue-50 hover:text-regal-blue" + }`; + + const iconClass = `transition-transform duration-200 group-hover:scale-110 + ${item.danger + ? "text-red-500" + : "text-gray-400 group-hover:text-regal-blue" + }`; + + return ( +
+ {item.divider && index > 0 && ( +
+ )} + + {item.href ? ( + + {item.icon} + + {loadingItem === item.id ? t("header.processing") : t(item.labelKey)} + + + ) : ( + item.visible && ( + + ) + )} +
+ ); + })} +
+ )} +
+
+ )} +
+
+ + {/* Progress Bar - Only show for non-CC roles */} + {!isCCRole && ( +
+
+
+ )} +
+ ); +}; + +export default Header; \ No newline at end of file diff --git a/src/components/EmailTemplateEditorModules/EmailTemplateEditor.jsx b/src/components/EmailTemplateEditorModules/EmailTemplateEditor.jsx new file mode 100644 index 0000000..4571822 --- /dev/null +++ b/src/components/EmailTemplateEditorModules/EmailTemplateEditor.jsx @@ -0,0 +1,437 @@ +import React, { useState, useCallback, useEffect, useRef } from 'react'; +import { + IconMinus, + IconPhoto, + IconH1, + IconLayoutList, + IconTextSize, + IconRectangle, + IconLayoutBottombar, + IconRotate, + IconArrowUp, + IconLoader2, + IconAlertCircle, + IconChevronDown, + IconChevronRight, + IconDeviceDesktop, + IconPalette, + IconAlignLeft, + IconAlignCenter, + IconAlignRight, + IconEye, + IconEyeOff, + IconBuilding, + IconLink, + IconPhone, + IconMapPin, +} from '@tabler/icons-react'; +import { DEFAULT_CONFIG_JSON } from './EmailTemplateJson'; +import { AlignField, applyConfigToHTML, ColorField, Section, ToggleSwitch } from './EmailTemplateFeatures'; +import { X } from 'lucide-react'; +import axios from 'axios'; +import Loader from '../../helper/Loader'; +import { HeaderEmailIcon } from './HeaderEmailIcon'; + + + +// ─── Main Component ─────────────────────────────────────────────────────────── +const EmailTemplateEditor = ({ originalHTML, jsonConfig, setJsonConfig, isLoading, error, authDataSF, resetConfig }) => { + const iframeRef = useRef(null); + const [isSaving, setIsSaving] = useState(false); + + const updateConfig = useCallback((key, value) => { + console.log(`🔄 Updating ${key}:`, value); + setJsonConfig((prev) => { + const newConfig = { ...prev, [key]: value }; + console.log('📝 New config:', newConfig); + return newConfig; + }); + }, []); + + useEffect(() => { + if (!iframeRef.current || !originalHTML) return; + const patched = applyConfigToHTML(originalHTML, jsonConfig); + const doc = iframeRef.current.contentDocument; + if (doc) { + doc.open(); + doc.write(patched); + doc.close(); + } + }, [jsonConfig, originalHTML]); + + const handleReset = () => { + setJsonConfig(resetConfig); + }; + + const handleClose = () => { + window.parent.postMessage({ + type: "TEMPLATE_CLOSED", + success: true, + }, "*") + } + + const handleSave = async () => { + try { + setIsSaving(true); + const finalHTML = originalHTML ? applyConfigToHTML(originalHTML, jsonConfig) : ''; + const payload = { buId: authDataSF?.buId, html: finalHTML, config: JSON.stringify(jsonConfig) }; + + + console.log('Saving config:', jsonConfig); + console.log('Saving HTML:', finalHTML); + + const res = await axios.post( + `${import.meta.env.VITE_BASE_API_URL}/email/template?businessUnitId=${authDataSF.buid}`, + jsonConfig, + { + headers: { + 'X-AUTH-TYPE': 'USER', + 'Authorization': `Bearer ${authDataSF.token}`, + "ngrok-skip-browser-warning": "69420", + } + } + ); + + console.log("Response Save", res) + + if (res.status === 200) { + window.parent.postMessage({ + type: "TEMPLATE_SAVED", + success: true, + messgae: "Template Save", + data: res?.data + }, "*") + console.log("End") + } + } catch (err) { + console.error('Save failed:', err); + window.parent.postMessage( + { + type: "TEMPLATE_SAVED", + success: false, + error: err?.message || "Unknown error", + message: "An error occurred while saving the configuration. Please contact support.", + }, + "*" + ); + } finally { + setIsSaving(false); + } + }; + + + // Add this check - if config is null and not loading, show error + if (!jsonConfig && !isLoading) { + return ( +
+
+ +

No Configuration Found

+

Unable to load template configuration from server.

+ +
+
+ ); + } + + // If still loading or no config yet, show loading + if (!jsonConfig || isLoading) { + return ( + + ); + } + + + return ( +
+ {/* Sidebar */} +
+
+
+
+
+ +
+
+

Customize Email Template

+
+
+ {isLoading && } +
+
+ + {error && ( +
+ +
+

Failed to load template

+

{error}

+
+
+ )} + +
+
+
} defaultExpanded={true}> + + + {/* */} + {/* */} +
+ +
} defaultExpanded={false}> + + + {/* */} + {/*
+ + + + +
*/} +
+ +
} defaultExpanded={false}> + {/* */} + + + + {/* */} + {/*
+ + +
*/} +
+ +
} defaultExpanded={false}> + + + + {/*
+ + + + +
*/} +
+ +
} defaultExpanded={false}> + {/* */} + + {/* */} + {/* */} +
+ + + +
} defaultExpanded={false}> + {/* + {jsonConfig.show_custom_message && ( + <> */} + {/* */} + + + {/* */} + {/* */} + {/* */} + {/* + )} */} +
+ + {/*
} defaultExpanded={false}> + + {jsonConfig.show_instruction && ( + <> + + + + + + )} +
*/} + +
} defaultExpanded={false}> + {/* */} + {/* {jsonConfig.show_button && ( + <> */} + {/* */} + + + {/* */} + {/*
+ + +
*/} + {/* + */} + {/* + )} */} +
+ +
} defaultExpanded={false}> + {/* + {jsonConfig.show_reassign_section && ( + <> */} + {/* */} + {/* */} + + {/* + )} */} +
+ {/* + {jsonConfig.show_audit_trail_section && ( + <> */} + {/* */} + {/* */} + + {/* + )} */} +
+ + {/*
} defaultExpanded={false}> + + {jsonConfig.show_transaction_id && ( + <> + + + + )} +
+ + {jsonConfig.show_regards && ( + <> + + + + )} +
*/} + +
} defaultExpanded={false}> + {/* + {jsonConfig.show_company_address && ( + <> */} + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} + + + + {/* */} + {/* + )} */} +
+ + {/*
} defaultExpanded={false}> + + {jsonConfig.show_footer && ( + <> + + + + + + + + )} +
*/} + + {/*
} defaultExpanded={false}> + + + +
*/} +
+
+ + {/*
+ + + {showToast && ( +
+
+ + + + Config saved successfully! +
+
+ )} +
*/} +
+ + {/* Preview Area */} +
+ {/* Preview Header */} +
+
+ + + + +
+
+ +
+
+ {isLoading ? ( +
+ +

Loading your email template...

+
+ ) : ( +