import { createContext, useContext, useEffect, useRef, useState } from "react"; import { Animated, View } from "react-native"; import { Text } from "@/components/ui/Text"; import { cn } from "@/lib/utils"; const toastVariants = { default: "bg-foreground", destructive: "bg-destructive", success: "bg-green-500", info: "bg-blue-500", }; interface ToastProps { id: number; message: string; onHide: (id: number) => void; variant?: keyof typeof toastVariants; duration?: number; showProgress?: boolean; } function Toast({ id, message, onHide, variant = "default", duration = 3000, showProgress = true, }: ToastProps) { const opacity = useRef(new Animated.Value(0)).current; const progress = useRef(new Animated.Value(0)).current; useEffect(() => { Animated.sequence([ Animated.timing(opacity, { toValue: 1, duration: 500, useNativeDriver: true, }), Animated.timing(progress, { toValue: 1, duration: duration - 1000, useNativeDriver: false, }), Animated.timing(opacity, { toValue: 0, duration: 500, useNativeDriver: true, }), ]).start(() => onHide(id)); }, [duration]); return ( {message} {showProgress && ( )} ); } type ToastVariant = keyof typeof toastVariants; interface ToastMessage { id: number; text: string; variant: ToastVariant; duration?: number; position?: string; showProgress?: boolean; } interface ToastContextProps { toast: (t: { message: string; variant?: keyof typeof toastVariants; duration?: number; position?: "top" | "bottom"; showProgress?: boolean; }) => void; removeToast: (id: number) => void; } const ToastContext = createContext(undefined); // TODO: refactor to pass position to Toast instead of ToastProvider function ToastProvider({ children, position = "top", }: { children: React.ReactNode; position?: "top" | "bottom"; }) { const [messages, setMessages] = useState([]); const toast: ToastContextProps["toast"] = ({ message, variant = "default", duration = 3000, position = "top", showProgress = true, }: { message: string; variant?: ToastVariant; duration?: number; position?: "top" | "bottom"; showProgress?: boolean; }) => { setMessages((prev) => [ ...prev, { id: Date.now(), text: message, variant, duration, position, showProgress, }, ]); }; const removeToast = (id: number) => { setMessages((prev) => prev.filter((message) => message.id !== id)); }; return ( {children} {messages.map((message) => ( ))} ); } function useToast() { const context = useContext(ToastContext); if (!context) { throw new Error("useToast must be used within ToastProvider"); } return context; } export { ToastProvider, ToastVariant, Toast, toastVariants, useToast };