// 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 (
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 && }
{/* 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}
{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}
)}
);
}
Object.assign(window, { NovoLarScreen, ServicesScreen, RoteiroGastrScreen });