import { createContext, useCallback, useContext, useEffect, useMemo, useState, type ReactNode, } from 'react'; import { api, hasStoredSession, type LoginInput, type Me, type RegisterInput, } from '../lib/api'; import { getSocket, disconnectSocket } from '../lib/socket'; type AuthStatus = 'loading' | 'authenticated' | 'unauthenticated'; interface AuthContextValue { status: AuthStatus; user: Me | null; login: (input: LoginInput) => Promise; register: (input: RegisterInput) => Promise; logout: () => Promise; refreshMe: () => Promise; } const AuthContext = createContext(null); export function AuthProvider({ children }: { children: ReactNode }) { const [status, setStatus] = useState('loading'); const [user, setUser] = useState(null); // Bootstrap: if we have a refresh token on disk, try /auth/me useEffect(() => { let cancelled = false; (async () => { if (!(await hasStoredSession())) { if (!cancelled) setStatus('unauthenticated'); return; } try { const me = await api.me(); if (cancelled) return; setUser(me); setStatus('authenticated'); // Connect WebSocket on session restore getSocket().catch(() => {}); } catch { if (cancelled) return; setUser(null); setStatus('unauthenticated'); } })(); return () => { cancelled = true; }; }, []); const login = useCallback(async (input: LoginInput) => { await api.login(input); const me = await api.me(); setUser(me); setStatus('authenticated'); // Connect WebSocket after login getSocket().catch(() => {}); }, []); const register = useCallback(async (input: RegisterInput) => { await api.register(input); const me = await api.me(); setUser(me); setStatus('authenticated'); }, []); const logout = useCallback(async () => { disconnectSocket(); await api.logout(); setUser(null); setStatus('unauthenticated'); }, []); const refreshMe = useCallback(async () => { const me = await api.me(); setUser(me); }, []); const value = useMemo( () => ({ status, user, login, register, logout, refreshMe }), [status, user, login, register, logout, refreshMe], ); return {children}; } export function useAuth(): AuthContextValue { const ctx = useContext(AuthContext); if (!ctx) throw new Error('useAuth must be used inside '); return ctx; }