feat: update hospital management system - cama fuera de área features and dashboard fixes

This commit is contained in:
2026-08-10 02:14:30 +00:00
parent 735ccb9920
commit 091bbc0e95
4 changed files with 65 additions and 31 deletions
+9 -10
View File
@@ -1269,28 +1269,27 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
}, [state.cultivos]); }, [state.cultivos]);
const getEstadisticas = useCallback(() => { const getEstadisticas = useCallback(() => {
const fueraDeGrupoList = state.camas.filter(c => isCamaFueraDeGrupo(c, state.grupos)); const camasEnArea = state.camas.filter(c => !isCamaFueraDeGrupo(c));
const camasActivas = state.camas.filter(c => !isCamaFueraDeGrupo(c, state.grupos)); const camasFueraDeArea = state.camas.filter(c => isCamaFueraDeGrupo(c));
const camaPrincipal = state.camas.filter(c => !isCamaFueraDeGrupo(c, state.grupos));
const camaOcupadas = state.camas.filter(c => c.estado === 'Ocupada' && !isCamaFueraDeGrupo(c, state.grupos)).length; const camasOcupadas = camasEnArea.filter(c => c.estado === 'Ocupada').length;
const camasDisponibles = state.camas.filter(c => c.estado === 'Disponible' && !isCamaFueraDeGrupo(c, state.grupos)).length; const camasDisponibles = camasEnArea.filter(c => c.estado === 'Disponible').length;
const camasMantenimiento = state.camas.filter(c => c.estado === 'Reparacion').length; const camasMantenimiento = state.camas.filter(c => c.estado === 'Reparacion').length;
const internacionesActivas = state.internaciones.filter(i => i.activa).length; const internacionesActivas = state.internaciones.filter(i => i.activa).length;
const totalPacientes = state.pacientes.length; const totalPacientes = state.pacientes.length;
const cultivosPendientes = state.cultivos.filter(c => c.estado === 'NAF/Pendiente').length; const cultivosPendientes = state.cultivos.filter(c => c.estado === 'NAF/Pendiente').length;
return { return {
camaOcupadas, camasOcupadas,
camasOcupadas: camaOcupadas,
camasDisponibles, camasDisponibles,
camasMantenimiento, camasMantenimiento,
totalCamas: state.camas.length, totalCamas: state.camas.length,
totalCamasActivas: camasActivas.length, totalCamasActivas: camasEnArea.length,
camasFueraDeGrupo: fueraDeGrupoList.length, camasFueraDeArea: camasFueraDeArea.length,
internacionesActivas, internacionesActivas,
totalPacientes, totalPacientes,
cultivosPendientes, cultivosPendientes,
porcentajeOcupacion: camaPrincipal.length > 0 ? Math.round((camaOcupadas / camaPrincipal.length) * 100) : 0, porcentajeOcupacion: camasEnArea.length > 0 ? Math.round((camasOcupadas / camasEnArea.length) * 100) : 0,
}; };
}, [state]); }, [state]);
+6 -2
View File
@@ -55,11 +55,15 @@ export function computeSector(numero: string): "En Área" | "Fuera de Área" {
const salaNum = parseInt(salaStr, 10); const salaNum = parseInt(salaStr, 10);
if (isNaN(salaNum)) return 'En Área'; if (isNaN(salaNum)) return 'En Área';
if (salaNum >= 300 && salaNum < 400 && salaNum % 2 !== 0) { // 3XX-YY where XX is odd (so the whole 3XX is odd)
if (salaStr.length === 3 && salaStr.startsWith('3') && salaNum % 2 !== 0) {
return 'Fuera de Área'; return 'Fuera de Área';
} }
if (salaNum >= 400 && salaNum < 500) {
// All those starting with 4
if (salaStr.startsWith('4')) {
return 'Fuera de Área'; return 'Fuera de Área';
} }
return 'En Área'; return 'En Área';
} }
+3 -3
View File
@@ -75,7 +75,7 @@ export function Dashboard({
<CardContent> <CardContent>
<div className="flex items-baseline gap-2"> <div className="flex items-baseline gap-2">
<span className="text-3xl font-bold">{estadisticas.porcentajeOcupacion}%</span> <span className="text-3xl font-bold">{estadisticas.porcentajeOcupacion}%</span>
<span className="text-sm text-gray-500 dark:text-gray-400">{estadisticas.camasOcupadas}/{estadisticas.totalCamas}</span> <span className="text-sm text-gray-500 dark:text-gray-400">{estadisticas.camasOcupadas}/{estadisticas.totalCamasActivas}</span>
</div> </div>
<p className="text-xs text-gray-400 dark:text-gray-400 mt-1"> <p className="text-xs text-gray-400 dark:text-gray-400 mt-1">
{estadisticas.camasDisponibles} camas disponibles {estadisticas.camasDisponibles} camas disponibles
@@ -87,7 +87,7 @@ export function Dashboard({
<CardHeader className="pb-2"> <CardHeader className="pb-2">
<CardTitle className="text-sm font-medium text-gray-500 dark:text-gray-400 flex items-center gap-2"> <CardTitle className="text-sm font-medium text-gray-500 dark:text-gray-400 flex items-center gap-2">
<Users className="h-4 w-4" /> <Users className="h-4 w-4" />
Camas Fuera de Área Camas fuera de área
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
@@ -95,7 +95,7 @@ export function Dashboard({
<span className="text-3xl font-bold">{estadisticas.camasFueraDeArea}</span> <span className="text-3xl font-bold">{estadisticas.camasFueraDeArea}</span>
</div> </div>
<p className="text-xs text-gray-400 dark:text-gray-400 mt-1"> <p className="text-xs text-gray-400 dark:text-gray-400 mt-1">
Camas Fuera de Grupo Total de camas fuera de área
</p> </p>
</CardContent> </CardContent>
</Card> </Card>
+47 -16
View File
@@ -40,6 +40,7 @@ export function NuevoIngreso({ pacientes, camas, grupos, onIniciarInternacion, o
const [antecedentesEnfermedadActual, setAntecedentesEnfermedadActual] = useState(''); const [antecedentesEnfermedadActual, setAntecedentesEnfermedadActual] = useState('');
const [apache, setApache] = useState(''); const [apache, setApache] = useState('');
const [derivacion, setDerivacion] = useState(''); const [derivacion, setDerivacion] = useState('');
const [grupoSeleccionado, setGrupoSeleccionado] = useState<string>('');
const [isSubmitting, setIsSubmitting] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false);
const resetFormulario = () => { const resetFormulario = () => {
@@ -47,6 +48,7 @@ export function NuevoIngreso({ pacientes, camas, grupos, onIniciarInternacion, o
setBusqueda(''); setBusqueda('');
setCamaSeleccionada(''); setCamaSeleccionada('');
setCamaInput(''); setCamaInput('');
setGrupoSeleccionado('');
setFechaIngresoHospital(''); setFechaIngresoHospital('');
setFechaIngresoClinica(''); setFechaIngresoClinica('');
setMotivoConsulta(''); setMotivoConsulta('');
@@ -57,11 +59,6 @@ export function NuevoIngreso({ pacientes, camas, grupos, onIniciarInternacion, o
setDerivacion(''); setDerivacion('');
}; };
const normalizeStr = (str?: string) => (str || '').normalize('NFD').replace(/[\u0300-\u036f]/g, '').trim().toLowerCase();
const grupoFueraDeGrupo = grupos.find(a => normalizeStr(a.nombre) === 'fuera de grupo');
const grupoFueraDeGrupoId = grupoFueraDeGrupo?.id || grupos[0]?.id || 'fuera-de-grupo';
const pacientesSinInternar = pacientes.filter(p => { const pacientesSinInternar = pacientes.filter(p => {
const internacionActiva = internaciones.find(i => i.pacienteId === p.id && i.activa); const internacionActiva = internaciones.find(i => i.pacienteId === p.id && i.activa);
return !internacionActiva; return !internacionActiva;
@@ -127,6 +124,11 @@ export function NuevoIngreso({ pacientes, camas, grupos, onIniciarInternacion, o
return; return;
} }
if (!grupoSeleccionado) {
toast.error('Debe seleccionar un grupo para el seguimiento');
return;
}
if (!diagnosticoIngreso.trim()) { if (!diagnosticoIngreso.trim()) {
toast.error('Debe completar el Diagnóstico de Ingreso'); toast.error('Debe completar el Diagnóstico de Ingreso');
return; return;
@@ -146,22 +148,22 @@ export function NuevoIngreso({ pacientes, camas, grupos, onIniciarInternacion, o
try { try {
let camaId = ''; let camaId = '';
let newGrupoId = '';
if (modoCama === 'escribir') { if (modoCama === 'escribir') {
const numeroCama = camaInput.trim(); const numeroCama = camaInput.trim();
const camaExistente = camas.find(c => c.numero === numeroCama); const camaExistente = camas.find(c => c.numero === numeroCama);
if (camaExistente) { if (camaExistente) {
camaId = camaExistente.id; toast.error(`La cama ${numeroCama} ya existe en el sistema. Seleccione la cama del listado o ingrese un número diferente.`);
newGrupoId = camaExistente.grupoId || grupoFueraDeGrupoId; setIsSubmitting(false);
return;
} else if (onAgregarCama) { } else if (onAgregarCama) {
camaId = await onAgregarCama({ camaId = await onAgregarCama({
numero: numeroCama, numero: numeroCama,
grupoId: grupoFueraDeGrupoId, grupoId: grupoSeleccionado,
tipo: 'General', tipo: 'General',
estado: 'Ocupada' estado: 'Ocupada',
sector: 'Fuera de Área'
}); });
newGrupoId = grupoFueraDeGrupoId;
} else { } else {
toast.error('No se puede crear la cama'); toast.error('No se puede crear la cama');
setIsSubmitting(false); setIsSubmitting(false);
@@ -175,13 +177,12 @@ export function NuevoIngreso({ pacientes, camas, grupos, onIniciarInternacion, o
return; return;
} }
camaId = camaSeleccionada; camaId = camaSeleccionada;
newGrupoId = camaElegida.grupoId || grupoFueraDeGrupoId;
} }
await onIniciarInternacion({ await onIniciarInternacion({
pacienteId: pacienteSeleccionado, pacienteId: pacienteSeleccionado,
camaId: camaId, camaId: camaId,
grupoId: newGrupoId, grupoId: grupoSeleccionado,
medicoIngresante: effectiveMedico.trim(), medicoIngresante: effectiveMedico.trim(),
diagnosticoIngreso: diagnosticoIngreso.trim(), diagnosticoIngreso: diagnosticoIngreso.trim(),
motivoConsulta: motivoConsulta.trim() || undefined, motivoConsulta: motivoConsulta.trim() || undefined,
@@ -317,17 +318,47 @@ export function NuevoIngreso({ pacientes, camas, grupos, onIniciarInternacion, o
<Button <Button
className="flex-1 text-xs sm:text-sm" className="flex-1 text-xs sm:text-sm"
variant={modoCama === 'escribir' ? 'default' : 'outline'} variant={modoCama === 'escribir' ? 'default' : 'outline'}
onClick={() => setModoCama('escribir')} onClick={() => {
setModoCama('escribir');
setGrupoSeleccionado('');
}}
> >
Escribir Cama Cama Fuera Área
</Button> </Button>
</div> </div>
{modoCama === 'escribir' && (
<div className="space-y-2">
<Label>Grupo de Seguimiento *</Label>
<Select value={grupoSeleccionado} onValueChange={setGrupoSeleccionado}>
<SelectTrigger>
<SelectValue placeholder="Seleccionar grupo" />
</SelectTrigger>
<SelectContent>
{grupos.map(g => (
<SelectItem key={g.id} value={g.id}>
{g.nombre}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
)}
{modoCama === 'seleccionar' ? ( {modoCama === 'seleccionar' ? (
<> <>
<div> <div>
<Label>Cama *</Label> <Label>Cama *</Label>
<Select value={camaSeleccionada} onValueChange={setCamaSeleccionada}> <Select
value={camaSeleccionada}
onValueChange={(val) => {
setCamaSeleccionada(val);
const cama = camas.find(c => c.id === val);
if (cama?.grupoId) {
setGrupoSeleccionado(cama.grupoId);
}
}}
>
<SelectTrigger> <SelectTrigger>
<SelectValue placeholder="Seleccionar cama" /> <SelectValue placeholder="Seleccionar cama" />
</SelectTrigger> </SelectTrigger>