// mb-novolar.jsx — "Novo Lar" guided immersion (stage → curated results) function NovoLarScreen({ onBack, onOpenStore }) { const [stageId, setStageId] = React.useState(null); // Dados reais da API const [apiStages, setApiStages] = React.useState(null); React.useEffect(() => { API.journeyStages().then(d => { const stages = (d.stages || []).map(s => ({ id: s.slug, icon: s.icon || "home", title: s.title, sub: s.subtitle || "", sections: (s.sections || []).map(sec => ({ title: sec.title, ids: (sec.companies || []).map(c => c.id), companies: sec.companies || [], })), _raw: s, })); if (stages.length) setApiStages(stages); }).catch(() => {}); }, []); const stages = apiStages || NOVO_LAR_STAGES; const stage = stages.find(s => s.id === stageId); // ── stage selection ── if (!stage) { return (
{/* hero image com overlay escuro */}
{/* overlay degradê: escurece topo (para legibilidade do texto) e faz transição suave para o card branco */}
NOVO LAR

Seu novo lar,
do começo ao fim

Tudo o que você precisa em um só lugar — de terrenos e imóveis a móveis e decoração. Conta pra gente em que fase você está.

Em que fase você está?
{stages.map((s, i) => ( ))}
); } // ── curated results ── return (
setStageId(null)} />
SUA FASE
{stage.title}
{stage.sections.map((sec, si) => { const sectionPartners = sec.companies && sec.companies.length ? sec.companies.map(c => typeof c === "string" ? partnerById(c) : (c._mapped || { ...apiCompanyToPartner(c), _mapped: true })).filter(Boolean) : (sec.ids || []).map(id => partnerById(id)).filter(Boolean); const sorted = [...sectionPartners].sort((a, b) => planRank(b) - planRank(a) || b.rating - a.rating); return (
{/* cabeçalho do subgrupo */}
{sec.title} {sorted.length} parceiro{sorted.length !== 1 ? "s" : ""}
{sorted.length > 0 ? sorted.map(p => ) :
Nenhum parceiro nesta categoria ainda.
}
); })}
); } // ── Serviços do Lar hub ────────────────────────────────────── const CAT_LIMIT = 7; // mostra 7 categorias + posição 8 = "Ver mais" function ServicesScreen({ onBack, onOpenStore }) { const [cat, setCat] = React.useState(null); const [apiCats, setApiCats] = React.useState(null); const [moreCatsOpen, setMoreCatsOpen] = React.useState(false); React.useEffect(() => { API.homeServiceCats().then(d => { const cats = (d.categories || []).map(c => ({ id: c.id || c.slug, label: c.label || c.name, icon: c.icon || "home", ids: (c.companies || []).map(x => x.id || x), companies: c.companies || [], _raw: c, })); if (cats.length) setApiCats(cats); }).catch(() => {}); }, []); const homeSvc = apiCats || HOME_SVC; const catPartners = (c) => { if (c.companies && c.companies.length) return c.companies.map(x => typeof x === "string" ? partnerById(x) : apiCompanyToPartner(x)).filter(Boolean); return (c.ids || []).map(id => partnerById(id)).filter(Boolean); }; // flatMap pode repetir a mesma empresa em múltiplas categorias; // sem filtro ativo, deduplica por id const allProviders = homeSvc.flatMap(catPartners); const providers = cat ? allProviders // com filtro, preserva tudo da categoria selecionada : allProviders.filter((p, i, arr) => arr.findIndex(x => x.id === p.id) === i); const shown = cat ? catPartners(homeSvc.find(c => c.id === cat) || { ids: [], companies: [] }) : providers; const sortedShown = [...shown].sort((a, b) => planRank(b) - planRank(a) || b.rating - a.rating); return (

Guia de Serviços

Tudo para o suporte da sua casa
{/* category grid — 7 visíveis + posição 8 = "Ver mais" */} {(() => { const visible = homeSvc.slice(0, CAT_LIMIT); const hasMore = homeSvc.length > CAT_LIMIT; const activeCatInMore = cat && homeSvc.slice(CAT_LIMIT).some(c => c.id === cat); const catBtn = (c, onClick) => { const on = cat === c.id; return ( ); }; return (
{visible.map(c => catBtn(c, () => setCat(cat === c.id ? null : c.id)))} {hasMore && (() => { const activeCat = activeCatInMore ? homeSvc.find(c => c.id === cat) : null; const iconName = activeCat ? (activeCat.icon || "home") : "grid"; const label = activeCat ? activeCat.label : "Ver mais"; return ( ); })()}
); })()}

{cat ? homeSvc.find(c => c.id === cat)?.label : "Prestadores perto de você"}

