"use client"; import { createContext, useCallback, useContext, useState, type ReactNode } from "react"; import { motion, AnimatePresence } from "framer-motion"; import { CheckCircle, AlertCircle, AlertTriangle, Info, X } from "lucide-react"; type ToastVariant = "success" | "error" | "warning" | "info"; interface Toast { id: string; variant: ToastVariant; message: string; duration?: number; } interface ToastContextType { toast: (variant: ToastVariant, message: string, duration?: number) => void; success: (message: string) => void; error: (message: string) => void; warning: (message: string) => void; info: (message: string) => void; } const ToastContext = createContext(null); const icons: Record = { success: CheckCircle, error: AlertCircle, warning: AlertTriangle, info: Info, }; const variantStyles: Record = { success: "bg-emerald-500/12 border-emerald-500/30 text-emerald-300 [--toast-icon:theme(colors.emerald.400)]", error: "bg-red-500/12 border-red-500/30 text-red-300 [--toast-icon:theme(colors.red.400)]", warning: "bg-amber-500/12 border-amber-500/30 text-amber-300 [--toast-icon:theme(colors.amber.400)]", info: "bg-violet-500/12 border-violet-500/30 text-violet-300 [--toast-icon:theme(colors.violet.400)]", }; export function ToastProvider({ children }: { children: ReactNode }) { const [toasts, setToasts] = useState([]); const removeToast = useCallback((id: string) => { setToasts((prev) => prev.filter((t) => t.id !== id)); }, []); const addToast = useCallback( (variant: ToastVariant, message: string, duration = 4000) => { const id = `toast-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`; setToasts((prev) => [...prev.slice(-4), { id, variant, message, duration }]); if (duration > 0) { setTimeout(() => removeToast(id), duration); } }, [removeToast], ); const ctx: ToastContextType = { toast: addToast, success: (msg) => addToast("success", msg), error: (msg) => addToast("error", msg), warning: (msg) => addToast("warning", msg), info: (msg) => addToast("info", msg), }; return ( {children} {/* Toast container — fixed bottom-right */}
{toasts.map((t) => { const Icon = icons[t.variant]; return (

{t.message}

); })}
); } export function useToast(): ToastContextType { const ctx = useContext(ToastContext); if (!ctx) { throw new Error("useToast must be used within "); } return ctx; }