import React, { createContext, useReducer, useEffect } from 'react'; import { isTokenValid, getAccessTokenFromCookie, getUserFromToken } from 'src/axios/authService'; // 사용자 타입 정의 export interface Member { memberId: string; memberName: string; } // 인증 상태 타입 정의 interface AuthState { isAuthenticated: boolean; member: Member | null; loading: boolean; error: string | null; } // 액션 타입 정의 type AuthAction = | { type: 'LOGIN_SUCCESS'; payload: { member: Member; token: string } } | { type: 'LOGOUT' } | { type: 'AUTH_ERROR'; payload: string } | { type: 'CLEAR_ERROR' } | { type: 'SET_LOADING' } | { type: 'MEMBER_LOADED'; payload: Member }; // 초기 상태 const initialState: AuthState = { isAuthenticated: false, member: null, loading: true, error: null }; // Context 타입 정의 export interface AuthContextType { state: AuthState; dispatch: React.Dispatch; login: (token: string, member: Member) => void; logout: () => void; } // Context 생성 export const AuthContext = createContext({ state: initialState, dispatch: () => null, login: () => null, logout: () => null }); // 리듀서 함수 const authReducer = (state: AuthState, action: AuthAction): AuthState => { switch (action.type) { case 'LOGIN_SUCCESS': localStorage.setItem('accessToken', action.payload.token); return { ...state, isAuthenticated: true, member: action.payload.member, loading: false, error: null }; case 'LOGOUT': localStorage.removeItem('accessToken'); return { ...state, isAuthenticated: false, member: null, loading: false, error: null }; case 'AUTH_ERROR': localStorage.removeItem('accessToken'); return { ...state, isAuthenticated: false, member: null, loading: false, error: action.payload }; case 'CLEAR_ERROR': return { ...state, error: null }; case 'SET_LOADING': return { ...state, loading: true }; case 'MEMBER_LOADED': return { ...state, isAuthenticated: true, member: action.payload, loading: false }; default: return state; } }; // Provider 컴포넌트 export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { const [state, dispatch] = useReducer(authReducer, initialState); // 로그인 함수 const login = (token: string, member: Member) => { dispatch({ type: 'LOGIN_SUCCESS', payload: { token, member } }); }; // 로그아웃 함수 const logout = () => { dispatch({ type: 'LOGOUT' }); }; // 초기 인증 상태 확인 useEffect(() => { const loadUser = async () => { // localStorage 또는 Cookie에서 토큰 확인 let token = localStorage.getItem('accessToken') || getAccessTokenFromCookie(); if (!token || !isTokenValid(token)) { dispatch({ type: 'LOGOUT' }); return; } try { // 토큰이 쿠키에만 있고 localStorage에 없으면 저장해줌 (일관성 유지) if (!localStorage.getItem('accessToken')) { localStorage.setItem('accessToken', token); } const decodedToken = getUserFromToken(token); if (decodedToken) { const member: Member = { memberId: decodedToken.memberId, memberName: decodedToken.memberName }; dispatch({ type: 'MEMBER_LOADED', payload: member }); } else { dispatch({ type: 'AUTH_ERROR', payload: 'Invalid token' }); } } catch (error) { dispatch({ type: 'AUTH_ERROR', payload: 'Authentication failed' }); } }; loadUser(); }, []); return ( {children} ); };