Renombrar 'Areas' a 'Grupos' y actualizar dependencias

This commit is contained in:
2026-08-09 20:05:08 +00:00
parent 91cde0e5d9
commit dc108a9699
12 changed files with 421 additions and 342 deletions
+9 -9
View File
@@ -49,7 +49,7 @@ function AppContent() {
return (
<MapaCamas
camas={store.camas}
areas={store.areas}
grupos={store.grupos}
pacientes={store.pacientes}
internaciones={store.internaciones}
onActualizarCama={store.actualizarCama}
@@ -58,9 +58,9 @@ function AppContent() {
onIniciarInternacion={store.iniciarInternacion}
getPacienteById={store.getPacienteById}
getInternacionById={store.getInternacionById}
onAgregarArea={store.agregarArea}
onActualizarArea={store.actualizarArea}
onEliminarArea={store.eliminarArea}
onAgregarGrupo={store.agregarGrupo}
onActualizarGrupo={store.actualizarGrupo}
onEliminarGrupo={store.eliminarGrupo}
/>
);
case 'pacientes':
@@ -79,7 +79,7 @@ function AppContent() {
internaciones={store.internaciones}
pacientes={store.pacientes}
camas={store.camas}
areas={store.areas}
grupos={store.grupos}
evoluciones={store.evoluciones}
laboratorios={store.laboratorios}
cultivos={store.cultivos}
@@ -207,11 +207,11 @@ function AppContent() {
<NuevoIngreso
pacientes={store.pacientes}
camas={store.camas}
areas={store.areas}
grupos={store.grupos}
onIniciarInternacion={store.iniciarInternacion}
onAgregarCama={store.agregarCama}
onVolver={() => store.setVista('internaciones')}
getAreaName={(areaId) => store.areas.find(a => a.id === areaId)?.nombre || ''}
getGrupoName={(grupoId) => store.grupos.find(a => a.id === grupoId)?.nombre || ''}
/>
);
@@ -234,11 +234,11 @@ function AppContent() {
cama={store.getCamaById(internacion.camaId)}
pacientes={store.pacientes}
camas={store.camas}
areas={store.areas}
grupos={store.grupos}
onActualizarInternacion={store.actualizarInternacion}
onAgregarCama={store.agregarCama}
onVolver={() => store.setVista('historiaclinica')}
getAreaName={(areaId) => store.areas.find(a => a.id === areaId)?.nombre || ''}
getGrupoName={(grupoId) => store.grupos.find(a => a.id === grupoId)?.nombre || ''}
/>
);
}
+161 -161
View File
@@ -1,10 +1,10 @@
import { useState, useEffect, useCallback } from 'react';
import { toast } from 'sonner';
import { getNombreProfesional, isCamaFueraDeArea } from '@/lib/utils';
import { getNombreProfesional, isCamaFueraDeGrupo } from '@/lib/utils';
import type {
Paciente,
Cama,
Area,
Grupo,
Internacion,
Evolucion,
Laboratorio,
@@ -36,7 +36,7 @@ function generateUUID(): string {
interface HospitalState {
pacientes: Paciente[];
camas: Cama[];
areas: Area[];
grupos: Grupo[];
internaciones: Internacion[];
evoluciones: Evolucion[];
laboratorios: Laboratorio[];
@@ -60,7 +60,7 @@ const API_BASE = import.meta.env.VITE_API_URL || '/api';
const defaultState = (): HospitalState => ({
pacientes: [],
areas: [],
grupos: [],
internaciones: [],
evoluciones: [],
laboratorios: [],
@@ -139,55 +139,55 @@ export function useHospitalStore() {
};
// Utility functions
const getCamaAreaId = useCallback((camaId: string): string | null => {
const getCamaGrupoId = useCallback((camaId: string): string | null => {
const cama = state.camas.find(c => c.id === camaId);
return cama?.areaId || null;
return cama?.grupoId || null;
}, [state.camas]);
const getInternacionAreaId = useCallback((internacionId: string): string | null => {
const getInternacionGrupoId = useCallback((internacionId: string): string | null => {
const internacion = state.internaciones.find(i => i.id === internacionId);
if (!internacion) return null;
return internacion.areaId || getCamaAreaId(internacion.camaId) || null;
}, [state.internaciones, getCamaAreaId]);
return internacion.grupoId || getCamaGrupoId(internacion.camaId) || null;
}, [state.internaciones, getCamaGrupoId]);
const getPacienteAreaId = useCallback((pacienteId: string): string | null => {
const getPacienteGrupoId = useCallback((pacienteId: string): string | null => {
const internacion = state.internaciones.find(i => i.pacienteId === pacienteId && i.activa);
if (!internacion) {
const anyInternacion = state.internaciones.find(i => i.pacienteId === pacienteId);
if (anyInternacion) return getCamaAreaId(anyInternacion.camaId);
if (anyInternacion) return getCamaGrupoId(anyInternacion.camaId);
return null;
}
return internacion.areaId || getCamaAreaId(internacion.camaId) || null;
}, [state.internaciones, getCamaAreaId]);
return internacion.grupoId || getCamaGrupoId(internacion.camaId) || null;
}, [state.internaciones, getCamaGrupoId]);
// Permission functions
const canAccessArea = useCallback((areaId: string | null | undefined): boolean => {
const canAccessGrupo = useCallback((grupoId: string | null | undefined): boolean => {
const user = state.currentUser;
if (!user) return false;
if (user.rol === 'admin') return true;
if (!areaId) return true;
if (!user.areaId) return true;
return user.areaId === areaId;
if (!grupoId) return true;
if (!user.grupoId) return true;
return user.grupoId === grupoId;
}, [state.currentUser]);
const checkAreaPermission = useCallback((areaId: string | null | undefined): boolean => {
const allowed = canAccessArea(areaId);
const checkGrupoPermission = useCallback((grupoId: string | null | undefined): boolean => {
const allowed = canAccessGrupo(grupoId);
if (!allowed) {
toast.error("no pertenecen al area de trabajo por la que se encuentra internado el paciente");
toast.error("no pertenecen al grupo de trabajo por la que se encuentra internado el paciente");
}
return allowed;
}, [canAccessArea]);
}, [canAccessGrupo]);
const canChangeBed = useCallback((internacionId: string): boolean => {
const internacion = state.internaciones.find(i => i.id === internacionId);
if (!internacion) return false;
return canAccessArea(internacion.areaId);
}, [state.internaciones, canAccessArea]);
return canAccessGrupo(internacion.grupoId);
}, [state.internaciones, canAccessGrupo]);
const canEditInternacion = useCallback((internacionId: string): boolean => {
const areaId = getInternacionAreaId(internacionId);
return canAccessArea(areaId);
}, [getInternacionAreaId, canAccessArea]);
const grupoId = getInternacionGrupoId(internacionId);
return canAccessGrupo(grupoId);
}, [getInternacionGrupoId, canAccessGrupo]);
const canEditIngreso = useCallback((internacionId: string): boolean => {
const internacion = state.internaciones.find(i => i.id === internacionId);
@@ -201,14 +201,14 @@ export function useHospitalStore() {
}, [state.internaciones, state.currentUser]);
const canEditCama = useCallback((camaId: string): boolean => {
const areaId = getCamaAreaId(camaId);
return canAccessArea(areaId);
}, [getCamaAreaId, canAccessArea]);
const grupoId = getCamaGrupoId(camaId);
return canAccessGrupo(grupoId);
}, [getCamaGrupoId, canAccessGrupo]);
const canEditPaciente = useCallback((pacienteId: string): boolean => {
const areaId = getPacienteAreaId(pacienteId);
return canAccessArea(areaId);
}, [getPacienteAreaId, canAccessArea]);
const grupoId = getPacienteGrupoId(pacienteId);
return canAccessGrupo(grupoId);
}, [getPacienteGrupoId, canAccessGrupo]);
const hasPermission = useCallback((permission: 'read' | 'write', section: string): boolean => {
const user = state.currentUser;
@@ -219,7 +219,7 @@ export function useHospitalStore() {
return permission === 'read';
}
if (user.rol === 'medico') {
if (section === 'miArea') return permission === 'read' || permission === 'write';
if (section === 'miGrupo') return permission === 'read' || permission === 'write';
return permission === 'read';
}
return false;
@@ -251,8 +251,8 @@ export function useHospitalStore() {
}, [apiCall]);
const actualizarPaciente = useCallback(async (id: string, datos: Partial<Paciente>) => {
const areaId = getPacienteAreaId(id);
if (!checkAreaPermission(areaId)) return;
const grupoId = getPacienteGrupoId(id);
if (!checkGrupoPermission(grupoId)) return;
try {
await apiCall('PUT', `/pacientes/${id}`, datos);
setState(prev => ({
@@ -263,11 +263,11 @@ export function useHospitalStore() {
console.error('Error al actualizar paciente:', err);
throw err;
}
}, [apiCall, checkAreaPermission, getPacienteAreaId]);
}, [apiCall, checkGrupoPermission, getPacienteGrupoId]);
const eliminarPaciente = useCallback(async (id: string) => {
const areaId = getPacienteAreaId(id);
if (!checkAreaPermission(areaId)) return;
const grupoId = getPacienteGrupoId(id);
if (!checkGrupoPermission(grupoId)) return;
try {
await apiCall('DELETE', `/pacientes/${id}`);
setState(prev => ({
@@ -278,15 +278,15 @@ export function useHospitalStore() {
console.error('Error al eliminar paciente:', err);
throw err;
}
}, [apiCall, checkAreaPermission, getPacienteAreaId]);
}, [apiCall, checkGrupoPermission, getPacienteGrupoId]);
// Acciones de camas
const actualizarCama = useCallback(async (id: string, datos: Partial<Cama>) => {
const cama = state.camas.find(c => c.id === id);
if (!cama) return;
const user = state.currentUser;
const areaId = cama.areaId || null;
if (user && user.rol !== 'admin' && areaId && user.areaId !== areaId) {
const grupoId = cama.grupoId || null;
if (user && user.rol !== 'admin' && grupoId && user.grupoId !== grupoId) {
console.warn('No tiene permisos para actualizar cama en esta área');
return;
}
@@ -300,7 +300,7 @@ export function useHospitalStore() {
console.error('Error al actualizar cama:', err);
throw err;
}
}, [state, canAccessArea, apiCall]);
}, [state, canAccessGrupo, apiCall]);
const agregarCama = useCallback(async (cama: Omit<Cama, 'id'>) => {
const nuevaCama: Cama = {
@@ -336,7 +336,7 @@ const agregarCama = useCallback(async (cama: Omit<Cama, 'id'>) => {
// Acciones de internaciones
const iniciarInternacion = useCallback(async (internacion: Omit<Internacion, 'id' | 'activa'>) => {
if (!checkAreaPermission(internacion.areaId)) {
if (!checkGrupoPermission(internacion.grupoId)) {
return null;
}
const nuevaInternacion: Internacion = {
@@ -380,9 +380,9 @@ const finalizarInternacion = useCallback(async (internacionId: string, datos: {
const internacion = state.internaciones.find(i => i.id === internacionId);
if (!internacion) return;
const areaFueraDeArea = state.areas.find(a => (a.nombre || '').toLowerCase().trim() === 'fuera de area');
const areaFueraDeAreaId = areaFueraDeArea?.id;
const esFueraDeArea = !internacion.areaId || !areaFueraDeAreaId || internacion.areaId === areaFueraDeAreaId;
const grupoFueraDeGrupo = state.grupos.find(a => (a.nombre || '').toLowerCase().trim() === 'fuera de grupo');
const grupoFueraDeGrupoId = grupoFueraDeGrupo?.id;
const esFueraDeGrupo = !internacion.grupoId || !grupoFueraDeGrupoId || internacion.grupoId === grupoFueraDeGrupoId;
const camaId = internacion.camaId;
try {
@@ -391,7 +391,7 @@ const finalizarInternacion = useCallback(async (internacionId: string, datos: {
// Eliminar o actualizar la cama según el área
if (camaId) {
if (esFueraDeArea) {
if (esFueraDeGrupo) {
// Eliminar la cama si es "Fuera de área"
await apiCall('DELETE', `/camas/${camaId}`);
} else {
@@ -411,7 +411,7 @@ const finalizarInternacion = useCallback(async (internacionId: string, datos: {
? { ...i, ...datos, activa: false }
: i
),
cams: esFueraDeArea
cams: esFueraDeGrupo
? prev.camas.filter(c => c.id !== camaId)
: prev.camas.map(c =>
c.id === camaId
@@ -449,11 +449,11 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
if (cambioDeCama && !canChangeBed(internacionId)) {
console.warn('No tiene permisos para cambiar la cama de esta internación');
checkAreaPermission(null); // triggers toast
checkGrupoPermission(null); // triggers toast
return;
}
if (!cambioDeCama && !checkAreaPermission(internacion.areaId)) {
if (!cambioDeCama && !checkGrupoPermission(internacion.grupoId)) {
console.warn('No tiene permisos para actualizar esta internación');
return;
}
@@ -497,13 +497,13 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
console.error('Error al actualizar internación:', err);
throw err;
}
}, [state, canAccessArea, checkAreaPermission, apiCall]);
}, [state, canAccessGrupo, checkGrupoPermission, apiCall]);
// Acciones de evoluciones
const agregarEvolucion = useCallback(async (evolucion: Omit<Evolucion, 'id'>) => {
const internacion = state.internaciones.find(i => i.id === evolucion.internacionId);
const areaId = internacion?.areaId || null;
if (!checkAreaPermission(areaId)) {
const grupoId = internacion?.grupoId || null;
if (!checkGrupoPermission(grupoId)) {
console.warn('No tiene permisos para agregar evolución en esta área');
return null;
}
@@ -523,14 +523,14 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
console.error('Error al agregar evolución:', err);
throw err;
}
}, [state, canAccessArea, checkAreaPermission, apiCall]);
}, [state, canAccessGrupo, checkGrupoPermission, apiCall]);
const eliminarEvolucion = useCallback(async (id: string) => {
const evolucion = state.evoluciones.find(e => e.id === id);
if (!evolucion) return;
const internacion = state.internaciones.find(i => i.id === evolucion.internacionId);
const areaId = internacion?.areaId || null;
if (!checkAreaPermission(areaId)) {
const grupoId = internacion?.grupoId || null;
if (!checkGrupoPermission(grupoId)) {
console.warn('No tiene permisos para eliminar evolución en esta área');
return;
}
@@ -545,14 +545,14 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
console.error('Error al eliminar evolución:', err);
throw err;
}
}, [state, canAccessArea, checkAreaPermission, apiCall]);
}, [state, canAccessGrupo, checkGrupoPermission, apiCall]);
const actualizarEvolucion = useCallback(async (id: string, datos: Partial<Evolucion>) => {
const evolucion = state.evoluciones.find(e => e.id === id);
if (!evolucion) return;
const internacion = state.internaciones.find(i => i.id === evolucion.internacionId);
const areaId = internacion?.areaId || null;
if (!checkAreaPermission(areaId)) {
const grupoId = internacion?.grupoId || null;
if (!checkGrupoPermission(grupoId)) {
console.warn('No tiene permisos para actualizar evolución en esta área');
return;
}
@@ -567,13 +567,13 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
console.error('Error al actualizar evolución:', err);
throw err;
}
}, [state, canAccessArea, checkAreaPermission, apiCall]);
}, [state, canAccessGrupo, checkGrupoPermission, apiCall]);
// Acciones de laboratorios
const agregarLaboratorio = useCallback(async (laboratorio: Omit<Laboratorio, 'id'>) => {
const internacion = state.internaciones.find(i => i.id === laboratorio.internacionId);
const areaId = internacion?.areaId || null;
if (!checkAreaPermission(areaId)) {
const grupoId = internacion?.grupoId || null;
if (!checkGrupoPermission(grupoId)) {
console.warn('No tiene permisos para agregar laboratorio en esta área');
return null;
}
@@ -592,14 +592,14 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
console.error('Error al agregar laboratorio:', err);
throw err;
}
}, [state, canAccessArea, checkAreaPermission, apiCall]);
}, [state, canAccessGrupo, checkGrupoPermission, apiCall]);
const eliminarLaboratorio = useCallback(async (id: string) => {
const laboratorio = state.laboratorios.find(l => l.id === id);
if (!laboratorio) return;
const internacion = state.internaciones.find(i => i.id === laboratorio.internacionId);
const areaId = internacion?.areaId || null;
if (!checkAreaPermission(areaId)) {
const grupoId = internacion?.grupoId || null;
if (!checkGrupoPermission(grupoId)) {
console.warn('No tiene permisos para eliminar laboratorio en esta área');
return;
}
@@ -613,14 +613,14 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
console.error('Error al eliminar laboratorio:', err);
throw err;
}
}, [state, canAccessArea, checkAreaPermission, apiCall]);
}, [state, canAccessGrupo, checkGrupoPermission, apiCall]);
const actualizarLaboratorio = useCallback(async (id: string, datos: Partial<Laboratorio>) => {
const laboratorio = state.laboratorios.find(l => l.id === id);
if (!laboratorio) return;
const internacion = state.internaciones.find(i => i.id === laboratorio.internacionId);
const areaId = internacion?.areaId || null;
if (!checkAreaPermission(areaId)) {
const grupoId = internacion?.grupoId || null;
if (!checkGrupoPermission(grupoId)) {
console.warn('No tiene permisos para actualizar laboratorio en esta área');
return;
}
@@ -634,13 +634,13 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
console.error('Error al actualizar laboratorio:', err);
throw err;
}
}, [state, canAccessArea, checkAreaPermission, apiCall]);
}, [state, canAccessGrupo, checkGrupoPermission, apiCall]);
// Acciones de glucemias
const agregarGlucemia = useCallback(async (glucemia: Omit<Glucemia, 'id'>) => {
const internacion = state.internaciones.find(i => i.id === glucemia.internacionId);
const areaId = internacion?.areaId || null;
if (!checkAreaPermission(areaId)) {
const grupoId = internacion?.grupoId || null;
if (!checkGrupoPermission(grupoId)) {
console.warn('No tiene permisos para agregar glucemia en esta área');
return null;
}
@@ -659,14 +659,14 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
console.error('Error al agregar glucemia:', err);
throw err;
}
}, [state, canAccessArea, checkAreaPermission, apiCall]);
}, [state, canAccessGrupo, checkGrupoPermission, apiCall]);
const eliminarGlucemia = useCallback(async (id: string) => {
const glucemia = state.glucemias.find(g => g.id === id);
if (!glucemia) return;
const internacion = state.internaciones.find(i => i.id === glucemia.internacionId);
const areaId = internacion?.areaId || null;
if (!checkAreaPermission(areaId)) {
const grupoId = internacion?.grupoId || null;
if (!checkGrupoPermission(grupoId)) {
console.warn('No tiene permisos para eliminar glucemia en esta área');
return;
}
@@ -680,14 +680,14 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
console.error('Error al eliminar glucemia:', err);
throw err;
}
}, [state, canAccessArea, checkAreaPermission, apiCall]);
}, [state, canAccessGrupo, checkGrupoPermission, apiCall]);
const actualizarGlucemia = useCallback(async (id: string, datos: Partial<Glucemia>) => {
const glucemia = state.glucemias.find(g => g.id === id);
if (!glucemia) return;
const internacion = state.internaciones.find(i => i.id === glucemia.internacionId);
const areaId = internacion?.areaId || null;
if (!checkAreaPermission(areaId)) {
const grupoId = internacion?.grupoId || null;
if (!checkGrupoPermission(grupoId)) {
console.warn('No tiene permisos para actualizar glucemia en esta área');
return;
}
@@ -701,13 +701,13 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
console.error('Error al actualizar glucemia:', err);
throw err;
}
}, [state, canAccessArea, checkAreaPermission, apiCall]);
}, [state, canAccessGrupo, checkGrupoPermission, apiCall]);
// Acciones de ácido-base
const agregarAcidoBase = useCallback(async (acidoBase: Omit<AcidoBase, 'id'>) => {
const internacion = state.internaciones.find(i => i.id === acidoBase.internacionId);
const areaId = internacion?.areaId || null;
if (!checkAreaPermission(areaId)) {
const grupoId = internacion?.grupoId || null;
if (!checkGrupoPermission(grupoId)) {
console.warn('No tiene permisos para agregar ácido-base en esta área');
return null;
}
@@ -726,14 +726,14 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
console.error('Error al agregar ácido-base:', err);
throw err;
}
}, [state, canAccessArea, checkAreaPermission, apiCall]);
}, [state, canAccessGrupo, checkGrupoPermission, apiCall]);
const actualizarAcidoBase = useCallback(async (id: string, datos: Partial<AcidoBase>) => {
const acidoBase = state.acidosBase.find(a => a.id === id);
if (!acidoBase) return;
const internacion = state.internaciones.find(i => i.id === acidoBase.internacionId);
const areaId = internacion?.areaId || null;
if (!checkAreaPermission(areaId)) {
const grupoId = internacion?.grupoId || null;
if (!checkGrupoPermission(grupoId)) {
console.warn('No tiene permisos para actualizar ácido-base en esta área');
return;
}
@@ -747,14 +747,14 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
console.error('Error al actualizar ácido-base:', err);
throw err;
}
}, [state, canAccessArea, checkAreaPermission, apiCall]);
}, [state, canAccessGrupo, checkGrupoPermission, apiCall]);
const eliminarAcidoBase = useCallback(async (id: string) => {
const acidoBase = state.acidosBase.find(a => a.id === id);
if (!acidoBase) return;
const internacion = state.internaciones.find(i => i.id === acidoBase.internacionId);
const areaId = internacion?.areaId || null;
if (!checkAreaPermission(areaId)) {
const grupoId = internacion?.grupoId || null;
if (!checkGrupoPermission(grupoId)) {
console.warn('No tiene permisos para eliminar ácido-base en esta área');
return;
}
@@ -768,13 +768,13 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
console.error('Error al eliminar ácido-base:', err);
throw err;
}
}, [state, canAccessArea, checkAreaPermission, apiCall]);
}, [state, canAccessGrupo, checkGrupoPermission, apiCall]);
// Acciones de cultivos
const agregarCultivo = useCallback(async (cultivo: Omit<Cultivo, 'id'>) => {
const internacion = state.internaciones.find(i => i.id === cultivo.internacionId);
const areaId = internacion?.areaId || null;
if (!checkAreaPermission(areaId)) {
const grupoId = internacion?.grupoId || null;
if (!checkGrupoPermission(grupoId)) {
console.warn('No tiene permisos para agregar cultivo en esta área');
return null;
}
@@ -793,14 +793,14 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
console.error('Error al agregar cultivo:', err);
throw err;
}
}, [state, canAccessArea, checkAreaPermission, apiCall]);
}, [state, canAccessGrupo, checkGrupoPermission, apiCall]);
const actualizarCultivo = useCallback(async (id: string, datos: Partial<Cultivo>) => {
const cultivo = state.cultivos.find(c => c.id === id);
if (!cultivo) return;
const internacion = state.internaciones.find(i => i.id === cultivo.internacionId);
const areaId = internacion?.areaId || null;
if (!checkAreaPermission(areaId)) {
const grupoId = internacion?.grupoId || null;
if (!checkGrupoPermission(grupoId)) {
console.warn('No tiene permisos para actualizar cultivo en esta área');
return;
}
@@ -814,14 +814,14 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
console.error('Error al actualizar cultivo:', err);
throw err;
}
}, [state, canAccessArea, checkAreaPermission, apiCall]);
}, [state, canAccessGrupo, checkGrupoPermission, apiCall]);
const eliminarCultivo = useCallback(async (id: string) => {
const cultivo = state.cultivos.find(c => c.id === id);
if (!cultivo) return;
const internacion = state.internaciones.find(i => i.id === cultivo.internacionId);
const areaId = internacion?.areaId || null;
if (!checkAreaPermission(areaId)) {
const grupoId = internacion?.grupoId || null;
if (!checkGrupoPermission(grupoId)) {
console.warn('No tiene permisos para eliminar cultivo en esta área');
return;
}
@@ -835,13 +835,13 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
console.error('Error al eliminar cultivo:', err);
throw err;
}
}, [state, canAccessArea, checkAreaPermission, apiCall]);
}, [state, canAccessGrupo, checkGrupoPermission, apiCall]);
// Acciones de estudios complementarios
const agregarEstudioComplementario = useCallback(async (estudio: Omit<EstudioComplementario, 'id'>) => {
const internacion = state.internaciones.find(i => i.id === estudio.internacionId);
const areaId = internacion?.areaId || null;
if (!checkAreaPermission(areaId)) {
const grupoId = internacion?.grupoId || null;
if (!checkGrupoPermission(grupoId)) {
console.warn('No tiene permisos para agregar estudio complementario en esta área');
return null;
}
@@ -860,14 +860,14 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
console.error('Error al agregar estudio:', err);
throw err;
}
}, [state, canAccessArea, checkAreaPermission, apiCall]);
}, [state, canAccessGrupo, checkGrupoPermission, apiCall]);
const actualizarEstudioComplementario = useCallback(async (id: string, datos: Partial<EstudioComplementario>) => {
const estudio = state.estudiosComplementarios.find(e => e.id === id);
if (!estudio) return;
const internacion = state.internaciones.find(i => i.id === estudio.internacionId);
const areaId = internacion?.areaId || null;
if (!checkAreaPermission(areaId)) {
const grupoId = internacion?.grupoId || null;
if (!checkGrupoPermission(grupoId)) {
console.warn('No tiene permisos para actualizar estudio complementario en esta área');
return;
}
@@ -881,14 +881,14 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
console.error('Error al actualizar estudio:', err);
throw err;
}
}, [state, canAccessArea, checkAreaPermission, apiCall]);
}, [state, canAccessGrupo, checkGrupoPermission, apiCall]);
const eliminarEstudioComplementario = useCallback(async (id: string) => {
const estudio = state.estudiosComplementarios.find(e => e.id === id);
if (!estudio) return;
const internacion = state.internaciones.find(i => i.id === estudio.internacionId);
const areaId = internacion?.areaId || null;
if (!checkAreaPermission(areaId)) {
const grupoId = internacion?.grupoId || null;
if (!checkGrupoPermission(grupoId)) {
console.warn('No tiene permisos para eliminar estudio complementario en esta área');
return;
}
@@ -902,13 +902,13 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
console.error('Error al eliminar estudio:', err);
throw err;
}
}, [state, canAccessArea, checkAreaPermission, apiCall]);
}, [state, canAccessGrupo, checkGrupoPermission, apiCall]);
// Acciones de interconsultas
const agregarInterconsulta = useCallback(async (interconsulta: Omit<Interconsulta, 'id'>) => {
const internacion = state.internaciones.find(i => i.id === interconsulta.internacionId);
const areaId = internacion?.areaId || null;
if (!checkAreaPermission(areaId)) {
const grupoId = internacion?.grupoId || null;
if (!checkGrupoPermission(grupoId)) {
console.warn('No tiene permisos para agregar interconsulta en esta área');
return null;
}
@@ -924,14 +924,14 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
console.error('Error al agregar interconsulta:', err);
throw err;
}
}, [state, canAccessArea, checkAreaPermission, apiCall]);
}, [state, canAccessGrupo, checkGrupoPermission, apiCall]);
const actualizarInterconsulta = useCallback(async (id: string, datos: Partial<Interconsulta>) => {
const interconsulta = (state.interconsultas || []).find(ic => ic.id === id);
if (!interconsulta) return;
const internacion = state.internaciones.find(i => i.id === interconsulta.internacionId);
const areaId = internacion?.areaId || null;
if (!checkAreaPermission(areaId)) {
const grupoId = internacion?.grupoId || null;
if (!checkGrupoPermission(grupoId)) {
console.warn('No tiene permisos para actualizar interconsulta en esta área');
return;
}
@@ -945,14 +945,14 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
console.error('Error al actualizar interconsulta:', err);
throw err;
}
}, [state, canAccessArea, checkAreaPermission, apiCall]);
}, [state, canAccessGrupo, checkGrupoPermission, apiCall]);
const eliminarInterconsulta = useCallback(async (id: string) => {
const interconsulta = (state.interconsultas || []).find(ic => ic.id === id);
if (!interconsulta) return;
const internacion = state.internaciones.find(i => i.id === interconsulta.internacionId);
const areaId = internacion?.areaId || null;
if (!checkAreaPermission(areaId)) {
const grupoId = internacion?.grupoId || null;
if (!checkGrupoPermission(grupoId)) {
console.warn('No tiene permisos para eliminar interconsulta en esta área');
return;
}
@@ -966,12 +966,12 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
console.error('Error al eliminar interconsulta:', err);
throw err;
}
}, [state, canAccessArea, checkAreaPermission, apiCall]);
}, [state, canAccessGrupo, checkGrupoPermission, apiCall]);
const agregarATB = useCallback(async (atb: Omit<ATB, 'id'>) => {
const internacion = state.internaciones.find(i => i.id === atb.internacionId);
const areaId = internacion?.areaId || null;
if (!checkAreaPermission(areaId)) {
const grupoId = internacion?.grupoId || null;
if (!checkGrupoPermission(grupoId)) {
console.warn('No tiene permisos para agregar ATB en esta área');
return null;
}
@@ -987,14 +987,14 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
console.error('Error al agregar ATB:', err);
throw err;
}
}, [state, canAccessArea, checkAreaPermission, apiCall]);
}, [state, canAccessGrupo, checkGrupoPermission, apiCall]);
const actualizarATB = useCallback(async (id: string, datos: Partial<ATB>) => {
const atb = state.atb.find(a => a.id === id);
if (!atb) return;
const internacion = state.internaciones.find(i => i.id === atb.internacionId);
const areaId = internacion?.areaId || null;
if (!checkAreaPermission(areaId)) {
const grupoId = internacion?.grupoId || null;
if (!checkGrupoPermission(grupoId)) {
console.warn('No tiene permisos para actualizar ATB en esta área');
return;
}
@@ -1008,14 +1008,14 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
console.error('Error al actualizar ATB:', err);
throw err;
}
}, [state, canAccessArea, checkAreaPermission, apiCall]);
}, [state, canAccessGrupo, checkGrupoPermission, apiCall]);
const eliminarATB = useCallback(async (id: string) => {
const atb = state.atb.find(a => a.id === id);
if (!atb) return;
const internacion = state.internaciones.find(i => i.id === atb.internacionId);
const areaId = internacion?.areaId || null;
if (!checkAreaPermission(areaId)) {
const grupoId = internacion?.grupoId || null;
if (!checkGrupoPermission(grupoId)) {
console.warn('No tiene permisos para eliminar ATB en esta área');
return;
}
@@ -1029,12 +1029,12 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
console.error('Error al eliminar ATB:', err);
throw err;
}
}, [state, canAccessArea, checkAreaPermission, apiCall]);
}, [state, canAccessGrupo, checkGrupoPermission, apiCall]);
const agregarIndicacion = useCallback(async (indicacion: Omit<Indicacion, 'id'>) => {
const internacion = state.internaciones.find(i => i.id === indicacion.internacionId);
const areaId = internacion?.areaId || null;
if (!checkAreaPermission(areaId)) {
const grupoId = internacion?.grupoId || null;
if (!checkGrupoPermission(grupoId)) {
console.warn('No tiene permisos para agregar indicación en esta área');
return null;
}
@@ -1050,14 +1050,14 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
console.error('Error al agregar indicación:', err);
throw err;
}
}, [state.internaciones, canAccessArea, checkAreaPermission, apiCall]);
}, [state.internaciones, canAccessGrupo, checkGrupoPermission, apiCall]);
const actualizarIndicacion = useCallback(async (id: string, datos: Partial<Indicacion>) => {
const indicacion = state.indicaciones.find(i => i.id === id);
if (!indicacion) return;
const internacion = state.internaciones.find(i => i.id === indicacion.internacionId);
const areaId = internacion?.areaId || null;
if (!checkAreaPermission(areaId)) {
const grupoId = internacion?.grupoId || null;
if (!checkGrupoPermission(grupoId)) {
console.warn('No tiene permisos para actualizar indicación en esta área');
return;
}
@@ -1071,14 +1071,14 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
console.error('Error al actualizar indicación:', err);
throw err;
}
}, [state.indicaciones, state.internaciones, canAccessArea, checkAreaPermission, apiCall]);
}, [state.indicaciones, state.internaciones, canAccessGrupo, checkGrupoPermission, apiCall]);
const eliminarIndicacion = useCallback(async (id: string) => {
const indicacion = state.indicaciones.find(i => i.id === id);
if (!indicacion) return;
const internacion = state.internaciones.find(i => i.id === indicacion.internacionId);
const areaId = internacion?.areaId || null;
if (!checkAreaPermission(areaId)) {
const grupoId = internacion?.grupoId || null;
if (!checkGrupoPermission(grupoId)) {
console.warn('No tiene permisos para eliminar indicación en esta área');
return;
}
@@ -1092,12 +1092,12 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
console.error('Error al eliminar indicación:', err);
throw err;
}
}, [state.indicaciones, state.internaciones, canAccessArea, checkAreaPermission, apiCall]);
}, [state.indicaciones, state.internaciones, canAccessGrupo, checkGrupoPermission, apiCall]);
const agregarMovimientoIndicacion = useCallback(async (movimiento: any) => {
const internacion = state.internaciones.find(i => i.id === movimiento.internacionId);
const areaId = internacion?.areaId || null;
if (!checkAreaPermission(areaId)) {
const grupoId = internacion?.grupoId || null;
if (!checkGrupoPermission(grupoId)) {
console.warn('No tiene permisos para agregar movimiento de indicación en esta área');
return;
}
@@ -1112,7 +1112,7 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
console.error('Error al agregar movimiento:', err);
throw err;
}
}, [state, canAccessArea, checkAreaPermission, apiCall]);
}, [state, canAccessGrupo, checkGrupoPermission, apiCall]);
const getMovimientosByInternacion = useCallback((internacionId: string) => {
return (state.movimientosIndicaciones || [])
@@ -1120,28 +1120,28 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
.sort((a: any, b: any) => new Date(b.fecha).getTime() - new Date(a.fecha).getTime());
}, [state.movimientosIndicaciones]);
// Acciones de areas
const agregarArea = useCallback(async (area: Omit<Area, 'id'>) => {
const nuevaArea: Area = { ...area, id: generateUUID() };
// Acciones de grupos
const agregarGrupo = useCallback(async (grupo: Omit<Grupo, 'id'>) => {
const nuevaGrupo: Grupo = { ...grupo, id: generateUUID() };
try {
await apiCall('POST', '/areas', nuevaArea);
await apiCall('POST', '/grupos', nuevaGrupo);
setState(prev => ({
...prev,
areas: [...prev.areas, nuevaArea],
grupos: [...prev.grupos, nuevaGrupo],
}));
return nuevaArea.id;
return nuevaGrupo.id;
} catch (err) {
console.error('Error al agregar área:', err);
throw err;
}
}, [apiCall]);
const actualizarArea = useCallback(async (id: string, datos: Partial<Area>) => {
const actualizarGrupo = useCallback(async (id: string, datos: Partial<Grupo>) => {
try {
await apiCall('PUT', `/areas/${id}`, datos);
await apiCall('PUT', `/grupos/${id}`, datos);
setState(prev => ({
...prev,
areas: prev.areas.map(a => a.id === id ? { ...a, ...datos } : a),
grupos: prev.grupos.map(a => a.id === id ? { ...a, ...datos } : a),
}));
} catch (err) {
console.error('Error al actualizar área:', err);
@@ -1149,13 +1149,13 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
}
}, [apiCall]);
const eliminarArea = useCallback(async (id: string) => {
const eliminarGrupo = useCallback(async (id: string) => {
try {
await apiCall('DELETE', `/areas/${id}`);
await apiCall('DELETE', `/grupos/${id}`);
setState(prev => ({
...prev,
areas: prev.areas.filter(a => a.id !== id),
camas: prev.camas.map(c => c.areaId === id ? { ...c, areaId: undefined } : c),
grupos: prev.grupos.filter(a => a.id !== id),
camas: prev.camas.map(c => c.grupoId === id ? { ...c, grupoId: undefined } : c),
}));
} catch (err) {
console.error('Error al eliminar área:', err);
@@ -1211,11 +1211,11 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
}, [state.cultivos]);
const getEstadisticas = useCallback(() => {
const fueraDeAreaList = state.camas.filter(c => isCamaFueraDeArea(c, state.areas));
const camasActivas = state.camas.filter(c => !isCamaFueraDeArea(c, state.areas));
const camaPrincipal = state.camas.filter(c => !isCamaFueraDeArea(c, state.areas));
const camaOcupadas = state.camas.filter(c => c.estado === 'Ocupada' && !isCamaFueraDeArea(c, state.areas)).length;
const camasDisponibles = state.camas.filter(c => c.estado === 'Disponible' && !isCamaFueraDeArea(c, state.areas)).length;
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 camasMantenimiento = state.camas.filter(c => c.estado === 'Reparacion').length;
const internacionesActivas = state.internaciones.filter(i => i.activa).length;
const totalPacientes = state.pacientes.length;
@@ -1228,7 +1228,7 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
camasMantenimiento,
totalCamas: state.camas.length,
totalCamasActivas: camasActivas.length,
camasFueraDeArea: fueraDeAreaList.length,
camasFueraDeGrupo: fueraDeGrupoList.length,
internacionesActivas,
totalPacientes,
cultivosPendientes,
@@ -1338,9 +1338,9 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
eliminarIndicacion,
agregarMovimientoIndicacion,
getMovimientosByInternacion,
agregarArea,
actualizarArea,
eliminarArea,
agregarGrupo,
actualizarGrupo,
eliminarGrupo,
getPacienteById,
getCamaById,
getInternacionById,
@@ -1357,14 +1357,14 @@ const actualizarInternacion = useCallback(async (internacionId: string, datos: P
changePassword,
updateEmail,
hasPermission,
canAccessArea,
canAccessGrupo,
canChangeBed,
canEditInternacion,
canEditIngreso,
canEditCama,
canEditPaciente,
getCamaAreaId,
getInternacionAreaId,
getPacienteAreaId,
getCamaGrupoId,
getInternacionGrupoId,
getPacienteGrupoId,
};
}
+13 -10
View File
@@ -38,18 +38,21 @@ export function calcularEdad(fechaNacimiento?: string): string | number {
return edad;
}
export function isCamaFueraDeArea(
cama: { numero: string; areaId?: string },
areas?: { id: string; nombre: string }[]
export function isCamaFueraDeGrupo(
cama: { numero: string; grupoId?: string; areaId?: string },
gruposOrAreas?: { id: string; nombre: string }[]
): boolean {
if (cama.areaId === 'Fuera de Area') {
if (cama.grupoId === 'Fuera de Area' || cama.areaId === 'Fuera de Area') {
return true;
}
if (areas && cama.areaId) {
const area = areas.find(a => (a.nombre || '').toLowerCase().trim() === 'fuera de area');
if (area && cama.areaId === area.id) {
return true;
if (gruposOrAreas) {
const targetId = cama.grupoId || cama.areaId;
if (targetId) {
const g = gruposOrAreas.find(a => (a.nombre || '').toLowerCase().trim() === 'fuera de area');
if (g && targetId === g.id) {
return true;
}
}
}
@@ -61,12 +64,12 @@ export function isCamaFueraDeArea(
const salaNum = parseInt(salaStr, 10);
if (isNaN(salaNum)) return false;
// Formato 3XX que sean impares
// Formato 3XX que sean impares (301, 303, 305, etc.)
if (salaNum >= 300 && salaNum < 400 && salaNum % 2 !== 0) {
return true;
}
// Todas las 4XX (sean pares o impares)
// Formato 4XX (todas las 4XX, pares o impares)
if (salaNum >= 400 && salaNum < 500) {
return true;
}
+1 -1
View File
@@ -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 Area
Camas Fuera de Grupo
</p>
</CardContent>
</Card>
+17 -17
View File
@@ -7,7 +7,7 @@ import { Label } from '@/components/ui/label';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Badge } from '@/components/ui/badge';
import { toast } from 'sonner';
import type { Paciente, Cama, Area, Internacion } from '@/types';
import type { Paciente, Cama, Grupo, Internacion } from '@/types';
import { getNombreProfesional, calcularEdad } from '@/lib/utils';
import { useHospitalStore } from '@/hooks/useHospitalStore';
@@ -17,18 +17,18 @@ interface EditIngresoProps {
cama?: Cama;
pacientes: Paciente[];
camas: Cama[];
areas: Area[];
grupos: Grupo[];
onActualizarInternacion: (id: string, datos: Partial<Internacion>) => Promise<void> | void;
onAgregarCama?: (cama: Omit<Cama, 'id'>) => Promise<string>;
onVolver: () => void;
getAreaName: (areaId: string | undefined) => string;
getGrupoName: (grupoId: string | undefined) => string;
}
export function EditIngreso({
internacion,
pacientes,
camas,
areas,
grupos,
onActualizarInternacion,
onAgregarCama,
onVolver,
@@ -36,7 +36,7 @@ export function EditIngreso({
const { currentUser } = useHospitalStore();
const [pacienteSeleccionado] = useState(internacion.pacienteId);
const [camaSeleccionada] = useState(internacion.camaId);
const [areaSeleccionada] = useState(internacion.areaId);
const [grupoSeleccionada] = useState(internacion.grupoId);
const [camaInput, setCamaInput] = useState('');
const [modoCama, setModoCama] = useState<'seleccionar' | 'escribir'>('seleccionar');
const effectiveMedico = getNombreProfesional(currentUser);
@@ -52,8 +52,8 @@ export function EditIngreso({
const selectedPaciente = pacientes.find(p => p.id === pacienteSeleccionado);
const normalizeStr = (str?: string) => (str || '').normalize('NFD').replace(/[\u0300-\u036f]/g, '').trim().toLowerCase();
const areaFueraDeArea = areas.find(a => normalizeStr(a.nombre) === 'fuera de area');
const areaFueraDeAreaId = areaFueraDeArea?.id || areas[0]?.id || 'fuera-de-area';
const grupoFueraDeGrupo = grupos.find(a => normalizeStr(a.nombre) === 'fuera de grupo');
const grupoFueraDeGrupoId = grupoFueraDeGrupo?.id || grupos[0]?.id || 'fuera-de-grupo';
const parseBedNumber = (numero: string) => {
const match = numero.match(/^(\d{3})-(\d+)$/);
@@ -123,7 +123,7 @@ export function EditIngreso({
try {
let camaId = '';
let newAreaId = '';
let newGrupoId = '';
if (modoCama === 'escribir') {
if (!camaInput.trim()) {
@@ -135,15 +135,15 @@ export function EditIngreso({
const camaExistente = camas.find(c => c.numero === numeroCama);
if (camaExistente) {
camaId = camaExistente.id;
newAreaId = camaExistente.areaId || areaFueraDeAreaId;
newGrupoId = camaExistente.grupoId || grupoFueraDeGrupoId;
} else if (onAgregarCama) {
camaId = await onAgregarCama({
numero: numeroCama,
areaId: areaFueraDeAreaId,
grupoId: grupoFueraDeGrupoId,
tipo: 'General',
estado: 'Ocupada'
});
newAreaId = areaFueraDeAreaId;
newGrupoId = grupoFueraDeGrupoId;
} else {
toast.error('No se puede crear la cama');
setIsSubmitting(false);
@@ -157,10 +157,10 @@ export function EditIngreso({
setIsSubmitting(false);
return;
}
newAreaId = camaElegida.areaId || areaFueraDeAreaId;
newGrupoId = camaElegida.grupoId || grupoFueraDeGrupoId;
camaId = camaSeleccionada;
} else {
newAreaId = areaSeleccionada || internacion.areaId || areaFueraDeAreaId;
newGrupoId = grupoSeleccionada || internacion.grupoId || grupoFueraDeGrupoId;
camaId = internacion.camaId;
}
}
@@ -168,7 +168,7 @@ export function EditIngreso({
await onActualizarInternacion(internacion.id, {
pacienteId: pacienteSeleccionado,
camaId: camaId,
areaId: newAreaId,
grupoId: newGrupoId,
medicoIngresante: effectiveMedico.trim(),
diagnosticoIngreso: diagnosticoIngreso.trim(),
motivoConsulta: motivoConsulta.trim() || undefined,
@@ -290,13 +290,13 @@ export function EditIngreso({
</Card>
</div>
{/* Columna 2: Cama y Área */}
{/* Columna 2: Cama y Grupo */}
<div className="space-y-6">
<Card className="min-h-[200px]">
<CardContent className="pt-6 space-y-4">
<h3 className="font-semibold text-gray-900 dark:text-white flex items-center gap-2">
<Bed className="h-4 w-4" />
Asignación de Cama y Área
Asignación de Cama y Grupo
</h3>
<div className="flex gap-2 mb-4">
@@ -325,7 +325,7 @@ export function EditIngreso({
<SelectContent>
{sortedCamas.map(c => (
<SelectItem key={c.id} value={c.id}>
{c.numero} - {getAreaName(c.areaId)}
{c.numero} - {getGrupoName(c.grupoId)}
</SelectItem>
))}
</SelectContent>
+20 -20
View File
@@ -1,6 +1,6 @@
import { useState, useEffect } from 'react';
import { useHospitalStore } from '@/hooks/useHospitalStore';
import type { Usuario, RolUsuario, Area } from '@/types';
import type { Usuario, RolUsuario, Grupo } from '@/types';
import { Card, CardContent } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
@@ -16,7 +16,7 @@ const API_BASE = import.meta.env.VITE_API_URL || '/api';
export function GestionUsuarios() {
const { currentUser } = useHospitalStore();
const [usuarios, setUsuarios] = useState<Usuario[]>([]);
const [areas, setAreas] = useState<Area[]>([]);
const [grupos, setGrupos] = useState<Grupo[]>([]);
const [loading, setLoading] = useState(true);
const [dialogOpen, setDialogOpen] = useState(false);
const [editUsuario, setEditUsuario] = useState<Usuario | null>(null);
@@ -30,12 +30,12 @@ export function GestionUsuarios() {
rol: 'medico' as RolUsuario,
matriculaProfesional: '',
password: '',
areaId: '',
grupoId: '',
});
useEffect(() => {
fetchUsuarios();
fetchAreas();
fetchGrupos();
}, []);
const fetchUsuarios = async () => {
@@ -50,11 +50,11 @@ export function GestionUsuarios() {
}
};
const fetchAreas = async () => {
const fetchGrupos = async () => {
try {
const res = await fetch(`${API_BASE}/areas`);
const res = await fetch(`${API_BASE}/grupos`);
const data = await res.json();
setAreas(data);
setGrupos(data);
} catch (err) {
console.error(err);
}
@@ -70,7 +70,7 @@ export function GestionUsuarios() {
rol: 'medico',
matriculaProfesional: '',
password: '',
areaId: '',
grupoId: '',
});
setEditUsuario(null);
};
@@ -86,7 +86,7 @@ export function GestionUsuarios() {
rol: usu.rol,
matriculaProfesional: usu.matriculaProfesional || '',
password: '',
areaId: usu.areaId || '',
grupoId: usu.grupoId || '',
});
setDialogOpen(true);
};
@@ -152,9 +152,9 @@ export function GestionUsuarios() {
}
};
const getAreaName = (areaId?: string) => {
if (!areaId) return '-';
return areas.find(a => a.id === areaId)?.nombre || '-';
const getGrupoName = (grupoId?: string) => {
if (!grupoId) return '-';
return grupos.find(a => a.id === grupoId)?.nombre || '-';
};
if (!currentUser || currentUser.rol !== 'admin') {
@@ -191,7 +191,7 @@ export function GestionUsuarios() {
<TableHead>Apellido, Nombre</TableHead>
<TableHead>DNI</TableHead>
<TableHead>Rol</TableHead>
<TableHead>Área</TableHead>
<TableHead>Grupo</TableHead>
<TableHead>Email</TableHead>
<TableHead>Matrícula</TableHead>
<TableHead>Acciones</TableHead>
@@ -207,7 +207,7 @@ export function GestionUsuarios() {
{getRolLabel(usu.rol)}
</Badge>
</TableCell>
<TableCell>{getAreaName(usu.areaId)}</TableCell>
<TableCell>{getGrupoName(usu.grupoId)}</TableCell>
<TableCell>{usu.email || '-'}</TableCell>
<TableCell>{usu.matriculaProfesional || '-'}</TableCell>
<TableCell>
@@ -245,8 +245,8 @@ export function GestionUsuarios() {
<div className="grid grid-cols-2 gap-2 text-sm pt-2 border-t border-gray-100 dark:border-gray-800">
<div>
<span className="text-xs text-gray-400 block">Área</span>
<span className="font-medium text-gray-700 dark:text-gray-300">{getAreaName(usu.areaId)}</span>
<span className="text-xs text-gray-400 block">Grupo</span>
<span className="font-medium text-gray-700 dark:text-gray-300">{getGrupoName(usu.grupoId)}</span>
</div>
<div>
<span className="text-xs text-gray-400 block">Matrícula</span>
@@ -329,14 +329,14 @@ export function GestionUsuarios() {
{form.rol !== 'admin' && (
<div className="space-y-2">
<Label>Área Asignada</Label>
<Select value={form.areaId} onValueChange={(v) => setForm({ ...form, areaId: v })}>
<Label>Grupo Asignado</Label>
<Select value={form.grupoId} onValueChange={(v) => setForm({ ...form, grupoId: v })}>
<SelectTrigger>
<SelectValue placeholder="Seleccionar área" />
</SelectTrigger>
<SelectContent>
{areas.map((area) => (
<SelectItem key={area.id} value={area.id}>{area.nombre}</SelectItem>
{grupos.map((grupo) => (
<SelectItem key={grupo.id} value={grupo.id}>{grupo.nombre}</SelectItem>
))}
</SelectContent>
</Select>
+12 -12
View File
@@ -10,7 +10,7 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu';
import { toast } from 'sonner';
import type { Internacion, Paciente, Cama, Area, Evolucion, Laboratorio, Cultivo } from '@/types';
import type { Internacion, Paciente, Cama, Grupo, Evolucion, Laboratorio, Cultivo } from '@/types';
import { formatDateDDMMYYYY, getNombreProfesional } from '@/lib/utils';
import { useHospitalStore } from '@/hooks/useHospitalStore';
@@ -21,7 +21,7 @@ interface InternacionesProps {
evoluciones?: Evolucion[];
laboratorios?: Laboratorio[];
cultivos?: Cultivo[];
areas: Area[];
grupos: Grupo[];
onIniciarInternacion: (internacion: Omit<Internacion, 'id' | 'activa'>) => void;
onFinalizarInternacion: (internacionId: string, datos: {
fechaEgreso: string;
@@ -42,7 +42,7 @@ export function Internaciones({
onFinalizarInternacion,
getPacienteById,
getCamaById,
areas,
grupos,
onVerHC,
onNuevoIngreso,
}: InternacionesProps) {
@@ -54,7 +54,7 @@ export function Internaciones({
const [busqueda, setBusqueda] = useState('');
const [pacienteSeleccionado, setPacienteSeleccionado] = useState<string>('');
const [camaSeleccionada, setCamaSeleccionada] = useState<string>('');
const [areaSeleccionada, setAreaSeleccionada] = useState<string>('');
const [grupoSeleccionada, setGrupoSeleccionada] = useState<string>('');
const [diagnosticoIngreso, setDiagnosticoIngreso] = useState('');
const [enfermedadActual, setEnfermedadActual] = useState('');
const [motivoConsulta, setMotivoConsulta] = useState('');
@@ -69,7 +69,7 @@ export function Internaciones({
const resetFormularioNueva = () => {
setPacienteSeleccionado('');
setCamaSeleccionada('');
setAreaSeleccionada('');
setGrupoSeleccionada('');
setDiagnosticoIngreso('');
setEnfermedadActual('');
setAntecedentesEnfermedadActual('');
@@ -83,12 +83,12 @@ export function Internaciones({
};
const handleIniciarInternacion = async () => {
if (pacienteSeleccionado && camaSeleccionada && areaSeleccionada && (diagnosticoIngreso || motivoConsulta) && enfermedadActual && effectiveMedico) {
if (pacienteSeleccionado && camaSeleccionada && grupoSeleccionada && (diagnosticoIngreso || motivoConsulta) && enfermedadActual && effectiveMedico) {
try {
await onIniciarInternacion({
pacienteId: pacienteSeleccionado,
camaId: camaSeleccionada,
areaId: areaSeleccionada,
grupoId: grupoSeleccionada,
diagnosticoIngreso: diagnosticoIngreso || motivoConsulta,
motivoConsulta,
enfermedadActual,
@@ -166,7 +166,7 @@ export function Internaciones({
return oa.suborden - ob.suborden;
});
const getAreaName = (areaId?: string) => areas.find(a => a.id === areaId)?.nombre;
const getGrupoName = (grupoId?: string) => grupos.find(a => a.id === grupoId)?.nombre;
const calcularEdad = (fechaNacimiento?: string) => {
if (!fechaNacimiento) return '-';
@@ -286,13 +286,13 @@ export function Internaciones({
)}
</div>
<div>
<Label>Área de Trabajo *</Label>
<Select value={areaSeleccionada} onValueChange={setAreaSeleccionada}>
<Label>Grupo de Trabajo *</Label>
<Select value={grupoSeleccionada} onValueChange={setGrupoSeleccionada}>
<SelectTrigger>
<SelectValue placeholder="Seleccionar área" />
</SelectTrigger>
<SelectContent>
{areas.filter(a => a.nombre !== 'Fuera de area').map(a => (
{grupos.filter(a => a.nombre !== 'Fuera de grupo').map(a => (
<SelectItem key={a.id} value={a.id}>
{a.nombre}
</SelectItem>
@@ -309,7 +309,7 @@ export function Internaciones({
<SelectContent>
{sortedCamas.filter(c => c.estado === 'Disponible').map(c => (
<SelectItem key={c.id} value={c.id}>
{c.numero} - {getAreaName(c.areaId) || 'Sin área'} ({c.tipo})
{c.numero} - {getGrupoName(c.grupoId) || 'Sin grupo'} ({c.tipo})
</SelectItem>
))}
</SelectContent>
+62 -62
View File
@@ -3,76 +3,76 @@ import { Bed, CheckCircle2, Clock, Wrench, User, Plus, Trash, Edit2, Save, X } f
import { Card, CardContent } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { formatDateDDMMYYYY, getNombreProfesional, isCamaFueraDeArea } from '@/lib/utils';
import { formatDateDDMMYYYY, getNombreProfesional, isCamaFueraDeGrupo } from '@/lib/utils';
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Label } from '@/components/ui/label';
import { Input } from '@/components/ui/input';
import type { Cama, Paciente, Internacion, Area } from '@/types';
import type { Cama, Paciente, Internacion, Grupo } from '@/types';
import { useHospitalStore } from '@/hooks/useHospitalStore';
interface MapaCamasProps {
camas: Cama[];
areas: Area[];
grupos: Grupo[];
pacientes: Paciente[];
internaciones: Internacion[];
onActualizarCama: (id: string, datos: Partial<Cama>) => void;
onAgregarCama: (cama: Omit<Cama, 'id'>) => any;
onEliminarCama: (id: string) => void;
onIniciarInternacion: (internacion: Omit<Internacion, 'id' | 'activa'>) => Promise<string>;
onAgregarArea: (area: Omit<Area, 'id'>) => any;
onActualizarArea: (id: string, datos: Partial<Area>) => void;
onEliminarArea: (id: string) => void;
onAgregarGrupo: (grupo: Omit<Grupo, 'id'>) => any;
onActualizarGrupo: (id: string, datos: Partial<Grupo>) => void;
onEliminarGrupo: (id: string) => void;
getPacienteById: (id: string) => Paciente | undefined;
getInternacionById: (id: string) => Internacion | undefined;
}
export function MapaCamas({
camas,
areas,
grupos,
pacientes,
internaciones,
onActualizarCama,
onAgregarCama,
onEliminarCama,
onIniciarInternacion,
onAgregarArea,
onActualizarArea,
onEliminarArea,
onAgregarGrupo,
onActualizarGrupo,
onEliminarGrupo,
getPacienteById,
getInternacionById
}: MapaCamasProps) {
const { canEditCama, canAccessArea, currentUser } = useHospitalStore();
const { canEditCama, canAccessGrupo, currentUser } = useHospitalStore();
const [filtroSala, setFiltroSala] = useState<string>('todas');
const [filtroTipo, setFiltroTipo] = useState<string>('todos');
const [filtroEstado, setFiltroEstado] = useState<string>('todos');
const [camaSeleccionada, setCamaSeleccionada] = useState<Cama | null>(null);
const [areaSeleccionada, setAreaSeleccionada] = useState<string>('');
const [grupoSeleccionada, setGrupoSeleccionada] = useState<string>('');
const [pacienteSeleccionado, setPacienteSeleccionado] = useState<string>('');
const [diagnostico, setDiagnostico] = useState('');
const [enfermedadActual, setEnfermedadActual] = useState('');
const [antecedentesEnfermedadActual, setAntecedentesEnfermedadActual] = useState('');
const effectiveMedico = getNombreProfesional(currentUser);
const [dialogoAbierto, setDialogoAbierto] = useState(false);
// Area dialog state
const [areaDialogOpen, setAreaDialogOpen] = useState(false);
const [areaNombre, setAreaNombre] = useState('');
const [editingAreaId, setEditingAreaId] = useState<string | null>(null);
// Grupo dialog state
const [grupoDialogOpen, setGrupoDialogOpen] = useState(false);
const [grupoNombre, setGrupoNombre] = useState('');
const [editingGrupoId, setEditingGrupoId] = useState<string | null>(null);
// Cama dialog state
const [bedDialogOpen, setBedDialogOpen] = useState(false);
const [editingBed, setEditingBed] = useState<Cama | null>(null);
const [bedNumero, setBedNumero] = useState('');
const [bedTipo, setBedTipo] = useState<Cama['tipo']>('General');
const [bedAreaId, setBedAreaId] = useState<string | undefined>(undefined);
const [bedGrupoId, setBedGrupoId] = useState<string | undefined>(undefined);
const salas = Array.from(new Set(camas.map(c => c.areaId).filter(Boolean))) as string[];
const areaById = Object.fromEntries(areas.map(a => [a.id, a.nombre]));
const salas = Array.from(new Set(camas.map(c => c.grupoId).filter(Boolean))) as string[];
const grupoById = Object.fromEntries(grupos.map(a => [a.id, a.nombre]));
const tipos = Array.from(new Set(camas.map(c => c.tipo)));
const camasFiltradas = camas.filter(cama => {
if (filtroSala !== 'todas' && cama.areaId !== filtroSala) return false;
if (filtroSala !== 'todas' && cama.grupoId !== filtroSala) return false;
if (filtroTipo !== 'todos' && cama.tipo !== filtroTipo) return false;
if (filtroEstado !== 'todos' && cama.estado !== filtroEstado) return false;
return true;
@@ -149,11 +149,11 @@ export function MapaCamas({
});
const handleOcuparCama = () => {
if (camaSeleccionada && areaSeleccionada && pacienteSeleccionado && diagnostico && enfermedadActual && effectiveMedico) {
if (camaSeleccionada && grupoSeleccionada && pacienteSeleccionado && diagnostico && enfermedadActual && effectiveMedico) {
onIniciarInternacion({
pacienteId: pacienteSeleccionado,
camaId: camaSeleccionada.id,
areaId: areaSeleccionada,
grupoId: grupoSeleccionada,
diagnosticoIngreso: diagnostico,
enfermedadActual,
antecedentesEnfermedadActual: antecedentesEnfermedadActual || undefined,
@@ -161,7 +161,7 @@ export function MapaCamas({
});
setDialogoAbierto(false);
setCamaSeleccionada(null);
setAreaSeleccionada('');
setGrupoSeleccionada('');
setPacienteSeleccionado('');
setDiagnostico('');
setEnfermedadActual('');
@@ -187,24 +187,24 @@ export function MapaCamas({
</div>
<div className="flex items-center gap-2">
<Badge variant="outline" className="bg-green-50 text-green-700 dark:bg-green-900 dark:text-green-300 dark:border-green-700">
{camas.filter(c => c.estado === 'Disponible' && !isCamaFueraDeArea(c, areas)).length} Disponibles
{camas.filter(c => c.estado === 'Disponible' && !isCamaFueraDeGrupo(c, grupos)).length} Disponibles
</Badge>
<Badge variant="outline" className="bg-red-50 text-red-700 dark:bg-red-900 dark:text-red-300 dark:border-red-700">
{camas.filter(c => c.estado === 'Ocupada' && !isCamaFueraDeArea(c, areas)).length} Ocupadas
{camas.filter(c => c.estado === 'Ocupada' && !isCamaFueraDeGrupo(c, grupos)).length} Ocupadas
</Badge>
<div className="ml-4 flex items-center gap-2 flex-wrap sm:flex-nowrap">
<Button variant="outline" onClick={() => {
setEditingAreaId(null);
setAreaNombre('');
setAreaDialogOpen(true);
setEditingGrupoId(null);
setGrupoNombre('');
setGrupoDialogOpen(true);
}} className="text-xs px-2 py-1 sm:text-sm sm:px-4 sm:py-2">
Administrar Áreas
Administrar Grupos
</Button>
<Button variant="outline" onClick={() => {
setEditingBed(null);
setBedNumero('');
setBedTipo('General');
setBedAreaId(areas?.[0]?.id);
setBedGrupoId(grupos?.[0]?.id);
setBedDialogOpen(true);
}} className="text-xs px-2 py-1 sm:text-sm sm:px-4 sm:py-2">
<Plus className="h-3 w-3 sm:h-4 sm:w-4 sm:mr-1" />
@@ -219,15 +219,15 @@ export function MapaCamas({
<CardContent className="p-4">
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
<div>
<Label className="text-xs text-gray-500 mb-1 block">Área</Label>
<Label className="text-xs text-gray-500 mb-1 block">Grupo / Área</Label>
<Select value={filtroSala} onValueChange={setFiltroSala}>
<SelectTrigger>
<SelectValue placeholder="Todas las áreas" />
<SelectValue placeholder="Todos los grupos" />
</SelectTrigger>
<SelectContent>
<SelectItem value="todas">Todas las áreas</SelectItem>
<SelectItem value="todas">Todos los grupos</SelectItem>
{salas.map(sala => (
<SelectItem key={sala} value={sala}>{areaById[sala] ?? sala}</SelectItem>
<SelectItem key={sala} value={sala}>{grupoById[sala] ?? sala}</SelectItem>
))}
</SelectContent>
</Select>
@@ -284,7 +284,7 @@ export function MapaCamas({
{getEstadoIcono(cama)}
</div>
<p className="font-bold text-sm sm:text-lg">{cama.numero}</p>
<p className="text-xs opacity-75 truncate">{cama.areaId ? areaById[cama.areaId] ?? 'Área desconocida' : 'Sin área'}</p>
<p className="text-xs opacity-75 truncate">{cama.grupoId ? grupoById[cama.grupoId] ?? 'Grupo desconocido' : 'Sin grupo'}</p>
<Badge variant="outline" className="mt-1 sm:mt-2 text-xs bg-white/50 dark:bg-gray-800 dark:text-gray-300">
{cama.tipo}
</Badge>
@@ -305,7 +305,7 @@ export function MapaCamas({
<DialogHeader>
<DialogTitle className="flex items-center gap-2">
<Bed className="h-5 w-5" />
Cama {cama.numero} - {cama.areaId ? areaById[cama.areaId] ?? 'Área desconocida' : 'Sin área'}
Cama {cama.numero} - {cama.grupoId ? grupoById[cama.grupoId] ?? 'Grupo desconocido' : 'Sin grupo'}
</DialogTitle>
</DialogHeader>
<div className="space-y-4">
@@ -365,13 +365,13 @@ export function MapaCamas({
</Select>
</div>
<div>
<Label>Área de Trabajo *</Label>
<Select value={areaSeleccionada} onValueChange={setAreaSeleccionada}>
<Label>Grupo de Trabajo *</Label>
<Select value={grupoSeleccionada} onValueChange={setGrupoSeleccionada}>
<SelectTrigger>
<SelectValue placeholder="Seleccionar área" />
</SelectTrigger>
<SelectContent>
{areas.filter(a => a.nombre !== 'Fuera de area').map(a => (
{grupos.filter(a => a.nombre !== 'Fuera de grupo').map(a => (
<SelectItem key={a.id} value={a.id}>
{a.nombre}
</SelectItem>
@@ -471,7 +471,7 @@ export function MapaCamas({
setEditingBed(cama);
setBedNumero(cama.numero);
setBedTipo(cama.tipo);
setBedAreaId(cama.areaId);
setBedGrupoId(cama.grupoId);
setBedDialogOpen(true);
}}>
<Edit2 className="h-4 w-4 mr-1" />Editar
@@ -496,46 +496,46 @@ export function MapaCamas({
})}
</div>
{/* Area dialog */}
<Dialog open={areaDialogOpen} onOpenChange={setAreaDialogOpen}>
{/* Grupo dialog */}
<Dialog open={grupoDialogOpen} onOpenChange={setGrupoDialogOpen}>
<DialogContent className="sm:max-w-md">
<DialogHeader>
<DialogTitle>{editingAreaId ? 'Editar Área' : 'Nueva Área'}</DialogTitle>
<DialogTitle>{editingGrupoId ? 'Editar Grupo' : 'Nuevo Grupo'}</DialogTitle>
</DialogHeader>
<div className="space-y-4">
<div>
<Label>Nombre</Label>
<Input value={areaNombre} onChange={(e) => setAreaNombre(e.target.value)} />
<Input value={grupoNombre} onChange={(e) => setGrupoNombre(e.target.value)} />
</div>
<div className="flex gap-2 justify-end">
{editingAreaId && (
<Button size="sm" variant="destructive" onClick={() => { if (confirm('Eliminar área?')) { onEliminarArea(editingAreaId); setAreaDialogOpen(false); } }}>
{editingGrupoId && (
<Button size="sm" variant="destructive" onClick={() => { if (confirm('Eliminar grupo?')) { onEliminarGrupo(editingGrupoId); setGrupoDialogOpen(false); } }}>
<Trash className="h-4 w-4" />
</Button>
)}
<Button size="sm" variant="outline" onClick={() => setAreaDialogOpen(false)}>
<Button size="sm" variant="outline" onClick={() => setGrupoDialogOpen(false)}>
<X className="h-4 w-4" />
</Button>
<Button size="sm" variant="outline" onClick={() => {
if (!areaNombre.trim()) return alert('Nombre requerido');
if (editingAreaId) onActualizarArea(editingAreaId, { nombre: areaNombre });
else onAgregarArea({ nombre: areaNombre });
setAreaDialogOpen(false);
if (!grupoNombre.trim()) return alert('Nombre requerido');
if (editingGrupoId) onActualizarGrupo(editingGrupoId, { nombre: grupoNombre });
else onAgregarGrupo({ nombre: grupoNombre });
setGrupoDialogOpen(false);
}}>
<Save className="h-4 w-4" />
</Button>
</div>
<div>
<p className="text-sm font-medium">Áreas existentes</p>
<p className="text-sm font-medium">Grupos existentes</p>
<div className="mt-2 space-y-2">
{areas.map(a => (
{grupos.map(a => (
<div key={a.id} className="flex items-center justify-between">
<div>{a.nombre}</div>
<div className="flex gap-1">
<Button size="sm" variant="outline" onClick={() => { setEditingAreaId(a.id); setAreaNombre(a.nombre); }}>
<Button size="sm" variant="outline" onClick={() => { setEditingGrupoId(a.id); setGrupoNombre(a.nombre); }}>
<Edit2 className="h-4 w-4" />
</Button>
<Button size="sm" variant="outline" className="text-red-600" onClick={() => { if (confirm('Eliminar área?')) onEliminarArea(a.id); }}>
<Button size="sm" variant="outline" className="text-red-600" onClick={() => { if (confirm('Eliminar grupo?')) onEliminarGrupo(a.id); }}>
<Trash className="h-4 w-4" />
</Button>
</div>
@@ -574,14 +574,14 @@ export function MapaCamas({
</Select>
</div>
<div>
<Label>Área</Label>
<Select value={bedAreaId ?? '__none'} onValueChange={(v) => setBedAreaId(v === '__none' ? undefined : v)}>
<Label>Grupo / Área</Label>
<Select value={bedGrupoId ?? '__none'} onValueChange={(v) => setBedGrupoId(v === '__none' ? undefined : v)}>
<SelectTrigger>
<SelectValue placeholder="Seleccione área" />
<SelectValue placeholder="Seleccione grupo" />
</SelectTrigger>
<SelectContent>
<SelectItem value="__none">Sin área</SelectItem>
{areas.map(a => (
<SelectItem value="__none">Sin grupo</SelectItem>
{grupos.map(a => (
<SelectItem key={a.id} value={a.id}>{a.nombre}</SelectItem>
))}
</SelectContent>
@@ -597,9 +597,9 @@ export function MapaCamas({
<Button variant="outline" onClick={() => {
if (!bedNumero.trim()) return alert('Número requerido');
if (editingBed) {
onActualizarCama(editingBed.id, { numero: bedNumero, tipo: bedTipo, areaId: bedAreaId });
onActualizarCama(editingBed.id, { numero: bedNumero, tipo: bedTipo, grupoId: bedGrupoId });
} else {
onAgregarCama({ numero: bedNumero, tipo: bedTipo, estado: 'Disponible', areaId: bedAreaId });
onAgregarCama({ numero: bedNumero, tipo: bedTipo, estado: 'Disponible', grupoId: bedGrupoId });
}
setBedDialogOpen(false);
}}>Guardar</Button>
+15 -15
View File
@@ -7,23 +7,23 @@ import { Label } from '@/components/ui/label';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Badge } from '@/components/ui/badge';
import { toast } from 'sonner';
import type { Paciente, Cama, Area, Internacion } from '@/types';
import type { Paciente, Cama, Grupo, Internacion } from '@/types';
import { getNombreProfesional } from '@/lib/utils';
import { useHospitalStore } from '@/hooks/useHospitalStore';
interface NuevoIngresoProps {
pacientes: Paciente[];
camas: Cama[];
areas: Area[];
grupos: Grupo[];
onIniciarInternacion: (internacion: Omit<Internacion, 'id' | 'activa'>) => Promise<string>;
onAgregarCama?: (cama: Omit<Cama, 'id'>) => Promise<string>;
onAgregarPaciente?: (paciente: Omit<Paciente, 'id'>) => void;
onActualizarPaciente?: (id: string, datos: Partial<Paciente>) => void;
onVolver: () => void;
getAreaName: (areaId: string | undefined) => string;
getGrupoName: (grupoId: string | undefined) => string;
}
export function NuevoIngreso({ pacientes, camas, areas, onIniciarInternacion, onAgregarCama, onVolver, getAreaName }: NuevoIngresoProps) {
export function NuevoIngreso({ pacientes, camas, grupos, onIniciarInternacion, onAgregarCama, onVolver, getGrupoName }: NuevoIngresoProps) {
const { currentUser } = useHospitalStore();
const [pacienteSeleccionado, setPacienteSeleccionado] = useState<string>('');
const [busqueda, setBusqueda] = useState('');
@@ -58,8 +58,8 @@ export function NuevoIngreso({ pacientes, camas, areas, onIniciarInternacion, on
const normalizeStr = (str?: string) => (str || '').normalize('NFD').replace(/[\u0300-\u036f]/g, '').trim().toLowerCase();
const areaFueraDeArea = areas.find(a => normalizeStr(a.nombre) === 'fuera de area');
const areaFueraDeAreaId = areaFueraDeArea?.id || areas[0]?.id || 'fuera-de-area';
const grupoFueraDeGrupo = grupos.find(a => normalizeStr(a.nombre) === 'fuera de grupo');
const grupoFueraDeGrupoId = grupoFueraDeGrupo?.id || grupos[0]?.id || 'fuera-de-grupo';
const pacientesSinInternar = pacientes;
@@ -142,22 +142,22 @@ export function NuevoIngreso({ pacientes, camas, areas, onIniciarInternacion, on
try {
let camaId = '';
let newAreaId = '';
let newGrupoId = '';
if (modoCama === 'escribir') {
const numeroCama = camaInput.trim();
const camaExistente = camas.find(c => c.numero === numeroCama);
if (camaExistente) {
camaId = camaExistente.id;
newAreaId = camaExistente.areaId || areaFueraDeAreaId;
newGrupoId = camaExistente.grupoId || grupoFueraDeGrupoId;
} else if (onAgregarCama) {
camaId = await onAgregarCama({
numero: numeroCama,
areaId: areaFueraDeAreaId,
grupoId: grupoFueraDeGrupoId,
tipo: 'General',
estado: 'Ocupada'
});
newAreaId = areaFueraDeAreaId;
newGrupoId = grupoFueraDeGrupoId;
} else {
toast.error('No se puede crear la cama');
setIsSubmitting(false);
@@ -171,13 +171,13 @@ export function NuevoIngreso({ pacientes, camas, areas, onIniciarInternacion, on
return;
}
camaId = camaSeleccionada;
newAreaId = camaElegida.areaId || areaFueraDeAreaId;
newGrupoId = camaElegida.grupoId || grupoFueraDeGrupoId;
}
await onIniciarInternacion({
pacienteId: pacienteSeleccionado,
camaId: camaId,
areaId: newAreaId,
grupoId: newGrupoId,
medicoIngresante: effectiveMedico.trim(),
diagnosticoIngreso: diagnosticoIngreso.trim(),
motivoConsulta: motivoConsulta.trim() || undefined,
@@ -293,13 +293,13 @@ export function NuevoIngreso({ pacientes, camas, areas, onIniciarInternacion, on
</Card>
</div>
{/* Columna 2: Cama y Área */}
{/* Columna 2: Cama y Grupo */}
<div className="space-y-6">
<Card className="min-h-[200px]">
<CardContent className="pt-6 space-y-4">
<h3 className="font-semibold text-gray-900 dark:text-white flex items-center gap-2">
<Bed className="h-4 w-4" />
Asignación de Cama y Área
Asignación de Cama y Grupo
</h3>
<div className="flex flex-col sm:flex-row gap-2 mb-4">
@@ -330,7 +330,7 @@ export function NuevoIngreso({ pacientes, camas, areas, onIniciarInternacion, on
<SelectContent>
{sortedCamas.map(c => (
<SelectItem key={c.id} value={c.id}>
{c.numero} - {getAreaName(c.areaId)}
{c.numero} - {getGrupoName(c.grupoId)}
</SelectItem>
))}
</SelectContent>
+11 -6
View File
@@ -21,9 +21,17 @@ export interface Paciente {
}
export interface Grupo {
id: string;
nombre: string;
}
export type Area = Grupo;
export interface Cama {
id: string;
numero: string;
grupoId?: string;
areaId?: string;
tipo: 'General' | 'Aislamiento KPC' | 'Aislamiento COVID' | 'Aislamiento Clostridium' | 'Aislamiento Neutropenico';
estado: 'Disponible' | 'Ocupada' | 'Reparacion' | 'Reservada';
@@ -31,16 +39,12 @@ export interface Cama {
internacionId?: string;
}
export interface Area {
id: string;
nombre: string;
}
export interface Internacion {
id: string;
pacienteId: string;
camaId: string;
areaId: string;
grupoId?: string;
areaId?: string;
fechaIngresoHospital?: string;
fechaIngresoClinica?: string;
fechaEgreso?: string;
@@ -229,6 +233,7 @@ export interface Usuario {
rol: RolUsuario;
matriculaProfesional?: string;
passwordHash: string;
grupoId?: string;
areaId?: string;
fechaCreacion: string;
}