BrixCafe/app/screens/user/CartScreen.tsx
2025-04-25 17:28:14 +01:00

258 lines
7.1 KiB
TypeScript

import React, { useState, useCallback } from 'react';
import { View,Text,Alert,StyleSheet,FlatList,Platform,TouchableOpacity} from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { getAuth } from 'firebase/auth';
import {collection,addDoc,query,orderBy,limit,getDocs} from 'firebase/firestore';
import * as Haptics from 'expo-haptics';
import Animated, {useAnimatedStyle,useSharedValue,withSequence,withTiming} from 'react-native-reanimated';
import { ArrowLeft } from 'lucide-react-native';
import { useRouter } from 'expo-router';
import { useCart, CartItem as CartItemType } from '@/context/cartContext';
import { db } from '@/firebase/config';
import CartItem from '@/components/CartItem';
import COLORS from '@/constants/colors';
export default function CartScreen() {
const { cart, clearCart, updateQuantity } = useCart();
const totalAmount = cart.total;
const [isProcessingOrder, setIsProcessingOrder] = useState(false);
const auth = getAuth();
const router = useRouter();
const totalValue = useSharedValue(1);
const buttonScale = useSharedValue(1);
const totalAnimatedStyle = useAnimatedStyle(() => ({
transform: [{ scale: totalValue.value }],
}));
const handleConfirmOrder = useCallback(async () => {
if (totalAmount <= 0) {
Alert.alert('Panier vide', 'Veuillez ajouter des produits à votre panier');
return;
}
setIsProcessingOrder(true);
buttonScale.value = withSequence(
withTiming(0.95, { duration: 100 }),
withTiming(1, { duration: 150 })
);
if (Platform.OS !== 'web') {
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
}
try {
const user = auth.currentUser;
if (!user) {
Alert.alert('Utilisateur non connecté', 'Veuillez vous connecter pour passer une commande.');
return;
}
const orderRef = collection(db, 'orders');
const q = query(orderRef, orderBy('createdAt', 'desc'), limit(1));
const orderSnapshot = await getDocs(q);
let lastOrderId = 0;
if (!orderSnapshot.empty) {
const lastOrderDoc = orderSnapshot.docs[0].data();
lastOrderId = parseInt(lastOrderDoc.orderId.replace(/^0+/, '')) || 0;
}
const newOrderId = String(lastOrderId + 1).padStart(3, '0');
const orderData: any = {
orderId: newOrderId,
userId: user.uid,
status: 'En attente',
createdAt: new Date().toISOString(),
totalAmount,
};
cart.items.forEach((item, index) => {
orderData[`item${index + 1}`] = {
name: item.name,
quantity: item.quantity,
};
});
await addDoc(orderRef, orderData);
Alert.alert('Commande confirmée', `Montant Total : ${totalAmount}DT`);
clearCart();
} catch (error) {
console.error('Erreur commande :', error);
Alert.alert('Erreur', "Impossible d'enregistrer la commande.");
} finally {
setIsProcessingOrder(false);
}
}, [cart, totalAmount]);
const renderItem = useCallback(({ item }: { item: CartItemType }) => (
<CartItem
item={item}
onUpdateQuantity={(id, newQty) => {
updateQuantity(id, newQty);
totalValue.value = withSequence(
withTiming(1.05, { duration: 100 }),
withTiming(1, { duration: 100 })
);
}}
/>
), []);
const keyExtractor = useCallback((item: CartItemType) => item.id, []);
return (
<SafeAreaView style={styles.container}>
<View style={styles.header}>
<TouchableOpacity style={styles.backButton} onPress={() => router.back()}>
<ArrowLeft size={24} color="#666" />
</TouchableOpacity>
<Text style={styles.headerTitle}>Mon Panier</Text>
</View>
<View style={styles.content}>
<FlatList
data={cart.items}
renderItem={renderItem}
keyExtractor={keyExtractor}
showsVerticalScrollIndicator={false}
ListEmptyComponent={
<View style={styles.emptyContainer}>
<Text style={styles.emptyText}>Votre panier est vide</Text>
</View>
}
/>
</View>
<View style={styles.footer}>
<View style={styles.totalContainer}>
<Text style={styles.totalLabel}>Total : </Text>
<Animated.Text style={[styles.totalAmount, totalAnimatedStyle]}>
{totalAmount}DT
</Animated.Text>
</View>
<TouchableOpacity
style={styles.ConfirmButton}
onPress={() =>
Alert.alert(
'Confirmer la commande',
'Êtes-vous sûr de vouloir confirmer la commande?',
[
{ text: 'Annuler', style: 'cancel' },
{ text: 'Confirmer', style: 'destructive', onPress: handleConfirmOrder },
]
)
}
disabled={totalAmount <= 0}
>
<Text style={styles.ConfirmButtonText}>Confirmer la commande</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.clearCartButton}
onPress={() =>
Alert.alert(
'Vider le panier',
'Êtes-vous sûr de vouloir supprimer tous les articles du panier ?',
[
{ text: 'Annuler', style: 'cancel' },
{ text: 'Confirmer', style: 'destructive', onPress: clearCart },
]
)
}
disabled={cart.items.length === 0}
>
<Text style={styles.clearCartButtonText}>Vider le panier</Text>
</TouchableOpacity>
</View>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
header: {
height: 60,
justifyContent: 'center',
alignItems: 'center',
position: 'relative',
backgroundColor: '#fff',
borderBottomWidth: 1,
borderBottomColor: '#eee',
marginTop: 5,
},
backButton: {
position: 'absolute',
left: 20,
top: '50%',
transform: [{ translateY: -12 }],
},
headerTitle: {
fontSize: 20,
fontWeight: '600',
color: '#333',
},
content: {
flex: 1,
padding: 5,
},
footer: {
paddingHorizontal: 20,
paddingVertical: 10,
backgroundColor: COLORS.background_user,
borderTopWidth: 1,
borderTopColor: COLORS.secondary,
},
totalContainer: {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
marginBottom: 10,
},
totalLabel: {
fontSize: 20,
},
totalAmount: {
fontSize: 20,
color: COLORS.primary,
},
ConfirmButton: {
backgroundColor: '#B07B4F',
borderRadius: 12,
padding: 16,
alignItems: 'center',
},
ConfirmButtonText: {
color: '#fff',
fontSize: 16,
fontWeight: '600',
},
clearCartButton: {
backgroundColor: '#D9534F',
borderRadius: 12,
padding: 16,
alignItems: 'center',
marginTop: 10,
},
clearCartButtonText: {
color: '#fff',
fontSize: 16,
fontWeight: '600',
},
emptyContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
paddingVertical: 10,
},
emptyText: {
fontSize: 18,
},
});