diff --git a/components/AuthProvider.tsx b/components/AuthProvider.tsx index 0357270..075c854 100644 --- a/components/AuthProvider.tsx +++ b/components/AuthProvider.tsx @@ -11,10 +11,13 @@ const AuthProvider = ({ children }: { children: React.ReactNode }) => { const { refresh } = useAuth(); useEffect(() => { + // refresh 여부를 알 수 있는 코드, 당장은 필요 없으나 이후 의도치 않은 refresh가 계속 발생할 경우 사용 + // const entries = performance.getEntriesByType('navigation')[0]; + // const entriesNavigationTiming = entries as PerformanceNavigationTiming; + // entriesNavigationTiming.type === 'reload' + const refreshToken = localStorage.getItem('refreshToken'); - if (!isAuthorized && refreshToken) { - refresh(refreshToken as string); - } + if (!isAuthorized && refreshToken) refresh(refreshToken as string); }, [isAuthorized, refresh]); return
{children}
; diff --git a/components/withAuth.tsx b/components/withAuth.tsx new file mode 100644 index 0000000..3ddf50c --- /dev/null +++ b/components/withAuth.tsx @@ -0,0 +1,32 @@ +'use client'; + +import { useRouter } from 'next/navigation'; +import { useEffect } from 'react'; +import { useAuthStore } from '@/stores/authStore'; + +export interface WithAuthProps {} // 추후에 인증 과정에 더 필요한 props를 위해 + +export default function withAuth( + Component: React.ComponentType, +) { + const ComponentWithAuth = (props: Omit) => { + const isAuthorized = useAuthStore((state) => state.authInfo.isAuthorized); + const isLoading = useAuthStore((state) => state.authInfo.isLoading); + const router = useRouter(); + + useEffect(() => { + // 가장 초기 상태에는 undefined이므로, 해당 경우를 고려 해주어야 함 + if (isLoading !== undefined && !isLoading && !isAuthorized) { + router.push('/login'); + } + }); + + return !isLoading && isAuthorized ? ( + + ) : ( +
loading
// 렌더링과 라우팅 사이의 딜레이 시 보여질 화면 + ); + }; + + return ComponentWithAuth; +} diff --git a/hooks/auth.ts b/hooks/auth.ts index f45ba71..564bea8 100644 --- a/hooks/auth.ts +++ b/hooks/auth.ts @@ -7,6 +7,7 @@ export const useAuth = () => { const setAuthInfo = useAuthStore((state) => state.setAuthInfo); const login = async (provider: string, code: string) => { + setAuthInfo({ isLoading: true }); const res = await fetch( `${process.env.NEXT_PUBLIC_SERVER_BASE_URL}/v1/login/${provider}?code=${code}`, { cache: 'no-store' }, @@ -15,13 +16,15 @@ export const useAuth = () => { if (res.ok) { const result: TAuthInfo = await res.json(); localStorage.setItem('refreshToken', result.refreshToken as string); - setAuthInfo(result); + setAuthInfo({ ...result, isAuthorized: true, isLoading: false }); return result; } + setAuthInfo(null); return false; }; const refresh = async (token: string) => { + setAuthInfo({ isLoading: true }); const headers = new Headers(); headers.set('Authorization', `Bearer ${token}`); const res = await fetch( @@ -31,8 +34,8 @@ export const useAuth = () => { if (res.ok) { const result: TAuthInfo = await res.json(); localStorage.setItem('refreshToken', result.refreshToken as string); - setAuthInfo(result); - return res.json(); + setAuthInfo({ ...result, isAuthorized: true, isLoading: false }); + return result; } localStorage.removeItem('refreshToken'); setAuthInfo(null); @@ -40,6 +43,7 @@ export const useAuth = () => { }; const logout = async (provider: string, token: string) => { + setAuthInfo({ isLoading: true }); const headers = new Headers(); headers.set('Authorization', `bearer ${token}`); const res = await fetch( @@ -52,6 +56,7 @@ export const useAuth = () => { setAuthInfo(null); return true; } + setAuthInfo({ isLoading: false }); return false; }; diff --git a/stores/authStore.tsx b/stores/authStore.tsx index aed46fc..a52d72a 100644 --- a/stores/authStore.tsx +++ b/stores/authStore.tsx @@ -10,6 +10,7 @@ interface TUseAuth { const initialState: TAuthInfo = { isAuthorized: false, + isLoading: false, id: null, nickName: null, email: null, @@ -23,9 +24,7 @@ export const useAuthStore = create( authInfo: initialState, setAuthInfo: (payload) => set((state) => ({ - authInfo: payload - ? { ...state.authInfo, ...payload, isAuthorized: true } - : initialState, + authInfo: payload ? { ...state.authInfo, ...payload } : initialState, })), })), ); diff --git a/types/index.ts b/types/index.ts index 9ee6c07..2ba566d 100644 --- a/types/index.ts +++ b/types/index.ts @@ -28,6 +28,7 @@ export interface TQna { } export interface TAuthInfo { + isLoading: boolean; isAuthorized: boolean; id: number | null; nickName: string | null;