// PatientPanel — central patient data sheet. // User enters demographics + vitals + planned solutions once, // and every relevant calculator auto-populates with results. const { useState: usePS, useMemo: usePM, useEffect: usePE } = React; function PatientPanel() { const [p, setP] = window.PatientStore.usePatient(); const { NumberField, fmt, fmt0, classifyImc } = window.Calc; const tipo = p.poblacion || 'adulto'; const peso = +p.peso; const tallaM = (+p.talla) / 100; const fc = +p.fc; const tas = +p.tas; const tad = +p.tad; const temp = +p.temp; const horas = +p.horas || 8; // ─── Derived: IMC ───────────────────────────────────── const imc = (peso && tallaM) ? peso / (tallaM * tallaM) : NaN; const imcKlass = classifyImc(imc); // ─── Derived: PAM ───────────────────────────────────── const pam = (tas && tad) ? (tas + 2 * tad) / 3 : NaN; const pp = (tas && tad) ? tas - tad : NaN; // ─── Derived: Índice de choque ──────────────────────── const si = (fc && tas) ? fc / tas : NaN; // ─── Derived: Pérdidas insensibles automáticas ──────── let perdidasPerHora = NaN; let perdidasNota = ''; let perdidasFormula = []; let perdidasFactor = NaN; if (tipo === 'adulto' && peso) { const factor = !isFinite(temp) || temp === 0 ? 0.5 : temp < 37 ? 0.5 : temp < 38 ? 0.6 : temp < 39 ? 0.7 : 1; perdidasFactor = factor; perdidasPerHora = peso * factor; perdidasNota = `Adulto · factor temperatura ×${factor}`; perdidasFormula = [ 'Pérdidas/h = Peso × Factor térmico', ` = ${fmt(peso, 1)} kg × ${factor}`, ` = ${fmt(perdidasPerHora, 1)} ml/h`, ]; } else if ((tipo === 'pediatra' || tipo === 'neonato') && peso) { const C = { estable: 400, puntas: 500, fiebre: 600, ventilador: 700, calor: 300 }[p.apoyo || 'estable']; const sc = peso <= 10 ? (peso * 4 + 9) / 100 : (peso * 4 + 7) / (90 + peso); perdidasPerHora = (sc * C) / 24; perdidasNota = `${tipo === 'neonato' ? 'Neonato' : 'Pediátrico'} · SC ${fmt(sc, 3)} m² · constante ${C}`; perdidasFormula = [ `SC = ${peso <= 10 ? '(Peso×4 + 9) ÷ 100' : '(Peso×4 + 7) ÷ (90 + Peso)'}`, ` = ${fmt(sc, 3)} m²`, 'Pérdidas/h = (SC × Constante) ÷ 24', ` = (${fmt(sc, 3)} × ${C}) ÷ 24`, ` = ${fmt(perdidasPerHora, 1)} ml/h`, ]; } const perdidas24 = perdidasPerHora * 24; const perdidasCustom = perdidasPerHora * horas; // ─── Fórmulas y escalas de clasificación (para el resumen) ── const imcFormula = isFinite(imc) ? [ 'IMC = Peso ÷ Talla²', ` = ${fmt(peso, 1)} ÷ (${fmt(tallaM, 2)})²`, ` = ${fmt(peso, 1)} ÷ ${fmt(tallaM * tallaM, 3)}`, ` = ${fmt(imc, 2)} kg/m²`, ] : ['IMC = Peso (kg) ÷ Talla² (m)']; const pamFormula = isFinite(pam) ? [ 'PAM = (PAS + 2 × PAD) ÷ 3', ` = (${fmt0(tas)} + 2 × ${fmt0(tad)}) ÷ 3`, ` = ${fmt0(tas + 2 * tad)} ÷ 3`, ` = ${fmt(pam, 1)} mmHg`, ] : ['PAM = (PAS + 2 × PAD) ÷ 3']; const siFormula = isFinite(si) ? [ 'IC = FC ÷ PAS', ` = ${fmt0(fc)} ÷ ${fmt0(tas)}`, ` = ${fmt(si, 2)}`, ] : ['IC = Frecuencia cardiaca ÷ PAS']; const imcScale = [ { lbl: 'Bajo peso', rng: '< 18.5', hit: imc < 18.5 }, { lbl: 'Peso normal', rng: '18.5 – 24.9', hit: imc >= 18.5 && imc < 25 }, { lbl: 'Sobrepeso', rng: '25.0 – 29.9', hit: imc >= 25 && imc < 30 }, { lbl: 'Obesidad I', rng: '30.0 – 34.9', hit: imc >= 30 && imc < 35 }, { lbl: 'Obesidad II', rng: '35.0 – 39.9', hit: imc >= 35 && imc < 40 }, { lbl: 'Obesidad III', rng: '≥ 40.0', hit: imc >= 40 }, ]; const pamScale = [ { lbl: 'Hipoperfusión', rng: '< 60', hit: pam < 60 }, { lbl: 'Límite inferior', rng: '60 – 69', hit: pam >= 60 && pam < 70 }, { lbl: 'Perfusión adecuada', rng: '70 – 105',hit: pam >= 70 && pam <= 105 }, { lbl: 'Elevada', rng: '> 105', hit: pam > 105 }, ]; const siScale = [ { lbl: 'Sobrecarga / inadecuado', rng: '< 0.5', hit: si < 0.5 }, { lbl: 'Normal', rng: '0.5 – 0.7', hit: si >= 0.5 && si <= 0.7 }, { lbl: 'Choque leve', rng: '0.7 – 0.9', hit: si > 0.7 && si < 1 }, { lbl: 'Choque moderado', rng: '1.0 – 1.3', hit: si >= 1 && si < 1.4 }, { lbl: 'Choque severo', rng: '≥ 1.4', hit: si >= 1.4 }, ]; const tempScale = [ { lbl: 'Normotermia', rng: '< 37 °C', f: '0.5', hit: tipo === 'adulto' && (!isFinite(temp) || temp === 0 || temp < 37) }, { lbl: 'Subfebril', rng: '37 – 37.9 °C', f: '0.6', hit: tipo === 'adulto' && temp >= 37 && temp < 38 }, { lbl: 'Fiebre', rng: '38 – 38.9 °C', f: '0.7', hit: tipo === 'adulto' && temp >= 38 && temp < 39 }, { lbl: 'Hipertermia', rng: '≥ 39 °C', f: '1.0', hit: tipo === 'adulto' && temp >= 39 }, ]; const [sel, setSel] = usePS(null); const toggleSel = (k) => setSel(s => (s === k ? null : k)); // Chips de entrada y bloque de detalle reutilizable const Chip = ({ k, v }) => {k}{v}; const Formula = ({ lines }) =>
{lines.join('\n')}
; const Scale = ({ rows }) => (
{rows.map((r, i) => (
{r.lbl} {r.rng}{r.f ? ` · ×${r.f}` : ''}
))}
); // ─── Soluciones planificadas ────────────────────────── const soluciones = p.soluciones || []; const addSolucion = () => setP({ soluciones: [...soluciones, { nombre: 'Solución salina 0.9%', volumen: 500, tiempo: 8, equipo: 'macro' }] }); const updSol = (i, patch) => { const next = [...soluciones]; next[i] = { ...next[i], ...patch }; setP({ soluciones: next }); }; const rmSol = (i) => setP({ soluciones: soluciones.filter((_, j) => j !== i) }); // For each solucion compute gtt/min and mL/h const computedSols = soluciones.map(s => { const gpm = { macro: 10, normo: 20, micro: 60, trans: 15 }[s.equipo] || 20; const totalMin = (+s.tiempo || 0) * 60; const gtt = totalMin > 0 ? ((+s.volumen || 0) * gpm) / totalMin : NaN; const mlh = (+s.tiempo) > 0 ? (+s.volumen) / (+s.tiempo) : NaN; return { ...s, gpm, gtt, mlh }; }); const isReady = peso && tallaM; const clearPatient = () => { if (confirm('¿Borrar todos los datos del paciente?')) { setP({ poblacion: 'adulto', nombre: '', edad: '', edadUnit: 'años', sexo: 'F', peso: '', talla: '', fc: '', fr: '', tas: '', tad: '', temp: '', spo2: '', apoyo: 'estable', horas: 8, soluciones: [], }); } }; return (
{/* ─── LEFT: input form ─── */}

