import { useEffect, useState } from "react"; import "./theme.css"; import type { Meta } from "./api"; import { useApi } from "./api"; import Dashboard from "./Dashboard"; import Gestion from "./Gestion"; import Nowcast from "./Nowcast"; import Proyeccion from "./Proyeccion"; import { nf } from "./charts"; const NOMBRE_MES = [ "enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "setiembre", "octubre", "noviembre", "diciembre", ]; /** "2026-08-05" → "5 de agosto de 2026" */ function fechaLarga(iso: string) { const [a, m, d] = iso.split("-"); return `${+d} de ${NOMBRE_MES[+m - 1]} de ${a}`; } type Pestana = "dashboard" | "proyeccion" | "nowcast" | "gestion"; /** * Marca cuándo se comprobó por última vez si MINSA publicó datos nuevos. * Se pone en ámbar si pasaron más de 36 horas: eso ya no es "sin novedades", * es que el proceso automático dejó de correr. */ function VerificadoChip({ iso }: { iso: string }) { const t = new Date(iso); const horas = (Date.now() - t.getTime()) / 36e5; const alDia = horas < 36; const cuando = horas < 24 ? `hoy ${t.toLocaleTimeString("es-PE", { hour: "2-digit", minute: "2-digit" })}` : t.toLocaleString("es-PE", { day: "numeric", month: "short", hour: "2-digit", minute: "2-digit", }); return ( {alDia ? "✓" : "!"} verificado {cuando} ); } export default function App() { const { data: meta } = useApi("/api/meta"); const [tema, setTema] = useState<"auto" | "light" | "dark">("auto"); const [pestana, setPestana] = useState("dashboard"); useEffect(() => { const r = document.documentElement; if (tema === "auto") r.removeAttribute("data-theme"); else r.setAttribute("data-theme", tema); }, [tema]); if (!meta) return
Cargando SINADEF…
; return (

SINADEF — Defunciones en el Perú

{nf.format(meta.filas)} registros · {meta.anio_min}–{meta.anio_max} · fuente: Datos Abiertos MINSA

Última defunción registrada en SINADEF: {fechaLarga(meta.fecha_max)} · base recargada el{" "} {new Date(meta.actualizado * 1000).toLocaleString("es-PE", { day: "numeric", month: "short", year: "numeric", hour: "2-digit", minute: "2-digit", })} {/* El ETL corre a diario pero solo recarga si MINSA publicó algo nuevo. Sin este dato no se puede distinguir "sin novedades" de "el proceso dejó de correr". */} {meta.verificado && }
{/* Ambas pestañas se mantienen montadas: cambiar de pestaña no debe descartar una proyección que tardó medio minuto en calcularse. */}
); }