import React, { createContext, useContext, useState, useCallback } from 'react'; import { Animated, Text } from 'react-native'; import { useAppTheme } from '@theme'; import { getStyles } from './toast.styles'; export type ToastType = 'success' | 'error' | 'info'; interface ToastOptions { message: string; type?: ToastType; duration?: number; } interface ToastContextType { showToast: (options: ToastOptions) => void; } const ToastContext = createContext(undefined); export const ToastProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { const { colors } = useAppTheme(); const styles = getStyles(colors); const [toast, setToast] = useState<{ message: string; type: ToastType } | null>(null); const [fadeAnim] = useState(new Animated.Value(0)); const showToast = useCallback( ({ message, type = 'info', duration = 3000 }: ToastOptions) => { setToast({ message, type }); // Animate In Animated.timing(fadeAnim, { toValue: 1, duration: 300, useNativeDriver: true, }).start(); // Dismiss after duration setTimeout(() => { Animated.timing(fadeAnim, { toValue: 0, duration: 300, useNativeDriver: true, }).start(() => setToast(null)); }, duration); }, [fadeAnim] ); const getStyleConfig = () => { if (!toast) return { bg: null, text: null }; switch (toast.type) { case 'success': return { bg: styles.successBg, text: styles.successText }; case 'error': return { bg: styles.errorBg, text: styles.errorText }; case 'info': return { bg: styles.infoBg, text: styles.infoText }; } }; const config = getStyleConfig(); return ( {children} {toast ? ( {toast.message} ) : null} ); }; export const useToast = () => { const context = useContext(ToastContext); if (!context) { throw new Error('useToast must be used within a ToastProvider'); } return context; };