/* ============================================================ AfricaSpares — Parts & Engines service page ============================================================ */ const SPARES_CATS = [ { k: "engine", label: { en: "Engine", fr: "Moteur" }, icon: "gear", count: 2840 }, { k: "trans", label: { en: "Transmission", fr: "Transmission" }, icon: "gauge", count: 1120 }, { k: "brakes", label: { en: "Brakes", fr: "Freinage" }, icon: "shield", count: 1680 }, { k: "electrical", label: { en: "Electrical", fr: "\u00c9lectricit\u00e9" }, icon: "bolt", count: 2210 }, { k: "suspension", label: { en: "Suspension", fr: "Suspension" }, icon: "truck", count: 940 }, { k: "filters", label: { en: "Filters & Fluids", fr: "Filtres & Fluides" }, icon: "box", count: 3050 }, { k: "body", label: { en: "Body & Trim", fr: "Carrosserie" }, icon: "car", count: 760 }, { k: "cooling", label: { en: "Cooling", fr: "Refroidissement" }, icon: "leaf", count: 880 }, ]; /* Parts now load live from Supabase (see gg-supabase.js). window.GG_DATA.parts is filled before React mounts. */ const PARTS = (window.GG_DATA && window.GG_DATA.parts) || []; /* Part → Unsplash image by category */ const PART_PHOTOS = { engine: "1486262715619-67b85e0b08d3", trans: "1493397234905-8c698b6a7f66", brakes: "1492144534655-ae79c964c9d7", electrical: "1558618666-fcd25c85cd64", suspension: "1558618047-f8a0efc64a41", filters: "1511919884226-fd3ccc8e827f", cooling: "1563213126-2f10d8629b78", body: "1578662996442-48f60103fc96", }; /* Exact part image map — one image per product name */ /* Image map merges local fallback files with live Supabase paths. We use a Proxy so lookups always check the latest GG_DATA, even though this constant is defined before the data finishes loading. */ const PARTS_IMGS_LOCAL = { "Turbocharger Assembly": "assets/parts/turbocharger.png", "Complete Clutch Kit": "assets/parts/clutch-kit.png", "Front Brake Disc (pair)": "assets/parts/brake-disc-pair.png", "Alternator 120A": "assets/parts/alternator-120a.png", "Shock Absorber Set": "assets/parts/shock-absorber.png", "Oil + Air + Fuel Filter Kit": "assets/parts/filter-kit.png", "Radiator Assembly": "assets/parts/radiator.png", "Headlamp Unit (LH)": "assets/parts/headlamp.png", "Timing Chain Kit": "assets/parts/timing-chain.png", "Water Pump": "assets/parts/water-pump.png", "Glow Plug Set (4)": "assets/parts/glow-plugs.png", "Leaf Spring (rear)": "assets/parts/leaf-spring.png", "Battery 100Ah": "assets/parts/battery-100ah.png", "Front Brake Pad Set": "assets/parts/brake-pads.png", "A/C Compressor": "assets/parts/ac-compressor.png", "Fuel Injector": "assets/parts/fuel-injector.png", "Wiper Blade Set": "assets/parts/wiper-blades.png", }; const PARTS_IMGS = new Proxy(PARTS_IMGS_LOCAL, { get(local, key) { const live = (window.GG_DATA && window.GG_DATA.partImgs) || {}; return live[key] || local[key]; }, }); const PROD_BG = { width: "100%", height: "100%", background: "var(--paper-0)", display: "flex", alignItems: "center", justifyContent: "center" }; const PROD_IMG = { width: "100%", height: "100%", objectFit: "contain", mixBlendMode: "multiply" }; function AfricaSpares() { const [cat, setCat] = useState("all"); const [make, setMake] = useState(""); const [query, setQuery] = useState(""); const [sugOpen, setSugOpen] = useState(false); const sugRef = useRef(null); useEffect(() => { const h = (e) => { if (sugRef.current && !sugRef.current.contains(e.target)) setSugOpen(false); }; document.addEventListener("mousedown", h); return () => document.removeEventListener("mousedown", h); }, []); const goCatalog = () => { const el = document.getElementById("sec-catalog"); if (el) window.scrollTo({ top: el.getBoundingClientRect().top + window.scrollY - 70, behavior: "smooth" }); }; // keyword search: split into tokens, every token must match name / fitment / SKU / tag / category label const catLabel = (c) => { const f = SPARES_CATS.find((x) => x.k === c); return f ? f.label.en + " " + f.label.fr : ""; }; const tokens = query.trim().toLowerCase().split(/\s+/).filter(Boolean); const filtered = PARTS.filter((p) => { if (cat !== "all" && p.cat !== cat) return false; if (make && !p.fit.toLowerCase().includes(make.toLowerCase())) return false; if (tokens.length === 0) return true; const hay = (p.name + " " + p.fit + " " + p.sku + " " + p.tag + " " + catLabel(p.cat)).toLowerCase(); return tokens.every((t) => hay.includes(t)); }); // live suggestions for the search box const ql = query.trim().toLowerCase(); const suggest = ql.length >= 1 ? PARTS.filter((p) => (p.name + " " + p.fit + " " + p.sku + " " + catLabel(p.cat)).toLowerCase().includes(ql)).slice(0, 6) : []; return (
} style={{ position: "absolute", inset: 0 }} />
Guero’s Group AfricaSpares
{L("AfricaSpares · A Guero\u2019s Group service", "AfricaSpares · Un service du Guero\u2019s Group")}

