// portal-vitales.jsx — Health vitals tracker const { useState } = React; const VITAL_CONFIGS = { glucose: { label: 'Glucosa', unit: 'mg/dL', icon: '●', targetMin: 70, targetMax: 130, targetLabel: 'Meta: 70–130 mg/dL', color: '#E8743A', getValue: d => d.value, getDisplay: d => `${d.value}`, }, bloodPressure: { label: 'Presión arterial', unit: 'mmHg', icon: '♥', targetMin: 110, targetMax: 130, targetLabel: 'Meta sistólica: <130 mmHg', color: '#DC2626', getValue: d => d.sys, getDisplay: d => `${d.sys}/${d.dia}`, }, uricAcid: { label: 'Ácido úrico', unit: 'mg/dL', icon: '●', targetMin: 2.5, targetMax: 6.0, targetLabel: 'Meta: <6.0 mg/dL', color: '#7C3AED', getValue: d => d.value, getDisplay: d => `${d.value}`, }, weight: { label: 'Peso corporal', unit: 'kg', icon: '●', targetMin: null, targetMax: null, targetLabel: null, color: '#059669', getValue: d => d.value, getDisplay: d => `${d.value}`, }, }; function LogModal({ vitalKey, config, onSave, onClose }) { const C = window.C; const [val, setVal] = useState(''); const [val2, setVal2] = useState(''); const [date, setDate] = useState(new Date().toISOString().split('T')[0]); const isBP = vitalKey === 'bloodPressure'; const handleSave = () => { if (!val) return; const entry = { date }; if (isBP) { entry.sys = parseFloat(val); entry.dia = parseFloat(val2 || 0); } else { entry.value = parseFloat(val); } onSave(vitalKey, entry); onClose(); }; return (
Fecha
setDate(e.target.value)} style={{ width: '100%', padding: '10px 14px', borderRadius: 10, border: `1.5px solid ${C.border}`, fontFamily: 'inherit', fontSize: 14, color: C.text1, background: C.bg }} />
{isBP ? (
Sistólica (mmHg)
setVal(e.target.value)} placeholder="120" style={{ width: '100%', padding: '10px 14px', borderRadius: 10, border: `1.5px solid ${C.border}`, fontFamily: 'inherit', fontSize: 16, color: C.text1, background: C.bg }} />
Diastólica (mmHg)
setVal2(e.target.value)} placeholder="80" style={{ width: '100%', padding: '10px 14px', borderRadius: 10, border: `1.5px solid ${C.border}`, fontFamily: 'inherit', fontSize: 16, color: C.text1, background: C.bg }} />
) : (
{config.label} ({config.unit})
setVal(e.target.value)} placeholder="0.0" step="0.1" style={{ width: '100%', padding: '10px 14px', borderRadius: 10, border: `1.5px solid ${C.border}`, fontFamily: 'inherit', fontSize: 20, fontWeight: 700, color: C.text1, background: C.bg }} />
)} {config.targetLabel && (
{config.targetLabel}
)}
); } function VitalCard({ vitalKey, config, data, onLog }) { const C = window.C; const sorted = [...(data || [])].sort((a, b) => a.date > b.date ? 1 : -1); const latest = sorted[sorted.length - 1]; const latestVal = latest ? config.getValue(latest) : null; const inTarget = latestVal && config.targetMin && config.targetMax ? (latestVal >= config.targetMin && latestVal <= config.targetMax) : null; const statusColor = inTarget === null ? C.text3 : inTarget ? C.success : C.danger; const chartData = sorted.map(d => ({ ...d, value: config.getValue(d) })); return (
{config.icon}
{config.label}
{config.targetLabel &&
{config.targetLabel}
}
{latestVal ? ( <>
{config.getDisplay(latest)}
{config.unit}
) : (
Sin datos
)}
{/* Status pill */} {inTarget !== null && (
{inTarget ? '✓ En rango objetivo' : '! Fuera de rango objetivo'}
)} {/* Chart */} {sorted.length >= 2 && (
{new Date(sorted[0].date).toLocaleDateString('es-HN', { month: 'short', day: 'numeric' })} {new Date(sorted[sorted.length-1].date).toLocaleDateString('es-HN', { month: 'short', day: 'numeric' })}
)} {/* History */} {sorted.length > 0 && (
{[...sorted].reverse().slice(0, 5).map((d, i) => (
{new Date(d.date).toLocaleDateString('es-HN', { day: 'numeric', month: 'short', year: '2-digit' })} {config.getDisplay(d)} {config.unit}
))}
)}
); } function VitalesTab({ patient, vitals, onLogVital }) { const C = window.C; const [logging, setLogging] = useState(null); const myVitals = vitals[patient.id] || {}; // Which vitals are relevant to their conditions const conditions = patient.condiciones || []; const hasDiabetes = conditions.some(c => c.toLowerCase().includes('diabet')); const hasGout = conditions.some(c => c.toLowerCase().includes('gota') || c.toLowerCase().includes('uricemi')); const showUric = hasGout || (myVitals.uricAcid || []).length > 0; const keys = ['glucose', 'bloodPressure', ...(showUric ? ['uricAcid'] : []), 'weight']; return (
{conditions.length > 0 && (
Condiciones crónicas: {conditions.join(' · ')}
)} {keys.map(key => ( setLogging(k)} /> ))} {logging && ( { onLogVital(patient.id, key, entry); }} onClose={() => setLogging(null)} /> )}
); } Object.assign(window, { VitalesTab });