Datos del paciente

Estos datos se comparten con todas las calculadoras.

Población
{[ ['neonato', 'Neonato', true], ['pediatra', 'Pediátrico', false], ['adulto', 'Adulto', false], ].map(([k, l, soon]) => ( ))}
Identidad
setP({ nombre: e.target.value })} maxLength="6" placeholder="ej. M. G."/>
setP({ edad: e.target.value === '' ? '' : +e.target.value })} min="0" placeholder="—"/>
{(tipo === 'pediatra' || tipo === 'neonato') && (
)}
Antropometría
setP({ peso: v })} unit="kg" step="0.1" placeholder="ej. 15"/> setP({ talla: v })} unit="cm" placeholder="ej. 95"/>
Signos vitales
setP({ fc: v })} unit="lpm" placeholder="ej. 96"/> setP({ tas: v })} unit="mmHg" placeholder="ej. 120"/> setP({ tad: v })} unit="mmHg" placeholder="ej. 80"/> setP({ temp: v })} unit="°C" step="0.1" placeholder="ej. 37.4"/> setP({ horas: v })} unit="h" placeholder="8"/>
{/* ─── Soluciones ─── */}

Soluciones planificadas

Agrega cada solución para conocer goteo y velocidad de infusión.

{computedSols.length === 0 ? (

Sin soluciones aún. Agrega la primera para calcular gotas por minuto y ml/h.

) : (
{computedSols.map((s, i) => (
updSol(i, { nombre: e.target.value })} placeholder="Nombre de la solución" />
updSol(i, { volumen: +e.target.value || 0 })}/>ml
updSol(i, { tiempo: +e.target.value || 0 })} step="0.5"/>h
Velocidad{fmt0(s.mlh)} ml/h
Goteo{fmt0(s.gtt)} gtt/min
Equivalencia{s.gpm} gtt = 1 ml
))}
)}
{/* ─── RIGHT: live results ─── */}
); } window.PatientPanel = PatientPanel;