import { createContext, useCallback, useEffect, useMemo, useRef, useState } from "react"; const MAX_ACTION_TOASTS = 5; const DEFAULT_DURATION_MS = { success: 3500, info: 3500, error: 5000, }; export const ActionToastContext = createContext(null); function createToastId() { if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") { return crypto.randomUUID(); } return `toast_${Date.now()}_${Math.random().toString(16).slice(2)}`; } export function ActionToastProvider({ children }) { const [toasts, setToasts] = useState([]); const timerByIdRef = useRef(new Map()); const dismiss = useCallback((id) => { const timer = timerByIdRef.current.get(id); if (timer) { clearTimeout(timer); timerByIdRef.current.delete(id); } setToasts((prev) => prev.filter((toast) => toast.id !== id)); }, []); const pushToast = useCallback( (variant, title, message, options = {}) => { const id = createToastId(); const durationMs = options.durationMs ?? DEFAULT_DURATION_MS[variant] ?? 3500; const nextToast = { id, variant, title: String(title || ""), message: String(message || ""), createdAt: Date.now(), durationMs, }; setToasts((prev) => { const next = [...prev, nextToast]; if (next.length > MAX_ACTION_TOASTS) { const oldest = next.shift(); if (oldest) { const timer = timerByIdRef.current.get(oldest.id); if (timer) { clearTimeout(timer); timerByIdRef.current.delete(oldest.id); } } } return next; }); if (durationMs > 0) { const timer = setTimeout(() => dismiss(id), durationMs); timerByIdRef.current.set(id, timer); } return id; }, [dismiss] ); const success = useCallback( (title, message, options) => pushToast("success", title, message, options), [pushToast] ); const error = useCallback( (title, message, options) => pushToast("error", title, message, options), [pushToast] ); const info = useCallback( (title, message, options) => pushToast("info", title, message, options), [pushToast] ); useEffect(() => { return () => { for (const timer of timerByIdRef.current.values()) { clearTimeout(timer); } timerByIdRef.current.clear(); }; }, []); const value = useMemo( () => ({ toasts, success, error, info, dismiss, }), [toasts, success, error, info, dismiss] ); return {children}; }