ErrorNotification.tsx 4,73 ko
Newer Older
import React, { useEffect, useRef } from 'react';
import {
    View,
    Text,
    StyleSheet,
    Animated,
    TouchableOpacity,
    Platform,
} from 'react-native';

import { SafeAreaView } from "react-native-safe-area-context";

interface ErrorNotificationProps {
    message: string | null;
    onClose: () => void;
    type?: 'error' | 'success';
}

const ErrorNotification: React.FC<ErrorNotificationProps> = ({ message, onClose, type = 'error' }) => {
    const translateY = useRef(new Animated.Value(-100)).current;
    const opacity = useRef(new Animated.Value(0)).current;

    useEffect(() => {
        if (message) {
            Animated.parallel([
                Animated.spring(translateY, {
                    toValue: 0,
                    useNativeDriver: true,
                    friction: 6,
                    tension: 50
                }),
                Animated.timing(opacity, {
                    toValue: 1,
                    duration: 200,
                    useNativeDriver: true,
                }),
            ]).start();

            const timer = setTimeout(() => {
                handleClose();
            }, 4000);

            return () => clearTimeout(timer);
        } else {
            translateY.setValue(-100);
            opacity.setValue(0);
        }
    }, [message]);

    const handleClose = () => {
        Animated.parallel([
            Animated.timing(translateY, {
                toValue: -100,
                duration: 300,
                useNativeDriver: true,
            }),
            Animated.timing(opacity, {
                toValue: 0,
                duration: 200,
                useNativeDriver: true,
            }),
        ]).start(() => {
            onClose();
        });
    };

    if (!message) return null;

    const isError = type === 'error';
    const backgroundColor = isError ? '#FEF2F2' : '#F0FDF4';
    const borderColor = isError ? '#EF4444' : '#22C55E';
    const textColor = isError ? '#991B1B' : '#166534';
    const icon = isError ? '⚠️' : '🎉';

    return (
        <SafeAreaView style={styles.safeArea}>
            <Animated.View
                style={[
                    styles.toastContainer,
                    {
                        transform: [{ translateY }],
                        opacity: opacity
                    }
                ]}
            >
                <View style={[styles.card, { backgroundColor, borderLeftColor: borderColor }]}>
                    <View style={styles.contentRow}>
                        <Text style={styles.icon}>{icon}</Text>
                        <View style={styles.textWrapper}>
                            <Text style={[styles.title, { color: borderColor }]}>
                                {isError ? 'Erreur' : 'Succès'}
                            </Text>
                            <Text style={[styles.message, { color: textColor }]}>
                                {message}
                            </Text>
                        </View>
                    </View>

                    <TouchableOpacity onPress={handleClose} style={styles.closeButton} hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}>
                        <Text style={[styles.closeText, { color: textColor }]}></Text>
                    </TouchableOpacity>
                </View>
            </Animated.View>
        </SafeAreaView>
    );
};

const styles = StyleSheet.create({
    safeArea: {
        position: 'absolute',
        top: 0,
        left: 0,
        right: 0,
        zIndex: 9999,
        alignItems: 'center',
    },
    toastContainer: {
        width: '90%',
        maxWidth: 400,
        marginTop: Platform.OS === 'android' ? 40 : 10,
    },
    card: {
        flexDirection: 'row',
        alignItems: 'center',
        justifyContent: 'space-between',
        padding: 16,
        borderRadius: 12,
        borderLeftWidth: 5,
        backgroundColor: 'white',

        shadowColor: "#000",
        shadowOffset: {
            width: 0,
            height: 4,
        },
        shadowOpacity: 0.15,
        shadowRadius: 12,
        elevation: 8,
    },
    contentRow: {
        flexDirection: 'row',
        alignItems: 'center',
        flex: 1,
    },
    icon: {
        fontSize: 24,
        marginRight: 12,
    },
    textWrapper: {
        flex: 1,
        justifyContent: 'center',
    },
    title: {
        fontWeight: 'bold',
        fontSize: 14,
        marginBottom: 2,
        textTransform: 'uppercase',
        letterSpacing: 0.5,
    },
    message: {
        fontSize: 14,
        fontWeight: '500',
        lineHeight: 18,
    },
    closeButton: {
        paddingLeft: 12,
    },
    closeText: {
        fontSize: 16,
        fontWeight: 'bold',
        opacity: 0.6,
    }
});

export default ErrorNotification;