import React, { useState } from "react"; import { View, Text, TouchableOpacity, Image, StyleSheet, Dimensions, Modal, Pressable, ScrollView, } from "react-native"; function getTextColor(hex: string): string { const h = hex.replace("#", ""); const full = h.length === 3 ? h.split("").map((c) => c + c).join("") : h; const r = parseInt(full.slice(0, 2), 16); const g = parseInt(full.slice(2, 4), 16); const b = parseInt(full.slice(4, 6), 16); return (r * 299 + g * 587 + b * 114) / 1000 > 128 ? "#000000" : "#ffffff"; } import { Ionicons } from "@expo/vector-icons"; import { Video, ResizeMode } from "expo-av"; import { spacing, borderRadius, fontSize, fontWeight } from "../theme"; import { useTheme } from "../context/ThemeContext"; import { API_BASE_URL } from "../api/client"; import { useCart } from "../context/CartContext"; const { width: SCREEN_WIDTH } = Dimensions.get("window"); const CARD_WIDTH = SCREEN_WIDTH - 48; interface ProductCardProps { product: { id: number; name: string; category: string; stock: number; unit?: string; prices?: Array<{ quantity: number; price: number }>; media?: Array<{ url: string; type: string }>; }; onPress: () => void; categoryColor?: string; } export default function ProductCard({ product, onPress, categoryColor }: ProductCardProps) { const { colors } = useTheme(); const { addToCart } = useCart(); const catColor = categoryColor ?? colors.accent; const isSoldOut = product.stock <= 0; const firstPrice = product.prices?.[0]?.price ?? null; const imageMedia = product.media?.find((m) => m.type === "image"); const videoMedia = product.media?.find((m) => m.type === "video"); const imageUri = imageMedia ? `${API_BASE_URL}${imageMedia.url}` : null; const videoUri = videoMedia ? `${API_BASE_URL}${videoMedia.url}` : null; const [showQuantitySelect, setShowQuantitySelect] = useState(false); const [showSuccess, setShowSuccess] = useState(false); const [showVideo, setShowVideo] = useState(false); const handleQuickAdd = () => { if (!isSoldOut && product.prices && product.prices.length > 0) { setShowQuantitySelect(!showQuantitySelect); } }; const handleSelectQuantity = (priceOption: { quantity: number; price: number; }) => { addToCart({ product_id: product.id, name_product: product.name, category: (product.category || "autre").toLowerCase().trim(), quantity: priceOption.quantity, price: priceOption.price, }); setShowSuccess(true); setShowQuantitySelect(false); setTimeout(() => setShowSuccess(false), 1500); }; return ( {imageUri ? ( ) : ( )} {videoUri && !isSoldOut && ( setShowVideo(true)} activeOpacity={0.7} > )} Details {isSoldOut && ( SOLD OUT )} {product.name} {firstPrice !== null ? `${firstPrice.toFixed(2)} €` : "Prix non disponible"} {showSuccess ? ( Ajoute ! ) : ( {isSoldOut ? "Rupture de stock" : "Ajouter rapidement"} )} setShowQuantitySelect(false)} > setShowQuantitySelect(false)} > Choisir une quantite {product.prices?.map((p) => ( handleSelectQuantity(p)} activeOpacity={0.6} > {p.quantity}{product.unit || "g"} {p.price.toFixed(2)} € ))} setShowQuantitySelect(false)} > Fermer setShowVideo(false)} > setShowVideo(false)} > setShowVideo(false)} > {videoUri && ( ); } const styles = StyleSheet.create({ card: { borderRadius: 15, borderWidth: 2, overflow: "hidden", width: CARD_WIDTH, shadowOffset: { width: 0, height: 0 }, shadowOpacity: 0.6, shadowRadius: 20, elevation: 8, }, soldOut: { opacity: 0.75 }, imageContainer: { width: "100%", aspectRatio: 1, position: "relative", overflow: "hidden", }, image: { width: "100%", height: "100%" }, imagePlaceholder: { width: "100%", height: "100%", justifyContent: "center", alignItems: "center", }, videoBtn: { position: "absolute", top: 12, right: 12, width: 40, height: 40, borderRadius: 20, justifyContent: "center", alignItems: "center", borderWidth: 2, borderColor: "rgba(255,255,255,0.3)", }, detailsBtn: { position: "absolute", bottom: 12, alignSelf: "center", flexDirection: "row", alignItems: "center", gap: 6, backgroundColor: "rgba(0,0,0,0.85)", borderRadius: 25, paddingHorizontal: 20, paddingVertical: 8, borderWidth: 2, borderColor: "rgba(255,255,255,0.3)", }, detailsBtnText: { fontSize: 14, fontWeight: fontWeight.semibold, letterSpacing: 0.5, }, soldOutOverlay: { position: "absolute", top: "50%", left: "50%", transform: [ { translateX: -80 }, { translateY: -25 }, { rotate: "-15deg" }, ], backgroundColor: "rgba(0,0,0,0.8)", borderWidth: 4, borderColor: "rgba(255,0,0,0.95)", paddingHorizontal: 30, paddingVertical: 12, }, soldOutText: { color: "rgba(255,0,0,0.95)", fontSize: 28, fontWeight: "900", letterSpacing: 3, textTransform: "uppercase", textShadowColor: "rgba(0,0,0,0.9)", textShadowOffset: { width: 2, height: 2 }, textShadowRadius: 6, }, info: { padding: spacing.m, borderTopWidth: 1 }, name: { fontSize: fontSize.lg, fontWeight: fontWeight.semibold, textAlign: "center", marginBottom: spacing.xs, }, price: { fontSize: fontSize.xl, fontWeight: fontWeight.bold, textAlign: "center", }, quickAddSection: { padding: spacing.m, borderTopWidth: 1 }, quickAddBtn: { width: "100%", paddingVertical: 12, paddingHorizontal: 16, borderRadius: 8, alignItems: "center", }, quickAddBtnText: { fontSize: fontSize.md, fontWeight: "700", textTransform: "uppercase", letterSpacing: 0.5, }, successBanner: { width: "100%", paddingVertical: 12, borderRadius: 8, alignItems: "center", }, successText: { fontSize: fontSize.md, fontWeight: "700" }, pickerOverlay: { flex: 1, backgroundColor: "rgba(0,0,0,0.7)", justifyContent: "flex-end", }, pickerSheet: { borderTopLeftRadius: 20, borderTopRightRadius: 20, paddingHorizontal: 24, paddingBottom: 40, maxHeight: "70%", }, pickerHandle: { width: 40, height: 4, borderRadius: 2, alignSelf: "center", marginTop: 12, marginBottom: 16, }, pickerTitle: { fontSize: fontSize.lg, fontWeight: fontWeight.bold, textAlign: "center", marginBottom: 16, }, pickerScroll: { maxHeight: 350 }, pickerOption: { flexDirection: "row", justifyContent: "space-between", alignItems: "center", borderRadius: 12, borderWidth: 1, paddingVertical: 16, paddingHorizontal: 20, marginBottom: 10, }, pickerOptionLeft: { gap: 2 }, pickerOptionQty: { fontSize: fontSize.lg, fontWeight: fontWeight.bold }, pickerOptionPrice: { fontSize: fontSize.md, fontWeight: fontWeight.semibold, }, pickerCloseBtn: { marginTop: 12, borderRadius: 10, paddingVertical: 14, alignItems: "center", }, pickerCloseBtnText: { fontSize: fontSize.md, fontWeight: fontWeight.semibold, }, videoModalOverlay: { flex: 1, backgroundColor: "rgba(0,0,0,0.92)", justifyContent: "center", alignItems: "center", }, videoModalContent: { width: SCREEN_WIDTH - 10, backgroundColor: "#000", borderRadius: 12, overflow: "hidden", position: "relative", }, videoCloseBtn: { position: "absolute", top: 10, right: 10, width: 36, height: 36, borderRadius: 18, backgroundColor: "rgba(239,68,68,0.85)", justifyContent: "center", alignItems: "center", zIndex: 10, }, videoPlayer: { width: "100%", height: Math.round((SCREEN_WIDTH - 10) * 9 / 16), }, });