import { createContext, useCallback, useContext, useEffect, useState } from 'react' import type { ReactNode } from 'react' import * as authApi from '../api/auth' import { setAuthFailureHandler, tokenStorage } from '../api/client' import type { User } from '../api/types' interface AuthContextValue { user: User | null loading: boolean login: (email: string, password: string) => Promise register: (email: string, username: string, password: string) => Promise logout: () => void refreshUser: () => Promise } const AuthContext = createContext(undefined) export function AuthProvider({ children }: { children: ReactNode }) { const [user, setUser] = useState(null) const [loading, setLoading] = useState(true) const refreshMe = useCallback(async () => { if (!tokenStorage.getAccess()) { setUser(null) setLoading(false) return } try { setUser(await authApi.getMe()) } catch { tokenStorage.clear() setUser(null) } finally { setLoading(false) } }, []) useEffect(() => { refreshMe() }, [refreshMe]) // Fires when a request's 401 survives a refresh attempt (refresh token // missing/expired/revoked) — drop back to logged-out state so // ProtectedRoute sends the user to /login instead of the app silently // failing every request. useEffect(() => { setAuthFailureHandler(() => setUser(null)) return () => setAuthFailureHandler(() => {}) }, []) const login = async (email: string, password: string) => { await authApi.login(email, password) await refreshMe() } const register = async (email: string, username: string, password: string) => { await authApi.register(email, username, password) await refreshMe() } const logout = () => { authApi.logout() setUser(null) } return ( {children} ) } export function useAuth(): AuthContextValue { const ctx = useContext(AuthContext) if (!ctx) throw new Error('useAuth must be used within AuthProvider') return ctx }