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]);
|
}, [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
@@ -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';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user