From 5c3b17ebddf70f83c512a9c21a7a169715956fa2 Mon Sep 17 00:00:00 2001 From: oaoong Date: Tue, 2 Jan 2024 16:41:27 +0900 Subject: [PATCH] =?UTF-8?q?:sparkles:=20NABI-392=20validation=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useValidate.ts | 123 +++++++++++++++++++++------------------ 1 file changed, 65 insertions(+), 58 deletions(-) diff --git a/src/hooks/useValidate.ts b/src/hooks/useValidate.ts index e21924b0..aaf39648 100644 --- a/src/hooks/useValidate.ts +++ b/src/hooks/useValidate.ts @@ -1,6 +1,6 @@ 'use client' -import { useEffect, useState } from 'react' +import { useCallback, useEffect } from 'react' import { useQuery } from '@tanstack/react-query' import Cookies from 'js-cookie' import { usePathname, useRouter } from 'next/navigation' @@ -8,33 +8,16 @@ import AppPath from '@/config/appPath' import { Environment } from '@/config/environment' import apiClient from '@/services/apiClient' import { getValidateUser, reissueAccessToken } from '@/services/auth/auth' -import type { User } from '@/types/user' import { useToast } from './useToast' const useValidate = () => { const router = useRouter() - const { toast } = useToast() const pathname = usePathname() + const { toast } = useToast() const accessToken = Cookies.get(Environment.tokenName()) const refreshToken = Cookies.get(Environment.refreshTokenName()) - const [isLoggedIn, setIsLoggedIn] = useState(() => !!accessToken) - const [currentUser, setCurrentUser] = useState(() => null) - - const handleTokenRefresh = ({ - token, - expiresInHours = 1, - }: { - token: string - expiresInHours?: number - }) => { - let expiry = new Date() - expiry.setHours(expiry.getHours() + expiresInHours) - Cookies.set(Environment.tokenName(), token, { expires: expiry }) - return token - } - const validateUserQuery = useQuery({ queryKey: ['validate', accessToken], queryFn: async () => { @@ -61,58 +44,82 @@ const useValidate = () => { throwOnError: false, }) - const updateLoginState = (userInfo: User) => { - setCurrentUser(() => userInfo) - setIsLoggedIn(() => !!userInfo) + /** + * + * @description 재발급 된 토큰을 쿠키에 저장합니다. + */ + const handleTokenRefresh = ({ + token, + expiresInHours = 1, + }: { + token?: string + expiresInHours?: number + }) => { + if (!token) return + let expiry = new Date() + expiry.setHours(expiry.getHours() + expiresInHours) + Cookies.set(Environment.tokenName(), token, { expires: expiry }) window.location.reload() } - useEffect(() => { - if (validateUserQuery.isError) { - Cookies.remove(Environment.tokenName()) - if (!refreshToken || reissueTokenQuery.isError) { - router.push(AppPath.login(), { scroll: false }) - toast({ - title: '인증 에러', - description: '만료되거나 잘못된 토큰입니다. 다시 로그인해주세요.', - variant: 'destructive', - duration: 3000, - }) - } else if (reissueTokenQuery.data?.data?.accessToken) { - handleTokenRefresh({ - token: reissueTokenQuery.data.data.accessToken, - }) - updateLoginState(validateUserQuery.data?.data?.userInfo) - } + const showAuthErrorToast = useCallback(() => { + toast({ + title: '인증 에러', + description: '만료되거나 잘못된 토큰입니다. 다시 로그인해주세요.', + variant: 'destructive', + duration: 3000, + }) + }, [toast]) + + /** + * @description: 세션 만료시 로그인 페이지로 이동합니다. + * @description: 리프레시 토큰까지 만료되었을 경우 + */ + const handleSessionExpiration = useCallback(() => { + Cookies.remove(Environment.tokenName()) + router.push(AppPath.login(), { scroll: false }) + showAuthErrorToast() + }, [router, showAuthErrorToast]) + + /** + * @description: 토큰 재발급이 필요한 경우, 재발급 후 새로고침합니다. + * @description: 리프레시 토큰까지 만료되었을 경우 handleSessionExpiration 실행 + */ + const refreshTokenIfNeeded = useCallback(async () => { + if (!refreshToken || reissueTokenQuery.isError) { + handleSessionExpiration() + } else if (reissueTokenQuery.data?.data?.accessToken) { + const newToken = reissueTokenQuery.data.data.accessToken + handleTokenRefresh({ token: newToken }) } + }, [ + refreshToken, + reissueTokenQuery.isError, + reissueTokenQuery.data?.data.accessToken, + handleSessionExpiration, + ]) - if (!accessToken && !!refreshToken) { - if (reissueTokenQuery.data?.data?.accessToken) { - handleTokenRefresh({ - token: reissueTokenQuery.data.data.accessToken, - }) - updateLoginState(validateUserQuery.data?.data?.userInfo) - } + useEffect(() => { + if (validateUserQuery.isError) { + refreshTokenIfNeeded() } + }, [validateUserQuery.isError, refreshTokenIfNeeded]) - if (validateUserQuery.data?.data?.userInfo) { - const userInfo = validateUserQuery.data.data.userInfo - setCurrentUser(() => userInfo) - setIsLoggedIn(() => !!userInfo) + useEffect(() => { + if (!accessToken && refreshToken) { + handleTokenRefresh({ token: reissueTokenQuery?.data?.data.accessToken }) } }, [ - validateUserQuery.data?.data?.userInfo, - reissueTokenQuery.data?.data.accessToken, - router, - pathname, - toast, - validateUserQuery.isError, accessToken, refreshToken, - reissueTokenQuery.isError, + reissueTokenQuery?.data?.data.accessToken, + pathname, ]) - return { isLoggedIn, currentUser } + return { + isLoggedIn: !!accessToken, + currentUser: validateUserQuery?.data?.data.userInfo, + } } export default useValidate