/* ============================================================
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 (
{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.")} {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.")}
{L(<>The right part,
first time>, <>La bonne pièce,
du premier coup>)}.{L("What are you fixing today?", "Que r\u00e9parez-vous aujourd\u2019hui ?")}
{L(<>Parts you can stake
a job on.>, <>Des pièces sur lesquelles
compter.>)}{p.name}