{cat && }
{sortedShown.map(p => )}
{/* Bottom sheet — mais categorias */} {moreCatsOpen && (
setMoreCatsOpen(false)} style={{ position: "absolute", inset: 0, background: "rgba(0,0,0,.45)", backdropFilter: "blur(3px)" }} />
Mais categorias
{homeSvc.slice(CAT_LIMIT).map(c => { const on = cat === c.id; return ( ); })}
{cat && homeSvc.slice(CAT_LIMIT).some(c => c.id === cat) && ( )}
)}
); } // ── Roteiro Gastronômico ───────────────────────────────────── function RoteiroGastrScreen({ onBack, onOpenStore }) { const [region, setRegion] = React.useState(null); const [curIdx, setCurIdx] = React.useState(0); // índice do carrossel const [cuisineId, setCuisineId] = React.useState(null); const [apiCuisines, setApiCuisines] = React.useState(null); const [apiPartners, setApiPartners] = React.useState(null); const [loading, setLoading] = React.useState(false); React.useEffect(() => { API.gastroCuisines().then(d => { const cuisines = (d.categories || []).map(c => ({ id: c.id, label: c.name || c.label, icon: c.icon || "food", color: c.color || "#E8552D", image_url: c.image_url || null, sort_order: c.sort_order || 0, _raw: c, })); if (cuisines.length) setApiCuisines(cuisines); }).catch(() => {}); }, []); const cuisines = apiCuisines || GASTRO_CUISINES; // Sinc curIdx → cuisineId (fonte única de verdade) React.useEffect(() => { if (region !== null && cuisines.length > 0) { const idx = Math.max(0, Math.min(curIdx, cuisines.length - 1)); setCuisineId(cuisines[idx].id); } }, [curIdx, region, cuisines.length]); React.useEffect(() => { if (!cuisineId || !region) { setApiPartners(null); return; } setLoading(true); const regionName = region === "Todas" ? null : region; API.gastroPartners(cuisineId, regionName ? { regionId: regionName } : {}) .then(d => { const mapped = (d.companies || []).map(apiCompanyToPartner) .sort((a, b) => planRank(b) - planRank(a) || b.rating - a.rating); setApiPartners(mapped); }) .catch(() => setApiPartners(null)) .finally(() => setLoading(false)); }, [cuisineId, region]); const mockPartners = cuisineId && region != null ? gastroPartnersFor(cuisineId, region === "Todas" ? null : region) .sort((a, b) => planRank(b) - planRank(a) || b.rating - a.rating) : []; const partners = apiPartners !== null ? apiPartners : mockPartners; // Navegação do carrossel const goPrev = () => setCurIdx(i => Math.max(0, i - 1)); const goNext = () => setCurIdx(i => Math.min(cuisines.length - 1, i + 1)); const curC = cuisines[curIdx] || null; const prevC = cuisines[curIdx - 1] || null; const nextC = cuisines[curIdx + 1] || null; // Imagens para o mosaico do fundo (landing) const bgCuisines = cuisines.filter(c => c.image_url); // Step 1: escolher região — fundo mosaico de fotos de culinárias if (region === null) { const regionCards = [ { id: "Todas", label: "Ver todas as regiões", sub: "Mostra o guia completo" }, { id: "Aracaju", label: "Aracaju", sub: "Capital sergipana" }, { id: "Barra dos Coqueiros", label: "Barra dos Coqueiros", sub: "Travessia da ponte" }, { id: "Zona de Expansão", label: "Zona de Expansão", sub: "Mosqueiro e arredores" }, ]; // Tiles do mosaico: 9 posições, tila se necessário const tiles = bgCuisines.length >= 3 ? Array.from({ length: 9 }, (_, i) => bgCuisines[i % bgCuisines.length]) : null; return (
{/* ── Mosaico de fundo ── */} {tiles ? (
{tiles.map((c, i) => (
))}
{/* fade da imagem para o branco do card */}
{/* gradiente suave de transição */}
) : ( /* fallback se não tiver imagens ainda */
)}
ROTEIRO GASTRONÔMICO

A gastronomia
da nossa região

Escolha a região e explore frutos do mar, pizzas artesanais, culinária japonesa e muito mais.

{/* card branco com as regiões */}
Qual região você quer explorar?
{regionCards.map(r => ( ))}
); } // Step 2: carrossel por estado (sem scroll) + lista de parceiros // Card helper // Layout: center 74% centrado; miniaturas laterais 58% x scale(0.83) mostrando ~11% do container em cada borda const GastroCard = ({ c, role }) => { const isCenter = role === "center"; const cfgMap = { center: { left: "50%", width: "74%", transform: "translateX(-50%) scale(1)", opacity: 1, zIndex: 2 }, left: { left: "0%", width: "58%", transform: "translateX(-72%) scale(0.83)", opacity: 0.72, zIndex: 1 }, right: { left: "100%", width: "58%", transform: "translateX(-28%) scale(0.83)", opacity: 0.72, zIndex: 1 }, }; const cfg = cfgMap[role]; return (
{c.image_url ? {c.label} :
}
{c.label} {isCenter && !loading && partners.length > 0 && ( {partners.length} parceiro{partners.length !== 1 ? "s" : ""} na região )}
); }; return (
{/* cabeçalho */}
{ setRegion(null); setCuisineId(null); setCurIdx(0); }} size={40} bg="rgba(255,255,255,.16)" color="#fff" />

Guia Gastronômico

{region === "Todas" ? "Todas as regiões" : region}
{/* carrossel de 3 cards (prev | center | next) */}
{prevC && } {curC && } {nextC && } {/* botão esquerda */} {/* REMOVIDO: contador "X / N" que cobria as descrições */} {/* contador + botão direita */} {/* dots de navegação (substituem o contador numérico) */} {cuisines.length > 1 && (
{cuisines.map((_, i) => (
setCurIdx(i)} style={{ width: i === curIdx ? 18 : 6, height: 6, borderRadius: 999, background: i === curIdx ? "#fff" : "rgba(255,255,255,.45)", transition: "width .25s", cursor: "pointer" }} /> ))}
)}
{/* lista de parceiros */}
{loading &&
Carregando…
} {!loading && partners.length === 0 && cuisineId && (
Nenhum parceiro desta culinária na região selecionada.
)} {!loading && partners.length > 0 && (

{curC?.label}

)}
{partners.map(p => )}
); } Object.assign(window, { NovoLarScreen, ServicesScreen, RoteiroGastrScreen });