diff --git a/src/app/layout.tsx b/src/app/layout.tsx index cdf6dfee..1097658b 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -5,8 +5,8 @@ import Header from '@/shared/components/header/Header'; import FooterWrapper from '@/shared/components/footer/FooterWrapper'; import ScrollTopBtnWrapper from '@/shared/components/scroll-top/ScrollTopBtnWrapper'; import KaKaoScript from './api/kakao/KaKaoScript'; -import IdleHandler from '@/domains/login/components/IdleHandler'; import Provider from '@/shared/api/Provider'; +import ClientInitHook from '@/domains/login/components/ClientInitHook'; export const metadata: Metadata = { title: { default: 'SSOUL', template: 'SSOUL | %s' }, @@ -24,7 +24,7 @@ export default function RootLayout({
- +
{children}
diff --git a/src/domains/login/components/ClientInitHook.tsx b/src/domains/login/components/ClientInitHook.tsx new file mode 100644 index 00000000..a73a7ba9 --- /dev/null +++ b/src/domains/login/components/ClientInitHook.tsx @@ -0,0 +1,11 @@ +'use client'; + +import { useFetchInterceptor } from '@/shared/hook/useFetchInterceptor'; +import { useIdleLogout } from '../hook/useIdleLogout'; + +function ClientInitHook() { + useIdleLogout(); + useFetchInterceptor(); + return null; +} +export default ClientInitHook; diff --git a/src/domains/login/components/IdleHandler.tsx b/src/domains/login/components/IdleHandler.tsx deleted file mode 100644 index 4edbf6c8..00000000 --- a/src/domains/login/components/IdleHandler.tsx +++ /dev/null @@ -1,9 +0,0 @@ -'use client'; - -import { useIdleLogout } from '../hook/useIdleLogout'; - -function IdleHandler() { - useIdleLogout(); - return null; -} -export default IdleHandler; diff --git a/src/domains/recipe/components/main/Cocktails.tsx b/src/domains/recipe/components/main/Cocktails.tsx index c33933e7..4d075d04 100644 --- a/src/domains/recipe/components/main/Cocktails.tsx +++ b/src/domains/recipe/components/main/Cocktails.tsx @@ -10,7 +10,6 @@ import CocktailSearchBar from './CocktailSearchBar'; import useSearchControl from '../../hook/useSearchControl'; import CocktailSearch from '../../api/CocktailSearch'; - function Cocktails() { const [data, setData] = useState([]); const [lastId, setLastId] = useState(null); diff --git a/src/shared/hook/useFetchInterceptor.tsx b/src/shared/hook/useFetchInterceptor.tsx new file mode 100644 index 00000000..3d8df3ac --- /dev/null +++ b/src/shared/hook/useFetchInterceptor.tsx @@ -0,0 +1,43 @@ +'use client'; + +import { useEffect } from 'react'; +import { getApi } from '@/app/api/config/appConfig'; +import { useRouter } from 'next/navigation'; +import { useToast } from '@/shared/hook/useToast'; + +export const useFetchInterceptor = () => { + const router = useRouter(); + const { toastInfo } = useToast(); + + useEffect(() => { + const originalFetch = global.fetch; + + (global.fetch as typeof global.fetch) = async (input, init?) => { + const response = await originalFetch(input, { ...init, credentials: 'include' }); + + if (response.status === 401) { + try { + const refreshRes = await originalFetch(`${getApi}/user/auth/refresh`, { + method: 'POST', + credentials: 'include', + }); + + if (refreshRes.ok) { + return originalFetch(input, { ...init, credentials: 'include' }); + } else { + toastInfo('로그인 인증 만료로 다시 로그인해주세요.'); + router.push('/login'); + } + } catch { + toastInfo('로그인 인증 만료로 다시 로그인해주세요.'); + router.push('/login'); + } + } + return response; + }; + + return () => { + global.fetch = originalFetch; + }; + }, [router, toastInfo]); +};