// Visões principais: Demanda (mapa + hospitais) e Pacientes (série + funil + coorte) const { useState: useS, useMemo: useM } = React; const fmt = (n) => n.toLocaleString("pt-BR"); const fmtCompact = (n) => { if (n >= 1_000_000) return (n / 1_000_000).toFixed(n >= 10_000_000 ? 0 : 1).replace(".", ",") + "M"; if (n >= 1_000) return (n / 1_000).toFixed(n >= 10_000 ? 0 : 1).replace(".", ",") + "k"; return n.toString(); }; // ─── Visão Demanda ──────────────────────────────────────────── function DemandaView({ market, period, showInsight = true }) { const { stateData, hospitals, kpis, monthly } = window.FARMA_DATA; const [metric, setMetric] = useS("dispensed"); const [selectedUF, setSelectedUF] = useS("SP"); const stateSel = stateData.find(s => s.uf === selectedUF); const hospitalsInState = hospitals.filter(h => h.uf === selectedUF); const hospitalsToShow = useM(() => { const base = selectedUF ? hospitalsInState : hospitals; return base.slice(0, 8); }, [selectedUF]); const sparkAtivos = monthly.slice(-12).map(m => m.ativos); const sparkCaixas = monthly.slice(-12).map(m => m.caixas); const ufRuptura = stateData.filter(s => s.ruptureRate >= 0.18).sort((a, b) => b.ruptureRate - a.ruptureRate); const topRupturaUF = ufRuptura[0]; return ( <>
Demanda & abastecimento · {kpis.competencia}

Onde a Pancreatina é dispensada

Cada quadrado é um estado. Cor mais intensa = mais demanda. Pontos amarelos sinalizam UFs onde 18% ou mais dos estabelecimentos estão em ruptura.

{showInsight && topRupturaUF && (
!
{topRupturaUF.name} ({topRupturaUF.uf}) lidera ruptura nesta competência —{" "} {topRupturaUF.ruptureEstabs} de {topRupturaUF.estabs} estabelecimentos com dispensação abaixo de 60% da média de 6 meses.
)}
Cápsulas dispensadas — {kpis.competencia}
{fmtCompact(kpis.capsulas)}cáps.
▲ 2,3% vs. mês anterior
Caixas / mês
{fmtCompact(kpis.caixas)}
▲ 2,3%vs. mês anterior
Estabelecimentos ativos
{fmt(kpis.estabsAtivos)}
▲ 12desde dezembro
Em ruptura
{kpis.estabsRuptura} {((kpis.estabsRuptura / kpis.estabsAtivos) * 100).toFixed(1).replace(".", ",")}%
▼ 3 estab.vs. mês anterior
Brasil em quadrados
Clique em um estado para detalhar.
{kpis.ufsAtendidas} UFs · {kpis.estabsAtivos} estab.
Estado selecionado
{stateSel.name}{stateSel.uf}
{stateSel.region === "SE" ? "Sudeste" : stateSel.region === "S" ? "Sul" : stateSel.region === "NE" ? "Nordeste" : stateSel.region === "N" ? "Norte" : "Centro-Oeste"}
Pacientes ativos
{fmt(stateSel.patients)}
{((stateSel.patients / kpis.pacientesAtivos) * 100).toFixed(1).replace(".", ",")}% do total
Cápsulas / mês
{fmtCompact(stateSel.dispensed)}
{fmt(stateSel.caixas)} caixas
Estabelecimentos
{stateSel.estabs}
{stateSel.ruptureEstabs} em ruptura
Taxa de ruptura
0.15 ? "warn" : "")}> {(stateSel.ruptureRate * 100).toFixed(0)}%
{stateSel.ruptureRate > 0.2 ? "Atenção crítica" : stateSel.ruptureRate > 0.1 ? "Monitorar" : "Saudável"}
Dispensação × Ruptura no tempo
Caixas dispensadas por mês vs. taxa de ruptura nacional.
Caixas Ruptura
Hospitais {selectedUF ? `em ${stateSel.name}` : "no Brasil"}
Ordenados por dispensação. Barra = indicador qt_atual ÷ média 6m.
#EstabelecimentoUFDispensação vs. média 6mStatus
{(hospitalsToShow.length ? hospitalsToShow : hospitals.slice(0, 8)).map((h, i) => { let text = "Saudável", tone = "ok"; if (h.indicator === 0 || h.indicator < 0.6) { text = "Ruptura"; tone = "danger"; } else if (h.indicator < 0.85) { text = "Atenção"; tone = "warn"; } return (
{String(i + 1).padStart(2, "0")}
{h.name}
{h.city} · CNES {h.cnes} · {fmt(h.patients)} pac · {fmt(h.caixas)} caixas
{h.uf} {text}
); })}
{selectedUF && hospitalsInState.length === 0 && (
Sem hospitais no top 20 para {stateSel.name}.{" "}
)}
); } // ─── Visão Pacientes ────────────────────────────────────────── function PacientesView() { const { monthly, markets, cohort, dropoutReasons, kpis } = window.FARMA_DATA; const last = monthly[monthly.length - 1]; const prev = monthly[monthly.length - 2]; const deltaAtivos = ((last.ativos - prev.ativos) / prev.ativos) * 100; const yearAgo = monthly[monthly.length - 13]; const totalPatients = markets.reduce((a, m) => a + m.patients, 0); const funnel = [ { label: "Novos tratamentos em 2025", value: kpis.naive2025, tone: "green" }, { label: "Pacientes ativos hoje", value: kpis.pacientesAtivos, tone: "" }, { label: "Retornaram após desistência", value: kpis.retorno + 84, tone: "green" }, { label: "Desistências neste mês", value: kpis.dropoutMes, tone: "warn" }, ]; return ( <>
Jornada de pacientes · {kpis.competencia}

{fmt(last.ativos)} pessoas em tratamento

Quem entrou, quem ficou e quem abandonou — desde a regulamentação pelo SUS em julho de 2025.

Pacientes ativos
{fmt(last.ativos)}
▲ {deltaAtivos.toFixed(1).replace(".", ",")}% vs. mês anterior
Novos no mês
+{fmt(last.novos)}
{fmt(kpis.naive2026)} desde jan/26
Desistências no mês
−{last.dropout}
▼ 4vs. mês anterior
Compliance médio
{(kpis.complianceRate * 100).toFixed(1).replace(".", ",")}%
{kpis.tempoMedioDias} dias entre dispensações
Pacientes ativos ao longo do tempo
Entrada de cobertura SUS em julho/2025 expandiu o mercado em ~120×.
{fmtMonth(monthly[0].c, true)} → {fmtMonth(monthly[monthly.length - 1].c, true)}
Funil do tratamento
Da primeira dispensação ao abandono — última competência.
Desistência = 4+ meses sem dispensação Taxa: {((kpis.dropoutMes / kpis.pacientesAtivos) * 100).toFixed(2).replace(".", ",")}%
Retenção por coorte
% dos pacientes que iniciaram em 2025 e continuam ativos.
{cohort[cohort.length - 1].pct}% ativos após 12 meses
Por mercado terapêutico
Fibrose cística e insuficiência exócrina pancreática.
{markets.map(m => (
{m.name}
CID {m.cids.join(" · ")}
{fmt(m.patients)}
Novos 2025 {fmt(m.naive2025)} Share {((m.patients / totalPatients) * 100).toFixed(0)}%
))}
Por que abandonam?
Distribuição dos motivos de desistência.
); } Object.assign(window, { DemandaView, PacientesView });