import './ToastProvider.css'; import { createContext, useCallback, useMemo, useRef, useState, type ReactNode } from 'react'; export type ToastKind = 'success' | 'error' | 'info'; interface Toast { id: number; kind: ToastKind; message: string; } export interface ToastApi { success: (message: string) => void; error: (message: string) => void; info: (message: string) => void; } export const ToastContext = createContext(null); const DEFAULT_DURATION_MS = 4000; /** * Fournit un système de notifications transitoires. À monter une fois, haut * dans l'arbre (cf. main.tsx). Les composants consomment `useToast()`. */ export function ToastProvider({ children }: { children: ReactNode }) { const [toasts, setToasts] = useState([]); const nextId = useRef(0); const remove = useCallback((id: number) => { setToasts((current) => current.filter((t) => t.id !== id)); }, []); const push = useCallback( (kind: ToastKind, message: string) => { const id = ++nextId.current; setToasts((current) => [...current, { id, kind, message }]); setTimeout(() => remove(id), DEFAULT_DURATION_MS); }, [remove], ); const api = useMemo( () => ({ success: (message) => push('success', message), error: (message) => push('error', message), info: (message) => push('info', message), }), [push], ); return ( {children}
{toasts.map((toast) => (
{toast.message}
))}
); }