"use client"; import { useState, useEffect, useRef, useCallback } from "react"; import { X, CheckCircle2, XCircle, AlertTriangle, Info, Loader2, ChevronDown, } from "lucide-react"; import { cn } from "@/lib/utils"; import type { ToastItem } from "@/lib/notifications"; interface ToastProps { toast: ToastItem; onDismiss: (id: string) => void; } const VARIANT_CONFIG = { success: { border: "border-green-800", bg: "bg-green-950/90", icon: CheckCircle2, iconColor: "text-green-400", progress: "bg-green-500", }, error: { border: "border-red-800", bg: "bg-red-950/90", icon: XCircle, iconColor: "text-red-400", progress: "bg-red-500", }, warning: { border: "border-yellow-800", bg: "bg-yellow-950/90", icon: AlertTriangle, iconColor: "text-yellow-400", progress: "bg-yellow-500", }, info: { border: "border-blue-800", bg: "bg-blue-950/90", icon: Info, iconColor: "text-blue-400", progress: "bg-blue-500", }, loading: { border: "border-surface-700", bg: "bg-surface-800", icon: Loader2, iconColor: "text-brand-400", progress: "bg-brand-500", }, } as const; export function Toast({ toast, onDismiss }: ToastProps) { const [paused, setPaused] = useState(false); const [expanded, setExpanded] = useState(false); const [progress, setProgress] = useState(100); // Track remaining time across pause/resume cycles const remainingRef = useRef(toast.duration); const dismiss = useCallback(() => onDismiss(toast.id), [onDismiss, toast.id]); useEffect(() => { if (toast.duration === 0) return; // loading: never auto-dismiss if (paused) return; const snapRemaining = remainingRef.current; const start = Date.now(); const interval = setInterval(() => { const elapsed = Date.now() - start; const newRemaining = Math.max(0, snapRemaining - elapsed); remainingRef.current = newRemaining; setProgress((newRemaining / toast.duration) * 100); if (newRemaining === 0) { clearInterval(interval); dismiss(); } }, 50); return () => clearInterval(interval); }, [paused, toast.duration, dismiss]); const config = VARIANT_CONFIG[toast.variant]; const Icon = config.icon; return (
{toast.title}
{toast.description && ({toast.description}
)} {/* Action button */} {toast.action && ( )} {/* Expandable details */} {toast.details && (
{toast.details}
)}