import { createContext, use, useCallback, useEffect, useMemo, useState } from 'react'; import type { ReactNode } from 'react'; import { ApiError, api } from '@/api/client'; import type { CurrentUser } from '@/api/types'; interface AuthState { user: CurrentUser | null; /** Vrai tant que la session n'a pas été vérifiée au démarrage. */ loading: boolean; login: (email: string, password: string) => Promise; logout: () => Promise; } const AuthContext = createContext(null); export function AuthProvider({ children }: { children: ReactNode }) { const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); // Première requête de l'application : « qui suis-je ? ». Le cookie de // session est déjà là ou il ne l'est pas ; rien à lire dans localStorage, // rien à rafraîchir. C'est le bénéfice concret du choix cookie sur JWT. useEffect(() => { let cancelled = false; api.me() .then((me) => { if (!cancelled) setUser(me); }) .catch(() => { if (!cancelled) setUser(null); }) .finally(() => { if (!cancelled) setLoading(false); }); return () => { cancelled = true; }; }, []); const login = useCallback(async (email: string, password: string) => { setUser(await api.login(email, password)); }, []); const logout = useCallback(async () => { await api.logout(); setUser(null); }, []); const value = useMemo( () => ({ user, loading, login, logout }), [user, loading, login, logout], ); return {children}; } export function useAuth(): AuthState { const context = use(AuthContext); if (context === null) { throw new Error('useAuth doit être utilisé dans un AuthProvider.'); } return context; } /** * Message d'erreur destiné à l'utilisateur. * * Les messages de l'API sont déjà rédigés pour être lus : les reformuler ici * ferait perdre leur précision (« la variable {prenom} est absente » devient * « une erreur est survenue », ce qui n'aide personne). */ export function humanMessage(error: unknown): string { if (error instanceof ApiError) return error.message; if (error instanceof Error) return error.message; return 'Une erreur inattendue est survenue.'; }