import React, { useEffect, useState } from 'react'; import { CheckCircle, XCircle, AlertCircle, Info, X } from 'lucide-react'; export type ToastType = 'success' | 'error' | 'warning' | 'info'; export interface ToastMessage { id: string; type: ToastType; title: string; message?: string; duration?: number; } interface ToastItemProps { toast: ToastMessage; onRemove: (id: string) => void; } const ToastItem: React.FC = ({ toast, onRemove }) => { const [isExiting, setIsExiting] = useState(false); const [progress, setProgress] = useState(100); const duration = toast.duration || 5000; useEffect(() => { // Progress bar animation const interval = setInterval(() => { setProgress((prev) => { const newProgress = prev - (100 / (duration / 50)); return newProgress <= 0 ? 0 : newProgress; }); }, 50); // Auto dismiss const timer = setTimeout(() => { handleClose(); }, duration); return () => { clearInterval(interval); clearTimeout(timer); }; }, [duration]); const handleClose = () => { setIsExiting(true); setTimeout(() => { onRemove(toast.id); }, 300); }; const getIcon = () => { switch (toast.type) { case 'success': return ; case 'error': return ; case 'warning': return ; case 'info': return ; } }; const getStyles = () => { const baseStyles = 'relative overflow-hidden backdrop-blur-xl border shadow-2xl'; switch (toast.type) { case 'success': return `${baseStyles} bg-gradient-to-r from-emerald-50/95 to-green-50/95 border-emerald-200/50`; case 'error': return `${baseStyles} bg-gradient-to-r from-red-50/95 to-rose-50/95 border-red-200/50`; case 'warning': return `${baseStyles} bg-gradient-to-r from-amber-50/95 to-yellow-50/95 border-amber-200/50`; case 'info': return `${baseStyles} bg-gradient-to-r from-blue-50/95 to-indigo-50/95 border-blue-200/50`; } }; const getProgressColor = () => { switch (toast.type) { case 'success': return 'bg-gradient-to-r from-emerald-400 to-green-500'; case 'error': return 'bg-gradient-to-r from-red-400 to-rose-500'; case 'warning': return 'bg-gradient-to-r from-amber-400 to-yellow-500'; case 'info': return 'bg-gradient-to-r from-blue-400 to-indigo-500'; } }; return (
{getIcon()}

{toast.title}

{toast.message && (

{toast.message}

)}
{/* Progress bar */}
); }; interface ToastContainerProps { toasts: ToastMessage[]; onRemove: (id: string) => void; } export const ToastContainer: React.FC = ({ toasts, onRemove }) => { return (
{toasts.map((toast) => (
))}
); }; // Toast Hook export const useToast = () => { const [toasts, setToasts] = useState([]); const addToast = (type: ToastType, title: string, message?: string, duration?: number) => { const id = `toast-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; const newToast: ToastMessage = { id, type, title, message, duration }; setToasts((prev) => [...prev, newToast]); return id; }; const removeToast = (id: string) => { setToasts((prev) => prev.filter((t) => t.id !== id)); }; const toast = { success: (title: string, message?: string, duration?: number) => addToast('success', title, message, duration), error: (title: string, message?: string, duration?: number) => addToast('error', title, message, duration), warning: (title: string, message?: string, duration?: number) => addToast('warning', title, message, duration), info: (title: string, message?: string, duration?: number) => addToast('info', title, message, duration), }; return { toasts, toast, removeToast }; }; // Global Toast Context import { createContext, useContext } from 'react'; interface ToastContextType { toast: { success: (title: string, message?: string, duration?: number) => string; error: (title: string, message?: string, duration?: number) => string; warning: (title: string, message?: string, duration?: number) => string; info: (title: string, message?: string, duration?: number) => string; }; } export const ToastContext = createContext(null); export const useToastContext = () => { const context = useContext(ToastContext); if (!context) { throw new Error('useToastContext must be used within a ToastProvider'); } return context; }; interface ToastProviderProps { children: React.ReactNode; } export const ToastProvider: React.FC = ({ children }) => { const { toasts, toast, removeToast } = useToast(); return ( {children} ); }; export default ToastItem;