/* ============================================================ AfricaSpares — Cart Context (shared state) Used by: PartCard → CartPanel → CheckoutModal ============================================================ */ const CartCtx = React.createContext({ cart: [], addItem: () => {}, removeItem: () => {}, updateQty: () => {}, clearCart: () => {} }); const useCart = () => React.useContext(CartCtx); function CartProvider({ children }) { const [cart, setCart] = React.useState(() => { try { const s = localStorage.getItem("gg_as_cart"); return s ? JSON.parse(s) : []; } catch { return []; } }); const save = (items) => { setCart(items); try { localStorage.setItem("gg_as_cart", JSON.stringify(items)); } catch {} }; const addItem = (part) => { setCart(prev => { const exists = prev.find(i => i.sku === part.sku); const next = exists ? prev.map(i => i.sku === part.sku ? { ...i, qty: i.qty + 1 } : i) : [...prev, { ...part, qty: 1 }]; try { localStorage.setItem("gg_as_cart", JSON.stringify(next)); } catch {} return next; }); }; const removeItem = (sku) => save(cart.filter(i => i.sku !== sku)); const updateQty = (sku, qty) => { if (qty < 1) { removeItem(sku); return; } save(cart.map(i => i.sku === sku ? { ...i, qty } : i)); }; const clearCart = () => save([]); const total = cart.reduce((s, i) => s + i.price * i.qty, 0); return ( {children} ); } /* ─── Cart icon button (used in page header) ─────────────── */ function CartButton({ onClick }) { const { cart } = useCart(); const count = cart.reduce((s, i) => s + i.qty, 0); return ( ); } /* ─── Cart slide-in panel ────────────────────────────────── */ function CartPanel({ open, onClose, onCheckout }) { const { cart, removeItem, updateQty, total } = useCart(); if (!open) return null; return (
e.stopPropagation()} style={{ width: "min(480px,100vw)", background: "var(--paper)", display: "flex", flexDirection: "column", height: "100%" }}> {/* Header */}
{L("Your Cart", "Votre Panier")} ({cart.reduce((s,i)=>s+i.qty,0)} {L("items","articles")})
{/* Items */}
{cart.length === 0 ? (

{L("Your cart is empty", "Votre panier est vide")}

{L("Add parts from the catalogue", "Ajoutez des pièces depuis le catalogue")}

) : ( cart.map(item => (
{/* Image */}
{item.img ? {item.name} : }
{item.name}
{item.sku} · {item.fit}
{/* Qty */}
{item.qty}
{(item.price * item.qty).toLocaleString("fr-FR")} XOF
)) )}
{/* Footer */} {cart.length > 0 && (
{L("Subtotal", "Sous-total")} {total.toLocaleString("fr-FR")} XOF

{L("Shipping and taxes calculated at checkout", "Livraison et taxes calculées à la commande")}

)}
); } /* ─── Checkout modal ─────────────────────────────────────── */ const PAYMENT_METHODS = [ { id: "card", label: L("Bank card", "Carte bancaire"), icon: "💳", color: "#1A1F71", sub: "Visa · Mastercard · GIM-UEMOA", full: true }, { id: "orange_money", label: "Orange Money", icon: "📱", color: "#FF7900", sub: "+227 XX XX XX XX" }, { id: "airtel_money", label: "Airtel Money", icon: "📱", color: "#E40000", sub: "+227 XX XX XX XX" }, { id: "bank", label: L("Bank Transfer", "Virement bancaire"), icon: "🏦", color: "#1F4E79", sub: "BSIC / Ecobank / BIA" }, { id: "cash", label: L("Cash on delivery", "Paiement à la livraison"), icon: "💵", color: "#2D6A4F", sub: L("Niamey only", "Niamey uniquement") }, ]; function CheckoutModal({ open, onClose }) { const { cart, total, clearCart } = useCart(); const [step, setStep] = React.useState(1); // 1=info, 2=payment, 3=confirm const [method, setMethod] = React.useState("card"); const [card, setCard] = React.useState({ number: "", name: "", exp: "", cvv: "" }); const [form, setForm] = React.useState({ name: "", phone: "", email: "", address: "", notes: "" }); const [placed, setPlaced] = React.useState(false); const [orderId, setOrderId] = React.useState(""); const set = (k, v) => setForm(f => ({ ...f, [k]: v })); const fInp = { width: "100%", border: "1px solid var(--line)", borderRadius: 3, padding: "9px 12px", fontSize: 14.5, background: "var(--paper-0)", outline: "none", fontFamily: "inherit", color: "var(--ink)", boxSizing: "border-box" }; const lbl = { display: "block", fontSize: 11.5, fontFamily: "var(--fsemi)", fontWeight: 700, textTransform: "uppercase", letterSpacing: ".1em", color: "var(--muted)", marginBottom: 5 }; const setC = (k, v) => setCard(c => ({ ...c, [k]: v })); const fmtCardNum = (v) => v.replace(/\D/g, "").slice(0, 16).replace(/(\d{4})(?=\d)/g, "$1 "); const fmtExp = (v) => { const d = v.replace(/\D/g, "").slice(0, 4); return d.length > 2 ? d.slice(0, 2) + "/" + d.slice(2) : d; }; const cardOk = method !== "card" || (card.number.replace(/\s/g, "").length >= 15 && card.name.trim() !== "" && /^\d{2}\/\d{2}$/.test(card.exp) && card.cvv.length >= 3); const placeOrder = () => { const id = "AS-" + Date.now().toString(36).toUpperCase(); setOrderId(id); setPlaced(true); clearCart(); }; if (!open) return null; if (placed) return (
{L("Order Placed!", "Commande reçue !")}
# {orderId}

{method === "card" ? L(`Payment accepted. Our team will contact you on ${form.phone} to arrange delivery.`, `Paiement accepté. Notre équipe vous contactera au ${form.phone} pour organiser la livraison.`) : L(`Our team will contact you on ${form.phone} to confirm your order and arrange delivery.`, `Notre équipe vous contactera au ${form.phone} pour confirmer votre commande et organiser la livraison.`)}

{L("A confirmation will be sent to", "Une confirmation sera envoyée à")} {form.email || L("your email", "votre email")}

); return (
e.stopPropagation()} style={{ background: "var(--paper)", borderRadius: 5, maxWidth: 680, width: "100%", boxShadow: "0 30px 80px rgba(0,0,0,.3)" }}> {/* Header */}
{L("Checkout", "Finaliser la commande")}
{[1,2,3].map(s => ( = s ? "var(--spares)" : "var(--paper-2)", color: step >= s ? "#fff" : "var(--muted)", transition: "all .2s" }}>{s} ))}
{/* Step 1 — Contact info */} {step === 1 && (
■ {L("01 / CONTACT INFORMATION", "01 / INFORMATIONS DE CONTACT")}
set("name", e.target.value)} required style={fInp} placeholder="Ibrahim Moussa" />
set("phone", e.target.value)} required style={fInp} placeholder="+227 XX XX XX XX" />
set("email", e.target.value)} style={fInp} placeholder="vous@exemple.com" />
set("address", e.target.value)} required style={fInp} placeholder={L("Niamey — Plateau, Koira Tegui…", "Niamey — Plateau, Koira Tegui…")} />