From 7001ae4bf99059eaf2c338305e5c4a58931ea0ea Mon Sep 17 00:00:00 2001 From: jjangminii Date: Thu, 11 Sep 2025 23:19:23 +0900 Subject: [PATCH 1/7] =?UTF-8?q?feat:=20=ED=98=84=EC=9E=AC=20=EC=8B=9C?= =?UTF-8?q?=EA=B0=84=20=ED=8F=AC=EB=A7=B7=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/client/src/pages/level/Level.tsx | 11 +++++++++-- apps/client/src/shared/utils/formatDateTime.ts | 9 +++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 apps/client/src/shared/utils/formatDateTime.ts diff --git a/apps/client/src/pages/level/Level.tsx b/apps/client/src/pages/level/Level.tsx index 77debd4d..fb1519ce 100644 --- a/apps/client/src/pages/level/Level.tsx +++ b/apps/client/src/pages/level/Level.tsx @@ -6,16 +6,19 @@ import TreeStatusCard from '@pages/level/components/TreeStatusCard'; import { getTreeLevel } from '@shared/utils/treeLevel'; import { TreeLevel } from '@pages/level/types/treeLevelType'; import { Badge } from '@pinback/design-system/ui'; +import { formatLocalDateTime } from '@shared/utils/formatDateTime'; export default function Level() { const acorns = 1; // TODO: API 연결되면 교체 const info = getTreeLevel(acorns); + const now = new Date(); + const remindDateTime = formatLocalDateTime(now); + console.log(remindDateTime); return (
-
@@ -42,7 +45,11 @@ export default function Level() {
- +
diff --git a/apps/client/src/shared/utils/formatDateTime.ts b/apps/client/src/shared/utils/formatDateTime.ts new file mode 100644 index 00000000..fb5d2356 --- /dev/null +++ b/apps/client/src/shared/utils/formatDateTime.ts @@ -0,0 +1,9 @@ +export const formatLocalDateTime = (date: Date = new Date()) => { + const yyyy = date.getFullYear(); + const mm = String(date.getMonth() + 1).padStart(2, '0'); + const dd = String(date.getDate()).padStart(2, '0'); + const hh = String(date.getHours()).padStart(2, '0'); + const mi = String(date.getMinutes()).padStart(2, '0'); + const ss = String(date.getSeconds()).padStart(2, '0'); + return `${yyyy}-${mm}-${dd}T${hh}:${mi}:${ss}`; +}; From 3ad75e57553594f358c0003a196626d5035a0fa5 Mon Sep 17 00:00:00 2001 From: jjangminii Date: Fri, 12 Sep 2025 01:01:33 +0900 Subject: [PATCH 2/7] =?UTF-8?q?feat:=20=EB=A0=88=EB=B2=A8=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20API=20=EC=97=B0=EA=B2=B0=20=EB=B0=8F=20?= =?UTF-8?q?=EB=8C=80=EC=8B=9C=EB=B3=B4=EB=93=9C=20=EC=B9=B4=ED=85=8C?= =?UTF-8?q?=EA=B3=A0=EB=A6=AC=20=EA=B4=80=EB=A0=A8=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/client/.gitignore | 1 + apps/client/src/main.tsx | 2 +- apps/client/src/pages/level/Level.tsx | 18 ++-- apps/client/src/pages/level/apis/axios.ts | 10 ++ apps/client/src/pages/level/apis/queries.ts | 11 +++ apps/client/src/pages/level/types/api.ts | 4 + .../{components/sidebar => }/apis/axios.ts | 2 +- apps/client/src/shared/apis/axiosInstance.ts | 97 ------------------- .../{components/sidebar => }/apis/queries.ts | 7 +- .../{ => setting}/query/getQueryClient.ts | 0 .../{ => setting}/query/queryClientOptions.ts | 0 .../src/shared/components/sidebar/Sidebar.tsx | 2 +- .../{components/sidebar => }/types/api.ts | 0 13 files changed, 41 insertions(+), 113 deletions(-) create mode 100644 apps/client/src/pages/level/apis/axios.ts create mode 100644 apps/client/src/pages/level/apis/queries.ts create mode 100644 apps/client/src/pages/level/types/api.ts rename apps/client/src/shared/{components/sidebar => }/apis/axios.ts (84%) delete mode 100644 apps/client/src/shared/apis/axiosInstance.ts rename apps/client/src/shared/{components/sidebar => }/apis/queries.ts (72%) rename apps/client/src/shared/apis/{ => setting}/query/getQueryClient.ts (100%) rename apps/client/src/shared/apis/{ => setting}/query/queryClientOptions.ts (100%) rename apps/client/src/shared/{components/sidebar => }/types/api.ts (100%) diff --git a/apps/client/.gitignore b/apps/client/.gitignore index a547bf36..7ceb59f8 100644 --- a/apps/client/.gitignore +++ b/apps/client/.gitignore @@ -22,3 +22,4 @@ dist-ssr *.njsproj *.sln *.sw? +.env diff --git a/apps/client/src/main.tsx b/apps/client/src/main.tsx index ab96589b..397bfc03 100644 --- a/apps/client/src/main.tsx +++ b/apps/client/src/main.tsx @@ -2,7 +2,7 @@ import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; import App from './App.tsx'; import { QueryClientProvider } from '@tanstack/react-query'; -import getQueryClient from '@shared/apis/query/getQueryClient.ts'; +import getQueryClient from '@shared/apis/setting/query/getQueryClient.ts'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; const queryClient = getQueryClient(); diff --git a/apps/client/src/pages/level/Level.tsx b/apps/client/src/pages/level/Level.tsx index fb1519ce..56c2f711 100644 --- a/apps/client/src/pages/level/Level.tsx +++ b/apps/client/src/pages/level/Level.tsx @@ -6,14 +6,16 @@ import TreeStatusCard from '@pages/level/components/TreeStatusCard'; import { getTreeLevel } from '@shared/utils/treeLevel'; import { TreeLevel } from '@pages/level/types/treeLevelType'; import { Badge } from '@pinback/design-system/ui'; -import { formatLocalDateTime } from '@shared/utils/formatDateTime'; +import { useGetArcons } from './apis/queries'; export default function Level() { - const acorns = 1; // TODO: API 연결되면 교체 - const info = getTreeLevel(acorns); - const now = new Date(); - const remindDateTime = formatLocalDateTime(now); - console.log(remindDateTime); + const { data, isPending, isError } = useGetArcons(); + + if (isPending) return console.log('로딩중...'); + if (isError) return console.log('에러...'); + + const acornCount = data.acornCount; + const info = getTreeLevel(acornCount); return (
@@ -47,11 +49,11 @@ export default function Level() {
- +
diff --git a/apps/client/src/pages/level/apis/axios.ts b/apps/client/src/pages/level/apis/axios.ts new file mode 100644 index 00000000..86ae6f3b --- /dev/null +++ b/apps/client/src/pages/level/apis/axios.ts @@ -0,0 +1,10 @@ +import apiRequest from '@shared/apis/setting/axiosInstance'; +import { formatLocalDateTime } from '@shared/utils/formatDateTime'; + +export const getAcorns = async () => { + const now = formatLocalDateTime(new Date()); + const { data } = await apiRequest.get('/api/v1/users/acorns?now=', { + params: { now }, + }); + return data.data; +}; diff --git a/apps/client/src/pages/level/apis/queries.ts b/apps/client/src/pages/level/apis/queries.ts new file mode 100644 index 00000000..c7f05412 --- /dev/null +++ b/apps/client/src/pages/level/apis/queries.ts @@ -0,0 +1,11 @@ +import { useQuery, UseQueryResult } from '@tanstack/react-query'; +import { getAcorns } from './axios'; +import { AxiosError } from 'axios'; +import { AcornsResponse } from '@pages/level/types/api'; + +export const useGetArcons = (): UseQueryResult => { + return useQuery({ + queryKey: ['arcons'], + queryFn: () => getAcorns(), + }); +}; diff --git a/apps/client/src/pages/level/types/api.ts b/apps/client/src/pages/level/types/api.ts new file mode 100644 index 00000000..3fac73b3 --- /dev/null +++ b/apps/client/src/pages/level/types/api.ts @@ -0,0 +1,4 @@ +export type AcornsResponse = { + acornCount: number; + remindDateTime: string; +}; diff --git a/apps/client/src/shared/components/sidebar/apis/axios.ts b/apps/client/src/shared/apis/axios.ts similarity index 84% rename from apps/client/src/shared/components/sidebar/apis/axios.ts rename to apps/client/src/shared/apis/axios.ts index 6accc4bb..d87741f3 100644 --- a/apps/client/src/shared/components/sidebar/apis/axios.ts +++ b/apps/client/src/shared/apis/axios.ts @@ -1,4 +1,4 @@ -import apiRequest from '@shared/apis/axiosInstance'; +import apiRequest from '@shared/apis/setting/axiosInstance'; export const getDashboardCategories = async () => { const { data } = await apiRequest.get('/api/v1/categories/dashboard'); diff --git a/apps/client/src/shared/apis/axiosInstance.ts b/apps/client/src/shared/apis/axiosInstance.ts deleted file mode 100644 index eb64dfe2..00000000 --- a/apps/client/src/shared/apis/axiosInstance.ts +++ /dev/null @@ -1,97 +0,0 @@ -import axios from 'axios'; - -// Axios 인스턴스 -const apiRequest = axios.create({ - baseURL: import.meta.env.VITE_BASE_URL, - headers: { - 'Content-Type': 'application/json', - }, -}); - -const refreshToken = async (email: string) => { - try { - const response = await axios.get( - `${import.meta.env.VITE_BASE_URL}/api/v1/auth/token`, - { - params: { email }, - } - ); - - const newToken = response.data.data?.token || response.data.token; - - if (newToken) { - localStorage.setItem('token', newToken); - return newToken; - } - - throw new Error('토큰 재발급 실패'); - } catch (error) { - console.error('토큰 재발급 실패:', error); - throw error; - } -}; - -// 요청 인터셉터 -apiRequest.interceptors.request.use(async (config) => { - const noAuthNeeded = ['/api/v1/auth/token', '/api/v1/auth/signup']; - const isNoAuth = noAuthNeeded.some((url) => config.url?.includes(url)); - - if (!isNoAuth) { - const token = localStorage.getItem('token'); - - if (!token || token === 'undefined' || token === 'null' || token === '') { - console.error('토큰이 없습니다. 온보딩을 먼저 완료해주세요.'); - throw new Error('토큰이 없습니다. 온보딩을 먼저 완료해주세요.'); - } - - config.headers.Authorization = `Bearer ${token}`; - } - - return config; -}); - -// 응답 인터셉터 -apiRequest.interceptors.response.use( - (response) => response, - async (error) => { - const originalRequest = error.config; - const noAuthNeeded = ['/api/v1/auth/token', '/api/v1/auth/signup']; - const isNoAuth = noAuthNeeded.some((url) => - originalRequest.url?.includes(url) - ); - - if ( - error.response && - (error.response.status === 401 || error.response.status === 403) && - !originalRequest._retry && - !isNoAuth - ) { - originalRequest._retry = true; - - try { - const email = localStorage.getItem('email'); - - if (email) { - const newToken = await refreshToken(email); - originalRequest.headers.Authorization = `Bearer ${newToken}`; - return apiRequest(originalRequest); - } else { - console.error( - '사용자 이메일이 없습니다. 온보딩을 다시 완료해주세요.' - ); - localStorage.removeItem('token'); - window.location.href = '/onboarding'; - } - } catch (refreshError) { - console.error('토큰 재발급 실패:', refreshError); - localStorage.removeItem('token'); - localStorage.removeItem('email'); - window.location.href = '/onboarding'; - } - } - - return Promise.reject(error); - } -); - -export default apiRequest; diff --git a/apps/client/src/shared/components/sidebar/apis/queries.ts b/apps/client/src/shared/apis/queries.ts similarity index 72% rename from apps/client/src/shared/components/sidebar/apis/queries.ts rename to apps/client/src/shared/apis/queries.ts index 18e1ec34..a8446ca0 100644 --- a/apps/client/src/shared/components/sidebar/apis/queries.ts +++ b/apps/client/src/shared/apis/queries.ts @@ -1,10 +1,7 @@ import { useMutation, useQuery, UseQueryResult } from '@tanstack/react-query'; -import { - getDashboardCategories, - postCategory, -} from '@shared/components/sidebar/apis/axios'; +import { getDashboardCategories, postCategory } from '@shared/apis/axios'; import { AxiosError } from 'axios'; -import { DashboardCategoriesResponse } from '@shared/components/sidebar/types/api'; +import { DashboardCategoriesResponse } from '@shared/types/api'; export const useGetDashboardCategories = (): UseQueryResult< DashboardCategoriesResponse, diff --git a/apps/client/src/shared/apis/query/getQueryClient.ts b/apps/client/src/shared/apis/setting/query/getQueryClient.ts similarity index 100% rename from apps/client/src/shared/apis/query/getQueryClient.ts rename to apps/client/src/shared/apis/setting/query/getQueryClient.ts diff --git a/apps/client/src/shared/apis/query/queryClientOptions.ts b/apps/client/src/shared/apis/setting/query/queryClientOptions.ts similarity index 100% rename from apps/client/src/shared/apis/query/queryClientOptions.ts rename to apps/client/src/shared/apis/setting/query/queryClientOptions.ts diff --git a/apps/client/src/shared/components/sidebar/Sidebar.tsx b/apps/client/src/shared/components/sidebar/Sidebar.tsx index ffdcd284..cb809892 100644 --- a/apps/client/src/shared/components/sidebar/Sidebar.tsx +++ b/apps/client/src/shared/components/sidebar/Sidebar.tsx @@ -13,7 +13,7 @@ import PopupPortal from './PopupPortal'; import { useGetDashboardCategories, usePostCategory, -} from '@shared/components/sidebar/apis/queries'; +} from '@shared/apis/queries'; import { useState } from 'react'; import { useQueryClient } from '@tanstack/react-query'; diff --git a/apps/client/src/shared/components/sidebar/types/api.ts b/apps/client/src/shared/types/api.ts similarity index 100% rename from apps/client/src/shared/components/sidebar/types/api.ts rename to apps/client/src/shared/types/api.ts From 93abd43c7baec851859b6cb996dab73550282c1d Mon Sep 17 00:00:00 2001 From: jjangminii Date: Fri, 12 Sep 2025 01:21:47 +0900 Subject: [PATCH 3/7] =?UTF-8?q?api:=20=EC=82=AC=EC=9D=B4=EB=93=9C=EB=B0=94?= =?UTF-8?q?=20=EB=8F=84=ED=86=A0=EB=A6=AC=20get=20api=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/client/src/pages/level/Level.tsx | 2 +- apps/client/src/pages/level/apis/axios.ts | 10 ---------- apps/client/src/pages/level/apis/queries.ts | 11 ----------- apps/client/src/pages/level/types/api.ts | 4 ---- apps/client/src/shared/apis/axios.ts | 9 +++++++++ apps/client/src/shared/apis/queries.ts | 10 +++++++++- apps/client/src/shared/components/sidebar/Sidebar.tsx | 8 +++++++- apps/client/src/shared/types/api.ts | 5 +++++ 8 files changed, 31 insertions(+), 28 deletions(-) delete mode 100644 apps/client/src/pages/level/apis/axios.ts delete mode 100644 apps/client/src/pages/level/apis/queries.ts delete mode 100644 apps/client/src/pages/level/types/api.ts diff --git a/apps/client/src/pages/level/Level.tsx b/apps/client/src/pages/level/Level.tsx index 56c2f711..3e5c72d1 100644 --- a/apps/client/src/pages/level/Level.tsx +++ b/apps/client/src/pages/level/Level.tsx @@ -6,7 +6,7 @@ import TreeStatusCard from '@pages/level/components/TreeStatusCard'; import { getTreeLevel } from '@shared/utils/treeLevel'; import { TreeLevel } from '@pages/level/types/treeLevelType'; import { Badge } from '@pinback/design-system/ui'; -import { useGetArcons } from './apis/queries'; +import { useGetArcons } from '@shared/apis/queries'; export default function Level() { const { data, isPending, isError } = useGetArcons(); diff --git a/apps/client/src/pages/level/apis/axios.ts b/apps/client/src/pages/level/apis/axios.ts deleted file mode 100644 index 86ae6f3b..00000000 --- a/apps/client/src/pages/level/apis/axios.ts +++ /dev/null @@ -1,10 +0,0 @@ -import apiRequest from '@shared/apis/setting/axiosInstance'; -import { formatLocalDateTime } from '@shared/utils/formatDateTime'; - -export const getAcorns = async () => { - const now = formatLocalDateTime(new Date()); - const { data } = await apiRequest.get('/api/v1/users/acorns?now=', { - params: { now }, - }); - return data.data; -}; diff --git a/apps/client/src/pages/level/apis/queries.ts b/apps/client/src/pages/level/apis/queries.ts deleted file mode 100644 index c7f05412..00000000 --- a/apps/client/src/pages/level/apis/queries.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { useQuery, UseQueryResult } from '@tanstack/react-query'; -import { getAcorns } from './axios'; -import { AxiosError } from 'axios'; -import { AcornsResponse } from '@pages/level/types/api'; - -export const useGetArcons = (): UseQueryResult => { - return useQuery({ - queryKey: ['arcons'], - queryFn: () => getAcorns(), - }); -}; diff --git a/apps/client/src/pages/level/types/api.ts b/apps/client/src/pages/level/types/api.ts deleted file mode 100644 index 3fac73b3..00000000 --- a/apps/client/src/pages/level/types/api.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type AcornsResponse = { - acornCount: number; - remindDateTime: string; -}; diff --git a/apps/client/src/shared/apis/axios.ts b/apps/client/src/shared/apis/axios.ts index d87741f3..c7175346 100644 --- a/apps/client/src/shared/apis/axios.ts +++ b/apps/client/src/shared/apis/axios.ts @@ -1,4 +1,5 @@ import apiRequest from '@shared/apis/setting/axiosInstance'; +import { formatLocalDateTime } from '@shared/utils/formatDateTime'; export const getDashboardCategories = async () => { const { data } = await apiRequest.get('/api/v1/categories/dashboard'); @@ -11,3 +12,11 @@ export const postCategory = async (categoryName: string) => { }); return response; }; + +export const getAcorns = async () => { + const now = formatLocalDateTime(new Date()); + const { data } = await apiRequest.get('/api/v1/users/acorns?now=', { + params: { now }, + }); + return data.data; +}; diff --git a/apps/client/src/shared/apis/queries.ts b/apps/client/src/shared/apis/queries.ts index a8446ca0..45bcc054 100644 --- a/apps/client/src/shared/apis/queries.ts +++ b/apps/client/src/shared/apis/queries.ts @@ -1,7 +1,8 @@ import { useMutation, useQuery, UseQueryResult } from '@tanstack/react-query'; import { getDashboardCategories, postCategory } from '@shared/apis/axios'; import { AxiosError } from 'axios'; -import { DashboardCategoriesResponse } from '@shared/types/api'; +import { DashboardCategoriesResponse, AcornsResponse } from '@shared/types/api'; +import { getAcorns } from './axios'; export const useGetDashboardCategories = (): UseQueryResult< DashboardCategoriesResponse, @@ -18,3 +19,10 @@ export const usePostCategory = () => { mutationFn: (categoryName: string) => postCategory(categoryName), }); }; + +export const useGetArcons = (): UseQueryResult => { + return useQuery({ + queryKey: ['arcons'], + queryFn: () => getAcorns(), + }); +}; diff --git a/apps/client/src/shared/components/sidebar/Sidebar.tsx b/apps/client/src/shared/components/sidebar/Sidebar.tsx index cb809892..2637ee47 100644 --- a/apps/client/src/shared/components/sidebar/Sidebar.tsx +++ b/apps/client/src/shared/components/sidebar/Sidebar.tsx @@ -13,6 +13,7 @@ import PopupPortal from './PopupPortal'; import { useGetDashboardCategories, usePostCategory, + useGetArcons, } from '@shared/apis/queries'; import { useState } from 'react'; import { useQueryClient } from '@tanstack/react-query'; @@ -23,6 +24,7 @@ export function Sidebar() { const { data: categories } = useGetDashboardCategories(); const { mutate: createCategory } = usePostCategory(); + const { data, isPending, isError } = useGetArcons(); const { activeTab, @@ -65,6 +67,10 @@ export function Sidebar() { }); }; + if (isPending) return console.log('로딩중...'); + if (isError) return console.log('에러...'); + const acornCount = data.acornCount; + return (