// 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 (
{isBP ? (
) : (
)}
{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 });