/* ============================================================ Guero's Group — App router + i18n + Tweaks ============================================================ */ const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{ "groupColor": "#D8A046", "sparesColor": "#C9622E", "rentColor": "#3E84C4", "displayFont": "Saira Condensed" }/*EDITMODE-END*/; const HUB_VIEWS = ["home", "group", "services", "coverage", "contact"]; const ALL_VIEWS = [...HUB_VIEWS, "spares", "rent", "basket"]; function App() { const [t, setTweak] = useTweaks(TWEAK_DEFAULTS); const [lang, setLangState] = useState(() => { try { return localStorage.getItem("gg_lang") || "fr"; } catch (e) { return "fr"; } }); setActiveLang(lang); // ensure L() reflects current lang for THIS render (top-down) const setLang = (l) => { setActiveLang(l); try { localStorage.setItem("gg_lang", l); } catch (e) {} setLangState(l); }; useEffect(() => { document.documentElement.lang = lang; }, [lang]); const [view, setView] = useState(() => { const h = (window.location.hash || "").replace("#", ""); return ALL_VIEWS.includes(h) ? h : "home"; }); const go = (v) => { if (!ALL_VIEWS.includes(v)) v = "home"; if (v === view) { window.scrollTo({ top: 0, behavior: "smooth" }); return; } setView(v); window.location.hash = v; window.scrollTo({ top: 0, behavior: "auto" }); }; useEffect(() => { const onHash = () => { const h = (window.location.hash || "").replace("#", ""); if (ALL_VIEWS.includes(h)) setView(h); }; window.addEventListener("hashchange", onHash); return () => window.removeEventListener("hashchange", onHash); }, []); // apply tweak overrides to CSS custom properties useEffect(() => { const r = document.documentElement.style; const darken = (hex, amt = 0.16) => { const n = parseInt(hex.slice(1), 16); let R = (n >> 16) & 255, G = (n >> 8) & 255, B = n & 255; R = Math.round(R * (1 - amt)); G = Math.round(G * (1 - amt)); B = Math.round(B * (1 - amt)); return "#" + ((1 << 24) + (R << 16) + (G << 8) + B).toString(16).slice(1); }; r.setProperty("--group", t.groupColor); r.setProperty("--group-d", darken(t.groupColor)); r.setProperty("--spares", t.sparesColor); r.setProperty("--spares-d", darken(t.sparesColor)); r.setProperty("--rent", t.rentColor); r.setProperty("--rent-d", darken(t.rentColor)); r.setProperty("--fdisp", `"${t.displayFont}", "Saira Condensed", sans-serif`); }, [t]); const Page = { home: Home, group: GroupPage, services: ServicesPage, coverage: CoveragePage, contact: ContactPage, spares: AfricaSpares, rent: RentACar, basket: BasketPage }[view] || Home; return ( setLang(v)} /> setTweak("groupColor", v)} /> setTweak("sparesColor", v)} /> setTweak("rentColor", v)} /> setTweak("displayFont", v)} /> ); } /* Wait for Supabase data to load (window.GG_READY from gg-supabase.js) before mounting, so PARTS and FLEET are populated. Falls back to mounting anyway after 5s if the network is slow. */ (function mountWhenReady() { const mount = () => ReactDOM.createRoot(document.getElementById("root")).render(); if (window.GG_READY && typeof window.GG_READY.then === "function") { const timeout = new Promise((res) => setTimeout(res, 5000)); Promise.race([window.GG_READY, timeout]).then(mount); } else { mount(); } })();