/* eslint-disable react-hooks/set-state-in-effect */ // Toast Notification System - Slide-in notifications from top-right "use client"; import { useEffect, useState, useCallback } from "react"; import { createPortal } from "react-dom"; type ToastType = "success" | "error" | "warning" | "info"; interface Toast { id: string; type: ToastType; title: string; message?: string; duration?: number; } interface ToastNotificationProps { toast: Toast; onDismiss: (id: string) => void; } function ToastItem({ toast, onDismiss }: ToastNotificationProps) { const [progress, setProgress] = useState(100); const [isExiting, setIsExiting] = useState(false); const duration = toast.duration ?? 5000; useEffect(() => { const startTime = Date.now(); const interval = setInterval(() => { const elapsed = Date.now() - startTime; const remaining = Math.max(0, 100 - (elapsed / duration) * 100); setProgress(remaining); if (remaining === 0) { clearInterval(interval); setIsExiting(true); setTimeout(() => onDismiss(toast.id), 300); } }, 50); return () => clearInterval(interval); }, [toast.id, duration, onDismiss]); const handleDismiss = () => { setIsExiting(true); setTimeout(() => onDismiss(toast.id), 300); }; const icons = { success: ( ), error: ( ), warning: ( ), info: ( ), }; const colors = { success: "bg-emerald-50 border-emerald-200 text-emerald-800", error: "bg-red-50 border-red-200 text-red-800", warning: "bg-amber-50 border-amber-200 text-amber-800", info: "bg-blue-50 border-blue-200 text-blue-800", }; const iconColors = { success: "text-emerald-500", error: "text-red-500", warning: "text-amber-500", info: "text-blue-500", }; return (
{toast.title}
{toast.message &&{toast.message}
}