import { createContext, useContext, useState, useCallback, useMemo, useRef, useEffect, type ReactNode, } from "react"; interface Alert { id: string; message: string; type: "success" | "error" | "warning" | "info"; } interface AlertMethods { addAlert: (message: string, type?: string, duration?: number) => string; removeAlert: (id: string) => void; success: (message: string, duration?: number) => string; error: (message: string, duration?: number) => string; warning: (message: string, duration?: number) => string; info: (message: string, duration?: number) => string; } interface AlertStateValue { alerts: Alert[]; removeAlert: (id: string) => void; } const AlertContext = createContext(null); const AlertStateContext = createContext(null); export function AlertProvider({ children }: { children: ReactNode }) { const [alerts, setAlerts] = useState([]); const removeAlert = useCallback((id: string) => { setAlerts((prev) => prev.filter((alert) => alert.id !== id)); }, []); const counterRef = useRef(0); const timeoutsRef = useRef>>(new Set()); useEffect(() => { const timeouts = timeoutsRef.current; return () => { timeouts.forEach(clearTimeout); timeouts.clear(); }; }, []); const addAlert = useCallback( (message: string, type = "success", duration = 4000) => { const id = `${Date.now()}-${counterRef.current++}`; setAlerts((prev) => [ ...prev, { id, message, type: type as Alert["type"] }, ]); if (duration > 0) { const timeoutId = setTimeout(() => { timeoutsRef.current.delete(timeoutId); removeAlert(id); }, duration); timeoutsRef.current.add(timeoutId); } return id; }, [removeAlert], ); const methods = useMemo( () => ({ addAlert, removeAlert, success: (message, duration) => addAlert(message, "success", duration), error: (message, duration) => addAlert(message, "error", duration), warning: (message, duration) => addAlert(message, "warning", duration), info: (message, duration) => addAlert(message, "info", duration), }), [addAlert, removeAlert], ); return ( {children} ); } export function useAlert(): AlertMethods { const context = useContext(AlertContext); if (!context) throw new Error("useAlert must be used within an AlertProvider"); return context; } export function useAlertState(): AlertStateValue { const context = useContext(AlertStateContext); if (!context) throw new Error("useAlertState must be used within an AlertProvider"); return context; }