"use client"; import { useEffect, useState } from "react"; import { X, CheckCircle, AlertCircle, Info, AlertTriangle } from "lucide-react"; import { cn } from "@/app/_utils/cn"; export interface Toast { id: string; type: "success" | "error" | "info" | "warning"; title: string; message?: string; duration?: number; } interface ToastProps { toast: Toast; onRemove: (id: string) => void; } const toastIcons = { success: CheckCircle, error: AlertCircle, info: Info, warning: AlertTriangle, }; const toastStyles = { success: "border-green-500/20 bg-green-500/10 text-green-700 dark:text-green-400", error: "border-red-500/20 bg-red-500/10 text-red-700 dark:text-red-400", info: "border-blue-500/20 bg-blue-500/10 text-blue-700 dark:text-blue-400", warning: "border-yellow-500/20 bg-yellow-500/10 text-yellow-700 dark:text-yellow-400", }; export function Toast({ toast, onRemove }: ToastProps) { const [isVisible, setIsVisible] = useState(false); const Icon = toastIcons[toast.type]; useEffect(() => { setIsVisible(true); const timer = setTimeout(() => { setIsVisible(false); setTimeout(() => onRemove(toast.id), 300); }, toast.duration || 5000); return () => clearTimeout(timer); }, [toast.id, toast.duration, onRemove]); return (

{toast.title}

{toast.message && (

{toast.message}

)}
); } export function ToastContainer() { const [toasts, setToasts] = useState([]); const addToast = (toast: Omit) => { const id = Math.random().toString(36).substr(2, 9); setToasts((prev) => [...prev, { ...toast, id }]); }; const removeToast = (id: string) => { setToasts((prev) => prev.filter((toast) => toast.id !== id)); }; useEffect(() => { (window as any).showToast = addToast; return () => { delete (window as any).showToast; }; }, []); return (
{toasts.map((toast) => ( ))}
); } export function showToast( type: Toast["type"], title: string, message?: string, duration?: number ) { if (typeof window !== "undefined" && (window as any).showToast) { (window as any).showToast({ type, title, message, duration }); } }