Skip to content

Commit

Permalink
✨ NABI-392 validation 로직 리팩토링
Browse files Browse the repository at this point in the history
  • Loading branch information
oaoong committed Jan 2, 2024
1 parent 83194c3 commit 5c3b17e
Showing 1 changed file with 65 additions and 58 deletions.
123 changes: 65 additions & 58 deletions src/hooks/useValidate.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,23 @@
'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'
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<boolean>(() => !!accessToken)
const [currentUser, setCurrentUser] = useState<User | null>(() => 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 () => {
Expand All @@ -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

0 comments on commit 5c3b17e

Please sign in to comment.