From a93ce1a31c56d2104577759d2c155d0ce1918c8b Mon Sep 17 00:00:00 2001 From: ghoon99 Date: Thu, 10 Oct 2024 11:22:08 +0900 Subject: [PATCH] =?UTF-8?q?config:=20=ED=8F=B4=EB=8D=94=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=20=EC=84=B8=ED=8C=85,=20style=20=EC=84=B8=ED=8C=85=20?= =?UTF-8?q?=EB=B0=8F=20react=20query=20jotai=20=EC=84=A4=EC=B9=98=20?= =?UTF-8?q?=EB=93=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 334 ++++++++++++------ package.json | 12 +- src/configs/http-client/axios.config.ts | 95 +++++ src/configs/http-client/httpClient.ts | 23 ++ src/configs/http-client/httpErrors.ts | 69 ++++ src/configs/http-client/index.ts | 1 + src/configs/http-client/pageParam.ts | 8 + src/configs/react/libs/ReactToastify.tsx | 3 + src/configs/react/providers/QueryProvider.tsx | 45 +++ src/configs/react/stores/store.ts | 4 + src/features/users/models/user.ts | 5 + src/features/users/models/userLoginDto.ts | 4 + src/features/users/models/userRegisterDto.ts | 5 + src/features/users/models/validationErrors.ts | 5 + src/features/users/models/validationPolicy.ts | 3 + .../services/remotes/checkLoginRequest.ts | 5 + .../services/remotes/sendLoginRequest.ts | 8 + .../services/remotes/sendLogoutRequest.ts | 5 + .../users/services/validatePasswordInput.ts | 12 + .../users/services/validateUserIdInput.ts | 5 + .../users/services/validateUserNameInput.ts | 5 + .../users/ui/components/CardLayout.tsx | 9 + .../users/ui/hooks/useLoginFormState.ts | 33 ++ src/features/users/ui/hooks/useLoginQuery.ts | 12 + src/features/users/ui/screen/LoginScreen.tsx | 15 + .../users/ui/screen/RegisterScreen.tsx | 0 src/main.tsx | 16 +- src/pages/routes.ts | 1 + src/store/store.ts | 23 -- src/styles/GlobalStyles.tsx | 13 + src/styles/colors/backgrounds.ts | 9 + src/styles/colors/borders.ts | 8 + src/styles/colors/buttons.ts | 17 + src/styles/colors/dims.ts | 12 + src/styles/colors/index.ts | 7 + src/styles/colors/shadows.ts | 10 + src/styles/colors/texts.ts | 12 + src/styles/keyframes/fades.ts | 19 + src/styles/keyframes/index.ts | 1 + src/styles/keyframes/slides.ts | 23 ++ src/styles/miniReset.ts | 72 ++++ src/styles/pallete/pallete.ts | 162 +++++++++ src/styles/styled.d.ts | 7 + src/styles/theme.ts | 21 ++ src/ui/assets/icons/Icon.tsx | 0 src/ui/components/Button/Button.tsx | 0 src/utils/functions/dateUtils.ts | 10 + src/utils/functions/delay.ts | 5 + src/utils/functions/getRandomNumber.ts | 3 + src/utils/react/hooks/useBooleanToggle.ts | 6 + src/utils/react/hooks/useInputState.ts | 11 + src/utils/types/utilTypes.ts | 15 + tsconfig.app.json | 10 +- 53 files changed, 1053 insertions(+), 165 deletions(-) create mode 100644 src/configs/http-client/axios.config.ts create mode 100644 src/configs/http-client/httpClient.ts create mode 100644 src/configs/http-client/httpErrors.ts create mode 100644 src/configs/http-client/index.ts create mode 100644 src/configs/http-client/pageParam.ts create mode 100644 src/configs/react/libs/ReactToastify.tsx create mode 100644 src/configs/react/providers/QueryProvider.tsx create mode 100644 src/configs/react/stores/store.ts create mode 100644 src/features/users/models/user.ts create mode 100644 src/features/users/models/userLoginDto.ts create mode 100644 src/features/users/models/userRegisterDto.ts create mode 100644 src/features/users/models/validationErrors.ts create mode 100644 src/features/users/models/validationPolicy.ts create mode 100644 src/features/users/services/remotes/checkLoginRequest.ts create mode 100644 src/features/users/services/remotes/sendLoginRequest.ts create mode 100644 src/features/users/services/remotes/sendLogoutRequest.ts create mode 100644 src/features/users/services/validatePasswordInput.ts create mode 100644 src/features/users/services/validateUserIdInput.ts create mode 100644 src/features/users/services/validateUserNameInput.ts create mode 100644 src/features/users/ui/components/CardLayout.tsx create mode 100644 src/features/users/ui/hooks/useLoginFormState.ts create mode 100644 src/features/users/ui/hooks/useLoginQuery.ts create mode 100644 src/features/users/ui/screen/LoginScreen.tsx create mode 100644 src/features/users/ui/screen/RegisterScreen.tsx create mode 100644 src/pages/routes.ts delete mode 100644 src/store/store.ts create mode 100644 src/styles/GlobalStyles.tsx create mode 100644 src/styles/colors/backgrounds.ts create mode 100644 src/styles/colors/borders.ts create mode 100644 src/styles/colors/buttons.ts create mode 100644 src/styles/colors/dims.ts create mode 100644 src/styles/colors/index.ts create mode 100644 src/styles/colors/shadows.ts create mode 100644 src/styles/colors/texts.ts create mode 100644 src/styles/keyframes/fades.ts create mode 100644 src/styles/keyframes/index.ts create mode 100644 src/styles/keyframes/slides.ts create mode 100644 src/styles/miniReset.ts create mode 100644 src/styles/pallete/pallete.ts create mode 100644 src/styles/styled.d.ts create mode 100644 src/styles/theme.ts create mode 100644 src/ui/assets/icons/Icon.tsx create mode 100644 src/ui/components/Button/Button.tsx create mode 100644 src/utils/functions/dateUtils.ts create mode 100644 src/utils/functions/delay.ts create mode 100644 src/utils/functions/getRandomNumber.ts create mode 100644 src/utils/react/hooks/useBooleanToggle.ts create mode 100644 src/utils/react/hooks/useInputState.ts create mode 100644 src/utils/types/utilTypes.ts diff --git a/package-lock.json b/package-lock.json index 3f4e0f1..f9cfdff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,20 +8,19 @@ "name": "arom-fe", "version": "0.0.0", "dependencies": { - "@reduxjs/toolkit": "^2.2.8", + "@tanstack/react-query": "^5.59.8", + "@tanstack/react-query-devtools": "^5.59.8", "axios": "^1.7.7", + "jotai": "^2.10.0", "react": "^18.3.1", "react-dom": "^18.3.1", - "react-redux": "^9.1.2", "react-router-dom": "^6.26.2", - "redux-persist": "^6.0.0", - "styled-components": "^6.1.13", - "vite-plugin-svgr": "^4.2.0" + "styled-components": "^6.1.13" }, "devDependencies": { "@eslint/js": "^9.11.1", "@trivago/prettier-plugin-sort-imports": "^4.3.0", - "@types/node": "^22.7.5", + "@types/node": "^20", "@types/react": "^18.3.10", "@types/react-dom": "^18.3.0", "@types/styled-components": "^5.1.34", @@ -37,13 +36,19 @@ "prettier": "^3.3.3", "typescript": "^5.5.3", "typescript-eslint": "^8.7.0", - "vite": "^5.4.8" + "vite": "^5.4.8", + "vite-plugin-svgr": "^4.2.0" + }, + "engines": { + "node": ">=20", + "npm": ">=10" } }, "node_modules/@ampproject/remapping": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -57,6 +62,7 @@ "version": "7.25.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.25.7.tgz", "integrity": "sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g==", + "dev": true, "license": "MIT", "dependencies": { "@babel/highlight": "^7.25.7", @@ -70,6 +76,7 @@ "version": "7.25.7", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.7.tgz", "integrity": "sha512-9ickoLz+hcXCeh7jrcin+/SLWm+GkxE2kTvoYyp38p4WkdFXfQJxDFGWp/YHjiKLPx06z2A7W8XKuqbReXDzsw==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -79,6 +86,7 @@ "version": "7.25.7", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.7.tgz", "integrity": "sha512-yJ474Zv3cwiSOO9nXJuqzvwEeM+chDuQ8GJirw+pZ91sCGCyOZ3dJkVE09fTV0VEVzXyLWhh3G/AolYTPX7Mow==", + "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", @@ -109,6 +117,7 @@ "version": "7.25.7", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.7.tgz", "integrity": "sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.25.7", @@ -124,6 +133,7 @@ "version": "7.25.7", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.7.tgz", "integrity": "sha512-DniTEax0sv6isaw6qSQSfV4gVRNtw2rte8HHM45t9ZR0xILaufBRNkpMifCRiAPyvL4ACD6v0gfCwCmtOQaV4A==", + "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.25.7", @@ -180,6 +190,7 @@ "version": "7.25.7", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.7.tgz", "integrity": "sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.25.7", @@ -193,6 +204,7 @@ "version": "7.25.7", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.7.tgz", "integrity": "sha512-k/6f8dKG3yDz/qCwSM+RKovjMix563SLxQFo0UhRNo239SP6n9u5/eLtKD6EAjwta2JHJ49CsD8pms2HdNiMMQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.25.7", @@ -221,6 +233,7 @@ "version": "7.25.7", "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.7.tgz", "integrity": "sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.25.7", @@ -247,6 +260,7 @@ "version": "7.25.7", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz", "integrity": "sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -256,6 +270,7 @@ "version": "7.25.7", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz", "integrity": "sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -265,6 +280,7 @@ "version": "7.25.7", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.7.tgz", "integrity": "sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -274,6 +290,7 @@ "version": "7.25.7", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.7.tgz", "integrity": "sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.25.7", @@ -287,6 +304,7 @@ "version": "7.25.7", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.7.tgz", "integrity": "sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.25.7", @@ -302,6 +320,7 @@ "version": "7.25.7", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.7.tgz", "integrity": "sha512-aZn7ETtQsjjGG5HruveUK06cU3Hljuhd9Iojm4M8WWv3wLE6OkE5PWbDUkItmMgegmccaITudyuW5RPYrYlgWw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.25.7" @@ -349,6 +368,7 @@ "version": "7.25.7", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.7.tgz", "integrity": "sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.25.7", @@ -363,6 +383,7 @@ "version": "7.25.7", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.7.tgz", "integrity": "sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.25.7", @@ -381,6 +402,7 @@ "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -390,6 +412,7 @@ "version": "7.25.7", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.7.tgz", "integrity": "sha512-vwIVdXG+j+FOpkwqHRcBgHLYNL7XMkufrlaFvL9o6Ai9sJn9+PdyIL5qa0XzTZw084c+u9LOls53eoZWP/W5WQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.25.7", @@ -428,6 +451,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -444,6 +468,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -460,6 +485,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -476,6 +502,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -492,6 +519,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -508,6 +536,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -524,6 +553,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -540,6 +570,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -556,6 +587,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -572,6 +604,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -588,6 +621,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -604,6 +638,7 @@ "cpu": [ "loong64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -620,6 +655,7 @@ "cpu": [ "mips64el" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -636,6 +672,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -652,6 +689,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -668,6 +706,7 @@ "cpu": [ "s390x" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -684,6 +723,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -700,6 +740,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -716,6 +757,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -732,6 +774,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -748,6 +791,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -764,6 +808,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -780,6 +825,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -979,6 +1025,7 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.2.1", @@ -993,6 +1040,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -1002,6 +1050,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -1011,12 +1060,14 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, "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==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -1061,30 +1112,6 @@ "node": ">= 8" } }, - "node_modules/@reduxjs/toolkit": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.8.tgz", - "integrity": "sha512-eK/ieXftPRQfaBSmzsamXEyDwkntMTY0e9SG5ETsEOv5JIPKhu3mj992t6B8FJjlnSrZBAAqdT8oMkPe4j+P9g==", - "license": "MIT", - "dependencies": { - "immer": "^10.0.3", - "redux": "^5.0.1", - "redux-thunk": "^3.1.0", - "reselect": "^5.1.0" - }, - "peerDependencies": { - "react": "^16.9.0 || ^17.0.0 || ^18", - "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" - }, - "peerDependenciesMeta": { - "react": { - "optional": true - }, - "react-redux": { - "optional": true - } - } - }, "node_modules/@remix-run/router": { "version": "1.19.2", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.19.2.tgz", @@ -1098,6 +1125,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.2.tgz", "integrity": "sha512-/FIdS3PyZ39bjZlwqFnWqCOVnW7o963LtKMwQOD0NhQqw22gSr2YY1afu3FxRip4ZCZNsD5jq6Aaz6QV3D/Njw==", + "dev": true, "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", @@ -1123,6 +1151,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1136,6 +1165,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1149,6 +1179,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1162,6 +1193,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1175,6 +1207,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1188,6 +1221,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1201,6 +1235,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1214,6 +1249,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1227,6 +1263,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1240,6 +1277,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1253,6 +1291,7 @@ "cpu": [ "s390x" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1266,6 +1305,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1279,6 +1319,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1292,6 +1333,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1305,6 +1347,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1318,6 +1361,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1328,6 +1372,7 @@ "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==", + "dev": true, "license": "MIT", "engines": { "node": ">=14" @@ -1344,6 +1389,7 @@ "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==", + "dev": true, "license": "MIT", "engines": { "node": ">=14" @@ -1360,6 +1406,7 @@ "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==", + "dev": true, "license": "MIT", "engines": { "node": ">=14" @@ -1376,6 +1423,7 @@ "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==", + "dev": true, "license": "MIT", "engines": { "node": ">=14" @@ -1392,6 +1440,7 @@ "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==", + "dev": true, "license": "MIT", "engines": { "node": ">=14" @@ -1408,6 +1457,7 @@ "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==", + "dev": true, "license": "MIT", "engines": { "node": ">=14" @@ -1424,6 +1474,7 @@ "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==", + "dev": true, "license": "MIT", "engines": { "node": ">=14" @@ -1440,6 +1491,7 @@ "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==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -1456,6 +1508,7 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz", "integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==", + "dev": true, "license": "MIT", "dependencies": { "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", @@ -1482,6 +1535,7 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.21.3", @@ -1502,6 +1556,7 @@ "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==", + "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.21.3", @@ -1519,6 +1574,7 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz", "integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.21.3", @@ -1537,6 +1593,59 @@ "@svgr/core": "*" } }, + "node_modules/@tanstack/query-core": { + "version": "5.59.6", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.59.6.tgz", + "integrity": "sha512-g58YTHe4ClRrjJ50GY9fas/0zARJVozY0Hs+hcSBOmwZaeKY+to0/LX8wKnnH/EJiLYcC1sHmE11CAS3ncfZBg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/query-devtools": { + "version": "5.58.0", + "resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.58.0.tgz", + "integrity": "sha512-iFdQEFXaYYxqgrv63ots+65FGI+tNp5ZS5PdMU1DWisxk3fez5HG3FyVlbUva+RdYS5hSLbxZ9aw3yEs97GNTw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.59.8", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.59.8.tgz", + "integrity": "sha512-jkvObpbjBL6P/PHFIjvNGG19XyhI8sjP6/Mw7CbmgT6SAps/5fZY5pxDicRwAt1YGCiEQvwrJQ6IdbZ8j5CVfw==", + "license": "MIT", + "dependencies": { + "@tanstack/query-core": "5.59.6" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, + "node_modules/@tanstack/react-query-devtools": { + "version": "5.59.8", + "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.59.8.tgz", + "integrity": "sha512-zcuPadRnbGcOz5YIPDbX2Tbpf0cFsoSACYdQzhRv7R2tyJxFby3u9bn4y1TaYTWSEolH8PlCklznEkS7F2OqFQ==", + "license": "MIT", + "dependencies": { + "@tanstack/query-devtools": "5.58.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@tanstack/react-query": "^5.59.8", + "react": "^18 || ^19" + } + }, "node_modules/@trivago/prettier-plugin-sort-imports": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.3.0.tgz", @@ -1728,6 +1837,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true, "license": "MIT" }, "node_modules/@types/hoist-non-react-statics": { @@ -1749,10 +1859,10 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.7.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", - "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", - "devOptional": true, + "version": "20.16.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.11.tgz", + "integrity": "sha512-y+cTCACu92FyA5fgQSAI8A1H429g7aSK2HsO7K4XYUWc4dY5IUz55JSDIYT6/VsOLfGy8vmvQYC2hfb0iF16Uw==", + "dev": true, "license": "MIT", "dependencies": { "undici-types": "~6.19.2" @@ -1804,12 +1914,6 @@ "integrity": "sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw==", "license": "MIT" }, - "node_modules/@types/use-sync-external-store": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", - "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==", - "license": "MIT" - }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.8.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.1.tgz", @@ -2145,6 +2249,7 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, "license": "MIT", "dependencies": { "color-convert": "^1.9.0" @@ -2157,6 +2262,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, "license": "Python-2.0" }, "node_modules/asynckit": { @@ -2211,6 +2317,7 @@ "version": "4.24.0", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", + "dev": true, "funding": [ { "type": "opencollective", @@ -2243,6 +2350,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -2252,6 +2360,7 @@ "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -2273,6 +2382,7 @@ "version": "1.0.30001667", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001667.tgz", "integrity": "sha512-7LTwJjcRkzKFmtqGsibMeuXmvFDfZq/nzIjnmgCGzKKRVzjD72selLDK1oPF/Oxzmt4fNcPvTDvGqSDG4tCALw==", + "dev": true, "funding": [ { "type": "opencollective", @@ -2293,6 +2403,7 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", @@ -2340,6 +2451,7 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, "license": "MIT", "dependencies": { "color-name": "1.1.3" @@ -2349,6 +2461,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, "license": "MIT" }, "node_modules/colorette": { @@ -2391,12 +2504,14 @@ "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==", + "dev": true, "license": "MIT" }, "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==", + "dev": true, "license": "MIT", "dependencies": { "import-fresh": "^3.3.0", @@ -2464,6 +2579,7 @@ "version": "4.3.7", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -2497,6 +2613,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, "license": "MIT", "dependencies": { "no-case": "^3.0.4", @@ -2507,6 +2624,7 @@ "version": "1.5.33", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.33.tgz", "integrity": "sha512-+cYTcFB1QqD4j4LegwLfpCNxifb6dDFUAwk6RsLusCwIaZI6or2f+q8rs5tTB2YC53HhOlIbEaqHMAAC8IOIwA==", + "dev": true, "license": "ISC" }, "node_modules/emoji-regex": { @@ -2520,6 +2638,7 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.12" @@ -2545,6 +2664,7 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" @@ -2554,6 +2674,7 @@ "version": "0.21.5", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, "hasInstallScript": true, "license": "MIT", "bin": { @@ -2592,6 +2713,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -2601,6 +2723,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.8.0" @@ -2867,6 +2990,7 @@ "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==", + "dev": true, "license": "MIT" }, "node_modules/esutils": { @@ -3073,6 +3197,7 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -3087,6 +3212,7 @@ "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==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -3155,6 +3281,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -3206,20 +3333,11 @@ "node": ">= 4" } }, - "node_modules/immer": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz", - "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/immer" - } - }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, "license": "MIT", "dependencies": { "parent-module": "^1.0.0", @@ -3246,6 +3364,7 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, "license": "MIT" }, "node_modules/is-extglob": { @@ -3321,6 +3440,27 @@ "dev": true, "license": "MIT" }, + "node_modules/jotai": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/jotai/-/jotai-2.10.0.tgz", + "integrity": "sha512-8W4u0aRlOIwGlLQ0sqfl/c6+eExl5D8lZgAUolirZLktyaj4WnxO/8a0HEPmtriQAB6X5LMhXzZVmw02X0P0qQ==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=17.0.0", + "react": ">=17.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + } + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -3331,6 +3471,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -3343,6 +3484,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "dev": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" @@ -3362,6 +3504,7 @@ "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==", + "dev": true, "license": "MIT" }, "node_modules/json-schema-traverse": { @@ -3382,6 +3525,7 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, "license": "MIT", "bin": { "json5": "lib/cli.js" @@ -3431,6 +3575,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, "license": "MIT" }, "node_modules/lint-staged": { @@ -3604,6 +3749,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, "license": "MIT", "dependencies": { "tslib": "^2.0.3" @@ -3613,6 +3759,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, "license": "ISC", "dependencies": { "yallist": "^3.0.2" @@ -3713,6 +3860,7 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, "license": "MIT" }, "node_modules/nanoid": { @@ -3744,6 +3892,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, "license": "MIT", "dependencies": { "lower-case": "^2.0.2", @@ -3754,6 +3903,7 @@ "version": "2.0.18", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "dev": true, "license": "MIT" }, "node_modules/npm-run-path": { @@ -3855,6 +4005,7 @@ "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==", + "dev": true, "license": "MIT", "dependencies": { "callsites": "^3.0.0" @@ -3867,6 +4018,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.0.0", @@ -3905,6 +4057,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -3920,6 +4073,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -3945,6 +4099,7 @@ "version": "8.4.47", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", + "dev": true, "funding": [ { "type": "opencollective", @@ -4070,29 +4225,6 @@ "dev": true, "license": "MIT" }, - "node_modules/react-redux": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.2.tgz", - "integrity": "sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==", - "license": "MIT", - "dependencies": { - "@types/use-sync-external-store": "^0.0.3", - "use-sync-external-store": "^1.0.0" - }, - "peerDependencies": { - "@types/react": "^18.2.25", - "react": "^18.0", - "redux": "^5.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "redux": { - "optional": true - } - } - }, "node_modules/react-refresh": { "version": "0.14.2", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", @@ -4135,40 +4267,11 @@ "react-dom": ">=16.8" } }, - "node_modules/redux": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", - "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", - "license": "MIT" - }, - "node_modules/redux-persist": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/redux-persist/-/redux-persist-6.0.0.tgz", - "integrity": "sha512-71LLMbUq2r02ng2We9S215LtPu3fY0KgaGE0k8WRgl6RkqxtGfl7HUozz1Dftwsb0D/5mZ8dwAaPbtnzfvbEwQ==", - "license": "MIT", - "peerDependencies": { - "redux": ">4.0.0" - } - }, - "node_modules/redux-thunk": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", - "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", - "license": "MIT", - "peerDependencies": { - "redux": "^5.0.0" - } - }, - "node_modules/reselect": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", - "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==", - "license": "MIT" - }, "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==", + "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -4229,6 +4332,7 @@ "version": "4.24.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.0.tgz", "integrity": "sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==", + "dev": true, "license": "MIT", "dependencies": { "@types/estree": "1.0.6" @@ -4297,6 +4401,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -4378,6 +4483,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", + "dev": true, "license": "MIT", "dependencies": { "dot-case": "^3.0.4", @@ -4539,6 +4645,7 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, "license": "MIT", "dependencies": { "has-flag": "^3.0.0" @@ -4551,6 +4658,7 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", + "dev": true, "license": "MIT" }, "node_modules/text-table": { @@ -4564,6 +4672,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -4618,7 +4727,7 @@ "version": "5.6.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -4656,13 +4765,14 @@ "version": "6.19.8", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/update-browserslist-db": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "dev": true, "funding": [ { "type": "opencollective", @@ -4699,19 +4809,11 @@ "punycode": "^2.1.0" } }, - "node_modules/use-sync-external-store": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", - "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==", - "license": "MIT", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, "node_modules/vite": { "version": "5.4.8", "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz", "integrity": "sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==", + "dev": true, "license": "MIT", "dependencies": { "esbuild": "^0.21.3", @@ -4771,6 +4873,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/vite-plugin-svgr/-/vite-plugin-svgr-4.2.0.tgz", "integrity": "sha512-SC7+FfVtNQk7So0XMjrrtLAbEC8qjFPifyD7+fs/E6aaNdVde6umlVVh0QuwDLdOMu7vp5RiGFsB70nj5yo0XA==", + "dev": true, "license": "MIT", "dependencies": { "@rollup/pluginutils": "^5.0.5", @@ -4842,6 +4945,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, "license": "ISC" }, "node_modules/yaml": { diff --git a/package.json b/package.json index 5d2b3de..0973daa 100644 --- a/package.json +++ b/package.json @@ -24,20 +24,20 @@ "npm": ">=10" }, "dependencies": { - "@reduxjs/toolkit": "^2.2.8", + "@tanstack/react-query": "^5.59.8", + "@tanstack/react-query-devtools": "^5.59.8", "axios": "^1.7.7", + "jotai": "^2.10.0", "react": "^18.3.1", "react-dom": "^18.3.1", - "react-redux": "^9.1.2", "react-router-dom": "^6.26.2", - "redux-persist": "^6.0.0", - "styled-components": "^6.1.13", - "vite-plugin-svgr": "^4.2.0" + "styled-components": "^6.1.13" }, "devDependencies": { + "vite-plugin-svgr": "^4.2.0", "@eslint/js": "^9.11.1", "@trivago/prettier-plugin-sort-imports": "^4.3.0", - "@types/node": "^22.7.5", + "@types/node": "^20", "@types/react": "^18.3.10", "@types/react-dom": "^18.3.0", "@types/styled-components": "^5.1.34", diff --git a/src/configs/http-client/axios.config.ts b/src/configs/http-client/axios.config.ts new file mode 100644 index 0000000..f70e6ca --- /dev/null +++ b/src/configs/http-client/axios.config.ts @@ -0,0 +1,95 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import axios, { AxiosInstance, type AxiosResponse } from 'axios'; +import { type CommonHttpClient, type CommonHttpResponse } from './httpClient'; +import { + CommonHttpException, + SpecificHttpException, + UnauthorizedException, + UnknownHttpException, + isAuthenticationErrorCode, + isCommonErrorCode, +} from './httpErrors'; + +/** axios config */ +export const axiosClient = axios.create({ + baseURL: import.meta.env.VITE_API_URL, + withCredentials: true, + timeout: 15000, +}); + +/** interceptor config */ +axiosClient.interceptors.response.use( + response => { + return response.data; + }, + error => { + if (axios.isAxiosError(error) && error.response) { + const response = error.response as AxiosResponse< + CommonHttpResponse + >; + const errors = response.data.errors; + + // 전역 에러는 첫 에러를 중점으로 처리하기 + const errorCodeOfFisrtError = errors?.[0].errorCode; + + // 인증 에러 + if (isAuthenticationErrorCode(errorCodeOfFisrtError)) { + return Promise.reject( + new UnauthorizedException('UnauthorizedException'), + ); + } + + // 글로벌 에러 처리 + if (isCommonErrorCode(errorCodeOfFisrtError)) { + return Promise.reject(new CommonHttpException('CommonHttpException')); + } + + // 각 도메인의 에러 + if (errors) { + return Promise.reject( + new SpecificHttpException('SpecificHttpException', errors), + ); + } + } + + // 진짜 알 수 없는 에러 + console.error(error); + return Promise.reject(new UnknownHttpException('UnknownHttpException')); + }, +); + +class CommonHttpAxiosClientImpl implements CommonHttpClient { + constructor(private readonly client: AxiosInstance) {} + + async get(url: string, config?: any): Promise { + const response = await this.client.get(url, config); + return response.data; + } + + async post( + url: string, + data?: D, + config?: any, + ): Promise { + const response = await this.client.post(url, data, config); + return response.data; + } + + async patch( + url: string, + data?: D, + config?: any, + ): Promise { + const response = await this.client.patch(url, data, config); + return response.data; + } + + async delete(url: string, config?: any): Promise { + const response = await this.client.delete(url, config); + return response.data; + } +} + +export const httpClient: CommonHttpClient = new CommonHttpAxiosClientImpl( + axiosClient, +); diff --git a/src/configs/http-client/httpClient.ts b/src/configs/http-client/httpClient.ts new file mode 100644 index 0000000..254fd47 --- /dev/null +++ b/src/configs/http-client/httpClient.ts @@ -0,0 +1,23 @@ +/** 넓은 타입 정의를 위해 */ + +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { CommonHttpErrorScheme } from './httpErrors'; + +export type CommonHttpResponseStatus = 'success' | 'fail' | 'error'; + +export interface CommonHttpResponse { + apiVersion: string; + timestamp: string; + status: CommonHttpResponseStatus; + statusCode: number; + message?: string; + errors?: Array; + data: T; +} + +export interface CommonHttpClient { + get(url: string, config?: any): Promise; + post(url: string, data?: D, config?: any): Promise; + patch(url: string, data?: D, config?: any): Promise; + delete(url: string, config?: any): Promise; +} diff --git a/src/configs/http-client/httpErrors.ts b/src/configs/http-client/httpErrors.ts new file mode 100644 index 0000000..a88c366 --- /dev/null +++ b/src/configs/http-client/httpErrors.ts @@ -0,0 +1,69 @@ +import { type ValueOf } from '@/utils/types/utilTypes'; + +export type CommonHttpErrorScheme = { + field?: string; + errorCode: CommonHttpErrorCodeType; + message: string; +}; + +export const CommonHttpErrorCode = { + INTERNAL_SERVER_ERROR: 'INTERNAL_SERVER_ERROR', + AUTHENTICATION_ERROR: 'AUTHENTICATION_ERROR', + AUTHORIZATION_ERROR: 'AUTHORIZATION_ERROR', + INVALID_REQUEST: 'INVALID_REQUEST', + RESOURCE_NOT_FOUND: 'RESOURCE_NOT_FOUND', + SERVICE_UNAVAILABLE: 'SERVICE_UNAVAILABLE', +} as const; + +export type CommonHttpErrorCodeType = ValueOf; + +export type AuthenticationErrorCode = Extract< + CommonHttpErrorCodeType, + 'AUTHENTICATION_ERROR' | 'AUTHORIZATION_ERROR' +>; + +export const isCommonErrorCode = ( + errorCode: string | undefined, +): errorCode is CommonHttpErrorCodeType => { + return Object.values(CommonHttpErrorCode).includes(errorCode as never); +}; + +export const isAuthenticationErrorCode = ( + errorCode: string | undefined, +): errorCode is AuthenticationErrorCode => { + return ['AUTHENTICATION_ERROR', 'AUTHORIZATION_ERROR'].includes( + errorCode as never, + ); +}; + +// 각 기능에서 사용 될 구분 가능한 http 에러 +export class SpecificHttpException extends Error { + constructor( + message: string, + public errors: Array, + ) { + super(message); + this.name = 'SpecificHttpException'; + } +} + +export class UnauthorizedException extends Error { + constructor(message: string) { + super(message); + this.name = 'UnauthorizedException'; + } +} + +export class CommonHttpException extends Error { + constructor(message: string) { + super(message); + this.name = 'CommonHttpException'; + } +} + +export class UnknownHttpException extends Error { + constructor(message: string) { + super(message); + this.name = 'UnknownHttpException'; + } +} diff --git a/src/configs/http-client/index.ts b/src/configs/http-client/index.ts new file mode 100644 index 0000000..4ebfdee --- /dev/null +++ b/src/configs/http-client/index.ts @@ -0,0 +1 @@ +export { httpClient } from './axios.config'; diff --git a/src/configs/http-client/pageParam.ts b/src/configs/http-client/pageParam.ts new file mode 100644 index 0000000..f72d927 --- /dev/null +++ b/src/configs/http-client/pageParam.ts @@ -0,0 +1,8 @@ +export type PageParam = { + page: number; + size: number; +}; + +export type PageResponse = { + list: T[]; +} & PageParam; diff --git a/src/configs/react/libs/ReactToastify.tsx b/src/configs/react/libs/ReactToastify.tsx new file mode 100644 index 0000000..c5907eb --- /dev/null +++ b/src/configs/react/libs/ReactToastify.tsx @@ -0,0 +1,3 @@ +export const Toast = () => { + return; +}; diff --git a/src/configs/react/providers/QueryProvider.tsx b/src/configs/react/providers/QueryProvider.tsx new file mode 100644 index 0000000..b0d7308 --- /dev/null +++ b/src/configs/react/providers/QueryProvider.tsx @@ -0,0 +1,45 @@ +import { type ReactNode, useRef } from 'react'; +import { + QueryCache, + QueryClient, + QueryClientProvider, +} from '@tanstack/react-query'; +import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; +import { + SpecificHttpException, + UnauthorizedException, +} from '@/configs/http-client/httpErrors'; + +export const QueryProvider = ({ children }: { children: ReactNode }) => { + const queryClient = useRef( + new QueryClient({ + defaultOptions: { + queries: { + staleTime: 1000 * 60 * 5, + gcTime: 1000 * 60 * 10, + refetchOnWindowFocus: false, + refetchOnReconnect: false, + retry: false, + retryOnMount: false, + }, + }, + queryCache: new QueryCache({ + onError: (error: unknown) => { + if (error instanceof UnauthorizedException) { + return; + } + if (error instanceof SpecificHttpException) { + return; + } + }, + }), + }), + ); + + return ( + + + {children} + + ); +}; diff --git a/src/configs/react/stores/store.ts b/src/configs/react/stores/store.ts new file mode 100644 index 0000000..49707fc --- /dev/null +++ b/src/configs/react/stores/store.ts @@ -0,0 +1,4 @@ +export interface Store { + get: () => T; + set: (value: T) => void; +} diff --git a/src/features/users/models/user.ts b/src/features/users/models/user.ts new file mode 100644 index 0000000..dac5997 --- /dev/null +++ b/src/features/users/models/user.ts @@ -0,0 +1,5 @@ +export type User = { + userName: string; + userId: string; + isAdmin: boolean; +}; diff --git a/src/features/users/models/userLoginDto.ts b/src/features/users/models/userLoginDto.ts new file mode 100644 index 0000000..ec69b9c --- /dev/null +++ b/src/features/users/models/userLoginDto.ts @@ -0,0 +1,4 @@ +export type UserLoginDto = { + userId: string; + password: string; +}; diff --git a/src/features/users/models/userRegisterDto.ts b/src/features/users/models/userRegisterDto.ts new file mode 100644 index 0000000..746b4ac --- /dev/null +++ b/src/features/users/models/userRegisterDto.ts @@ -0,0 +1,5 @@ +export type UserRegisterDto = { + userId: string; + password: string; + userName: string; +}; diff --git a/src/features/users/models/validationErrors.ts b/src/features/users/models/validationErrors.ts new file mode 100644 index 0000000..c406847 --- /dev/null +++ b/src/features/users/models/validationErrors.ts @@ -0,0 +1,5 @@ +export class UserValidationException extends Error { + constructor(message: string) { + super(message); + } +} diff --git a/src/features/users/models/validationPolicy.ts b/src/features/users/models/validationPolicy.ts new file mode 100644 index 0000000..f557483 --- /dev/null +++ b/src/features/users/models/validationPolicy.ts @@ -0,0 +1,3 @@ +export const MAX_USER_NAME_LENGTH = 10; +export const MAX_USER_ID_LENGTH = 10; +export const MIN_USER_PASSWORD_LENGTH = 8; diff --git a/src/features/users/services/remotes/checkLoginRequest.ts b/src/features/users/services/remotes/checkLoginRequest.ts new file mode 100644 index 0000000..ed886dd --- /dev/null +++ b/src/features/users/services/remotes/checkLoginRequest.ts @@ -0,0 +1,5 @@ +import { httpClient } from '@/configs/http-client'; +import { User } from '../../models/user'; + +export const API_CHECK_LOGIN = 'v1/auth/check-login'; +export const checkLoginRequest = () => httpClient.post(API_CHECK_LOGIN); diff --git a/src/features/users/services/remotes/sendLoginRequest.ts b/src/features/users/services/remotes/sendLoginRequest.ts new file mode 100644 index 0000000..81e13db --- /dev/null +++ b/src/features/users/services/remotes/sendLoginRequest.ts @@ -0,0 +1,8 @@ +import { httpClient } from '@/configs/http-client'; +import { User } from '../../models/user'; +import { UserLoginDto } from '../../models/userLoginDto'; + +export const API_LOGIN = 'v1/auth/login'; + +export const sendLoginRequest = async (userLoginDto: UserLoginDto) => + httpClient.post(API_LOGIN, userLoginDto); diff --git a/src/features/users/services/remotes/sendLogoutRequest.ts b/src/features/users/services/remotes/sendLogoutRequest.ts new file mode 100644 index 0000000..32d7cd0 --- /dev/null +++ b/src/features/users/services/remotes/sendLogoutRequest.ts @@ -0,0 +1,5 @@ +import { httpClient } from '@/configs/http-client'; + +export const API_LOGOUT = 'v1/auth/logout'; + +export const sendLogoutRequest = async () => httpClient.post(API_LOGOUT); diff --git a/src/features/users/services/validatePasswordInput.ts b/src/features/users/services/validatePasswordInput.ts new file mode 100644 index 0000000..237822d --- /dev/null +++ b/src/features/users/services/validatePasswordInput.ts @@ -0,0 +1,12 @@ +import { MIN_USER_PASSWORD_LENGTH } from '../models/validationPolicy'; + +export const validatePasswordInput = (password: string) => { + return password.length >= MIN_USER_PASSWORD_LENGTH; +}; + +export const validateRePasswordInput = ( + password: string, + rePassword: string, +) => { + return validatePasswordInput(password) && password === rePassword; +}; diff --git a/src/features/users/services/validateUserIdInput.ts b/src/features/users/services/validateUserIdInput.ts new file mode 100644 index 0000000..c4606b0 --- /dev/null +++ b/src/features/users/services/validateUserIdInput.ts @@ -0,0 +1,5 @@ +import { MAX_USER_ID_LENGTH } from '../models/validationPolicy'; + +export const validateUserIdInput = (userId: string) => { + return userId.length > 0 && userId.length <= MAX_USER_ID_LENGTH; +}; diff --git a/src/features/users/services/validateUserNameInput.ts b/src/features/users/services/validateUserNameInput.ts new file mode 100644 index 0000000..7be25f0 --- /dev/null +++ b/src/features/users/services/validateUserNameInput.ts @@ -0,0 +1,5 @@ +import { MAX_USER_NAME_LENGTH } from '../models/validationPolicy'; + +export const validateUserNameInput = (userName: string) => { + return userName.length > 0 && userName.length <= MAX_USER_NAME_LENGTH; +}; diff --git a/src/features/users/ui/components/CardLayout.tsx b/src/features/users/ui/components/CardLayout.tsx new file mode 100644 index 0000000..82b4817 --- /dev/null +++ b/src/features/users/ui/components/CardLayout.tsx @@ -0,0 +1,9 @@ +import { type ReactNode } from 'react'; + +export const CardLayout = ({ children }: { children: ReactNode }) => { + return ( +
+ {children} +
+ ); +}; diff --git a/src/features/users/ui/hooks/useLoginFormState.ts b/src/features/users/ui/hooks/useLoginFormState.ts new file mode 100644 index 0000000..a8845ef --- /dev/null +++ b/src/features/users/ui/hooks/useLoginFormState.ts @@ -0,0 +1,33 @@ +import { useState } from 'react'; +import { useInputState } from '@/utils/react/hooks/useInputState'; +import { validatePasswordInput } from '../../services/validatePasswordInput'; +import { validateUserIdInput } from '../../services/validateUserIdInput'; + +export const useLoginFormState = () => { + const [userId, handleUserIdChange] = useInputState(''); + const [password, handlePasswordChange] = useInputState(''); + + const isUserIdValid = validateUserIdInput(userId); + const isPasswordValid = validatePasswordInput(password); + + const isFormValid = isUserIdValid && isPasswordValid; + const [isFormDirty, setIsFormDirty] = useState(false); + + return { + userId: { + value: userId, + onChange: handleUserIdChange, + isValid: isUserIdValid, + }, + password: { + value: password, + onChange: handlePasswordChange, + isValid: isPasswordValid, + }, + form: { + isValid: isFormValid, + isDirty: isFormDirty, + setIsDirty: setIsFormDirty, + }, + } as const; +}; diff --git a/src/features/users/ui/hooks/useLoginQuery.ts b/src/features/users/ui/hooks/useLoginQuery.ts new file mode 100644 index 0000000..5584360 --- /dev/null +++ b/src/features/users/ui/hooks/useLoginQuery.ts @@ -0,0 +1,12 @@ +import { useQuery } from '@tanstack/react-query'; +import { + API_CHECK_LOGIN, + checkLoginRequest, +} from '../../services/remotes/checkLoginRequest'; + +export const useLoginQuery = () => { + return useQuery({ + queryKey: [API_CHECK_LOGIN], + queryFn: checkLoginRequest, + }); +}; diff --git a/src/features/users/ui/screen/LoginScreen.tsx b/src/features/users/ui/screen/LoginScreen.tsx new file mode 100644 index 0000000..6256ff7 --- /dev/null +++ b/src/features/users/ui/screen/LoginScreen.tsx @@ -0,0 +1,15 @@ +import styled from 'styled-components'; + +export const LoginScreen = () => { + return ( +
+

Login

+
+ ); +}; + +export const StyledDiv = styled.div` + ${({ theme }) => ` + color: ${theme.backgrounds.gray1}; + `} +`; diff --git a/src/features/users/ui/screen/RegisterScreen.tsx b/src/features/users/ui/screen/RegisterScreen.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/main.tsx b/src/main.tsx index 87f1278..9056eeb 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,22 +1,12 @@ import ReactDOM from 'react-dom/client'; -import { Provider } from 'react-redux'; import { BrowserRouter } from 'react-router-dom'; -import { persistStore } from 'redux-persist'; -import { PersistGate } from 'redux-persist/integration/react'; import React from 'react'; -import { store } from '@store/store'; import App from './App.tsx'; -export const persist = persistStore(store); - ReactDOM.createRoot(document.getElementById('root')!).render( - - - - - - - + + + , ); diff --git a/src/pages/routes.ts b/src/pages/routes.ts new file mode 100644 index 0000000..69a7788 --- /dev/null +++ b/src/pages/routes.ts @@ -0,0 +1 @@ +export const routes = {}; diff --git a/src/store/store.ts b/src/store/store.ts deleted file mode 100644 index ffbd1c7..0000000 --- a/src/store/store.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { persistReducer } from 'redux-persist'; -import storage from 'redux-persist/lib/storage'; -import { combineReducers, configureStore } from '@reduxjs/toolkit'; - -const reducers = combineReducers({}); - -const persistConfig = { - key: 'root', // localStorage key - storage, // localStorage - whitelist: [], - blacklist: [], -}; - -const persistStore = persistReducer(persistConfig, reducers); - -export const store = configureStore({ - reducer: persistStore, - middleware: getDefaultMiddleware => - getDefaultMiddleware({ serializableCheck: false }), -}); - -export type RootState = ReturnType; -export type AppDispatch = typeof store.dispatch; diff --git a/src/styles/GlobalStyles.tsx b/src/styles/GlobalStyles.tsx new file mode 100644 index 0000000..b9ca716 --- /dev/null +++ b/src/styles/GlobalStyles.tsx @@ -0,0 +1,13 @@ +import { createGlobalStyle } from 'styled-components'; +import { miniReset } from './miniReset'; + +export const GlobalStyles = createGlobalStyle` + + ${miniReset} + + body { + font-family: 'Noto Sans KR', sans-serif; + background-color: black; + color:white + } +`; diff --git a/src/styles/colors/backgrounds.ts b/src/styles/colors/backgrounds.ts new file mode 100644 index 0000000..bfa168a --- /dev/null +++ b/src/styles/colors/backgrounds.ts @@ -0,0 +1,9 @@ +import { pallete } from '../pallete/pallete'; + +export const backgrounds = { + base: pallete.white, + gray1: pallete.gray[100], + gray2: pallete.gray[200], +} as const; + +export type Backgrounds = typeof backgrounds; diff --git a/src/styles/colors/borders.ts b/src/styles/colors/borders.ts new file mode 100644 index 0000000..12eaf02 --- /dev/null +++ b/src/styles/colors/borders.ts @@ -0,0 +1,8 @@ +import { pallete } from '../pallete/pallete'; + +export const borders = { + light: pallete.gray[100], + basic: pallete.gray[400], +} as const; + +export type Borders = typeof borders; diff --git a/src/styles/colors/buttons.ts b/src/styles/colors/buttons.ts new file mode 100644 index 0000000..9d16989 --- /dev/null +++ b/src/styles/colors/buttons.ts @@ -0,0 +1,17 @@ +import { pallete } from '../pallete/pallete'; + +export const buttons = { + cyan: pallete.cyan[300], + red: pallete.red[300], + gray: pallete.gray[500], +}; + +export const presseds = { + // 15% + light: `${pallete.white}26`, + // 5% + dark: `${pallete.gray[700]}0D`, +} as const; + +export type Buttons = typeof buttons; +export type Presseds = typeof presseds; diff --git a/src/styles/colors/dims.ts b/src/styles/colors/dims.ts new file mode 100644 index 0000000..d8833b0 --- /dev/null +++ b/src/styles/colors/dims.ts @@ -0,0 +1,12 @@ +import { pallete } from '../pallete/pallete'; + +export const dims = { + // 70% + thick: `${pallete.gray[700]}BF`, + // 50% + basic: `${pallete.gray[700]}80`, + // 15% + thin: `${pallete.gray[700]}26`, +} as const; + +export type Dims = typeof dims; diff --git a/src/styles/colors/index.ts b/src/styles/colors/index.ts new file mode 100644 index 0000000..1161b2c --- /dev/null +++ b/src/styles/colors/index.ts @@ -0,0 +1,7 @@ +export { backgrounds } from './backgrounds'; +export { borders } from './borders'; +export { buttons } from './buttons'; +export { dims } from './dims'; +export { pallete } from '../pallete/pallete'; +export { shadows } from './shadows'; +export { texts } from './texts'; diff --git a/src/styles/colors/shadows.ts b/src/styles/colors/shadows.ts new file mode 100644 index 0000000..6d854ce --- /dev/null +++ b/src/styles/colors/shadows.ts @@ -0,0 +1,10 @@ +import { pallete } from '../pallete/pallete'; + +export const shadows = { + // 25% + basic: `${pallete.gray[600]}40`, + // 10% + thin: `${pallete.gray[600]}1A`, +} as const; + +export type Shadows = typeof shadows; diff --git a/src/styles/colors/texts.ts b/src/styles/colors/texts.ts new file mode 100644 index 0000000..1fec601 --- /dev/null +++ b/src/styles/colors/texts.ts @@ -0,0 +1,12 @@ +import { pallete } from '../pallete/pallete'; + +export const texts = { + primary: pallete.black, + secondary: pallete.gray[700], + disabled: pallete.gray[300], + placeholder: pallete.gray[300], + warning: pallete.yellow[400], + error: pallete.red[600], +} as const; + +export type Texts = typeof texts; diff --git a/src/styles/keyframes/fades.ts b/src/styles/keyframes/fades.ts new file mode 100644 index 0000000..4f5c883 --- /dev/null +++ b/src/styles/keyframes/fades.ts @@ -0,0 +1,19 @@ +import { keyframes } from 'styled-components'; + +export const fadeIn = keyframes` + from{ + opacity: 0; + + }to{ + opacity: 1; + } +`; + +export const fadeOut = keyframes` + from{ + opacity: 1; + + }to{ + opacity: 0; + } +`; diff --git a/src/styles/keyframes/index.ts b/src/styles/keyframes/index.ts new file mode 100644 index 0000000..eda93d8 --- /dev/null +++ b/src/styles/keyframes/index.ts @@ -0,0 +1 @@ +export const keyFrames = {}; diff --git a/src/styles/keyframes/slides.ts b/src/styles/keyframes/slides.ts new file mode 100644 index 0000000..4d2d1df --- /dev/null +++ b/src/styles/keyframes/slides.ts @@ -0,0 +1,23 @@ +import { keyframes } from 'styled-components'; + +export const slideUp = keyframes` +from { + transform: translateY(400px); +} +to { + transform: translateY(0px); +} +`; + +export const slideDown = keyframes` +from { + transform: translateY(0px); +} +to { + transform: translateY(400px); +} +`; + +export const slideLeft = keyframes``; + +export const slideRight = keyframes``; diff --git a/src/styles/miniReset.ts b/src/styles/miniReset.ts new file mode 100644 index 0000000..d041417 --- /dev/null +++ b/src/styles/miniReset.ts @@ -0,0 +1,72 @@ +import { css } from 'styled-components'; + +export const miniReset = css` + /*! minireset.css v0.0.6 | MIT License | github.com/jgthms/minireset.css */ + html, + body, + p, + ol, + ul, + li, + dl, + dt, + dd, + blockquote, + figure, + fieldset, + legend, + textarea, + pre, + iframe, + hr, + h1, + h2, + h3, + h4, + h5, + h6 { + margin: 0; + padding: 0; + } + h1, + h2, + h3, + h4, + h5, + h6 { + font-size: 100%; + font-weight: normal; + } + ul { + list-style: none; + } + button, + input, + select { + margin: 0; + } + html { + box-sizing: border-box; + } + *, + *::before, + *::after { + box-sizing: inherit; + } + img, + video { + height: auto; + max-width: 100%; + } + iframe { + border: 0; + } + table { + border-collapse: collapse; + border-spacing: 0; + } + td, + th { + padding: 0; + } +`; diff --git a/src/styles/pallete/pallete.ts b/src/styles/pallete/pallete.ts new file mode 100644 index 0000000..4071776 --- /dev/null +++ b/src/styles/pallete/pallete.ts @@ -0,0 +1,162 @@ +export const pallete = { + white: '#ffffff', + black: '#000000', + gray: { + 50: '#f8f9fa', + 100: '#f1f3f5', + 200: '#e9ecef', + 300: '#dee2e6', + 400: '#ced4da', + 500: '#adb5bd', + 600: '#868e96', + 700: '#495057', + 800: '#343a40', + 900: '#212529', + }, + red: { + 50: '#fff5f5', + 100: '#ffe3e3', + 200: '#ffc9c9', + 300: '#ffa8a8', + 400: '#ff8787', + 500: '#ff6b6b', + 600: '#fa5252', + 700: '#f03e3e', + 800: '#e03131', + 900: '#c92a2a', + }, + pink: { + 50: '#fff0f6', + 100: '#ffdeeb', + 200: '#fcc2d7', + 300: '#faa2c1', + 400: '#f783ac', + 500: '#f06595', + 600: '#e64980', + 700: '#d6336c', + 800: '#c2255c', + 900: '#a61e4d', + }, + grape: { + 50: '#f8f0fc', + 100: '#f3d9fa', + 200: '#eebefa', + 300: '#e599f7', + 400: '#da77f2', + 500: '#cc5de8', + 600: '#be4bdb', + 700: '#ae3ec9', + 800: '#9c36b5', + 900: '#862e9c', + }, + violet: { + 50: '#f3f0ff', + 100: '#e5dbff', + 200: '#d0bfff', + 300: '#b197fc', + 400: '#9775fa', + 500: '#845ef7', + 600: '#7950f2', + 700: '#7048e8', + 800: '#6741d9', + 900: '#5f3dc4', + }, + indigo: { + 50: '#edf2ff', + 100: '#dbe4ff', + 200: '#bac8ff', + 300: '#91a7ff', + 400: '#748ffc', + 500: '#5c7cfa', + 600: '#4c6ef5', + 700: '#4263eb', + 800: '#3b5bdb', + 900: '#364fc7', + }, + blue: { + 50: '#e7f5ff', + 100: '#d0ebff', + 200: '#a5d8ff', + 300: '#74c0fc', + 400: '#4dabf7', + 500: '#339af0', + 600: '#228be6', + 700: '#1c7ed6', + 800: '#1971c2', + 900: '#1864ab', + }, + cyan: { + 50: '#e3fafc', + 100: '#c5f6fa', + 200: '#99e9f2', + 300: '#66d9e8', + 400: '#3bc9db', + 500: '#22b8cf', + 600: '#15aabf', + 700: '#1098ad', + 800: '#0c8599', + 900: '#0b7285', + }, + teal: { + 50: '#e6fcf5', + 100: '#c3fae8', + 200: '#96f2d7', + 300: '#63e6be', + 400: '#38d9a9', + 500: '#20c997', + 600: '#12b886', + 700: '#0ca678', + 800: '#099268', + 900: '#087f5b', + }, + green: { + 50: '#ebfbee', + 100: '#d3f9d8', + 200: '#b2f2bb', + 300: '#8ce99a', + 400: '#69db7c', + 500: '#51cf66', + 600: '#40c057', + 700: '#37b24d', + 800: '#2f9e44', + 900: '#2b8a3e', + }, + lime: { + 50: '#f4fce3', + 100: '#e9fac8', + 200: '#d8f5a2', + 300: '#c0eb75', + 400: '#a9e34b', + 500: '#94d82d', + 600: '#82c91e', + 700: '#74b816', + 800: '#66a80f', + 900: '#5c940d', + }, + yellow: { + 50: '#fff9db', + 100: '#fff3bf', + 200: '#ffec99', + 300: '#ffe066', + 400: '#ffd43b', + 500: '#fcc419', + 600: '#fab005', + 700: '#f59f00', + 800: '#f08c00', + 900: '#e67700', + }, + orange: { + 50: '#fff4e6', + 100: '#ffe8cc', + 200: '#ffd8a8', + 300: '#ffc078', + 400: '#ffa94d', + 500: '#ff922b', + 600: '#fd7e14', + 700: '#f76707', + 800: '#e8590c', + 900: '#d9480f', + }, +} as const; + +export type Pallete = typeof pallete; diff --git a/src/styles/styled.d.ts b/src/styles/styled.d.ts new file mode 100644 index 0000000..310542d --- /dev/null +++ b/src/styles/styled.d.ts @@ -0,0 +1,7 @@ +import 'styled-components'; +import { Theme } from './theme'; + +declare module 'styled-components' { + // eslint-disable-next-line @typescript-eslint/no-empty-object-type + export interface DefaultTheme extends Theme {} +} diff --git a/src/styles/theme.ts b/src/styles/theme.ts new file mode 100644 index 0000000..1eadfe1 --- /dev/null +++ b/src/styles/theme.ts @@ -0,0 +1,21 @@ +import { + backgrounds, + borders, + buttons, + dims, + pallete, + shadows, + texts, +} from './colors'; + +export const theme = { + pallete, + backgrounds, + texts, + shadows, + dims, + buttons, + borders, +} as const; + +export type Theme = typeof theme; diff --git a/src/ui/assets/icons/Icon.tsx b/src/ui/assets/icons/Icon.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/ui/components/Button/Button.tsx b/src/ui/components/Button/Button.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/utils/functions/dateUtils.ts b/src/utils/functions/dateUtils.ts new file mode 100644 index 0000000..a1b89c6 --- /dev/null +++ b/src/utils/functions/dateUtils.ts @@ -0,0 +1,10 @@ +export const formatDate = (dateString: string): string => { + const date = new Date(dateString); + + const year = date.getFullYear(); + + const month = (date.getMonth() + 1).toString().padStart(2, '0'); + const day = date.getDate().toString().padStart(2, '0'); + + return `${year}.${month}.${day}`; +}; diff --git a/src/utils/functions/delay.ts b/src/utils/functions/delay.ts new file mode 100644 index 0000000..09190a7 --- /dev/null +++ b/src/utils/functions/delay.ts @@ -0,0 +1,5 @@ +/** + * Delay (ms) + */ +export const delay = (ms: number) => + new Promise(resolve => setTimeout(resolve, ms)); diff --git a/src/utils/functions/getRandomNumber.ts b/src/utils/functions/getRandomNumber.ts new file mode 100644 index 0000000..31f4239 --- /dev/null +++ b/src/utils/functions/getRandomNumber.ts @@ -0,0 +1,3 @@ +export const getRandomNumber = (min: number, max: number) => { + return Math.floor(Math.random() * (max - min) + min); +}; diff --git a/src/utils/react/hooks/useBooleanToggle.ts b/src/utils/react/hooks/useBooleanToggle.ts new file mode 100644 index 0000000..a905e1e --- /dev/null +++ b/src/utils/react/hooks/useBooleanToggle.ts @@ -0,0 +1,6 @@ +import { useReducer } from 'react'; + +export const useBooleanToggle = (initialValue: boolean) => { + const [value, toggle] = useReducer((state: boolean) => !state, initialValue); + return [value, toggle] as const; +}; diff --git a/src/utils/react/hooks/useInputState.ts b/src/utils/react/hooks/useInputState.ts new file mode 100644 index 0000000..1f72b09 --- /dev/null +++ b/src/utils/react/hooks/useInputState.ts @@ -0,0 +1,11 @@ +import { type ChangeEvent, useCallback, useState } from 'react'; + +export const useInputState = (initialValue: string) => { + const [value, setValue] = useState(initialValue); + + const handleChange = useCallback((e: ChangeEvent) => { + setValue(e.target.value); + }, []); + + return [value, handleChange] as const; +}; diff --git a/src/utils/types/utilTypes.ts b/src/utils/types/utilTypes.ts new file mode 100644 index 0000000..28e16a0 --- /dev/null +++ b/src/utils/types/utilTypes.ts @@ -0,0 +1,15 @@ +/** + * keyof 의 value 버전 + * @example + * ```ts + * export const obj = { + * a: 'A', + * b: 'B', + * } as const; + * + * // ValueType = 'A' | 'B' + * export type ValueType = ValueOf; + * ``` + */ +export type ValueOf> = + T[keyof T]; diff --git a/tsconfig.app.json b/tsconfig.app.json index 6e476af..a865c8d 100644 --- a/tsconfig.app.json +++ b/tsconfig.app.json @@ -23,16 +23,10 @@ "noFallthroughCasesInSwitch": true, "baseUrl": "./src", "paths": { - "@/*": ["./*"], - "@components/*": ["components/*"], - "@pages/*": ["pages/*"], - "@assets/*": ["assets/*"], - "@store/*": ["store/*"], - "@plugins/*": ["plugins/*"], - "@apis/*": ["apis/*"] + "@/*": ["./*"] }, "esModuleInterop": true, "allowSyntheticDefaultImports": true }, - "include": ["src", "src/custom.d.ts"] + "include": ["src"] }