{L(<>The right part,
first time, <>La bonne pièce,
du premier coup)}.

{L("Search genuine and quality aftermarket parts by vehicle or part number. Order online with secure payment, delivered across Niger.", "Cherchez des pi\u00e8ces d\u2019origine et adaptables de qualit\u00e9 par v\u00e9hicule ou par r\u00e9f\u00e9rence. Commandez en ligne avec paiement s\u00e9curis\u00e9, livr\u00e9 dans tout le Niger.")}

{/* search bar */}
{ setQuery(e.target.value); setSugOpen(true); }} onFocus={() => setSugOpen(true)} onKeyDown={(e) => { if (e.key === "Enter") { setSugOpen(false); goCatalog(); } else if (e.key === "Escape") setSugOpen(false); }} placeholder={L("e.g. brake disc, turbo, ENG-TBO-2840", "ex. disque de frein, turbo, ENG-TBO-2840")} style={inpStyle} autoComplete="off" /> {sugOpen && suggest.length > 0 && (
{suggest.map((p) => ( ))}
)}
{[L("Genuine OEM available", "Pi\u00e8ces d\u2019origine"), L("Warranty on every order", "Garantie sur chaque commande"), L("Delivery across Niger", "Livraison dans tout le Niger")].map((t) => ( {t} ))}
{/* CATEGORIES */}
{L("Browse by category", "Parcourir par cat\u00e9gorie")}

{L("What are you fixing today?", "Que r\u00e9parez-vous aujourd\u2019hui ?")}

{SPARES_CATS.map((c, i) => { const active = cat === c.k; return ( ); })}
{/* CATALOG RESULTS */}
{filtered.length} {L(filtered.length !== 1 ? "results" : "result", filtered.length !== 1 ? "r\u00e9sultats" : "r\u00e9sultat")}{cat !== "all" && <> · {L(SPARES_CATS.find((c) => c.k === cat)?.label.en, SPARES_CATS.find((c) => c.k === cat)?.label.fr)}}
{(cat !== "all" || query) && }
{filtered.length === 0 ? (
{L("No parts match — try a different search or clear the filters.", "Aucune pi\u00e8ce trouv\u00e9e — essayez une autre recherche ou effacez les filtres.")}
) : (
{filtered.map((p, i) => )}
)}
{/* WHY */}
{L("Why AfricaSpares", "Pourquoi AfricaSpares")}

{L(<>Parts you can stake
a job on., <>Des pièces sur lesquelles
compter.)}

{L("Garages and fleet managers come back because the part fits, arrives on time, and is covered if it doesn't.", "Garages et gestionnaires de flotte reviennent : la pi\u00e8ce est conforme, arrive \u00e0 temps, et reste garantie si besoin.")}

{[ ["shield", { en: "Warranty-backed", fr: "Sous garantie" }, { en: "Every part carries a fitment and quality guarantee. Wrong fit? We make it right.", fr: "Chaque pi\u00e8ce est garantie en conformit\u00e9 et qualit\u00e9. Mauvais montage ? On corrige." }], ["box", { en: "Traceable sourcing", fr: "Appro tra\u00e7able" }, { en: "OEM and vetted aftermarket only — each part logged from supplier to shelf.", fr: "Origine et adaptable v\u00e9rifi\u00e9 uniquement — chaque pi\u00e8ce suivie du fournisseur au rayon." }], ["truck", { en: "Fast delivery", fr: "Livraison rapide" }, { en: "Dispatched quickly across Niger, with free local delivery within 25km.", fr: "Exp\u00e9di\u00e9 rapidement dans tout le Niger, livraison locale gratuite sous 25 km." }], ["users", { en: "Technical support", fr: "Support technique" }, { en: "Not sure of the part? Send your VIN or plate and our team confirms fitment.", fr: "Un doute sur la pi\u00e8ce ? Envoyez votre VIN ou plaque, notre \u00e9quipe confirme." }], ].map(([ic, h, d], i) => (
{L(h.en, h.fr)}
{L(d.en, d.fr)}
))}