mirror of
http://88.130.71.182:3000/BlitTech/contexta_mb.git
synced 2026-06-12 23:23:22 +00:00
Initial commit
This commit is contained in:
97
src/contexts/ToastContext.tsx
Normal file
97
src/contexts/ToastContext.tsx
Normal file
@@ -0,0 +1,97 @@
|
||||
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<ToastContextType>({
|
||||
success: () => {},
|
||||
error: () => {},
|
||||
info: () => {},
|
||||
});
|
||||
|
||||
export function ToastProvider({ children }: { children: React.ReactNode }) {
|
||||
const [toasts, setToasts] = useState<Toast[]>([]);
|
||||
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 (
|
||||
<ToastContext.Provider value={{ success, error, info }}>
|
||||
{children}
|
||||
<View style={styles.container} pointerEvents="none">
|
||||
{toasts.map(toast => (
|
||||
<ToastItem key={toast.id} toast={toast} />
|
||||
))}
|
||||
</View>
|
||||
</ToastContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
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 (
|
||||
<Animated.View style={[styles.toast, { backgroundColor: bg, opacity }]}>
|
||||
<Text style={styles.toastText}>{toast.message}</Text>
|
||||
</Animated.View>
|
||||
);
|
||||
}
|
||||
|
||||
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);
|
||||
Reference in New Issue
Block a user