From 158631bc277c4a7e1d6481cd590a58e3a0e29288 Mon Sep 17 00:00:00 2001 From: happyhyep Date: Mon, 18 Nov 2024 17:18:33 +0900 Subject: [PATCH 1/2] =?UTF-8?q?[FE][Feat]=20#186=20:=20=EA=B3=B5=ED=86=B5?= =?UTF-8?q?=20=ED=95=A8=EC=88=98=20=EC=84=B8=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - axios 관련 패키지 설치 및 세팅 - localStorage 세팅 - eslint max-classes-per-file 세팅 off --- eslint.config.mjs | 1 + frontend/package.json | 130 ++++++++++--------- frontend/src/api/client.api.ts | 31 +++++ frontend/src/api/dto/response.dto.ts | 16 +++ frontend/src/constants.ts | 16 +++ frontend/src/pages/Main.tsx | 2 +- frontend/src/utils/common/manageLocalData.ts | 53 ++++++++ pnpm-lock.yaml | 51 ++++++++ 8 files changed, 235 insertions(+), 65 deletions(-) create mode 100644 frontend/src/api/client.api.ts create mode 100644 frontend/src/api/dto/response.dto.ts create mode 100644 frontend/src/constants.ts create mode 100644 frontend/src/utils/common/manageLocalData.ts diff --git a/eslint.config.mjs b/eslint.config.mjs index 0e0dbab0..b98e43c0 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -56,6 +56,7 @@ export default [ 'prettier/prettier': 'error', 'no-underscore-dangle': 'warn', 'no-undef': 'off', + 'max-classes-per-file': 'off', 'import/extensions': [ 'error', 'always', diff --git a/frontend/package.json b/frontend/package.json index a52c70fa..684bf483 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,64 +1,66 @@ -{ - "name": "ddara-frontend", - "private": true, - "workspaces": [ - "frontend", - "backend" - ], - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc -b && vite build", - "test": "vitest", - "test:watch": "vitest --watch", - "test:coverage": "vitest run --coverage", - "lint": "pnpm lint-staged", - "preview": "vite preview", - "storybook": "storybook dev -p 6006", - "build-storybook": "storybook build" - }, - "dependencies": { - "@fontsource/pretendard": "^5.1.0", - "react": "^18.3.1", - "react-dom": "^18.3.1", - "react-icons": "^5.3.0", - "react-router-dom": "^6.28.0" - }, - "devDependencies": { - "@chromatic-com/storybook": "^3.2.2", - "@eslint/js": "^9.13.0", - "@storybook/addon-essentials": "^8.4.2", - "@storybook/addon-interactions": "^8.4.2", - "@storybook/addon-onboarding": "^8.4.2", - "@storybook/blocks": "^8.4.2", - "@storybook/react": "^8.4.2", - "@storybook/react-vite": "^8.4.2", - "@storybook/test": "^8.4.2", - "@types/navermaps": "^3.7.8", - "@types/react": "^18.3.12", - "@types/react-dom": "^18.3.1", - "@types/react-router-dom": "^5.3.3", - "@vitejs/plugin-react-swc": "^3.5.0", - "autoprefixer": "^10.4.20", - "classnames": "^2.5.1", - "eslint": "^9.13.0", - "eslint-import-resolver-typescript": "^3.6.3", - "eslint-plugin-react-hooks": "^5.0.0", - "eslint-plugin-react-refresh": "^0.4.14", - "eslint-plugin-storybook": "^0.11.0", - "globals": "^15.11.0", - "postcss": "^8.4.47", - "storybook": "^8.4.2", - "tailwindcss": "^3.4.14", - "typescript": "~5.6.2", - "typescript-eslint": "^8.11.0", - "vite": "^5.4.10", - "vite-tsconfig-paths": "^5.1.1" - }, - "eslintConfig": { - "extends": [ - "plugin:storybook/recommended" - ] - } - } \ No newline at end of file +{ + "name": "ddara-frontend", + "private": true, + "workspaces": [ + "frontend", + "backend" + ], + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "test": "vitest", + "test:watch": "vitest --watch", + "test:coverage": "vitest run --coverage", + "lint": "pnpm lint-staged", + "preview": "vite preview", + "storybook": "storybook dev -p 6006", + "build-storybook": "storybook build" + }, + "dependencies": { + "@fontsource/pretendard": "^5.1.0", + "axios": "^1.7.7", + "lz-string": "^1.5.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-icons": "^5.3.0", + "react-router-dom": "^6.28.0" + }, + "devDependencies": { + "@chromatic-com/storybook": "^3.2.2", + "@eslint/js": "^9.13.0", + "@storybook/addon-essentials": "^8.4.2", + "@storybook/addon-interactions": "^8.4.2", + "@storybook/addon-onboarding": "^8.4.2", + "@storybook/blocks": "^8.4.2", + "@storybook/react": "^8.4.2", + "@storybook/react-vite": "^8.4.2", + "@storybook/test": "^8.4.2", + "@types/navermaps": "^3.7.8", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", + "@types/react-router-dom": "^5.3.3", + "@vitejs/plugin-react-swc": "^3.5.0", + "autoprefixer": "^10.4.20", + "classnames": "^2.5.1", + "eslint": "^9.13.0", + "eslint-import-resolver-typescript": "^3.6.3", + "eslint-plugin-react-hooks": "^5.0.0", + "eslint-plugin-react-refresh": "^0.4.14", + "eslint-plugin-storybook": "^0.11.0", + "globals": "^15.11.0", + "postcss": "^8.4.47", + "storybook": "^8.4.2", + "tailwindcss": "^3.4.14", + "typescript": "~5.6.2", + "typescript-eslint": "^8.11.0", + "vite": "^5.4.10", + "vite-tsconfig-paths": "^5.1.1" + }, + "eslintConfig": { + "extends": [ + "plugin:storybook/recommended" + ] + } +} \ No newline at end of file diff --git a/frontend/src/api/client.api.ts b/frontend/src/api/client.api.ts new file mode 100644 index 00000000..78bdadb1 --- /dev/null +++ b/frontend/src/api/client.api.ts @@ -0,0 +1,31 @@ +import { AppConfig } from '@/constants'; +import { loadLocalData } from '@/utils/common/manageLocalData.ts'; +import axios from 'axios'; + +let apiClient = axios.create({ + baseURL: AppConfig.API_SERVER, + headers: { + 'Content-type': 'application/json', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Credentials': true, + }, +}); + +export function setApiToken(token: string): void { + if (apiClient) apiClient.defaults.headers.common.Authorization = `Bearer ${token}`; +} + +export const getApiClient = () => { + const token = loadLocalData(AppConfig.KEYS.LOGIN_TOKEN); + if (token) setApiToken(token); + if (!apiClient) { + apiClient = axios.create({ + baseURL: AppConfig.API_SERVER, + headers: { + 'Content-type': 'application/json', + 'Access-Control-Allow-Origin': '*', + }, + }); + } + return apiClient; +}; diff --git a/frontend/src/api/dto/response.dto.ts b/frontend/src/api/dto/response.dto.ts new file mode 100644 index 00000000..a071613b --- /dev/null +++ b/frontend/src/api/dto/response.dto.ts @@ -0,0 +1,16 @@ +export class ResponseDto { + resultCode = 0; + + resultMsg = ''; + + data?: T; + + totalCount = 0; + + constructor(data?: any) { + if (data.resultCode) this.resultCode = data.resultCode; + if (data.resultMsg) this.resultMsg = data.resultMsg; + if (data.data) this.data = data.data; + if (data.totalCount) this.totalCount = data.totalCount; + } +} diff --git a/frontend/src/constants.ts b/frontend/src/constants.ts new file mode 100644 index 00000000..9acb7b75 --- /dev/null +++ b/frontend/src/constants.ts @@ -0,0 +1,16 @@ +export const KEYS = { + LOGIN_USER: 'LUT', + LOGIN_TOKEN: 'LUT_TK', +}; + +export const AppConfig = { + /** + * API SERVER + */ + API_SERVER: 'http://http://223.130.151.43:3001/api', + + /** + * ETC + */ + KEYS, +}; diff --git a/frontend/src/pages/Main.tsx b/frontend/src/pages/Main.tsx index 42bd85bd..f3c99bb5 100644 --- a/frontend/src/pages/Main.tsx +++ b/frontend/src/pages/Main.tsx @@ -1,4 +1,4 @@ -import React, { Fragment } from 'react'; +import { Fragment } from 'react'; import { getUserLocation } from '@/hooks/getUserLocation'; import { Map } from '@/component/maps/Map'; import { BottomSheet } from '@/component/BottomSheet/BottomSheet'; diff --git a/frontend/src/utils/common/manageLocalData.ts b/frontend/src/utils/common/manageLocalData.ts new file mode 100644 index 00000000..c74b7317 --- /dev/null +++ b/frontend/src/utils/common/manageLocalData.ts @@ -0,0 +1,53 @@ +/* eslint-disable */ +import lzString from 'lz-string' + +export function saveLocalData(key: string, val: string): void { + if (typeof window !== 'undefined') { + const storage = window.localStorage; + + if (storage) { + try { + storage.setItem(key, lzString.compressToUTF16(val)); + } catch (e) { + console.error('Storage Full ... clean old data...'); + for (const k in storage) { + if (k.indexOf('DATA_MESSAGE_DETAIL_') > -1) { + storage.removeItem(k); + } + } + storage.setItem(key, lzString.compressToUTF16(val)); + } + } + } +} + +export function loadLocalData(key: string): string | null { + if (typeof window !== undefined) { + const storage = window.localStorage; + + if (storage) { + const keyValue = storage.getItem(key); + if (keyValue) return lzString.decompressFromUTF16(keyValue); + } + } + return null; +} + +export function clearLocalData() { + if (typeof window !== undefined) { + const storage = window.localStorage; + + if (storage) { + storage.clear(); + } + } +} + +export function removeLocalData(key: string): void { + if (typeof window !== undefined) { + const storage = window.localStorage; + if (storage) { + storage.removeItem(key); + } + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 91c80184..24a1058e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -202,6 +202,12 @@ importers: '@fontsource/pretendard': specifier: ^5.1.0 version: 5.1.0 + axios: + specifier: ^1.7.7 + version: 1.7.7 + lz-string: + specifier: ^1.5.0 + version: 1.5.0 react: specifier: ^18.3.1 version: 18.3.1 @@ -2870,6 +2876,9 @@ packages: resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==} hasBin: true + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + at-least-node@1.0.0: resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} engines: {node: '>= 4.0.0'} @@ -2889,6 +2898,9 @@ packages: resolution: {integrity: sha512-RE3mdQ7P3FRSe7eqCWoeQ/Z9QXrtniSjp1wUjt5nRC3WIpz5rSCve6o3fsZ2aCpJtrZjSZgjwXAoTO5k4tEI0w==} engines: {node: '>=4'} + axios@1.7.7: + resolution: {integrity: sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==} + axobject-query@4.1.0: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} @@ -3194,6 +3206,10 @@ packages: resolution: {integrity: sha512-VcQB1ziGD0NXrhKxiwyNbCDmRzs/OShMs2GqW2DlU2A/Sd0nQxE1oWDAE5O0ygSx5mgQOn9eIFh7yKPgFRVkPQ==} engines: {node: '>=10'} + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + comma-separated-tokens@2.0.3: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} @@ -3692,6 +3708,10 @@ packages: delaunator@5.0.1: resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==} + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + delegates@1.0.0: resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} @@ -4329,6 +4349,10 @@ packages: resolution: {integrity: sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==} engines: {node: '>= 14.17'} + form-data@4.0.1: + resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==} + engines: {node: '>= 6'} + format@0.2.2: resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} engines: {node: '>=0.4.x'} @@ -6458,6 +6482,9 @@ packages: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + punycode.js@2.3.1: resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} engines: {node: '>=6'} @@ -11479,6 +11506,8 @@ snapshots: astring@1.9.0: {} + asynckit@0.4.0: {} + at-least-node@1.0.0: {} autoprefixer@10.4.20(postcss@8.4.49): @@ -11497,6 +11526,14 @@ snapshots: axe-core@4.10.2: {} + axios@1.7.7: + dependencies: + follow-redirects: 1.15.9 + form-data: 4.0.1 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + axobject-query@4.1.0: {} babel-loader@9.2.1(@babel/core@7.26.0)(webpack@5.96.1): @@ -11832,6 +11869,10 @@ snapshots: combine-promises@1.2.0: {} + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + comma-separated-tokens@2.0.3: {} commander@10.0.1: {} @@ -12360,6 +12401,8 @@ snapshots: dependencies: robust-predicates: 3.0.2 + delayed-stream@1.0.0: {} + delegates@1.0.0: {} depd@1.1.2: {} @@ -13209,6 +13252,12 @@ snapshots: form-data-encoder@2.1.4: {} + form-data@4.0.1: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + format@0.2.2: {} forwarded@0.2.0: {} @@ -15601,6 +15650,8 @@ snapshots: forwarded: 0.2.0 ipaddr.js: 1.9.1 + proxy-from-env@1.1.0: {} + punycode.js@2.3.1: {} punycode@2.3.1: {} From 9fd2f57c8871c2c0520b6d22ef2a3b25ef758234 Mon Sep 17 00:00:00 2001 From: happyhyep Date: Mon, 18 Nov 2024 17:37:16 +0900 Subject: [PATCH 2/2] =?UTF-8?q?[FE][Feat]=20#186=20:=20=EA=B3=B5=ED=86=B5?= =?UTF-8?q?=20=ED=95=A8=EC=88=98=20=EC=84=B8=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - axios 관련 패키지 설치 및 세팅 - localStorage 세팅 - eslint max-classes-per-file 세팅 off --- frontend/src/constants.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/constants.ts b/frontend/src/constants.ts index 9acb7b75..1499d2fe 100644 --- a/frontend/src/constants.ts +++ b/frontend/src/constants.ts @@ -7,7 +7,8 @@ export const AppConfig = { /** * API SERVER */ - API_SERVER: 'http://http://223.130.151.43:3001/api', + API_SERVER: 'http://223.130.151.43:3001/api', + // API_SERVER: 'http://localhost:3001/api', /** * ETC