feat: update hospital management system - cama fuera de área features and dashboard fixes
This commit is contained in:
@@ -1269,28 +1269,27 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
|
||||
}, [state.cultivos]);
|
||||
|
||||
const getEstadisticas = useCallback(() => {
|
||||
const fueraDeGrupoList = state.camas.filter(c => isCamaFueraDeGrupo(c, state.grupos));
|
||||
const camasActivas = state.camas.filter(c => !isCamaFueraDeGrupo(c, state.grupos));
|
||||
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 camasDisponibles = state.camas.filter(c => c.estado === 'Disponible' && !isCamaFueraDeGrupo(c, state.grupos)).length;
|
||||
const camasEnArea = state.camas.filter(c => !isCamaFueraDeGrupo(c));
|
||||
const camasFueraDeArea = state.camas.filter(c => isCamaFueraDeGrupo(c));
|
||||
|
||||
const camasOcupadas = camasEnArea.filter(c => c.estado === 'Ocupada').length;
|
||||
const camasDisponibles = camasEnArea.filter(c => c.estado === 'Disponible').length;
|
||||
const camasMantenimiento = state.camas.filter(c => c.estado === 'Reparacion').length;
|
||||
const internacionesActivas = state.internaciones.filter(i => i.activa).length;
|
||||
const totalPacientes = state.pacientes.length;
|
||||
const cultivosPendientes = state.cultivos.filter(c => c.estado === 'NAF/Pendiente').length;
|
||||
|
||||
return {
|
||||
camaOcupadas,
|
||||
camasOcupadas: camaOcupadas,
|
||||
camasOcupadas,
|
||||
camasDisponibles,
|
||||
camasMantenimiento,
|
||||
totalCamas: state.camas.length,
|
||||
totalCamasActivas: camasActivas.length,
|
||||
camasFueraDeGrupo: fueraDeGrupoList.length,
|
||||
totalCamasActivas: camasEnArea.length,
|
||||
camasFueraDeArea: camasFueraDeArea.length,
|
||||
internacionesActivas,
|
||||
totalPacientes,
|
||||
cultivosPendientes,
|
||||
porcentajeOcupacion: camaPrincipal.length > 0 ? Math.round((camaOcupadas / camaPrincipal.length) * 100) : 0,
|
||||
porcentajeOcupacion: camasEnArea.length > 0 ? Math.round((camasOcupadas / camasEnArea.length) * 100) : 0,
|
||||
};
|
||||
}, [state]);
|
||||
|
||||
|
||||
+6
-2
@@ -55,11 +55,15 @@ export function computeSector(numero: string): "En Área" | "Fuera de Área" {
|
||||
const salaNum = parseInt(salaStr, 10);
|
||||
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';
|
||||
}
|
||||
if (salaNum >= 400 && salaNum < 500) {
|
||||
|
||||
// All those starting with 4
|
||||
if (salaStr.startsWith('4')) {
|
||||
return 'Fuera de Área';
|
||||
}
|
||||
|
||||
return 'En Área';
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ export function Dashboard({
|
||||
<CardContent>
|
||||
<div className="flex items-baseline gap-2">
|
||||
<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>
|
||||
<p className="text-xs text-gray-400 dark:text-gray-400 mt-1">
|
||||
{estadisticas.camasDisponibles} camas disponibles
|
||||
@@ -87,7 +87,7 @@ export function Dashboard({
|
||||
<CardHeader className="pb-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" />
|
||||
Camas Fuera de Área
|
||||
Camas fuera de área
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
@@ -95,7 +95,7 @@ export function Dashboard({
|
||||
<span className="text-3xl font-bold">{estadisticas.camasFueraDeArea}</span>
|
||||
</div>
|
||||
<p className="text-xs text-gray-400 dark:text-gray-400 mt-1">
|
||||
Camas Fuera de Grupo
|
||||
Total de camas fuera de área
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
@@ -40,6 +40,7 @@ export function NuevoIngreso({ pacientes, camas, grupos, onIniciarInternacion, o
|
||||
const [antecedentesEnfermedadActual, setAntecedentesEnfermedadActual] = useState('');
|
||||
const [apache, setApache] = useState('');
|
||||
const [derivacion, setDerivacion] = useState('');
|
||||
const [grupoSeleccionado, setGrupoSeleccionado] = useState<string>('');
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
|
||||
const resetFormulario = () => {
|
||||
@@ -47,6 +48,7 @@ export function NuevoIngreso({ pacientes, camas, grupos, onIniciarInternacion, o
|
||||
setBusqueda('');
|
||||
setCamaSeleccionada('');
|
||||
setCamaInput('');
|
||||
setGrupoSeleccionado('');
|
||||
setFechaIngresoHospital('');
|
||||
setFechaIngresoClinica('');
|
||||
setMotivoConsulta('');
|
||||
@@ -57,11 +59,6 @@ export function NuevoIngreso({ pacientes, camas, grupos, onIniciarInternacion, o
|
||||
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 internacionActiva = internaciones.find(i => i.pacienteId === p.id && i.activa);
|
||||
return !internacionActiva;
|
||||
@@ -127,6 +124,11 @@ export function NuevoIngreso({ pacientes, camas, grupos, onIniciarInternacion, o
|
||||
return;
|
||||
}
|
||||
|
||||
if (!grupoSeleccionado) {
|
||||
toast.error('Debe seleccionar un grupo para el seguimiento');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!diagnosticoIngreso.trim()) {
|
||||
toast.error('Debe completar el Diagnóstico de Ingreso');
|
||||
return;
|
||||
@@ -146,22 +148,22 @@ export function NuevoIngreso({ pacientes, camas, grupos, onIniciarInternacion, o
|
||||
|
||||
try {
|
||||
let camaId = '';
|
||||
let newGrupoId = '';
|
||||
|
||||
if (modoCama === 'escribir') {
|
||||
const numeroCama = camaInput.trim();
|
||||
const camaExistente = camas.find(c => c.numero === numeroCama);
|
||||
if (camaExistente) {
|
||||
camaId = camaExistente.id;
|
||||
newGrupoId = camaExistente.grupoId || grupoFueraDeGrupoId;
|
||||
toast.error(`La cama ${numeroCama} ya existe en el sistema. Seleccione la cama del listado o ingrese un número diferente.`);
|
||||
setIsSubmitting(false);
|
||||
return;
|
||||
} else if (onAgregarCama) {
|
||||
camaId = await onAgregarCama({
|
||||
numero: numeroCama,
|
||||
grupoId: grupoFueraDeGrupoId,
|
||||
grupoId: grupoSeleccionado,
|
||||
tipo: 'General',
|
||||
estado: 'Ocupada'
|
||||
estado: 'Ocupada',
|
||||
sector: 'Fuera de Área'
|
||||
});
|
||||
newGrupoId = grupoFueraDeGrupoId;
|
||||
} else {
|
||||
toast.error('No se puede crear la cama');
|
||||
setIsSubmitting(false);
|
||||
@@ -175,13 +177,12 @@ export function NuevoIngreso({ pacientes, camas, grupos, onIniciarInternacion, o
|
||||
return;
|
||||
}
|
||||
camaId = camaSeleccionada;
|
||||
newGrupoId = camaElegida.grupoId || grupoFueraDeGrupoId;
|
||||
}
|
||||
|
||||
await onIniciarInternacion({
|
||||
pacienteId: pacienteSeleccionado,
|
||||
camaId: camaId,
|
||||
grupoId: newGrupoId,
|
||||
grupoId: grupoSeleccionado,
|
||||
medicoIngresante: effectiveMedico.trim(),
|
||||
diagnosticoIngreso: diagnosticoIngreso.trim(),
|
||||
motivoConsulta: motivoConsulta.trim() || undefined,
|
||||
@@ -317,17 +318,47 @@ export function NuevoIngreso({ pacientes, camas, grupos, onIniciarInternacion, o
|
||||
<Button
|
||||
className="flex-1 text-xs sm:text-sm"
|
||||
variant={modoCama === 'escribir' ? 'default' : 'outline'}
|
||||
onClick={() => setModoCama('escribir')}
|
||||
onClick={() => {
|
||||
setModoCama('escribir');
|
||||
setGrupoSeleccionado('');
|
||||
}}
|
||||
>
|
||||
Escribir Cama
|
||||
Cama Fuera Área
|
||||
</Button>
|
||||
</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' ? (
|
||||
<>
|
||||
<div>
|
||||
<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>
|
||||
<SelectValue placeholder="Seleccionar cama" />
|
||||
</SelectTrigger>
|
||||
|
||||
Reference in New Issue
Block a user