"use client";
import * as React from "react";
import { cn } from "../../lib/utils";
import { X } from "lucide-react";
import { cva } from "class-variance-authority";
import { Progress } from "./progress";
/* Toast Components */
const ToastProvider = ({ children }: { children: React.ReactNode }) => {
return
{children}
;
};
const ToastViewport = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes
>(({ className, ...props }, ref) => (
));
ToastViewport.displayName = "ToastViewport";
const toastVariants = cva(
`group relative flex w-96 items-center justify-between overflow-hidden rounded-md border p-4 pr-8 shadow-lg transition-all
bg-background text-foreground`,
{
variants: {
variant: {
default: "border bg-background text-foreground",
destructive: "border-red-500 bg-red-100 text-red-800",
success: "border-green-500 bg-green-100 text-green-800",
warning: "border-yellow-500 bg-yellow-100 text-yellow-800",
info: "border-blue-500 bg-blue-100 text-blue-800",
},
},
defaultVariants: {
variant: "default",
},
}
);
export interface ToastProps extends React.HTMLAttributes {
variant?: "default" | "destructive" | "success" | "warning" | "info";
duration?: number;
onClose?: () => void;
}
const Toast = React.forwardRef(
({ className, variant = "default", duration = 5000, onClose, ...props }, ref) => {
const [progress, setProgress] = React.useState(0);
const [isOpen, setIsOpen] = React.useState(true);
const intervalRef = React.useRef | null>(null);
React.useEffect(() => {
if (!isOpen) return;
const startTime = Date.now();
const endTime = startTime + duration;
if (intervalRef.current) clearInterval(intervalRef.current);
setProgress(0);
intervalRef.current = setInterval(() => {
const now = Date.now();
const timeLeft = Math.max(0, endTime - now);
const newProgress = 100 - (timeLeft / duration) * 100;
setProgress(newProgress);
if (newProgress >= 100) {
clearInterval(intervalRef.current!);
setTimeout(() => {
setIsOpen(false);
onClose?.();
}, 100);
}
}, 10);
return () => {
if (intervalRef.current) clearInterval(intervalRef.current);
};
}, [isOpen, duration, onClose]);
if (!isOpen) return null;
return (
{props.children}
{/* Bottom Progress Bar */}
{/* Close Button */}
{
setIsOpen(false);
onClose?.();
}} />
);
}
);
Toast.displayName = "Toast";
const ToastClose = React.forwardRef<
HTMLButtonElement,
React.ButtonHTMLAttributes
>(({ className, ...props }, ref) => (
));
ToastClose.displayName = "ToastClose";
const ToastTitle = React.forwardRef<
HTMLHeadingElement,
React.HTMLAttributes
>(({ className, ...props }, ref) => (
));
ToastTitle.displayName = "ToastTitle";
const ToastDescription = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes
>(({ className, ...props }, ref) => (
));
ToastDescription.displayName = "ToastDescription";
export {
ToastProvider,
ToastViewport,
Toast,
ToastTitle,
ToastDescription,
ToastClose,
};