import { createContext, useContext, useState, useCallback, useRef, useEffect } from 'react'; import { ToastContainer, ToastData, ToastType } from '../components/UiComponents/Toast'; interface ToastOptions { title: string; message?: string; duration?: number; } interface ToastContextValue { showToast: (type: ToastType, options: ToastOptions) => void; showSuccess: (title: string, message?: string) => void; showError: (title: string, message?: string) => void; showWarning: (title: string, message?: string) => void; showInfo: (title: string, message?: string) => void; closeToast: (id: string) => void; } const ToastContext = createContext(null); const DEFAULT_DURATION = 5000; export const ToastProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { const [toasts, setToasts] = useState([]); const timeoutRefs = useRef>(new Map()); const closeToast = useCallback((id: string) => { // Clear timeout if exists const timeout = timeoutRefs.current.get(id); if (timeout) { clearTimeout(timeout); timeoutRefs.current.delete(id); } setToasts((prev) => prev.filter((toast) => toast.id !== id)); }, []); const showToast = useCallback((type: ToastType, options: ToastOptions) => { const id = `toast-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; const duration = options.duration ?? DEFAULT_DURATION; const newToast: ToastData = { id, type, title: options.title, message: options.message, duration, }; setToasts((prev) => [...prev, newToast]); // Auto-close after duration if (duration > 0) { const timeout = setTimeout(() => { closeToast(id); }, duration); timeoutRefs.current.set(id, timeout); } }, [closeToast]); const showSuccess = useCallback((title: string, message?: string) => { showToast('success', { title, message }); }, [showToast]); const showError = useCallback((title: string, message?: string) => { showToast('error', { title, message, duration: 8000 }); // Errors stay longer }, [showToast]); const showWarning = useCallback((title: string, message?: string) => { showToast('warning', { title, message, duration: 6000 }); }, [showToast]); const showInfo = useCallback((title: string, message?: string) => { showToast('info', { title, message }); }, [showToast]); // Cleanup timeouts on unmount useEffect(() => { return () => { timeoutRefs.current.forEach((timeout) => clearTimeout(timeout)); }; }, []); return ( {children} ); }; export const useToast = (): ToastContextValue => { const context = useContext(ToastContext); if (!context) { throw new Error('useToast must be used within a ToastProvider'); } return context; };