import React, { createContext, useContext, useState, useCallback } from 'react'; import { createPortal } from 'react-dom'; type ToastType = 'success' | 'error' | 'info' | 'warning'; interface Toast { id: number; message: string; type: ToastType; } interface ToastContextType { showToast: (message: string, type?: ToastType) => void; } const ToastContext = createContext(undefined); export function useToast() { const context = useContext(ToastContext); if (!context) throw new Error('useToast must be used within a ToastProvider'); return context; } export function ToastProvider({ children }: { children: React.ReactNode }) { const [toasts, setToasts] = useState([]); const showToast = useCallback((message: string, type: ToastType = 'success') => { const id = Date.now(); setToasts(prev => [...prev, { id, message, type }]); setTimeout(() => { setToasts(prev => prev.filter(toast => toast.id !== id)); }, 3000); }, []); return ( {children} ); } function ToastContainer({ toasts }: { toasts: Toast[] }) { if (typeof document === 'undefined') return null; return createPortal(
{toasts.map(toast => ( ))}
, document.body ); } function ToastItem({ toast }: { toast: Toast }) { const icons = { success: , error: , warning: , info: , }; const colors = { success: "bg-emerald-50 text-emerald-600 border-emerald-100 dark:bg-emerald-500/10 dark:text-emerald-400 dark:border-emerald-500/20", error: "bg-red-50 text-red-600 border-red-100 dark:bg-red-500/10 dark:text-red-400 dark:border-red-500/20", warning: "bg-amber-50 text-amber-600 border-amber-100 dark:bg-amber-500/10 dark:text-amber-400 dark:border-amber-500/20", info: "bg-blue-50 text-blue-600 border-blue-100 dark:bg-blue-500/10 dark:text-blue-400 dark:border-blue-500/20", }; return (
{icons[toast.type]}
{toast.message}
); }