From e3d39e016e161f63539f38c8315ab639cfd5432f Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 22:41:43 +0900 Subject: [PATCH 01/19] =?UTF-8?q?feat:=20=EC=A7=84=EB=8B=A8=20=ED=8F=BC?= =?UTF-8?q?=EC=97=90=20=EC=9C=84=ED=97=98=EB=8F=84=20=EB=B6=84=EC=84=9D=20?= =?UTF-8?q?=EC=84=B9=EC=85=98=EC=9C=BC=EB=A1=9C=20=EC=8A=A4=ED=81=AC?= =?UTF-8?q?=EB=A1=A4=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80=20=EB=B0=8F?= =?UTF-8?q?=20Props=20=ED=83=80=EC=9E=85=20=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../features/form/DiagnosticForm.tsx | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/features/main/components/features/form/DiagnosticForm.tsx b/src/features/main/components/features/form/DiagnosticForm.tsx index 6c00bf6..7450513 100644 --- a/src/features/main/components/features/form/DiagnosticForm.tsx +++ b/src/features/main/components/features/form/DiagnosticForm.tsx @@ -1,3 +1,4 @@ +import { type RefObject } from 'react'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; @@ -17,7 +18,11 @@ import { RentTypeField, } from '../../common'; -export const DiagnosticForm = () => { +type Props = { + scrollToRiskAnalysis: RefObject; +}; + +export const DiagnosticForm = ({ scrollToRiskAnalysis }: Props) => { const { setDiagnosisData } = useHouseData(); const form = useForm({ @@ -40,6 +45,20 @@ export const DiagnosticForm = () => { }), onSuccess: (data) => { setDiagnosisData(data); + + // 진단 완료 후 위험도 분석 섹션으로 스크롤 + setTimeout(() => { + if (scrollToRiskAnalysis.current) { + const element = scrollToRiskAnalysis.current; + const elementTop = element.offsetTop; + const offset = 80; + + window.scrollTo({ + top: elementTop - offset, + behavior: 'smooth', + }); + } + }, 100); }, }); From 3ddb954810863b997327a4ce01cf1db00e4d8973 Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 22:42:08 +0900 Subject: [PATCH 02/19] =?UTF-8?q?fix:=20DETAIL=5FADDRESS=EC=9D=98=20?= =?UTF-8?q?=EB=AC=B8=EC=9E=A5=20=EB=81=9D=20=EB=A7=88=EC=B9=A8=ED=91=9C=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/main/constants/form-type.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/features/main/constants/form-type.ts b/src/features/main/constants/form-type.ts index fba620c..2959f8b 100644 --- a/src/features/main/constants/form-type.ts +++ b/src/features/main/constants/form-type.ts @@ -9,7 +9,7 @@ export const FORM_FIELDS = { export const PLACEHOLDER_TEXTS = { ADDRESS: '주소를 알려주세요', HOUSE_TYPE: '주택유형을 알려주세요', - DETAIL_ADDRESS: '상세주소를 알려주세요.', + DETAIL_ADDRESS: '상세주소를 알려주세요', DEPOSIT: '전세금액', } as const; From 51c17053f39ee1c6e888a593548ff7402dc40a2a Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 22:42:25 +0900 Subject: [PATCH 03/19] =?UTF-8?q?feat:=20InputSection=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=EC=97=90=20scrollToRiskAnalysis=20prop=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=ED=83=80=EC=9E=85=20=EC=A0=95?= =?UTF-8?q?=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/main/ui/InputSection.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/features/main/ui/InputSection.tsx b/src/features/main/ui/InputSection.tsx index bcd4819..01a3b2d 100644 --- a/src/features/main/ui/InputSection.tsx +++ b/src/features/main/ui/InputSection.tsx @@ -1,6 +1,12 @@ +import { type RefObject } from 'react'; + import { DiagnosticForm } from '../components'; -export const InputSection = () => { +type Props = { + scrollToRiskAnalysis: RefObject; +}; + +export const InputSection = ({ scrollToRiskAnalysis }: Props) => { return (
@@ -11,7 +17,7 @@ export const InputSection = () => { 안심할 수 있는지 확인해봐요!
- +
); From 7cfa50bde1ba08ed60f161bfdab22c4fce4880c7 Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 22:44:30 +0900 Subject: [PATCH 04/19] =?UTF-8?q?feat:=20RiskAnalysisSummarySection=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=EB=A5=BC=20forwardRef?= =?UTF-8?q?=EB=A1=9C=20=EC=88=98=EC=A0=95=ED=95=98=EC=97=AC=20ref=20?= =?UTF-8?q?=EC=A0=84=EB=8B=AC=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/main/ui/RiskAnalysisSummarySection.tsx | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/features/main/ui/RiskAnalysisSummarySection.tsx b/src/features/main/ui/RiskAnalysisSummarySection.tsx index f05cbe1..0f6d1ce 100644 --- a/src/features/main/ui/RiskAnalysisSummarySection.tsx +++ b/src/features/main/ui/RiskAnalysisSummarySection.tsx @@ -1,10 +1,12 @@ +import { forwardRef } from 'react'; + import { Spinner } from '@/shared'; import { RiskChartBox, RiskFactorsBox } from '../components'; import { DEFAULT_RISK_ANALYSIS_DATA } from '../mock/risk-analysis.mock'; import { useHouseData } from '../store'; -export const RiskAnalysisSummarySection = () => { +export const RiskAnalysisSummarySection = forwardRef((_, ref) => { const { diagnosisData, isLoading, error } = useHouseData(); if (isLoading) return ; @@ -20,7 +22,10 @@ export const RiskAnalysisSummarySection = () => { } return ( -
+
{/* 메인 위험도 분석 섹션 */}
{/* 왼쪽: 위험도 게이지 */} @@ -30,4 +35,6 @@ export const RiskAnalysisSummarySection = () => {
); -}; +}); + +RiskAnalysisSummarySection.displayName = 'RiskAnalysisSummarySection'; From 8c8f326a0e13249104a294e456eb9331359440cf Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 22:44:46 +0900 Subject: [PATCH 05/19] =?UTF-8?q?feat:=20MainPage=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=EC=97=90=20=EC=9C=84=ED=97=98=EB=8F=84=20?= =?UTF-8?q?=EB=B6=84=EC=84=9D=20=EC=84=B9=EC=85=98=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=8A=A4=ED=81=AC=EB=A1=A4=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EB=B0=8F=20ref=20=EC=A0=84=EB=8B=AC=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/main/MainPage.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/pages/main/MainPage.tsx b/src/pages/main/MainPage.tsx index 8d07d37..ac7202c 100644 --- a/src/pages/main/MainPage.tsx +++ b/src/pages/main/MainPage.tsx @@ -1,3 +1,5 @@ +import { useRef } from 'react'; + import { AlternativeSection, ChartSection, @@ -9,13 +11,15 @@ import { } from '@/features'; export default function MainPage() { + const riskAnalysisRef = useRef(null); + return (
- + } />
- + From 286a15b91935e3a24247757f519f2607a91bd81d Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Sat, 23 Aug 2025 01:20:33 +0900 Subject: [PATCH 06/19] =?UTF-8?q?feat:=20Vite=20=EC=84=A4=EC=A0=95?= =?UTF-8?q?=EC=97=90=20API=20=ED=94=84=EB=A1=9D=EC=8B=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=ED=95=98=EC=97=AC=20=EA=B0=9C=EB=B0=9C=20=ED=99=98?= =?UTF-8?q?=EA=B2=BD=EC=97=90=EC=84=9C=20API=20=EC=9A=94=EC=B2=AD=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vite.config.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/vite.config.ts b/vite.config.ts index 915831b..d40e92e 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -11,4 +11,12 @@ export default defineConfig({ '@': path.resolve(__dirname, './src'), }, }, + server: { + proxy: { + '/api': { + target: 'http://43.200.101.253', + changeOrigin: true, + }, + }, + }, }); From 45add72b3f950db5cd31863bd3ca10e4a30411e3 Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Sat, 23 Aug 2025 01:21:21 +0900 Subject: [PATCH 07/19] =?UTF-8?q?feat:=20GET=5FTICKET=5FAPI=5FPATH?= =?UTF-8?q?=EB=A5=BC=20=ED=95=A8=EC=88=98=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= =?UTF-8?q?=ED=95=98=EC=97=AC=20=EB=8F=99=EC=A0=81=20=EA=B2=BD=EB=A1=9C=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/auth/apis/get-ticket.api.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/entities/auth/apis/get-ticket.api.ts b/src/entities/auth/apis/get-ticket.api.ts index 60f27c3..c04aa11 100644 --- a/src/entities/auth/apis/get-ticket.api.ts +++ b/src/entities/auth/apis/get-ticket.api.ts @@ -1,16 +1,17 @@ import { fetchInstance } from '@/shared'; -export const GET_TICKET_API_PATH = '/api/auth/ticket'; +export const GET_TICKET_API_PATH = () => '/auth/ticket'; interface GetTicketApiResponse { refreshToken: string; } export const getTicketApi = async (ticket: string): Promise => { - const response = await fetchInstance.get(GET_TICKET_API_PATH, { + const response = await fetchInstance.get(GET_TICKET_API_PATH(), { params: { ticket, }, }); + return response.data; }; From 08ecb153bdb09485487e4130c688d205b680f744 Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Sat, 23 Aug 2025 01:21:36 +0900 Subject: [PATCH 08/19] =?UTF-8?q?feat:=20refresh-token.api=EB=A5=BC=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=ED=95=98=EC=97=AC=20=EC=9D=B8=EC=A6=9D=20API?= =?UTF-8?q?=20=ED=99=95=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/auth/apis/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/entities/auth/apis/index.ts b/src/entities/auth/apis/index.ts index 5cbea31..97ec6b7 100644 --- a/src/entities/auth/apis/index.ts +++ b/src/entities/auth/apis/index.ts @@ -1 +1,2 @@ export * from './get-ticket.api'; +export * from './refresh-token.api'; From dfdf6d44c608442b4c81edfd5e3e463d1125f8d8 Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Sat, 23 Aug 2025 01:21:52 +0900 Subject: [PATCH 09/19] =?UTF-8?q?feat:=20refresh-token.api.ts=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=B6=94=EA=B0=80=ED=95=98=EC=97=AC=20=EC=9D=B8?= =?UTF-8?q?=EC=A6=9D=20=ED=86=A0=ED=81=B0=20=EA=B0=B1=EC=8B=A0=20API=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/auth/apis/refresh-token.api.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/entities/auth/apis/refresh-token.api.ts diff --git a/src/entities/auth/apis/refresh-token.api.ts b/src/entities/auth/apis/refresh-token.api.ts new file mode 100644 index 0000000..3fbed2c --- /dev/null +++ b/src/entities/auth/apis/refresh-token.api.ts @@ -0,0 +1,21 @@ +import { fetchInstance } from '@/shared'; + +export const REFRESH_TOKEN_API_PATH = '/auth/refresh'; + +interface RefreshTokenApiRequest { + refreshToken: string; +} + +interface RefreshTokenApiResponse { + accessToken: string; +} + +export const refreshTokenApi = async ({ + refreshToken, +}: RefreshTokenApiRequest): Promise => { + const response = await fetchInstance.post(REFRESH_TOKEN_API_PATH, { + refreshToken, + }); + + return response.data; +}; From 4b7fe0c2e9c4c16502a1855ee3108bb0fab41835 Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Sat, 23 Aug 2025 01:22:04 +0900 Subject: [PATCH 10/19] =?UTF-8?q?feat:=20getAuthTicket.ts=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=82=AD=EC=A0=9C=20=EB=B0=8F=20useGetAuthTicket?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD=ED=95=98=EC=97=AC=20=EC=9D=B8?= =?UTF-8?q?=EC=A6=9D=20=ED=8B=B0=EC=BC=93=20=ED=9B=85=20=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/auth/hooks/getAuthTicket.ts | 14 -------------- src/entities/auth/hooks/index.ts | 3 ++- 2 files changed, 2 insertions(+), 15 deletions(-) delete mode 100644 src/entities/auth/hooks/getAuthTicket.ts diff --git a/src/entities/auth/hooks/getAuthTicket.ts b/src/entities/auth/hooks/getAuthTicket.ts deleted file mode 100644 index 0dbd3f2..0000000 --- a/src/entities/auth/hooks/getAuthTicket.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { useQuery } from '@tanstack/react-query'; - -import { getTicketApi } from '../apis'; - -export const GetAuthTicketQueryKey = { - ticket: (ticket: string) => ['ticket', ticket], -}; - -export const useGetAuthTicket = (ticket: string) => { - return useQuery({ - queryKey: GetAuthTicketQueryKey.ticket(ticket), - queryFn: () => getTicketApi(ticket), - }); -}; diff --git a/src/entities/auth/hooks/index.ts b/src/entities/auth/hooks/index.ts index 83322f7..763029c 100644 --- a/src/entities/auth/hooks/index.ts +++ b/src/entities/auth/hooks/index.ts @@ -1,2 +1,3 @@ -export * from './getAuthTicket'; +export * from './useGetAuthTicket'; export * from './useKakaoLogin'; +export * from './useGetRefreshToken'; From 075fc19a9382fed149bc40b67a7456b8cdabde2b Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Sat, 23 Aug 2025 01:22:22 +0900 Subject: [PATCH 11/19] =?UTF-8?q?fix:=20auth-storage.ts=EC=97=90=EC=84=9C?= =?UTF-8?q?=20JSON=20=ED=8C=8C=EC=8B=B1=20=EB=B0=8F=20=EB=AC=B8=EC=9E=90?= =?UTF-8?q?=EC=97=B4=20=EB=B3=80=ED=99=98=20=EB=A1=9C=EC=A7=81=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/shared/utils/auth-storage/auth-storage.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/shared/utils/auth-storage/auth-storage.ts b/src/shared/utils/auth-storage/auth-storage.ts index 1db7db0..195e4af 100644 --- a/src/shared/utils/auth-storage/auth-storage.ts +++ b/src/shared/utils/auth-storage/auth-storage.ts @@ -9,7 +9,7 @@ const initStorage = (key: T, storage: Storage) = const get = (): AuthStorageKey[T] => { const value = storage.getItem(storageKey); - return JSON.parse(value as string); + return value as AuthStorageKey[T]; }; const set = (value: AuthStorageKey[T]) => { @@ -17,9 +17,7 @@ const initStorage = (key: T, storage: Storage) = return storage.removeItem(storageKey); } - const stringifiedValue = JSON.stringify(value); - - storage.setItem(storageKey, stringifiedValue); + storage.setItem(storageKey, String(value)); }; return { get, set }; From 9f2f7c7c939a4ebc65ee43ba590101127bb0b587 Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Sat, 23 Aug 2025 01:22:38 +0900 Subject: [PATCH 12/19] =?UTF-8?q?feat:=20fetch-instance.ts=EC=97=90=20?= =?UTF-8?q?=EC=9D=91=EB=8B=B5=20=EC=9D=B8=ED=84=B0=EC=85=89=ED=84=B0=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EC=9E=AC=EC=9D=B8=EC=A6=9D=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/shared/libs/fetch-instance.ts | 52 ++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/src/shared/libs/fetch-instance.ts b/src/shared/libs/fetch-instance.ts index 74c88ae..eab5f96 100644 --- a/src/shared/libs/fetch-instance.ts +++ b/src/shared/libs/fetch-instance.ts @@ -1,9 +1,14 @@ +import { toast } from 'sonner'; + +import { authStorage } from '../utils'; + import { initInstance } from './axios-instance'; export const BASE_URL = 'http://43.200.101.253'; +// export const BASE_URL = 'http://localhost:8080'; export const fetchInstance = initInstance({ - baseURL: BASE_URL, + baseURL: '/api', headers: { 'Content-Type': 'application/json', }, @@ -15,3 +20,48 @@ fetchInstance.interceptors.request.use( }, (error) => Promise.reject(error), ); + +fetchInstance.interceptors.response.use( + (response) => response, + async (error) => { + const originalRequest = error.config; + + if (error.response.status === 500 && !originalRequest._retry) { + originalRequest._retry = true; + + const refreshToken = authStorage.refreshToken.get(); + + if (!refreshToken) { + return Promise.reject(error); + } + + const response = await fetch(`${BASE_URL}/auth/refresh`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ refreshToken }), + }); + + if (response.ok) { + console.log('refreshToken success'); + toast.success('재인증 성공!'); + const data = await response.json(); + + authStorage.refreshToken.set(data.refreshToken); + authStorage.accessToken.set(data.accessToken); + + return fetchInstance(originalRequest); + } else if (response.status === 401) { + console.log('refreshToken failed'); + toast.error('재인증 실패!'); + + authStorage.refreshToken.set(''); + authStorage.accessToken.set(''); + + return Promise.reject(error); + } + } + return Promise.reject(error); + }, +); From d879a9b3dbb48c6f5c9b581276bc5f345ca78bee Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Sat, 23 Aug 2025 01:23:33 +0900 Subject: [PATCH 13/19] =?UTF-8?q?feat:=20useGetAuthTicket=20=ED=9B=85=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=ED=95=98=EC=97=AC=20=EC=9D=B8=EC=A6=9D=20?= =?UTF-8?q?=ED=8B=B0=EC=BC=93=EC=9D=84=20=EA=B0=80=EC=A0=B8=EC=98=A4?= =?UTF-8?q?=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/auth/hooks/useGetAuthTicket.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/entities/auth/hooks/useGetAuthTicket.ts diff --git a/src/entities/auth/hooks/useGetAuthTicket.ts b/src/entities/auth/hooks/useGetAuthTicket.ts new file mode 100644 index 0000000..b231a89 --- /dev/null +++ b/src/entities/auth/hooks/useGetAuthTicket.ts @@ -0,0 +1,13 @@ +import { useQuery } from '@tanstack/react-query'; + +import { GET_TICKET_API_PATH, getTicketApi } from '../apis'; + +export const GetAuthTicketQueryKey = [GET_TICKET_API_PATH()]; + +export const useGetAuthTicket = (ticket: string) => { + return useQuery({ + queryKey: [GetAuthTicketQueryKey, ticket], + queryFn: () => getTicketApi(ticket), + enabled: !!ticket && ticket.trim().length > 0, + }); +}; From 649615e957ff3d183bcef571f6117b0c386be887 Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Sat, 23 Aug 2025 01:23:50 +0900 Subject: [PATCH 14/19] =?UTF-8?q?feat:=20size-price.api.ts=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=B6=94=EA=B0=80=ED=95=98=EC=97=AC=20=EC=82=AC?= =?UTF-8?q?=EC=9D=B4=EC=A6=88=20=EA=B0=80=EA=B2=A9=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=20API=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/chart/apis/index.ts | 0 src/entities/chart/apis/size-price.api.ts | 16 ++++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 src/entities/chart/apis/index.ts create mode 100644 src/entities/chart/apis/size-price.api.ts diff --git a/src/entities/chart/apis/index.ts b/src/entities/chart/apis/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/entities/chart/apis/size-price.api.ts b/src/entities/chart/apis/size-price.api.ts new file mode 100644 index 0000000..8e01849 --- /dev/null +++ b/src/entities/chart/apis/size-price.api.ts @@ -0,0 +1,16 @@ +import { fetchInstance } from '@/shared'; + +export const SIZE_PRICE_API_PATH = '/graph/sizePriceIndex'; + +interface SizePriceApiResponse { + month: string; + sizeband: string; + baseindex: number; + changerate: number; +} + +export const sizePriceApi = async (): Promise => { + const response = await fetchInstance.get(SIZE_PRICE_API_PATH); + + return response.data; +}; From de4628e1031f284c9a2b6484cabb78962a17d0e8 Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Sat, 23 Aug 2025 01:24:04 +0900 Subject: [PATCH 15/19] =?UTF-8?q?fix:=20DIAGNOSIS=5FAPI=5FPATH=20=EA=B2=BD?= =?UTF-8?q?=EB=A1=9C=20=EC=88=98=EC=A0=95=ED=95=98=EC=97=AC=20API=20?= =?UTF-8?q?=EA=B2=BD=EB=A1=9C=20=EC=9D=BC=EA=B4=80=EC=84=B1=20=EC=9C=A0?= =?UTF-8?q?=EC=A7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/main/apis/diagnosis.api.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/features/main/apis/diagnosis.api.ts b/src/features/main/apis/diagnosis.api.ts index 58bc7e7..a3efad4 100644 --- a/src/features/main/apis/diagnosis.api.ts +++ b/src/features/main/apis/diagnosis.api.ts @@ -3,7 +3,7 @@ import { fetchInstance } from '@/shared'; import type { HouseType } from '../types'; -export const DIAGNOSIS_API_PATH = '/api/diagnosis'; +export const DIAGNOSIS_API_PATH = '/diagnosis'; interface DiagnosisApiRequest { address: string; From d927d1c90cc02fcfb3d476f400d9a38c21a64337 Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Sat, 23 Aug 2025 01:24:21 +0900 Subject: [PATCH 16/19] =?UTF-8?q?feat:=20=EC=B9=B4=EC=B9=B4=EC=98=A4=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EB=B2=84=ED=8A=BC=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20API=20=EA=B2=BD?= =?UTF-8?q?=EB=A1=9C=20=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/common/buttons/KakaoLoginButton.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/features/login/components/common/buttons/KakaoLoginButton.tsx b/src/features/login/components/common/buttons/KakaoLoginButton.tsx index 9f5688e..4150eaf 100644 --- a/src/features/login/components/common/buttons/KakaoLoginButton.tsx +++ b/src/features/login/components/common/buttons/KakaoLoginButton.tsx @@ -1,19 +1,19 @@ -import { useKakaoLogin } from '@/entities'; -import { Button } from '@/shared'; +import { BASE_URL, Button } from '@/shared'; import KakaoSymbol from '../../../_assets/kakao-symbol.webp'; export const KakaoLoginButton = () => { - const { mutate: startKakaoLogin, isPending } = useKakaoLogin(); + const startKakaoLogin = () => { + window.location.href = `${BASE_URL}/oauth2/authorization/kakao`; + }; + return ( ); }; From 170e603a81dabbdf572440d7f10e98b2ad9eecce Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Sat, 23 Aug 2025 01:24:33 +0900 Subject: [PATCH 17/19] =?UTF-8?q?feat:=20useGetRefreshToken=20=ED=9B=85=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=ED=95=98=EC=97=AC=20=EC=9D=B8=EC=A6=9D=20?= =?UTF-8?q?=ED=86=A0=ED=81=B0=20=EA=B0=B1=EC=8B=A0=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/auth/hooks/useGetRefreshToken.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/entities/auth/hooks/useGetRefreshToken.ts diff --git a/src/entities/auth/hooks/useGetRefreshToken.ts b/src/entities/auth/hooks/useGetRefreshToken.ts new file mode 100644 index 0000000..b5579ad --- /dev/null +++ b/src/entities/auth/hooks/useGetRefreshToken.ts @@ -0,0 +1,15 @@ +import { useQuery } from '@tanstack/react-query'; + +import { authStorage } from '@/shared'; + +import { REFRESH_TOKEN_API_PATH, refreshTokenApi } from '../apis'; + +export const GetRefreshTokenQueryKey = [REFRESH_TOKEN_API_PATH]; + +export const useGetRefreshToken = () => { + return useQuery({ + queryKey: [GetRefreshTokenQueryKey], + queryFn: () => refreshTokenApi({ refreshToken: authStorage.refreshToken.get() }), + enabled: !!authStorage.refreshToken.get(), + }); +}; From f4671cf24be29d7ff0eec42738c690f896a55994 Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Sat, 23 Aug 2025 01:24:49 +0900 Subject: [PATCH 18/19] =?UTF-8?q?feat:=20useGetTicket=20=ED=9B=85=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=ED=95=98=EC=97=AC=20=EC=B9=B4=EC=B9=B4?= =?UTF-8?q?=EC=98=A4=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EC=8B=9C=20=EC=9D=B8?= =?UTF-8?q?=EC=A6=9D=20=ED=8B=B0=EC=BC=93=EC=9D=84=20=EA=B0=80=EC=A0=B8?= =?UTF-8?q?=EC=98=A4=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/auth/hooks/useKakaoLogin.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/entities/auth/hooks/useKakaoLogin.ts b/src/entities/auth/hooks/useKakaoLogin.ts index 252b62d..12dde23 100644 --- a/src/entities/auth/hooks/useKakaoLogin.ts +++ b/src/entities/auth/hooks/useKakaoLogin.ts @@ -26,6 +26,12 @@ export const useKakaoCallback = (ticket: string) => { queryKey: KakaoCallbackQueryKey.callback(ticket), queryFn: () => getTicketApi(ticket), retry: 0, - staleTime: Infinity, + enabled: !!ticket, // ticket이 있을 때만 API 호출 + }); +}; + +export const useGetTicket = (ticket: string) => { + return useMutation({ + mutationFn: () => getTicketApi(ticket), }); }; From 07b254192f528b9199328469e3f37b2ab2840940 Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Sat, 23 Aug 2025 01:28:29 +0900 Subject: [PATCH 19/19] =?UTF-8?q?feat:=20OAuthRedirectPage=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=88=98=EC=A0=95=ED=95=98?= =?UTF-8?q?=EC=97=AC=20=EC=9D=B8=EC=A6=9D=20=ED=8B=B0=EC=BC=93=20=EB=B0=8F?= =?UTF-8?q?=20=EB=A6=AC=ED=94=84=EB=A0=88=EC=8B=9C=20=ED=86=A0=ED=81=B0=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EB=A1=9C=EC=A7=81=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/oauth/OAuthRedirectPage.tsx | 65 ++++++++++++++++++--------- 1 file changed, 43 insertions(+), 22 deletions(-) diff --git a/src/pages/oauth/OAuthRedirectPage.tsx b/src/pages/oauth/OAuthRedirectPage.tsx index 293c02a..31d5a05 100644 --- a/src/pages/oauth/OAuthRedirectPage.tsx +++ b/src/pages/oauth/OAuthRedirectPage.tsx @@ -1,33 +1,54 @@ import { useEffect } from 'react'; -import { useNavigate, useSearchParams } from 'react-router-dom'; +import { useLocation, useNavigate } from 'react-router-dom'; -import { toast } from 'sonner'; - -import { useKakaoCallback } from '@/entities'; -import { ROUTER_PATH, authStorage } from '@/shared'; +import { useGetAuthTicket, useGetRefreshToken } from '@/entities'; +import { ROUTER_PATH, Spinner, authStorage } from '@/shared'; export default function OAuthRedirectPage() { - const [searchParams] = useSearchParams(); - + const location = useLocation(); const navigate = useNavigate(); - const ticket = searchParams.get('ticket'); + const ticket = new URLSearchParams(location.search).get('ticket'); - const { data, isSuccess, isError } = useKakaoCallback(ticket ?? ''); + const { data, isLoading } = useGetAuthTicket(ticket ?? ''); useEffect(() => { - if (isSuccess && data) { - authStorage.refreshToken.set(data.refreshToken); - - navigate(ROUTER_PATH.ROOT); + if (data) { + const refreshToken = data.refreshToken; + authStorage.refreshToken.set(refreshToken); + navigate(ROUTER_PATH.ROOT, { replace: true }); } - - if (isError) { - // 실패 시, 에러 처리 후 로그인 페이지로 이동 - toast.error('카카오 로그인에 실패했습니다.'); - navigate(ROUTER_PATH.LOGIN); - } - }, [isSuccess, isError, data, navigate]); - - return
로그인 중입니다...
; + }, [data, navigate]); + + const { data: refreshTokenData, isLoading: isRefreshTokenLoading } = useGetRefreshToken(); + + if (!ticket) { + return
로그인을 다시 진행해주세요.
; + } + + if (isLoading || isRefreshTokenLoading) { + return ; + } + + if (!data || !refreshTokenData) { + return ; + } + + if (refreshTokenData) { + authStorage.accessToken.set(refreshTokenData.accessToken); + } + + return ( +
+
+
+ {isLoading ? '로그인 처리 중...' : '로그인 중입니다...'} +
+ +
+ {isLoading ? '서버와 통신 중입니다.' : '잠시만 기다려주세요.'} +
+
+
+ ); }