address
This commit is contained in:
@@ -2,5 +2,5 @@ VITE_TOKEN_NAME = 'dsc_token'
|
|||||||
VITE_REFRESH_TOKEN_NAME = 'dsc_refresh_token'
|
VITE_REFRESH_TOKEN_NAME = 'dsc_refresh_token'
|
||||||
VITE_DANAK_BASE_URL ='https://api.danakcorp.com'
|
VITE_DANAK_BASE_URL ='https://api.danakcorp.com'
|
||||||
VITE_BASE_URL = 'http://192.168.1.134:4000'
|
VITE_BASE_URL = 'http://192.168.1.134:4000'
|
||||||
VITE_BASE_URL = 'https://dmail-api.danakcorp.com'
|
# VITE_BASE_URL = 'https://dmail-api.danakcorp.com'
|
||||||
VITE_SERVICE_ID = 'e51afdc3-ea0b-49cf-8f49-2a6f131b024e'
|
VITE_SERVICE_ID = 'e51afdc3-ea0b-49cf-8f49-2a6f131b024e'
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
"orval": "orval"
|
"orval": "orval"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@hookform/resolvers": "^5.1.1",
|
||||||
"@radix-ui/react-checkbox": "^1.3.2",
|
"@radix-ui/react-checkbox": "^1.3.2",
|
||||||
"@radix-ui/react-switch": "^1.2.5",
|
"@radix-ui/react-switch": "^1.2.5",
|
||||||
"@react-three/drei": "^10.1.2",
|
"@react-three/drei": "^10.1.2",
|
||||||
@@ -31,6 +32,7 @@
|
|||||||
"react-date-object": "^2.1.9",
|
"react-date-object": "^2.1.9",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
"react-dropzone": "^14.3.8",
|
"react-dropzone": "^14.3.8",
|
||||||
|
"react-hook-form": "^7.60.0",
|
||||||
"react-i18next": "^15.5.1",
|
"react-i18next": "^15.5.1",
|
||||||
"react-loading-skeleton": "^3.5.0",
|
"react-loading-skeleton": "^3.5.0",
|
||||||
"react-multi-date-picker": "^4.5.2",
|
"react-multi-date-picker": "^4.5.2",
|
||||||
@@ -44,6 +46,7 @@
|
|||||||
"three": "^0.177.0",
|
"three": "^0.177.0",
|
||||||
"uuid": "^11.1.0",
|
"uuid": "^11.1.0",
|
||||||
"vite-tsconfig-paths": "^5.1.4",
|
"vite-tsconfig-paths": "^5.1.4",
|
||||||
|
"yup": "^1.6.1",
|
||||||
"zustand": "^5.0.3"
|
"zustand": "^5.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
Generated
+65
@@ -8,6 +8,9 @@ importers:
|
|||||||
|
|
||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@hookform/resolvers':
|
||||||
|
specifier: ^5.1.1
|
||||||
|
version: 5.1.1(react-hook-form@7.60.0(react@19.1.0))
|
||||||
'@radix-ui/react-checkbox':
|
'@radix-ui/react-checkbox':
|
||||||
specifier: ^1.3.2
|
specifier: ^1.3.2
|
||||||
version: 1.3.2(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
version: 1.3.2(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||||
@@ -68,6 +71,9 @@ importers:
|
|||||||
react-dropzone:
|
react-dropzone:
|
||||||
specifier: ^14.3.8
|
specifier: ^14.3.8
|
||||||
version: 14.3.8(react@19.1.0)
|
version: 14.3.8(react@19.1.0)
|
||||||
|
react-hook-form:
|
||||||
|
specifier: ^7.60.0
|
||||||
|
version: 7.60.0(react@19.1.0)
|
||||||
react-i18next:
|
react-i18next:
|
||||||
specifier: ^15.5.1
|
specifier: ^15.5.1
|
||||||
version: 15.5.2(i18next@25.2.1(typescript@5.7.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.7.3)
|
version: 15.5.2(i18next@25.2.1(typescript@5.7.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.7.3)
|
||||||
@@ -107,6 +113,9 @@ importers:
|
|||||||
vite-tsconfig-paths:
|
vite-tsconfig-paths:
|
||||||
specifier: ^5.1.4
|
specifier: ^5.1.4
|
||||||
version: 5.1.4(typescript@5.7.3)(vite@6.3.5(@types/node@24.0.7)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0))
|
version: 5.1.4(typescript@5.7.3)(vite@6.3.5(@types/node@24.0.7)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0))
|
||||||
|
yup:
|
||||||
|
specifier: ^1.6.1
|
||||||
|
version: 1.6.1
|
||||||
zustand:
|
zustand:
|
||||||
specifier: ^5.0.3
|
specifier: ^5.0.3
|
||||||
version: 5.0.5(@types/react@19.1.6)(immer@9.0.21)(react@19.1.0)(use-sync-external-store@1.5.0(react@19.1.0))
|
version: 5.0.5(@types/react@19.1.6)(immer@9.0.21)(react@19.1.0)(use-sync-external-store@1.5.0(react@19.1.0))
|
||||||
@@ -465,6 +474,11 @@ packages:
|
|||||||
'@gerrit0/mini-shiki@3.7.0':
|
'@gerrit0/mini-shiki@3.7.0':
|
||||||
resolution: {integrity: sha512-7iY9wg4FWXmeoFJpUL2u+tsmh0d0jcEJHAIzVxl3TG4KL493JNnisdLAILZ77zcD+z3J0keEXZ+lFzUgzQzPDg==}
|
resolution: {integrity: sha512-7iY9wg4FWXmeoFJpUL2u+tsmh0d0jcEJHAIzVxl3TG4KL493JNnisdLAILZ77zcD+z3J0keEXZ+lFzUgzQzPDg==}
|
||||||
|
|
||||||
|
'@hookform/resolvers@5.1.1':
|
||||||
|
resolution: {integrity: sha512-J/NVING3LMAEvexJkyTLjruSm7aOFx7QX21pzkiJfMoNG0wl5aFEjLTl7ay7IQb9EWY6AkrBy7tHL2Alijpdcg==}
|
||||||
|
peerDependencies:
|
||||||
|
react-hook-form: ^7.55.0
|
||||||
|
|
||||||
'@humanfs/core@0.19.1':
|
'@humanfs/core@0.19.1':
|
||||||
resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
|
resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
|
||||||
engines: {node: '>=18.18.0'}
|
engines: {node: '>=18.18.0'}
|
||||||
@@ -867,6 +881,9 @@ packages:
|
|||||||
'@shikijs/vscode-textmate@10.0.2':
|
'@shikijs/vscode-textmate@10.0.2':
|
||||||
resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==}
|
resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==}
|
||||||
|
|
||||||
|
'@standard-schema/utils@0.3.0':
|
||||||
|
resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==}
|
||||||
|
|
||||||
'@stoplight/better-ajv-errors@1.0.3':
|
'@stoplight/better-ajv-errors@1.0.3':
|
||||||
resolution: {integrity: sha512-0p9uXkuB22qGdNfy3VeEhxkU5uwvp/KrBTAbrLBURv6ilxIVwanKwjMc41lQfIVgPGcOkmLbTolfFrSsueu7zA==}
|
resolution: {integrity: sha512-0p9uXkuB22qGdNfy3VeEhxkU5uwvp/KrBTAbrLBURv6ilxIVwanKwjMc41lQfIVgPGcOkmLbTolfFrSsueu7zA==}
|
||||||
engines: {node: ^12.20 || >= 14.13}
|
engines: {node: ^12.20 || >= 14.13}
|
||||||
@@ -2408,6 +2425,9 @@ packages:
|
|||||||
prop-types@15.8.1:
|
prop-types@15.8.1:
|
||||||
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
|
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
|
||||||
|
|
||||||
|
property-expr@2.0.6:
|
||||||
|
resolution: {integrity: sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==}
|
||||||
|
|
||||||
proxy-from-env@1.1.0:
|
proxy-from-env@1.1.0:
|
||||||
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
|
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
|
||||||
|
|
||||||
@@ -2463,6 +2483,12 @@ packages:
|
|||||||
react: '>=16.8.0'
|
react: '>=16.8.0'
|
||||||
react-dom: '>=16.8.0'
|
react-dom: '>=16.8.0'
|
||||||
|
|
||||||
|
react-hook-form@7.60.0:
|
||||||
|
resolution: {integrity: sha512-SBrYOvMbDB7cV8ZfNpaiLcgjH/a1c7aK0lK+aNigpf4xWLO8q+o4tcvVurv3c4EOyzn/3dCsYt4GKD42VvJ/+A==}
|
||||||
|
engines: {node: '>=18.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.8.0 || ^17 || ^18 || ^19
|
||||||
|
|
||||||
react-i18next@15.5.2:
|
react-i18next@15.5.2:
|
||||||
resolution: {integrity: sha512-ePODyXgmZQAOYTbZXQn5rRsSBu3Gszo69jxW6aKmlSgxKAI1fOhDwSu6bT4EKHciWPKQ7v7lPrjeiadR6Gi+1A==}
|
resolution: {integrity: sha512-ePODyXgmZQAOYTbZXQn5rRsSBu3Gszo69jxW6aKmlSgxKAI1fOhDwSu6bT4EKHciWPKQ7v7lPrjeiadR6Gi+1A==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -2782,6 +2808,9 @@ packages:
|
|||||||
three@0.177.0:
|
three@0.177.0:
|
||||||
resolution: {integrity: sha512-EiXv5/qWAaGI+Vz2A+JfavwYCMdGjxVsrn3oBwllUoqYeaBO75J63ZfyaQKoiLrqNHoTlUc6PFgMXnS0kI45zg==}
|
resolution: {integrity: sha512-EiXv5/qWAaGI+Vz2A+JfavwYCMdGjxVsrn3oBwllUoqYeaBO75J63ZfyaQKoiLrqNHoTlUc6PFgMXnS0kI45zg==}
|
||||||
|
|
||||||
|
tiny-case@1.0.3:
|
||||||
|
resolution: {integrity: sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==}
|
||||||
|
|
||||||
tinyglobby@0.2.14:
|
tinyglobby@0.2.14:
|
||||||
resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==}
|
resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
@@ -2790,6 +2819,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
|
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
|
||||||
engines: {node: '>=8.0'}
|
engines: {node: '>=8.0'}
|
||||||
|
|
||||||
|
toposort@2.0.2:
|
||||||
|
resolution: {integrity: sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==}
|
||||||
|
|
||||||
tr46@0.0.3:
|
tr46@0.0.3:
|
||||||
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
|
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
|
||||||
|
|
||||||
@@ -2848,6 +2880,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
|
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
|
|
||||||
|
type-fest@2.19.0:
|
||||||
|
resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==}
|
||||||
|
engines: {node: '>=12.20'}
|
||||||
|
|
||||||
typed-array-buffer@1.0.3:
|
typed-array-buffer@1.0.3:
|
||||||
resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==}
|
resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -3057,6 +3093,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
|
yup@1.6.1:
|
||||||
|
resolution: {integrity: sha512-JED8pB50qbA4FOkDol0bYF/p60qSEDQqBD0/qeIrUCG1KbPBIQ776fCUNb9ldbPcSTxA69g/47XTo4TqWiuXOA==}
|
||||||
|
|
||||||
zustand@4.5.7:
|
zustand@4.5.7:
|
||||||
resolution: {integrity: sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==}
|
resolution: {integrity: sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==}
|
||||||
engines: {node: '>=12.7.0'}
|
engines: {node: '>=12.7.0'}
|
||||||
@@ -3365,6 +3404,11 @@ snapshots:
|
|||||||
'@shikijs/types': 3.7.0
|
'@shikijs/types': 3.7.0
|
||||||
'@shikijs/vscode-textmate': 10.0.2
|
'@shikijs/vscode-textmate': 10.0.2
|
||||||
|
|
||||||
|
'@hookform/resolvers@5.1.1(react-hook-form@7.60.0(react@19.1.0))':
|
||||||
|
dependencies:
|
||||||
|
'@standard-schema/utils': 0.3.0
|
||||||
|
react-hook-form: 7.60.0(react@19.1.0)
|
||||||
|
|
||||||
'@humanfs/core@0.19.1': {}
|
'@humanfs/core@0.19.1': {}
|
||||||
|
|
||||||
'@humanfs/node@0.16.6':
|
'@humanfs/node@0.16.6':
|
||||||
@@ -3797,6 +3841,8 @@ snapshots:
|
|||||||
|
|
||||||
'@shikijs/vscode-textmate@10.0.2': {}
|
'@shikijs/vscode-textmate@10.0.2': {}
|
||||||
|
|
||||||
|
'@standard-schema/utils@0.3.0': {}
|
||||||
|
|
||||||
'@stoplight/better-ajv-errors@1.0.3(ajv@8.17.1)':
|
'@stoplight/better-ajv-errors@1.0.3(ajv@8.17.1)':
|
||||||
dependencies:
|
dependencies:
|
||||||
ajv: 8.17.1
|
ajv: 8.17.1
|
||||||
@@ -5506,6 +5552,8 @@ snapshots:
|
|||||||
object-assign: 4.1.1
|
object-assign: 4.1.1
|
||||||
react-is: 16.13.1
|
react-is: 16.13.1
|
||||||
|
|
||||||
|
property-expr@2.0.6: {}
|
||||||
|
|
||||||
proxy-from-env@1.1.0: {}
|
proxy-from-env@1.1.0: {}
|
||||||
|
|
||||||
punycode.js@2.3.1: {}
|
punycode.js@2.3.1: {}
|
||||||
@@ -5566,6 +5614,10 @@ snapshots:
|
|||||||
react: 19.1.0
|
react: 19.1.0
|
||||||
react-dom: 19.1.0(react@19.1.0)
|
react-dom: 19.1.0(react@19.1.0)
|
||||||
|
|
||||||
|
react-hook-form@7.60.0(react@19.1.0):
|
||||||
|
dependencies:
|
||||||
|
react: 19.1.0
|
||||||
|
|
||||||
react-i18next@15.5.2(i18next@25.2.1(typescript@5.7.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.7.3):
|
react-i18next@15.5.2(i18next@25.2.1(typescript@5.7.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.7.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.27.3
|
'@babel/runtime': 7.27.3
|
||||||
@@ -5932,6 +5984,8 @@ snapshots:
|
|||||||
|
|
||||||
three@0.177.0: {}
|
three@0.177.0: {}
|
||||||
|
|
||||||
|
tiny-case@1.0.3: {}
|
||||||
|
|
||||||
tinyglobby@0.2.14:
|
tinyglobby@0.2.14:
|
||||||
dependencies:
|
dependencies:
|
||||||
fdir: 6.4.4(picomatch@4.0.2)
|
fdir: 6.4.4(picomatch@4.0.2)
|
||||||
@@ -5941,6 +5995,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
is-number: 7.0.0
|
is-number: 7.0.0
|
||||||
|
|
||||||
|
toposort@2.0.2: {}
|
||||||
|
|
||||||
tr46@0.0.3: {}
|
tr46@0.0.3: {}
|
||||||
|
|
||||||
troika-three-text@0.52.4(three@0.177.0):
|
troika-three-text@0.52.4(three@0.177.0):
|
||||||
@@ -5987,6 +6043,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
prelude-ls: 1.2.1
|
prelude-ls: 1.2.1
|
||||||
|
|
||||||
|
type-fest@2.19.0: {}
|
||||||
|
|
||||||
typed-array-buffer@1.0.3:
|
typed-array-buffer@1.0.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bound: 1.0.4
|
call-bound: 1.0.4
|
||||||
@@ -6196,6 +6254,13 @@ snapshots:
|
|||||||
|
|
||||||
yocto-queue@0.1.0: {}
|
yocto-queue@0.1.0: {}
|
||||||
|
|
||||||
|
yup@1.6.1:
|
||||||
|
dependencies:
|
||||||
|
property-expr: 2.0.6
|
||||||
|
tiny-case: 1.0.3
|
||||||
|
toposort: 2.0.2
|
||||||
|
type-fest: 2.19.0
|
||||||
|
|
||||||
zustand@4.5.7(@types/react@19.1.6)(immer@9.0.21)(react@19.1.0):
|
zustand@4.5.7(@types/react@19.1.6)(immer@9.0.21)(react@19.1.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
use-sync-external-store: 1.5.0(react@19.1.0)
|
use-sync-external-store: 1.5.0(react@19.1.0)
|
||||||
|
|||||||
+56
-2
@@ -12,6 +12,15 @@ import NewMessage from './components/newMessage/NewMessage';
|
|||||||
import { QueryCache, QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
import { QueryCache, QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||||
import { IApiErrorRepsonse } from './types/error.types';
|
import { IApiErrorRepsonse } from './types/error.types';
|
||||||
import ToastContainer from './components/Toast';
|
import ToastContainer from './components/Toast';
|
||||||
|
import { getRefreshToken, removeRefreshToken, removeToken, setRefreshToken, setToken } from './config/func';
|
||||||
|
import { refreshToken } from './pages/auth/service/Service';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
isRefreshingToken?: boolean;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
i18next.init({
|
i18next.init({
|
||||||
interpolation: { escapeValue: false },
|
interpolation: { escapeValue: false },
|
||||||
lng: 'fa',
|
lng: 'fa',
|
||||||
@@ -26,9 +35,54 @@ i18next.init({
|
|||||||
const queryClient = new QueryClient({
|
const queryClient = new QueryClient({
|
||||||
queryCache: new QueryCache({
|
queryCache: new QueryCache({
|
||||||
onError: async (error: IApiErrorRepsonse) => {
|
onError: async (error: IApiErrorRepsonse) => {
|
||||||
if (error?.response?.statusCode === 401) {
|
if (error?.response?.status === 401) {
|
||||||
console.log(401);
|
try {
|
||||||
|
// Use a flag to track if refresh is in progress
|
||||||
|
if (window.isRefreshingToken) {
|
||||||
|
// Wait for the refresh to complete
|
||||||
|
await new Promise(resolve => {
|
||||||
|
const checkComplete = setInterval(() => {
|
||||||
|
if (!window.isRefreshingToken) {
|
||||||
|
clearInterval(checkComplete);
|
||||||
|
resolve(true);
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the flag to indicate refresh is in progress
|
||||||
|
window.isRefreshingToken = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const refreshTokenValue = await getRefreshToken();
|
||||||
|
const { data } = await refreshToken({ refreshToken: refreshTokenValue || '' });
|
||||||
|
|
||||||
|
if (data?.accessToken?.token) {
|
||||||
|
// Save the new token
|
||||||
|
await setToken(data?.accessToken?.token);
|
||||||
|
|
||||||
|
// If refresh token also returned, update it
|
||||||
|
if (data.refreshToken?.token) {
|
||||||
|
await setRefreshToken(data.refreshToken?.token);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retry the failed request
|
||||||
|
queryClient.invalidateQueries();
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid token response');
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
window.isRefreshingToken = false;
|
||||||
|
}
|
||||||
|
} catch (refreshError: unknown) {
|
||||||
|
console.error('Token refresh failed:', refreshError);
|
||||||
|
// Clear tokens and redirect to login
|
||||||
|
await removeToken();
|
||||||
|
await removeRefreshToken();
|
||||||
|
window.location.href = '/auth/login';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -59,3 +59,8 @@ export const timeAgo = (date: string | Date): string => {
|
|||||||
|
|
||||||
return "همین الان";
|
return "همین الان";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const convertToGB = (bytes: number): string => {
|
||||||
|
const GB = bytes / (1024 * 1024 * 1024);
|
||||||
|
return GB.toFixed(2);
|
||||||
|
};
|
||||||
|
|||||||
+6
-1
@@ -17,6 +17,9 @@
|
|||||||
"header": {
|
"header": {
|
||||||
"search": "جستجو"
|
"search": "جستجو"
|
||||||
},
|
},
|
||||||
|
"errors": {
|
||||||
|
"required": "این فیلد اجباری است"
|
||||||
|
},
|
||||||
"received": {
|
"received": {
|
||||||
"title": "دریافتی ها",
|
"title": "دریافتی ها",
|
||||||
"from_date": "از تاریخ",
|
"from_date": "از تاریخ",
|
||||||
@@ -116,7 +119,9 @@
|
|||||||
"signature_description": "تصویر و توضیحات امضای خود را با دقت وارد کنید",
|
"signature_description": "تصویر و توضیحات امضای خود را با دقت وارد کنید",
|
||||||
"upload_sign": "آپلود امضا",
|
"upload_sign": "آپلود امضا",
|
||||||
"description_sign": "توضیحات امضا",
|
"description_sign": "توضیحات امضا",
|
||||||
"select_section": "لطفا یک بخش انتخاب کنید"
|
"select_section": "لطفا یک بخش انتخاب کنید",
|
||||||
|
"title1": "عنوان",
|
||||||
|
"quota": "فضا/ استفاده شده "
|
||||||
},
|
},
|
||||||
"domain": {
|
"domain": {
|
||||||
"table": {
|
"table": {
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import axiosDanak from "@/config/axiosDanak";
|
||||||
|
import { RefreshTokenType } from "../types/Types";
|
||||||
|
|
||||||
|
export const refreshToken = async (params: RefreshTokenType) => {
|
||||||
|
const { data } = await axiosDanak.post(`/auth/refresh`, params);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export type RefreshTokenType = {
|
||||||
|
refreshToken: string;
|
||||||
|
};
|
||||||
@@ -1,54 +1,47 @@
|
|||||||
import Input from '@/components/Input'
|
import Input from '@/components/Input'
|
||||||
import Select from '@/components/Select'
|
import Select from '@/components/Select'
|
||||||
import Table from '@/components/Table'
|
import Table from '@/components/Table'
|
||||||
import { Switch } from "@/components/ui/switch"
|
|
||||||
import { ColumnType } from '@/components/types/TableTypes'
|
import { ColumnType } from '@/components/types/TableTypes'
|
||||||
import { FC, useState } from 'react'
|
import { FC, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import Button from '@/components/Button'
|
import Button from '@/components/Button'
|
||||||
import { TickCircle } from 'iconsax-react'
|
import { TickCircle } from 'iconsax-react'
|
||||||
|
import { useForm } from 'react-hook-form'
|
||||||
|
import { AddressData, CreateAddressType } from './types/Types'
|
||||||
|
import { useGetDomains } from '../domain/hooks/useDomainData'
|
||||||
|
import { yupResolver } from "@hookform/resolvers/yup"
|
||||||
|
import * as yup from "yup"
|
||||||
|
import { useCreateAddress, useGetAddress } from './hooks/useAddressData'
|
||||||
|
import { toast } from '@/components/Toast'
|
||||||
|
import { ErrorType } from '@/helpers/types'
|
||||||
|
import ProgressBarEmail from './components/ProgressBarEmail'
|
||||||
|
import ToggleStatus from './components/ToggleStatus'
|
||||||
|
|
||||||
|
|
||||||
interface AddressData extends Record<string, unknown> {
|
|
||||||
id: number
|
|
||||||
title: string
|
|
||||||
email: string
|
|
||||||
status: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
const Address: FC = () => {
|
const Address: FC = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const [addresses] = useState<AddressData[]>([
|
|
||||||
{
|
const schema = yup.object().shape({
|
||||||
id: 1,
|
title: yup.string().required(t('errors.required')),
|
||||||
title: 'بازاریابی',
|
username: yup.string().required(t('errors.required')),
|
||||||
email: 'Marketing@example.com',
|
password: yup.string().required(t('errors.required')),
|
||||||
status: true
|
domainId: yup.string().required(t('errors.required')),
|
||||||
},
|
})
|
||||||
{
|
|
||||||
id: 2,
|
const [search, setSearch] = useState<string>('')
|
||||||
title: 'بازاریابی',
|
const [status, setStatus] = useState<string>('all')
|
||||||
email: 'Marketing@example.com',
|
|
||||||
status: true
|
const { data: domain } = useGetDomains()
|
||||||
},
|
const { mutate: createAddress, isPending } = useCreateAddress()
|
||||||
{
|
const { data: addresses, isPending: isPendingAddress } = useGetAddress(search, status)
|
||||||
id: 3,
|
const { register, handleSubmit, formState: { errors },
|
||||||
title: 'بازاریابی',
|
} = useForm<CreateAddressType>({
|
||||||
email: 'Marketing@example.com',
|
resolver: yupResolver(schema),
|
||||||
status: true
|
defaultValues: {
|
||||||
},
|
domainId: domain?.data?.domain?.id || '',
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
title: 'بازاریابی',
|
|
||||||
email: 'Marketing@example.com',
|
|
||||||
status: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 5,
|
|
||||||
title: 'بازاریابی',
|
|
||||||
email: 'Marketing@example.com',
|
|
||||||
status: true
|
|
||||||
}
|
}
|
||||||
])
|
})
|
||||||
|
|
||||||
const columns: ColumnType<AddressData>[] = [
|
const columns: ColumnType<AddressData>[] = [
|
||||||
{
|
{
|
||||||
@@ -59,7 +52,23 @@ const Address: FC = () => {
|
|||||||
{
|
{
|
||||||
title: t('setting.email'),
|
title: t('setting.email'),
|
||||||
key: 'email',
|
key: 'email',
|
||||||
width: '300px'
|
width: '300px',
|
||||||
|
render: (item: AddressData) => (
|
||||||
|
<div key={item.id} className='dltr flex justify-end'>
|
||||||
|
{item.emailAddress}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('setting.quota'),
|
||||||
|
key: 'quota',
|
||||||
|
width: '300px',
|
||||||
|
render: (item: AddressData) => {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ProgressBarEmail key={item.id} item={item} />
|
||||||
|
)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t('setting.status'),
|
title: t('setting.status'),
|
||||||
@@ -68,7 +77,7 @@ const Address: FC = () => {
|
|||||||
align: 'center',
|
align: 'center',
|
||||||
render: (item: AddressData) => (
|
render: (item: AddressData) => (
|
||||||
<div key={item.id} className='dltr flex justify-end'>
|
<div key={item.id} className='dltr flex justify-end'>
|
||||||
<Switch />
|
<ToggleStatus defaultStatus={item.isActive} id={item.id} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -80,6 +89,17 @@ const Address: FC = () => {
|
|||||||
{ value: 'inactive', label: t('setting.inactive') }
|
{ value: 'inactive', label: t('setting.inactive') }
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const onSubmit = (params: CreateAddressType) => {
|
||||||
|
createAddress(params, {
|
||||||
|
onSuccess: (data) => {
|
||||||
|
toast(data?.data?.message, 'success')
|
||||||
|
},
|
||||||
|
onError: (error: ErrorType) => {
|
||||||
|
toast(error.response?.data?.error?.message[0], 'error')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex xl:flex-row flex-col-reverse gap-8 mt-8'>
|
<div className='flex xl:flex-row flex-col-reverse gap-8 mt-8'>
|
||||||
<div className='flex-1'>
|
<div className='flex-1'>
|
||||||
@@ -89,6 +109,7 @@ const Address: FC = () => {
|
|||||||
placeholder={t('setting.status')}
|
placeholder={t('setting.status')}
|
||||||
items={statusOptions}
|
items={statusOptions}
|
||||||
className='w-[120px]'
|
className='w-[120px]'
|
||||||
|
onChange={(e) => setStatus(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -97,13 +118,15 @@ const Address: FC = () => {
|
|||||||
variant='search'
|
variant='search'
|
||||||
placeholder={t('setting.search')}
|
placeholder={t('setting.search')}
|
||||||
className='xl:w-[300px] flex-1'
|
className='xl:w-[300px] flex-1'
|
||||||
|
onChangeSearchFinal={(e) => setSearch(e)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Table
|
<Table
|
||||||
|
isLoading={isPendingAddress}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
data={addresses}
|
data={addresses?.data?.users}
|
||||||
pagination={{
|
pagination={{
|
||||||
currentPage: 1,
|
currentPage: 1,
|
||||||
totalPages: 6,
|
totalPages: 6,
|
||||||
@@ -117,26 +140,28 @@ const Address: FC = () => {
|
|||||||
{t('setting.add_address')}
|
{t('setting.add_address')}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='mt-8 flex items-center justify-between'>
|
{/* <div className='mt-8 flex items-center justify-between'>
|
||||||
<div>
|
<div>
|
||||||
{t('setting.status')}
|
{t('setting.status')}
|
||||||
</div>
|
</div>
|
||||||
<div className='dltr pt-2'>
|
<div className='dltr pt-2'>
|
||||||
<Switch />
|
<Switch />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div> */}
|
||||||
|
|
||||||
<div className='mt-6'>
|
<div className='mt-6'>
|
||||||
<Input
|
<Input
|
||||||
label={t('setting.domain1')}
|
label={t('setting.domain1')}
|
||||||
value={'example.com'}
|
value={domain?.data?.domain?.name}
|
||||||
readOnly
|
readOnly
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='mt-6'>
|
<div className='mt-6'>
|
||||||
<Input
|
<Input
|
||||||
label={t('setting.title')}
|
label={t('setting.title1')}
|
||||||
|
{...register('title')}
|
||||||
|
error_text={errors.title?.message}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -144,9 +169,11 @@ const Address: FC = () => {
|
|||||||
<Input
|
<Input
|
||||||
label={t('setting.username')}
|
label={t('setting.username')}
|
||||||
className='text-left'
|
className='text-left'
|
||||||
|
{...register('username')}
|
||||||
|
error_text={errors.username?.message}
|
||||||
/>
|
/>
|
||||||
<div className='absolute flex items-center dltr text-xs z-10 right-[1px] top-[29px] rounded-r-2.5 h-[38px] bg-[#EBEEF5] px-3'>
|
<div className='absolute flex items-center dltr text-xs z-10 right-[1px] top-[29px] rounded-r-2.5 h-[38px] bg-[#EBEEF5] px-3'>
|
||||||
@ example.com
|
@ {domain?.data?.domain?.name}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -154,6 +181,8 @@ const Address: FC = () => {
|
|||||||
<Input
|
<Input
|
||||||
label={t('setting.password')}
|
label={t('setting.password')}
|
||||||
type='password'
|
type='password'
|
||||||
|
{...register('password')}
|
||||||
|
error_text={errors.password?.message}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -170,6 +199,8 @@ const Address: FC = () => {
|
|||||||
<div className='mt-9 flex justify-end'>
|
<div className='mt-9 flex justify-end'>
|
||||||
<Button
|
<Button
|
||||||
className='w-fit px-20'
|
className='w-fit px-20'
|
||||||
|
onClick={handleSubmit(onSubmit)}
|
||||||
|
loading={isPending}
|
||||||
>
|
>
|
||||||
<div className='flex gap-2'>
|
<div className='flex gap-2'>
|
||||||
<TickCircle size={20} color='white' />
|
<TickCircle size={20} color='white' />
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import { convertToGB } from '@/config/func'
|
||||||
|
import { FC } from 'react'
|
||||||
|
import { AddressData } from '../types/Types'
|
||||||
|
|
||||||
|
const ProgressBarEmail: FC<{ item: AddressData }> = ({ item }) => {
|
||||||
|
const usedQuota = item.emailQuotaUsed || 0;
|
||||||
|
const totalQuota = item.emailQuota || 0;
|
||||||
|
const percentage = Math.min((usedQuota / totalQuota) * 100, 100);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='flex flex-col gap-2'>
|
||||||
|
<div className='flex justify-between text-sm'>
|
||||||
|
<span className='text-gray-600 dltr'>
|
||||||
|
{convertToGB(usedQuota)} GB / {convertToGB(totalQuota)} GB
|
||||||
|
</span>
|
||||||
|
{/* <span className='text-gray-500'>
|
||||||
|
{percentage.toFixed(1)}%
|
||||||
|
</span> */}
|
||||||
|
</div>
|
||||||
|
<div className='w-full bg-gray-200 dltr overflow-hidden rounded-full h-2'>
|
||||||
|
<div
|
||||||
|
className={`h-2 rounded-full transition-all duration-300 ${percentage > 90 ? 'bg-red-500' :
|
||||||
|
percentage > 70 ? 'bg-yellow-500' :
|
||||||
|
'bg-green-500'
|
||||||
|
}`}
|
||||||
|
style={{ width: `${percentage}%` }}
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ProgressBarEmail
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { Switch } from '@/components/ui/switch'
|
||||||
|
import { FC, useState } from 'react'
|
||||||
|
import { useToggleStatus } from '../hooks/useAddressData'
|
||||||
|
|
||||||
|
const ToggleStatus: FC<{ defaultStatus: boolean, id: string }> = ({ defaultStatus, id }) => {
|
||||||
|
const [isActive, setIsActive] = useState(defaultStatus)
|
||||||
|
const { mutate: toggleStatus } = useToggleStatus()
|
||||||
|
|
||||||
|
const handleToggleStatus = () => {
|
||||||
|
toggleStatus(id)
|
||||||
|
setIsActive(!isActive)
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Switch checked={isActive} onCheckedChange={handleToggleStatus} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ToggleStatus
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||||
|
import * as api from "../service/Service";
|
||||||
|
import { useQueryClient } from "@tanstack/react-query";
|
||||||
|
|
||||||
|
export const useGetAddress = (search: string, status: string) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ["address", search, status],
|
||||||
|
queryFn: () => api.getAddress(search, status),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useCreateAddress = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: api.createAddress,
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ["address"] });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useToggleStatus = () => {
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: api.toggleStatus,
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import axios from "@/config/axios";
|
||||||
|
import { CreateAddressType } from "../types/Types";
|
||||||
|
|
||||||
|
export const getAddress = async (search: string, status: string) => {
|
||||||
|
const query = new URLSearchParams();
|
||||||
|
if (search) query.set("q", search);
|
||||||
|
if (status && status !== "all")
|
||||||
|
query.set("isActive", status === "active" ? "1" : "0");
|
||||||
|
const { data } = await axios.get(`/users?${query.toString()}`);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createAddress = async (params: CreateAddressType) => {
|
||||||
|
const { data } = await axios.post(`/users`, params);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const toggleStatus = async (id: string) => {
|
||||||
|
const { data } = await axios.patch(`/users/${id}/toggle-status`);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
export type CreateAddressType = {
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
domainId: string;
|
||||||
|
title: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface AddressData extends Record<string, unknown> {
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
deletedAt: string | null;
|
||||||
|
title: string;
|
||||||
|
userName: string;
|
||||||
|
password: string;
|
||||||
|
emailAddress: string;
|
||||||
|
emailEnabled: boolean;
|
||||||
|
emailQuota: number;
|
||||||
|
emailQuotaUsed: number;
|
||||||
|
emailAccountId: string;
|
||||||
|
displayName: string;
|
||||||
|
isActive: boolean;
|
||||||
|
emailSignature: string | null;
|
||||||
|
role: string;
|
||||||
|
business: {
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
deletedAt: string | null;
|
||||||
|
danakSubscriptionId: string;
|
||||||
|
name: string;
|
||||||
|
slug: string;
|
||||||
|
logoUrl: string | null;
|
||||||
|
domain: string;
|
||||||
|
};
|
||||||
|
domain: {
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
deletedAt: string | null;
|
||||||
|
name: string;
|
||||||
|
status: string;
|
||||||
|
isVerified: boolean;
|
||||||
|
isActive: boolean;
|
||||||
|
verifiedAt: string;
|
||||||
|
lastCheckedAt: string | null;
|
||||||
|
notes: string;
|
||||||
|
dkimEnabled: boolean;
|
||||||
|
dkimSelector: string;
|
||||||
|
dkimPrivateKey: string;
|
||||||
|
dkimPublicKey: string;
|
||||||
|
spfEnabled: boolean;
|
||||||
|
spfRecord: string | null;
|
||||||
|
dmarcEnabled: boolean;
|
||||||
|
dmarcPolicy: string | null;
|
||||||
|
business: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -19,11 +19,11 @@ const Signture: FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='flex-1 mt-5 xl:mt-0'>
|
<div className='flex-1 mt-4 xl:mt-0'>
|
||||||
<UploadBox
|
<UploadBox
|
||||||
label={t('setting.upload_sign')}
|
label={t('setting.upload_sign')}
|
||||||
/>
|
/>
|
||||||
<div className='xl:mt-8'>
|
<div className='xl:mt-8 mt-5'>
|
||||||
<Textarea
|
<Textarea
|
||||||
label={t('setting.description_sign')}
|
label={t('setting.description_sign')}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
export interface IBaseResponse {
|
export interface IBaseResponse {
|
||||||
statusCode: number;
|
status: number;
|
||||||
success: boolean;
|
success: boolean;
|
||||||
}
|
}
|
||||||
export interface IResponse<T> extends IBaseResponse {
|
export interface IResponse<T> extends IBaseResponse {
|
||||||
|
|||||||
Reference in New Issue
Block a user