import { createContext, useContext, useEffect, useState, type ReactNode } from 'react' import { api, TOKEN_KEY, REFRESH_KEY, USER_KEY } from '@/lib/api' import type { AuthResponse, LoginPayload, UserInfo } from '@/types/auth' import type { MenuNode } from '@/types/menu' type AuthContextValue = { user: UserInfo | null menu: MenuNode[] isAuthenticated: boolean isBootstrapping: boolean login: (payload: LoginPayload) => Promise logout: () => void refreshMenu: () => Promise } const AuthContext = createContext(null) const MENU_KEY = 'solution-erp-user-menu' export function AuthProvider({ children }: { children: ReactNode }) { const [user, setUser] = useState(null) const [menu, setMenu] = useState([]) const [isBootstrapping, setIsBootstrapping] = useState(true) async function loadMenu() { try { const res = await api.get('/menus/me') setMenu(res.data) localStorage.setItem(MENU_KEY, JSON.stringify(res.data)) } catch { // keep cached } } useEffect(() => { const token = localStorage.getItem(TOKEN_KEY) const userRaw = localStorage.getItem(USER_KEY) const menuRaw = localStorage.getItem(MENU_KEY) if (token && userRaw) { try { setUser(JSON.parse(userRaw)) if (menuRaw) setMenu(JSON.parse(menuRaw)) loadMenu() } catch { localStorage.removeItem(USER_KEY) localStorage.removeItem(MENU_KEY) } } setIsBootstrapping(false) }, []) async function login(payload: LoginPayload) { const res = await api.post('/auth/login', payload) localStorage.setItem(TOKEN_KEY, res.data.accessToken) localStorage.setItem(REFRESH_KEY, res.data.refreshToken) localStorage.setItem(USER_KEY, JSON.stringify(res.data.user)) setUser(res.data.user) await loadMenu() } function logout() { localStorage.removeItem(TOKEN_KEY) localStorage.removeItem(REFRESH_KEY) localStorage.removeItem(USER_KEY) localStorage.removeItem(MENU_KEY) setUser(null) setMenu([]) // Close realtime socket — avoid leaking auth'd connection across users import('@/lib/realtime').then(m => m.stopConnection()).catch(() => {}) } return ( {children} ) } export function useAuth() { const ctx = useContext(AuthContext) if (!ctx) throw new Error('useAuth must be used inside AuthProvider') return ctx }