From 7fab2d7a7cb46204aaf17510a75c907cf6010621 Mon Sep 17 00:00:00 2001 From: hamo-o Date: Sun, 22 Jun 2025 15:25:41 +0900 Subject: [PATCH 01/14] =?UTF-8?q?fix:=20gitignore=20env=EB=A1=9C=20?= =?UTF-8?q?=EC=8B=9C=EC=9E=91=ED=95=98=EB=8A=94=20=EB=AA=A8=EB=93=A0=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/.gitignore b/frontend/.gitignore index f0abd802..348bb0b4 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -11,6 +11,7 @@ node_modules dist dist-ssr *.local +.env* # Editor directories and files .vscode/* From 54597fdb4f104f812be580f76cbe86cec3ca19ee Mon Sep 17 00:00:00 2001 From: hamo-o Date: Sun, 22 Jun 2025 15:26:02 +0900 Subject: [PATCH 02/14] =?UTF-8?q?feat:=20useEffect=EB=A5=BC=20=ED=95=9C?= =?UTF-8?q?=EB=B2=88=EB=A7=8C=20=ED=98=B8=EC=B6=9C=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=ED=9B=85=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apps/client/src/hooks/useEffectOnce.ts | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 frontend/apps/client/src/hooks/useEffectOnce.ts diff --git a/frontend/apps/client/src/hooks/useEffectOnce.ts b/frontend/apps/client/src/hooks/useEffectOnce.ts new file mode 100644 index 00000000..6ec28e38 --- /dev/null +++ b/frontend/apps/client/src/hooks/useEffectOnce.ts @@ -0,0 +1,29 @@ +import { useEffect, useRef } from 'react'; + +interface UseEffectOnceOptions { + condition?: boolean; + callback: () => void; +} + +/** + * + * @param options + * @param options.condition - 콜백을 실행할 조건 (기본값: true) + * @param options.callback - 한 번만 실행할 콜백 함수. useCallback을 사용하여 메모이제이션하는 것이 좋습니다. + */ +export const useEffectOnce = ({ condition = true, callback }: UseEffectOnceOptions) => { + const isCalled = useRef(false); + + useEffect(() => { + if (condition && !isCalled.current) { + callback(); + isCalled.current = true; + } + + return () => { + if (!isCalled.current) { + isCalled.current = true; + } + }; + }, [condition, callback]); +}; \ No newline at end of file From 750abb84adc2c930c044aa69ff17957f8ec8a1f0 Mon Sep 17 00:00:00 2001 From: hamo-o Date: Sun, 22 Jun 2025 15:39:10 +0900 Subject: [PATCH 03/14] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8,=20?= =?UTF-8?q?=EC=BA=98=EB=A6=B0=EB=8D=94=20=EA=B6=8C=ED=95=9C=EC=8A=B5?= =?UTF-8?q?=EB=93=9D=20=EB=A1=9C=EC=A7=81=EC=97=90=20useEffectOnce=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/routes/oauth.redirect/calendar/index.tsx | 7 +++++-- .../src/routes/oauth.redirect/login/index.tsx | 16 ++++++++++------ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/frontend/apps/client/src/routes/oauth.redirect/calendar/index.tsx b/frontend/apps/client/src/routes/oauth.redirect/calendar/index.tsx index cd68906c..b55a9d54 100644 --- a/frontend/apps/client/src/routes/oauth.redirect/calendar/index.tsx +++ b/frontend/apps/client/src/routes/oauth.redirect/calendar/index.tsx @@ -1,19 +1,22 @@ import { useQueryClient } from '@tanstack/react-query'; import { createFileRoute, useNavigate } from '@tanstack/react-router'; -import { useEffect } from 'react'; +import { useCallback } from 'react'; import { calendarKeys } from '@/features/my-calendar/api/keys'; +import { useEffectOnce } from '@/hooks/useEffectOnce'; const Redirect = () => { const queryClient = useQueryClient(); const navigate = useNavigate(); - useEffect(() => { + const clearCalendarCache = useCallback(() => { (async () => { await queryClient.invalidateQueries({ queryKey: calendarKeys.all }); navigate({ to: '/my-calendar' }); })(); }, [queryClient, navigate]); + + useEffectOnce({ callback: clearCalendarCache }); return null; }; diff --git a/frontend/apps/client/src/routes/oauth.redirect/login/index.tsx b/frontend/apps/client/src/routes/oauth.redirect/login/index.tsx index 8e3a91b9..bcbc6e36 100644 --- a/frontend/apps/client/src/routes/oauth.redirect/login/index.tsx +++ b/frontend/apps/client/src/routes/oauth.redirect/login/index.tsx @@ -1,7 +1,8 @@ import { createFileRoute, useSearch } from '@tanstack/react-router'; -import { useEffect } from 'react'; +import { useCallback } from 'react'; import { useJWTMutation } from '@/features/login/api/mutations'; +import { useEffectOnce } from '@/hooks/useEffectOnce'; import { getLastRoutePath } from '@/utils/route'; const Redirect = () => { @@ -10,11 +11,14 @@ const Redirect = () => { const params: { code: string } = useSearch({ from: '/oauth/redirect/login/' }); const { code } = params; - useEffect(() => { - if (code) { - loginMutate({ code, lastPath }); - } - }, [code, loginMutate, lastPath]); + const loginCache = useCallback(() => { + loginMutate({ code, lastPath }); + }, [loginMutate, code, lastPath]); + + useEffectOnce({ + condition: Boolean(code), + callback: loginCache, + }); return null; }; From eb42a18c5ca00214d9753525af262abc9d6bc829 Mon Sep 17 00:00:00 2001 From: hamo-o Date: Mon, 23 Jun 2025 09:20:14 +0900 Subject: [PATCH 04/14] =?UTF-8?q?chore:=20useEffectOnce=20=ED=9B=85=20core?= =?UTF-8?q?=20=ED=8C=A8=ED=82=A4=EC=A7=80=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apps/client/src/routes/oauth.redirect/calendar/index.tsx | 2 +- frontend/apps/client/src/routes/oauth.redirect/login/index.tsx | 2 +- frontend/packages/core/src/hooks/index.ts | 1 + .../{apps/client => packages/core}/src/hooks/useEffectOnce.ts | 0 4 files changed, 3 insertions(+), 2 deletions(-) rename frontend/{apps/client => packages/core}/src/hooks/useEffectOnce.ts (100%) diff --git a/frontend/apps/client/src/routes/oauth.redirect/calendar/index.tsx b/frontend/apps/client/src/routes/oauth.redirect/calendar/index.tsx index b55a9d54..8d3cb75c 100644 --- a/frontend/apps/client/src/routes/oauth.redirect/calendar/index.tsx +++ b/frontend/apps/client/src/routes/oauth.redirect/calendar/index.tsx @@ -1,9 +1,9 @@ +import { useEffectOnce } from '@endolphin/core/hooks'; import { useQueryClient } from '@tanstack/react-query'; import { createFileRoute, useNavigate } from '@tanstack/react-router'; import { useCallback } from 'react'; import { calendarKeys } from '@/features/my-calendar/api/keys'; -import { useEffectOnce } from '@/hooks/useEffectOnce'; const Redirect = () => { const queryClient = useQueryClient(); diff --git a/frontend/apps/client/src/routes/oauth.redirect/login/index.tsx b/frontend/apps/client/src/routes/oauth.redirect/login/index.tsx index bcbc6e36..70eccb09 100644 --- a/frontend/apps/client/src/routes/oauth.redirect/login/index.tsx +++ b/frontend/apps/client/src/routes/oauth.redirect/login/index.tsx @@ -1,8 +1,8 @@ +import { useEffectOnce } from '@endolphin/core/hooks'; import { createFileRoute, useSearch } from '@tanstack/react-router'; import { useCallback } from 'react'; import { useJWTMutation } from '@/features/login/api/mutations'; -import { useEffectOnce } from '@/hooks/useEffectOnce'; import { getLastRoutePath } from '@/utils/route'; const Redirect = () => { diff --git a/frontend/packages/core/src/hooks/index.ts b/frontend/packages/core/src/hooks/index.ts index f9880f43..718c9aaa 100644 --- a/frontend/packages/core/src/hooks/index.ts +++ b/frontend/packages/core/src/hooks/index.ts @@ -1,3 +1,4 @@ export * from './useClickOutside'; +export * from './useEffectOnce'; export * from './useSafeContext'; export * from './useSelectTime'; \ No newline at end of file diff --git a/frontend/apps/client/src/hooks/useEffectOnce.ts b/frontend/packages/core/src/hooks/useEffectOnce.ts similarity index 100% rename from frontend/apps/client/src/hooks/useEffectOnce.ts rename to frontend/packages/core/src/hooks/useEffectOnce.ts From cd4e2a8d83fd2ffc407a33dd6bb1728e3b18d831 Mon Sep 17 00:00:00 2001 From: hamo-o Date: Wed, 25 Jun 2025 12:48:43 +0900 Subject: [PATCH 05/14] =?UTF-8?q?fix:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=ED=81=B4=EB=A6=B0=EC=97=85=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/packages/core/src/hooks/useEffectOnce.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/frontend/packages/core/src/hooks/useEffectOnce.ts b/frontend/packages/core/src/hooks/useEffectOnce.ts index 6ec28e38..2d650572 100644 --- a/frontend/packages/core/src/hooks/useEffectOnce.ts +++ b/frontend/packages/core/src/hooks/useEffectOnce.ts @@ -19,11 +19,5 @@ export const useEffectOnce = ({ condition = true, callback }: UseEffectOnceOptio callback(); isCalled.current = true; } - - return () => { - if (!isCalled.current) { - isCalled.current = true; - } - }; }, [condition, callback]); }; \ No newline at end of file From 3fd68110bf69b368222f44271ded43806811db4c Mon Sep 17 00:00:00 2001 From: hamo-o Date: Wed, 25 Jun 2025 17:44:42 +0900 Subject: [PATCH 06/14] =?UTF-8?q?fix:=20=EB=A6=AC=EC=95=A1=ED=8A=B8?= =?UTF-8?q?=EC=9D=98=20=EC=9D=98=EB=8F=84=EC=99=80=20=EB=A7=9E=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=EB=8A=94=20useEffectOnce=20=ED=9B=85=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../packages/core/src/hooks/useEffectOnce.ts | 23 ------------------- 1 file changed, 23 deletions(-) delete mode 100644 frontend/packages/core/src/hooks/useEffectOnce.ts diff --git a/frontend/packages/core/src/hooks/useEffectOnce.ts b/frontend/packages/core/src/hooks/useEffectOnce.ts deleted file mode 100644 index 2d650572..00000000 --- a/frontend/packages/core/src/hooks/useEffectOnce.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { useEffect, useRef } from 'react'; - -interface UseEffectOnceOptions { - condition?: boolean; - callback: () => void; -} - -/** - * - * @param options - * @param options.condition - 콜백을 실행할 조건 (기본값: true) - * @param options.callback - 한 번만 실행할 콜백 함수. useCallback을 사용하여 메모이제이션하는 것이 좋습니다. - */ -export const useEffectOnce = ({ condition = true, callback }: UseEffectOnceOptions) => { - const isCalled = useRef(false); - - useEffect(() => { - if (condition && !isCalled.current) { - callback(); - isCalled.current = true; - } - }, [condition, callback]); -}; \ No newline at end of file From 2b2d1124579319daee7f7398286169e02ef753e1 Mon Sep 17 00:00:00 2001 From: hamo-o Date: Wed, 25 Jun 2025 17:45:24 +0900 Subject: [PATCH 07/14] =?UTF-8?q?feat:=20=EB=A6=AC=EC=95=A1=ED=8A=B8=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=99=B8=EB=B6=80?= =?UTF-8?q?=EC=97=90=EC=84=9C=EB=8F=84=20=EC=93=B8=20=EC=88=98=20=EC=9E=88?= =?UTF-8?q?=EB=8A=94=20createMutation=20=ED=95=A8=EC=88=98=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 --- frontend/packages/core/src/utils/index.ts | 3 +- .../core/src/utils/network/createMutation.ts | 30 +++++++++++++++++++ .../packages/core/src/utils/network/index.ts | 1 + 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 frontend/packages/core/src/utils/network/createMutation.ts create mode 100644 frontend/packages/core/src/utils/network/index.ts diff --git a/frontend/packages/core/src/utils/index.ts b/frontend/packages/core/src/utils/index.ts index ed1f3473..665a8368 100644 --- a/frontend/packages/core/src/utils/index.ts +++ b/frontend/packages/core/src/utils/index.ts @@ -2,4 +2,5 @@ export { default as clsx } from './clsx'; export * from './common'; export * from './context'; export * from './date'; -export * from './jsx'; \ No newline at end of file +export * from './jsx'; +export * from './network'; \ No newline at end of file diff --git a/frontend/packages/core/src/utils/network/createMutation.ts b/frontend/packages/core/src/utils/network/createMutation.ts new file mode 100644 index 00000000..781d9138 --- /dev/null +++ b/frontend/packages/core/src/utils/network/createMutation.ts @@ -0,0 +1,30 @@ +type MutationFn = (args: TArgs) => Promise; + +interface RedirectMutationOptions { + mutationFn: MutationFn; + onSuccess?: (response: TRes, args: TArgs) => unknown; + onError?: (error: unknown, args: TArgs) => unknown; +} + +type Mutation = (args: TArgs) => Promise; + +let globalHandleError: (error: unknown) => unknown; + +export const setDefaultMutationErrorHandler = (fn: (error: unknown) => void) => { + globalHandleError = fn; +}; + +/** + * 리액트 컴포넌트 외부에서 사용할 수 있는 뮤테이션 함수 생성기. + */ +export const createMutation = ( + options: RedirectMutationOptions, +): Mutation => async (args: TArgs) => { + try { + const res = await options.mutationFn(args); + options.onSuccess?.(res, args); + } catch (error) { + globalHandleError?.(error); + options.onError?.(error, args); + } +}; diff --git a/frontend/packages/core/src/utils/network/index.ts b/frontend/packages/core/src/utils/network/index.ts new file mode 100644 index 00000000..f8dac7fb --- /dev/null +++ b/frontend/packages/core/src/utils/network/index.ts @@ -0,0 +1 @@ +export * from './createMutation'; \ No newline at end of file From 658a6655bb22da1a82f5134b27a49e27c168897c Mon Sep 17 00:00:00 2001 From: hamo-o Date: Wed, 25 Jun 2025 17:45:52 +0900 Subject: [PATCH 08/14] =?UTF-8?q?feat:=20=EA=B3=B5=ED=86=B5=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=20=ED=95=B8=EB=93=A4=EB=9F=AC=20=EB=93=B1=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/apps/client/src/main.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frontend/apps/client/src/main.tsx b/frontend/apps/client/src/main.tsx index c54eb488..790de90e 100644 --- a/frontend/apps/client/src/main.tsx +++ b/frontend/apps/client/src/main.tsx @@ -1,3 +1,4 @@ +import { setDefaultMutationErrorHandler } from '@endolphin/core/utils'; import { QueryCache, QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { createRouter, RouterProvider } from '@tanstack/react-router'; import { StrictMode } from 'react'; @@ -41,6 +42,8 @@ const router = createRouter({ }, }); +setDefaultMutationErrorHandler(handleError); + declare module '@tanstack/react-router' { interface Register { router: typeof router; From cd58984be4fc423bdc81e2127b8c8d38a648061e Mon Sep 17 00:00:00 2001 From: hamo-o Date: Wed, 25 Jun 2025 17:52:42 +0900 Subject: [PATCH 09/14] =?UTF-8?q?feat:=20createMutation=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=EA=B0=80=20=EA=B0=9D=EC=B2=B4=EB=A5=BC=20=EB=B0=98?= =?UTF-8?q?=ED=99=98=ED=95=98=EB=8F=84=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/src/utils/network/createMutation.ts | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/frontend/packages/core/src/utils/network/createMutation.ts b/frontend/packages/core/src/utils/network/createMutation.ts index 781d9138..1f385037 100644 --- a/frontend/packages/core/src/utils/network/createMutation.ts +++ b/frontend/packages/core/src/utils/network/createMutation.ts @@ -6,7 +6,9 @@ interface RedirectMutationOptions { onError?: (error: unknown, args: TArgs) => unknown; } -type Mutation = (args: TArgs) => Promise; +type Mutation = { + mutate: (args: TArgs) => Promise; +}; let globalHandleError: (error: unknown) => unknown; @@ -19,12 +21,16 @@ export const setDefaultMutationErrorHandler = (fn: (error: unknown) => void) => */ export const createMutation = ( options: RedirectMutationOptions, -): Mutation => async (args: TArgs) => { - try { - const res = await options.mutationFn(args); - options.onSuccess?.(res, args); - } catch (error) { - globalHandleError?.(error); - options.onError?.(error, args); - } +): Mutation => { + const mutate = async (args: TArgs) => { + try { + const res = await options.mutationFn(args); + options.onSuccess?.(res, args); + } catch (error) { + globalHandleError?.(error); + options.onError?.(error, args); + } + }; + + return { mutate }; }; From 9143c5abf1a2a407e41a7fb25b37379c4945a25d Mon Sep 17 00:00:00 2001 From: hamo-o Date: Wed, 25 Jun 2025 17:54:44 +0900 Subject: [PATCH 10/14] =?UTF-8?q?fix:=20useEffectOnce=20=ED=9B=85=20?= =?UTF-8?q?=EB=82=B4=EB=B3=B4=EB=82=B4=EA=B8=B0=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/packages/core/src/hooks/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/packages/core/src/hooks/index.ts b/frontend/packages/core/src/hooks/index.ts index 718c9aaa..f9880f43 100644 --- a/frontend/packages/core/src/hooks/index.ts +++ b/frontend/packages/core/src/hooks/index.ts @@ -1,4 +1,3 @@ export * from './useClickOutside'; -export * from './useEffectOnce'; export * from './useSafeContext'; export * from './useSelectTime'; \ No newline at end of file From 54974154d2275d21b85020f27a7ff60927374df8 Mon Sep 17 00:00:00 2001 From: hamo-o Date: Wed, 25 Jun 2025 19:34:09 +0900 Subject: [PATCH 11/14] =?UTF-8?q?feat:=20Redirect=EB=8A=94=20throw=20?= =?UTF-8?q?=ED=95=B4=EB=8F=84=20=EA=B7=B8=EB=8C=80=EB=A1=9C=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=ED=95=98=EB=8F=84=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/src/utils/network/createMutation.ts | 28 +++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/frontend/packages/core/src/utils/network/createMutation.ts b/frontend/packages/core/src/utils/network/createMutation.ts index 1f385037..46033be1 100644 --- a/frontend/packages/core/src/utils/network/createMutation.ts +++ b/frontend/packages/core/src/utils/network/createMutation.ts @@ -7,11 +7,17 @@ interface RedirectMutationOptions { } type Mutation = { - mutate: (args: TArgs) => Promise; + mutate: (args: TArgs) => void; + mutateAsync: (args: TArgs) => Promise; }; let globalHandleError: (error: unknown) => unknown; +const isRedirectError = (error: unknown): boolean => ( + typeof error === 'object' && error !== null + && 'isRedirect' in error && error.isRedirect === true +); + export const setDefaultMutationErrorHandler = (fn: (error: unknown) => void) => { globalHandleError = fn; }; @@ -22,15 +28,27 @@ export const setDefaultMutationErrorHandler = (fn: (error: unknown) => void) => export const createMutation = ( options: RedirectMutationOptions, ): Mutation => { - const mutate = async (args: TArgs) => { + + const mutateAsync = async (args: TArgs) => { try { - const res = await options.mutationFn(args); - options.onSuccess?.(res, args); + const response = await options.mutationFn(args); + options.onSuccess?.(response, args); } catch (error) { + if (isRedirectError(error)) throw error; globalHandleError?.(error); options.onError?.(error, args); + throw error; } }; - return { mutate }; + const mutate = (args: TArgs) => { + options.mutationFn(args) + .then(res => options.onSuccess?.(res, args)) + .catch(err => { + globalHandleError?.(err); + options.onError?.(err, args); + }); + }; + + return { mutate, mutateAsync }; }; From 1c7c29f9bf799da87cf6a276825b121de93ed78b Mon Sep 17 00:00:00 2001 From: hamo-o Date: Wed, 25 Jun 2025 19:36:02 +0900 Subject: [PATCH 12/14] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20beforeLoad=EC=97=90=EC=84=9C=20=EC=BB=A4?= =?UTF-8?q?=EC=8A=A4=ED=85=80=20mutate=EB=A1=9C=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/features/login/api/mutations.ts | 16 ++++----- .../src/routes/oauth.redirect/login/index.tsx | 33 +++++++------------ 2 files changed, 19 insertions(+), 30 deletions(-) diff --git a/frontend/apps/client/src/features/login/api/mutations.ts b/frontend/apps/client/src/features/login/api/mutations.ts index 1ed1f5b2..d989f27f 100644 --- a/frontend/apps/client/src/features/login/api/mutations.ts +++ b/frontend/apps/client/src/features/login/api/mutations.ts @@ -1,5 +1,5 @@ -import { useMutation } from '@tanstack/react-query'; -import { useNavigate } from '@tanstack/react-router'; +import { createMutation } from '@endolphin/core/utils'; +import { redirect } from '@tanstack/react-router'; import { accessTokenService } from '@utils/auth/accessTokenService'; import type { JWTRequest } from '../model'; @@ -9,23 +9,21 @@ interface JWTMutationProps extends JWTRequest { lastPath: string | null; } -export const useJWTMutation = () => { - const navigate = useNavigate(); - - const { mutate } = useMutation({ +export const jwtMutation = () => { + const { mutateAsync } = createMutation({ mutationFn: ({ code }: JWTMutationProps) => loginApi.getJWT(code), onSuccess: (response, { lastPath }) => { accessTokenService.setAccessToken(response); - navigate({ + throw redirect({ to: lastPath || '/home', }); }, onError: () => { - navigate({ + throw redirect({ to: '/login', }); }, }); - return { loginMutate: mutate }; + return { loginMutate: mutateAsync }; }; \ No newline at end of file diff --git a/frontend/apps/client/src/routes/oauth.redirect/login/index.tsx b/frontend/apps/client/src/routes/oauth.redirect/login/index.tsx index 70eccb09..fda6f8de 100644 --- a/frontend/apps/client/src/routes/oauth.redirect/login/index.tsx +++ b/frontend/apps/client/src/routes/oauth.redirect/login/index.tsx @@ -1,28 +1,19 @@ -import { useEffectOnce } from '@endolphin/core/hooks'; -import { createFileRoute, useSearch } from '@tanstack/react-router'; -import { useCallback } from 'react'; +import { createFileRoute } from '@tanstack/react-router'; -import { useJWTMutation } from '@/features/login/api/mutations'; +import { jwtMutation } from '@/features/login/api/mutations'; import { getLastRoutePath } from '@/utils/route'; -const Redirect = () => { - const { loginMutate } = useJWTMutation(); - const lastPath = getLastRoutePath(); - const params: { code: string } = useSearch({ from: '/oauth/redirect/login/' }); - const { code } = params; - - const loginCache = useCallback(() => { - loginMutate({ code, lastPath }); - }, [loginMutate, code, lastPath]); - - useEffectOnce({ - condition: Boolean(code), - callback: loginCache, - }); - - return null; +type SearchWithCode = { + code?: string; }; export const Route = createFileRoute('/oauth/redirect/login/')({ - component: Redirect, + beforeLoad: async ({ search }: { search: SearchWithCode }) => { + const lastPath = getLastRoutePath(); + const { loginMutate } = jwtMutation(); + if (search.code) { + const redirect = await loginMutate({ code: search.code, lastPath }); + throw redirect; + } + }, }); \ No newline at end of file From c4a44fdd172bf3575b9f8ccc16d71f78db6d0599 Mon Sep 17 00:00:00 2001 From: hamo-o Date: Wed, 25 Jun 2025 19:36:34 +0900 Subject: [PATCH 13/14] =?UTF-8?q?feat:=20=EC=BA=98=EB=A6=B0=EB=8D=94=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20beforeLoad=EC=97=90=EC=84=9C=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../routes/oauth.redirect/calendar/index.tsx | 26 ++++--------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/frontend/apps/client/src/routes/oauth.redirect/calendar/index.tsx b/frontend/apps/client/src/routes/oauth.redirect/calendar/index.tsx index 8d3cb75c..f1016f8c 100644 --- a/frontend/apps/client/src/routes/oauth.redirect/calendar/index.tsx +++ b/frontend/apps/client/src/routes/oauth.redirect/calendar/index.tsx @@ -1,26 +1,10 @@ -import { useEffectOnce } from '@endolphin/core/hooks'; -import { useQueryClient } from '@tanstack/react-query'; -import { createFileRoute, useNavigate } from '@tanstack/react-router'; -import { useCallback } from 'react'; +import { createFileRoute, redirect } from '@tanstack/react-router'; import { calendarKeys } from '@/features/my-calendar/api/keys'; -const Redirect = () => { - const queryClient = useQueryClient(); - const navigate = useNavigate(); - - const clearCalendarCache = useCallback(() => { - (async () => { - await queryClient.invalidateQueries({ queryKey: calendarKeys.all }); - navigate({ to: '/my-calendar' }); - })(); - }, [queryClient, navigate]); - - useEffectOnce({ callback: clearCalendarCache }); - - return null; -}; - export const Route = createFileRoute('/oauth/redirect/calendar/')({ - component: Redirect, + beforeLoad: async ({ context }) => { + await context.queryClient.invalidateQueries({ queryKey: calendarKeys.all }); + throw redirect({ to: '/my-calendar' }); + }, }); \ No newline at end of file From 91e989f2a47019f9ade52bc2eb977a1c950ee3e4 Mon Sep 17 00:00:00 2001 From: hamo-o Date: Wed, 25 Jun 2025 19:38:08 +0900 Subject: [PATCH 14/14] =?UTF-8?q?refactor:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EC=BD=94=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/apps/client/src/routes/oauth.redirect/login/index.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/apps/client/src/routes/oauth.redirect/login/index.tsx b/frontend/apps/client/src/routes/oauth.redirect/login/index.tsx index fda6f8de..47a6b43e 100644 --- a/frontend/apps/client/src/routes/oauth.redirect/login/index.tsx +++ b/frontend/apps/client/src/routes/oauth.redirect/login/index.tsx @@ -12,8 +12,7 @@ export const Route = createFileRoute('/oauth/redirect/login/')({ const lastPath = getLastRoutePath(); const { loginMutate } = jwtMutation(); if (search.code) { - const redirect = await loginMutate({ code: search.code, lastPath }); - throw redirect; + await loginMutate({ code: search.code, lastPath }); } }, }); \ No newline at end of file