'use client'; import React, { createContext, useContext, useState, useEffect, useCallback } from 'react'; import { useRouter } from 'next/navigation'; import { API_URL } from './config'; interface AuthUser { userId: number; username: string; role: string; } interface AuthContextValue { user: AuthUser | null; loading: boolean; login: (username: string, password: string) => Promise; logout: () => void; isAuthenticated: boolean; } const AuthContext = createContext({ user: null, loading: true, login: async () => {}, logout: () => {}, isAuthenticated: false, }); export function AuthProvider({ children }: { children: React.ReactNode }) { const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); const loadUser = useCallback(async () => { const token = localStorage.getItem('hanarang_access_token'); if (!token) { setLoading(false); return; } try { const res = await fetch(`${API_URL}/api/auth/me`, { headers: { Authorization: `Bearer ${token}` }, }); if (res.ok) { const data = await res.json(); setUser({ userId: data.id, username: data.username, role: data.role }); } else if (res.status === 401) { // access token 만료 → refresh 시도 const refreshToken = localStorage.getItem('hanarang_refresh_token'); if (refreshToken) { try { const rRes = await fetch(`${API_URL}/api/auth/refresh`, { method: 'POST', headers: { 'x-refresh-token': refreshToken }, }); if (rRes.ok) { const d = await rRes.json(); localStorage.setItem('hanarang_access_token', d.accessToken); if (d.refreshToken) localStorage.setItem('hanarang_refresh_token', d.refreshToken); setUser({ userId: 0, username: d.username, role: d.role }); } else { localStorage.removeItem('hanarang_access_token'); localStorage.removeItem('hanarang_refresh_token'); } } catch { /* silent */ } } else { localStorage.removeItem('hanarang_access_token'); } } } catch { // silent } finally { setLoading(false); } }, []); useEffect(() => { loadUser(); }, [loadUser]); const login = async (username: string, password: string) => { const res = await fetch(`${API_URL}/api/auth/login`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }), }); if (!res.ok) { const d = await res.json(); throw new Error(d.message ?? '로그인 실패'); } const d = await res.json(); localStorage.setItem('hanarang_access_token', d.accessToken); if (d.refreshToken) { localStorage.setItem('hanarang_refresh_token', d.refreshToken); } // me API로 실제 userId 가져오기 try { const meRes = await fetch(`${API_URL}/api/auth/me`, { headers: { Authorization: `Bearer ${d.accessToken}` }, }); if (meRes.ok) { const me = await meRes.json(); setUser({ userId: me.id, username: me.username, role: me.role }); return; } } catch { /* fallback */ } setUser({ userId: 0, username: d.username, role: d.role }); }; const logout = () => { localStorage.removeItem('hanarang_access_token'); localStorage.removeItem('hanarang_refresh_token'); setUser(null); }; return ( {children} ); } export function useAuth() { return useContext(AuthContext); }