// App principal: enrutamiento por URL (History API), estado global — monta en #root const { useState: useStateA, useEffect: useEffectA, useMemo: useMemoA } = React; const TWEAK_DEFAULTS = { primaryColor: '#39a3d5' }; // Construye los mapas route↔url una sola vez, cuando los datos ya están en window function buildRouteMaps() { const toUrl = { home: '/', boutique: '/boutique/', funerariums: '/funerariums/', guide: '/guide/', contact: '/contact/', apropos: '/a-propos/', 'mentions-legales': '/mentions-legales/', 'politique-confidentialite': '/politique-confidentialite/', 'politique-cookies': '/politique-cookies/', cgv: '/cgv/', 'fleuriste-marseille': '/fleuriste-marseille/', 'livraison-marseille': '/livraison-marseille/', }; const fromUrl = {}; Object.entries(toUrl).forEach(([route, url]) => { fromUrl[url.replace(/^\/|\/$/g, '') || '__home__'] = route; }); fromUrl['__home__'] = 'home'; // Comunas — usar slug SEO (/fleurs-deuil-aix-en-provence/) (window.FDL_DATA?.COMMUNES || []).forEach(c => { const route = `commune-${c.key}`; toUrl[route] = `/${c.slug}/`; fromUrl[c.slug] = route; }); // Funérariums (window.FDL_DATA?.FUNERAL_HOMES || []).forEach(h => { const route = `funerarium-${h.id}`; toUrl[route] = `/funerarium-${h.id}/`; fromUrl[`funerarium-${h.id}`] = route; }); // Artículos (window.FDL_DATA?.GUIDE_ARTICLES || []).forEach(a => { const route = `article-${a.id}`; toUrl[route] = `/article-${a.id}/`; fromUrl[`article-${a.id}`] = route; }); return { toUrl, fromUrl }; } function routeToPath(toUrl, r) { return toUrl[r] || `/${r}/`; } function pathToRoute(fromUrl, pathname) { const clean = pathname.replace(/^\/|\/$/g, '') || '__home__'; return fromUrl[clean] || clean; } function App() { const { toUrl, fromUrl } = useMemoA(() => buildRouteMaps(), []); const [route, _setRoute] = useStateA(() => pathToRoute(fromUrl, window.location.pathname) ); const setRoute = (r) => { _setRoute(r); const path = routeToPath(toUrl, r); if (window.location.pathname !== path) { window.history.pushState({ route: r }, '', path); } window.scrollTo({ top: 0, behavior: 'smooth' }); }; // Botones atrás/adelante del navegador useEffectA(() => { const handler = (e) => { const r = e.state?.route || pathToRoute(fromUrl, window.location.pathname); _setRoute(r); window.scrollTo({ top: 0, behavior: 'smooth' }); }; window.addEventListener('popstate', handler); return () => window.removeEventListener('popstate', handler); }, [fromUrl]); const [cart, setCart] = useStateA([]); const [cartOpen, setCartOpen] = useStateA(false); const [product, setProduct] = useStateA(null); const [initialCat, setInitialCat] = useStateA(null); const goToBoutique = (cat) => { setInitialCat(cat || null); setRoute('boutique'); }; const [primaryColor, setPrimaryColor] = useStateA(TWEAK_DEFAULTS.primaryColor); const [tweaksOpen, setTweaksOpen] = useStateA(false); useEffectA(() => { document.documentElement.style.setProperty('--primary', primaryColor); }, [primaryColor]); function addToCart(prod, qty, ribbon) { setCart(c => [...c, { product: prod, qty, ribbon }]); setCartOpen(true); } function removeItem(i) { setCart(c => c.filter((_, idx) => idx !== i)); } function updateQty(i, qty) { setCart(c => c.map((it, idx) => idx === i ? { ...it, qty } : it)); } const cartCount = cart.reduce((s, i) => s + i.qty, 0); const isCommuneRoute = route.startsWith('commune-'); const isArticleRoute = route.startsWith('article-'); const isFunerariumDetail = route.startsWith('funerarium-') && route !== 'funerariums'; return (