import React, { createContext, useContext, useState, useCallback, useRef } from 'react'; import { View, Text, StyleSheet, Animated } from 'react-native'; import { COLORS, RADIUS, SPACING, FONT_SIZE } from '../theme'; type ToastType = 'success' | 'error' | 'info'; interface Toast { id: number; message: string; type: ToastType; } interface ToastContextType { success: (message: string) => void; error: (message: string) => void; info: (message: string) => void; } const ToastContext = createContext({ success: () => {}, error: () => {}, info: () => {}, }); export function ToastProvider({ children }: { children: React.ReactNode }) { const [toasts, setToasts] = useState([]); const counter = useRef(0); const show = useCallback((message: string, type: ToastType) => { const id = counter.current++; setToasts(prev => [...prev, { id, message, type }]); setTimeout(() => { setToasts(prev => prev.filter(t => t.id !== id)); }, 3500); }, []); const success = useCallback((msg: string) => show(msg, 'success'), [show]); const error = useCallback((msg: string) => show(msg, 'error'), [show]); const info = useCallback((msg: string) => show(msg, 'info'), [show]); return ( {children} {toasts.map(toast => ( ))} ); } function ToastItem({ toast }: { toast: Toast }) { const opacity = useRef(new Animated.Value(0)).current; React.useEffect(() => { Animated.sequence([ Animated.timing(opacity, { toValue: 1, duration: 250, useNativeDriver: true }), Animated.delay(2800), Animated.timing(opacity, { toValue: 0, duration: 300, useNativeDriver: true }), ]).start(); }, [opacity]); const bg = toast.type === 'success' ? COLORS.success : toast.type === 'error' ? COLORS.error : COLORS.info; return ( {toast.message} ); } const styles = StyleSheet.create({ container: { position: 'absolute', bottom: 90, left: SPACING.lg, right: SPACING.lg, zIndex: 9999, gap: SPACING.sm, }, toast: { borderRadius: RADIUS.md, paddingVertical: SPACING.md, paddingHorizontal: SPACING.lg, }, toastText: { color: '#fff', fontSize: FONT_SIZE.md, fontWeight: '500', }, }); export const useToast = () => useContext(ToastContext);