/**
* @file commandeContext.js
* @description Composant d'affichage du Panier.
* Il permet de visualiser les articles ajoutés, de modifier les quantités,
* de supprimer des articles et de consulter le récapitulatif financier (HT/TVA/TTC).
*/
import React from 'react';
import { Text, TouchableOpacity, View, ScrollView, Image, StyleSheet } from 'react-native';
import ProtectedRoute from "../components/ProtectedRoute";
import { usePanier } from './store';
import { EXPO_PUBLIC_API_URL } from "../config";
import { GlobalStyles } from '../styles/GlobalStyles';
/**
* Composant principal de l'écran Panier.
* * @component
* @param {Object} props - Propriétés du composant.
* @param {Object} props.navigation - Objet de navigation fourni par React Navigation pour la redirection vers la validation.
* @returns {React.JSX.Element} L'interface utilisateur du panier avec la liste des articles et le récapitulatif.
*/
const CommandeContext = ({ navigation }) => {
/** * Récupération des données et fonctions globales du panier depuis le Store.
* @see {@link ./store.js} pour la logique de modification/suppression.
*/
const { panier, supprimerDuPanier, modifierQuantite } = usePanier();
/** * Calcul du montant total Hors Taxes (HT).
* @type {number}
*/
const totalGeneral = panier.reduce((sum, item) => sum + (item.prix * item.quantite), 0);
/** * Calcul du montant de la TVA (basé sur un taux de 20%).
* @type {number}
*/
const tva = totalGeneral * 0.20;
return (
<ProtectedRoute>
<ScrollView style={styles.cardScreen}>
<View style={{ paddingVertical: 20 }}>
<Text style={styles.mainTitle}>
Mon Panier ({panier.length})
</Text>
{panier.length === 0 ? (
<View style={GlobalStyles.profileCard}>
<Text style={GlobalStyles.emptyText}>Votre panier est vide.</Text>
</View>
) : (
<>
{panier.map((item, index) => (
/**
* Rendu individuel de chaque article du panier.
* Clé basée sur l'index (attention : privilégier l'id en production).
*/
<View key={index} style={styles.cartCard}>
<View style={styles.cartItemContent}>
{/* Image du produit récupérée depuis le serveur distant */}
<Image
source={{ uri: `${EXPO_PUBLIC_API_URL}/images/produits/${item.imageUrl}` }}
style={styles.productImage}
/>
{/* Informations textuelles du produit */}
<View style={styles.productInfo}>
<Text style={styles.designationText} numberOfLines={1}>
{item.designation}
</Text>
<Text style={styles.unitPriceText}>{item.prix.toFixed(2)} € / unité</Text>
<Text style={styles.totalItemPrice}>
{(item.prix * item.quantite).toFixed(2)} €
</Text>
</View>
{/* Actions : Augmenter, Diminuer, Supprimer */}
<View style={styles.actionColumn}>
<View style={styles.stepper}>
{/* Diminuer la quantité (limité à 1 minimum par le store) */}
<TouchableOpacity
style={styles.stepBtn}
onPress={() => modifierQuantite(item.id, -1)}
>
<Image
source={require('../assets/bouttonDiminuer.jpg')}
style={styles.imageIcon}
/>
</TouchableOpacity>
<Text style={styles.quantityValue}>{item.quantite}</Text>
{/* Augmenter la quantité */}
<TouchableOpacity
style={styles.stepBtn}
onPress={() => modifierQuantite(item.id, 1)}
>
<Image
source={require('../assets/bouttonAjouter.jpg')}
style={styles.imageIcon}
/>
</TouchableOpacity>
</View>
{/* Suppression définitive de la ligne */}
<TouchableOpacity
onPress={() => supprimerDuPanier(item.id)}
style={styles.trashBtn}
>
<Image
source={require('../assets/poubelle.jpg')}
style={styles.imageIconTrash}
/>
</TouchableOpacity>
</View>
</View>
</View>
))}
{/* Carte récapitulative finale avant paiement/validation */}
<View style={styles.summaryCard}>
<Text style={styles.summaryTitle}>Récapitulatif</Text>
<View style={styles.summaryRow}>
<Text style={styles.summaryLabel}>Sous-total HT</Text>
<Text style={styles.summaryValue}>{totalGeneral.toFixed(2)} €</Text>
</View>
<View style={styles.summaryRow}>
<Text style={styles.summaryLabel}>TVA (20%)</Text>
<Text style={styles.summaryValue}>{tva.toFixed(2)} €</Text>
</View>
<View style={[styles.summaryRow, styles.totalRow]}>
<Text style={styles.totalLabel}>Total TTC</Text>
<Text style={styles.totalAmount}>{(totalGeneral + tva).toFixed(2)} €</Text>
</View>
/**
* Navigation vers l'écran de validation.
* @param {string} "ValidationCommande" - Nom de la route.
* @param {Object} params - Données transmises (HT et TVA).
*/
<TouchableOpacity
onPress={() => navigation.navigate('ValidationCommande', { totalHT: totalGeneral, tva: tva })}
style={styles.checkoutBtn}
>
<Text style={styles.checkoutBtnText}>Valider la commande</Text>
</TouchableOpacity>
</View>
</>
)}
</View>
</ScrollView>
</ProtectedRoute>
);
};
export default CommandeContext;
/** * Styles locaux spécifiques à la mise en page du panier et du stepper.
* @type {StyleSheet}
*/
const styles = StyleSheet.create({
cardScreen: { flex: 1, backgroundColor: '#F8F9FB' },
mainTitle: {
fontSize: 22,
fontWeight: '800',
color: '#1A1A1A',
marginHorizontal: 20,
marginBottom: 15,
},
cartCard: {
backgroundColor: '#FFF',
marginHorizontal: 20,
marginVertical: 8,
borderRadius: 16,
padding: 12,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.05,
shadowRadius: 8,
elevation: 3,
},
cartItemContent: { flexDirection: 'row', alignItems: 'center' },
productImage: { width: 85, height: 85, borderRadius: 12, backgroundColor: '#F0F0F0' },
productInfo: { flex: 1, paddingHorizontal: 15 },
designationText: { fontSize: 15, fontWeight: '700', color: '#2D3436', marginBottom: 4 },
unitPriceText: { fontSize: 13, color: '#636E72', marginBottom: 8 },
totalItemPrice: { fontSize: 17, fontWeight: '900', color: '#1E3C72' },
// Design du Stepper
actionColumn: { alignItems: 'flex-end', justifyContent: 'space-between', height: 85 },
stepper: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: '#F1F3F5',
borderRadius: 10,
padding: 4
},
stepBtn: {
width: 30,
height: 30,
justifyContent: 'center',
alignItems: 'center',
},
// Style pour tes images JPG/PNG dans les boutons
imageIcon: {
width: 24,
height: 24,
resizeMode: 'contain',
borderRadius: 4
},
imageIconTrash: {
width: 20,
height: 20,
resizeMode: 'contain',
},
quantityValue: { paddingHorizontal: 12, fontWeight: '700', fontSize: 14 },
trashBtn: {
padding: 8,
backgroundColor: '#FFF5F5',
borderRadius: 10,
borderWidth: 1,
borderColor: '#FFEBEB'
},
// Carte Récapitulatif
summaryCard: {
backgroundColor: '#FFF',
margin: 20,
padding: 20,
borderRadius: 20,
borderWidth: 1,
borderColor: '#EEE',
},
summaryTitle: { fontSize: 18, fontWeight: '800', marginBottom: 15, color: '#1A1A1A' },
summaryRow: { flexDirection: 'row', justifyContent: 'space-between', marginBottom: 10 },
summaryLabel: { color: '#636E72', fontSize: 14 },
summaryValue: { fontWeight: '600', color: '#2D3436' },
totalRow: { marginTop: 10, paddingTop: 15, borderTopWidth: 1, borderTopColor: '#EEE' },
totalLabel: { fontSize: 16, fontWeight: '800' },
totalAmount: { fontSize: 20, fontWeight: '900', color: '#1E3C72' },
checkoutBtn: {
backgroundColor: '#1E3C72',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
marginTop: 20,
paddingVertical: 16,
borderRadius: 14,
},
checkoutBtnText: { color: '#FFF', fontWeight: 'bold', fontSize: 16, textTransform: 'uppercase' }
});