import { createContext, useCallback, useContext, useEffect, useMemo, useState, type ReactNode, } from "react"; import { setUnauthorizedHandler, tokenStore } from "@/api/client"; import { fetchMe, login as loginRequest, logoutRequest } from "@/api/services"; import type { AppUser } from "@/api/types"; interface AuthContextValue { user: AppUser | null; loading: boolean; login: (email: string, password: string) => Promise; logout: () => void; } const AuthContext = createContext(undefined); export function AuthProvider({ children }: { children: ReactNode }) { const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); const logout = useCallback(() => { const refresh = tokenStore.getRefresh(); if (refresh) void logoutRequest(refresh).catch(() => undefined); // revoke server-side tokenStore.clear(); setUser(null); }, []); useEffect(() => { setUnauthorizedHandler(() => setUser(null)); }, []); // Restore session on load. useEffect(() => { const token = tokenStore.get(); if (!token) { setLoading(false); return; } fetchMe() .then((u) => { if (u.role === "admin") setUser(u); else logout(); }) .catch(() => logout()) .finally(() => setLoading(false)); }, [logout]); const login = useCallback(async (email: string, password: string) => { const token = await loginRequest(email, password); tokenStore.set(token.access_token, token.refresh_token); const me = await fetchMe(); setUser(me); }, []); const value = useMemo( () => ({ user, loading, login, logout }), [user, loading, login, logout], ); return {children}; } // eslint-disable-next-line react-refresh/only-export-components export function useAuth() { const ctx = useContext(AuthContext); if (!ctx) throw new Error("useAuth must be used within AuthProvider"); return ctx; }