/* Landings explicativas por prueba de especialidad (plantilla única).
*
* Datos: src/pruebas-landings-data.js. Reusa las piezas del formato FIT /
* Helicobacter de src/pages-recuperadas.jsx (RcpHeroAzul, RcpClaves,
* RcpRelacionados, RcpPro, RcpAviso, useRevela, useEstudiosApi) y su hoja de
* estilo. Lo propio de esta plantilla vive en , scope `.plp`.
*
* Orden: hero → claves → pruebas del catálogo (en vivo) → explicación por
* audiencia → lo que dice el doctor → descargas → relacionadas → cierre.
*/
const PL = () => window.PRUEBAS_LANDINGS;
/* El nombre de la prueba no se parte entre renglones («Q / Sepsis»). */
const plpNb = (s) => String(s || "").replace(/ /g, "\u00a0");
function PruebaStyles() {
return ;
}
/* Estudios del tema en InfectoApp: los ids conocidos y, además, los que
* encuentre la búsqueda y cumplan la regla de nombre (por si dieron de alta la
* prueba con un id nuevo). Lo que no existe en InfectoApp no se muestra. */
function useEstudiosDelTema(catalogo) {
const [lista, setLista] = React.useState(null);
React.useEffect(() => {
const API = window.InfectoAPI, E = window.InfectoEnrich;
if (!API || !catalogo) { setLista([]); return; }
let vivo = true;
const ids = catalogo.ids || [];
const porId = Promise.all(ids.map((id) => API.getEstudio(id).catch(() => null)));
const porBusqueda = catalogo.buscar
? API.getEstudios({ q: catalogo.buscar, per_page: 50 }).then((r) => r.estudios).catch(() => [])
: Promise.resolve([]);
Promise.all([porId, porBusqueda]).then(([a, b]) => {
if (!vivo) return;
const vistos = {};
const extra = b.filter((s) => catalogo.nombre && catalogo.nombre.test(s.name || s.titulo || ""));
const ocultar = catalogo.ocultar || [];
const todos = a.filter(Boolean).concat(extra).filter((s) => {
if (ocultar.indexOf(Number(s.id)) >= 0) return false;
if (vistos[s.id]) return false;
vistos[s.id] = true;
return true;
});
setLista(todos.map((s) => (E ? E.enriquecer(s) : s)));
});
return () => { vivo = false; };
}, [catalogo]);
return lista;
}
function plpWa(texto) {
return PL().WA + (texto ? "?text=" + encodeURIComponent(texto) : "");
}
function PlpBoton({ cta, clase, navigate }) {
if (!cta) return null;
if (cta.tipo === "orden") {
return (
{cta.texto}
);
}
return (
{cta.texto}
);
}
function PlpComparativo({ c }) {
return (
Precio, muestra y entrega vigentes, directo del sistema del laboratorio.
{!lista &&
Cargando precio vigente…
}
{lista && !lista.length && (
{l.catalogo.vacio || ("En este momento no encontramos " + l.nombre + " en el catálogo. Escríbenos por WhatsApp y te decimos cómo solicitarla.")}
)}
{(lista || []).map((s, i) => {
const e = et[s.id] || {};
return (
);
}
/* El nombre oficial de InfectoApp suele venir en mayúsculas sostenidas. */
function N_tituloOficial(nombre) {
const N = window.InfectoNorm;
return "Nombre en InfectoApp: " + (N && N.tituloClinico ? N.tituloClinico(nombre) : nombre);
}
/* Las tres vistas se renderizan siempre: la inactiva se oculta con `hidden`,
* no se desmonta, para que el contenido de todas quede en el DOM (SEO). */
function PlpAudiencias({ l, navigate }) {
const auds = l.audiencias || [];
const [activa, setActiva] = React.useState(auds[0] && auds[0].id);
if (!auds.length) return null;
const teclas = (e, i) => {
if (e.key !== "ArrowRight" && e.key !== "ArrowLeft") return;
const n = (i + (e.key === "ArrowRight" ? 1 : -1) + auds.length) % auds.length;
setActiva(auds[n].id);
const b = document.getElementById("plp-tab-" + auds[n].id);
if (b) b.focus();
};
return (
>
)}
{base ? "Para tu institución" : "Lo que debes saber"}
{a.puntos.map((p, i) =>
{p}
)}
{base &&
Incluye todo lo de la vista para médicos.
}
);
})}
);
}
/* Secciones del material del doctor. Tipos:
* tabla — cols + filas (la primera celda es encabezado de fila)
* grupos — tarjetas con lista (gérmenes, anticuerpos…); `italica` para nombres científicos
* cifras — números grandes sobre azul
* pasos — algoritmo numerado
* notas — puntos numerados (interpretación, criterios) */
function PlpSeccion({ s }) {
return (