/**
* @file ProductsCard.js
* @description Écran de détail d'un produit.
* Affiche l'image, le nom, la description et le prix du produit sélectionné.
* Gère l'affichage du prix barré en cas de promotion et permet l'ajout au panier
* avec un retour visuel temporaire sur le bouton.
*/
import React, { useState } from 'react';
import { usePanier } from './store';
import ProtectedRoute from "../components/ProtectedRoute";
import { View, Text, Image, ScrollView, StyleSheet, TouchableOpacity } from 'react-native';
import { useRoute } from '@react-navigation/native';
import { GlobalStyles } from '../styles/GlobalStyles';
import defaultImage from '../assets/other.jpg';
import { EXPO_PUBLIC_API_URL } from "../config";
/**
* Écran de fiche produit détaillée.
* Reçoit les données du produit via les paramètres de route React Navigation.
*
* @component
* @returns {React.JSX.Element} La fiche produit avec image, prix, description et bouton d'ajout au panier.
*/
const ProductsCard = () => {
const route = useRoute();
const product = route.params;
const { ajouterAuPanier } = usePanier();
/** @type {[boolean, Function]} Indicateur d'état du bouton après un ajout au panier (feedback visuel 2s). */
const [isAdded, setIsAdded] = useState(false);
/**
* Prix normal HT du produit (prix unitaire ou prix initial selon la source de données).
* @type {number}
*/
const prixNormal = Number(product.prix_unitaire_HT || product.prix_initiale || 0);
/**
* Nouveau prix en cas de promotion (0 si aucune promotion).
* @type {number}
*/
const nouveauPrix = Number(product.nouveau_prix || 0);
/**
* Indique si le produit est actuellement en promotion.
* @type {boolean}
*/
const hasPromotion = (prixNormal > 0 && nouveauPrix > 0) && (prixNormal > nouveauPrix);
/**
* Prix effectivement affiché : le nouveau prix si promotion, sinon le prix normal.
* @type {number}
*/
const prixAffiche = hasPromotion ? nouveauPrix : prixNormal;
/**
* Formate un prix numérique en chaîne avec deux décimales et virgule.
* Retourne 'N/D' si la valeur n'est pas un nombre valide.
*
* @param {number} price - Le prix à formater.
* @returns {string} Le prix formaté (ex. : "12,99") ou "N/D".
*/
const formatPrice = (price) => {
if (isNaN(price)) return 'N/D';
return price.toFixed(2).replace('.', ',');
};
/**
* Ajoute le produit courant au panier et déclenche le feedback visuel du bouton.
* Le bouton est désactivé pendant 2 secondes pour éviter les doublons.
*/
const handlePress = () => {
ajouterAuPanier({
id: product.reference,
designation: product.designation,
prix: prixAffiche,
imageUrl: product.imageUrl
});
setIsAdded(true);
setTimeout(() => {
setIsAdded(false);
}, 2000);
};
return (
<ScrollView style={styles.cardScreen}>
<View style={styles.cardContainer}>
<Image
source={{ uri: product.imageUrl ? `${EXPO_PUBLIC_API_URL}/images/produits/${product.imageUrl}` : defaultImage }}
style={styles.productDetailImage}
/>
<Text style={styles.productDetailName}>{product.designation}</Text>
<View style={styles.priceContainer}>
{hasPromotion && (
<Text style={styles.oldPrice}>{formatPrice(prixNormal)} €</Text>
)}
<Text style={[styles.productDetailPrice, hasPromotion && styles.promoPriceText]}>
{formatPrice(prixAffiche)} €
</Text>
</View>
<Text style={styles.productDetailDescription}>{product.commentaire}</Text>
{/* Bouton dynamique : change de couleur et de texte après ajout au panier */}
<TouchableOpacity
style={[
styles.btnAjouter,
isAdded && { backgroundColor: '#28a745' }
]}
onPress={handlePress}
disabled={isAdded}
>
<ProtectedRoute>
<Text style={styles.btnAjouterText}>
{isAdded ? "Article ajouté ✅" : "Ajouter au panier"}
</Text>
</ProtectedRoute>
</TouchableOpacity>
</View>
</ScrollView>
);
};
/**
* Styles locaux de l'écran ProductsCard.
* @type {import('react-native').StyleSheet.NamedStyles<any>}
*/
const styles = StyleSheet.create({
cardScreen: { flex: 1, backgroundColor: '#f0f2f5' },
cardContainer: {
backgroundColor: '#ffffff',
margin: 15,
borderRadius: 12,
padding: 20,
alignItems: 'center',
elevation: 5,
},
productDetailImage: { width: '100%', height: 250, resizeMode: 'contain', marginBottom: 20 },
productDetailName: { fontSize: 24, fontWeight: 'bold', color: '#333', marginBottom: 10, textAlign: 'center' },
productDetailPrice: { fontSize: 28, fontWeight: 'bold', color: '#1e3c72', marginBottom: 20 },
productDetailDescription: { fontSize: 16, color: '#555', lineHeight: 24, marginBottom: 20 },
oldPrice: { fontSize: 14, color: '#6c757d', textDecorationLine: 'line-through', marginRight: 8 },
priceContainer: { flexDirection: 'row', justifyContent: 'center', alignItems: 'baseline', marginBottom: 20 },
btnAjouter: {
backgroundColor: '#1e3c72',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
paddingVertical: 15,
paddingHorizontal: 25,
borderRadius: 30,
width: '100%',
elevation: 4,
},
btnAjouterText: {
color: '#ffffff',
fontSize: 16,
fontWeight: 'bold',
textTransform: 'uppercase',
letterSpacing: 1,
},
promoPriceText: { color: '#d9534f' }
});
export default ProductsCard;