1518 lines
53 KiB
TypeScript
1518 lines
53 KiB
TypeScript
import { useState, useEffect, useCallback } from 'react';
|
|
import { toast } from 'sonner';
|
|
import { getNombreProfesional, isCamaFueraDeGrupo, computeSector } from '@/lib/utils';
|
|
import type {
|
|
Paciente,
|
|
Cama,
|
|
Grupo,
|
|
Internacion,
|
|
Evolucion,
|
|
Laboratorio,
|
|
Glucemia,
|
|
AcidoBase,
|
|
Cultivo,
|
|
EstudioComplementario,
|
|
Interconsulta,
|
|
ATB,
|
|
Indicacion,
|
|
MovimientoIndicacion,
|
|
Pendiente,
|
|
Vista,
|
|
Usuario
|
|
} from '@/types';
|
|
|
|
// Fallback UUID generator for non-secure contexts (HTTP without localhost)
|
|
function generateUUID(): string {
|
|
if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
|
|
return crypto.randomUUID();
|
|
}
|
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
|
const r = (Math.random() * 16) | 0;
|
|
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
|
return v.toString(16);
|
|
});
|
|
}
|
|
|
|
|
|
interface HospitalState {
|
|
pacientes: Paciente[];
|
|
camas: Cama[];
|
|
grupos: Grupo[];
|
|
internaciones: Internacion[];
|
|
evoluciones: Evolucion[];
|
|
laboratorios: Laboratorio[];
|
|
glucemias: Glucemia[];
|
|
acidosBase: AcidoBase[];
|
|
cultivos: Cultivo[];
|
|
estudiosComplementarios: EstudioComplementario[];
|
|
interconsultas: Interconsulta[];
|
|
atb: ATB[];
|
|
indicaciones: Indicacion[];
|
|
movimientosIndicaciones: MovimientoIndicacion[];
|
|
pendientes: Pendiente[];
|
|
vistaActual: Vista;
|
|
currentInternacionId?: string | null;
|
|
usuarios: Usuario[];
|
|
currentUser: Usuario | null;
|
|
isAuthenticated: boolean;
|
|
}
|
|
|
|
|
|
const API_BASE = import.meta.env.VITE_API_URL || '/api';
|
|
|
|
const defaultState = (): HospitalState => ({
|
|
pacientes: [],
|
|
grupos: [],
|
|
internaciones: [],
|
|
evoluciones: [],
|
|
laboratorios: [],
|
|
glucemias: [],
|
|
acidosBase: [],
|
|
cultivos: [],
|
|
estudiosComplementarios: [],
|
|
interconsultas: [],
|
|
atb: [],
|
|
vistaActual: 'dashboard',
|
|
indicaciones: [],
|
|
movimientosIndicaciones: [],
|
|
pendientes: [],
|
|
camas: [],
|
|
usuarios: [],
|
|
currentUser: null,
|
|
isAuthenticated: false,
|
|
});
|
|
|
|
export function useHospitalStore() {
|
|
const [state, setState] = useState<HospitalState>(defaultState);
|
|
const [isLoaded, setIsLoaded] = useState(false);
|
|
|
|
// Load state from backend on mount
|
|
useEffect(() => {
|
|
let mounted = true;
|
|
(async () => {
|
|
try {
|
|
const res = await fetch(`${API_BASE}/state`);
|
|
if (!res.ok) throw new Error('no state');
|
|
const body = await res.json();
|
|
if (mounted && body) {
|
|
const defaults = defaultState();
|
|
const storedUser = sessionStorage.getItem('hospital_user');
|
|
const storedInternacionId = sessionStorage.getItem('hospital_current_internacion_id');
|
|
const currentUser = storedUser ? JSON.parse(storedUser) : null;
|
|
const normalized = {
|
|
...defaults,
|
|
...body,
|
|
estudiosComplementarios: body.estudiosComplementarios || [],
|
|
interconsultas: body.interconsultas || [],
|
|
atb: body.atb || [],
|
|
glucemias: body.glucemias || [],
|
|
movimientosIndicaciones: body.movimientosIndicaciones || [],
|
|
pendientes: body.pendientes || [],
|
|
currentInternacionId: storedInternacionId || body.currentInternacionId || null,
|
|
currentUser,
|
|
isAuthenticated: !!currentUser,
|
|
};
|
|
setState(normalized);
|
|
}
|
|
} catch {
|
|
// no remote state or unreachable — keep defaults
|
|
} finally {
|
|
if (mounted) setIsLoaded(true);
|
|
}
|
|
})();
|
|
return () => { mounted = false; };
|
|
}, []);
|
|
|
|
// Helper to make API calls with error handling
|
|
const apiCall = useCallback(async (method: string, endpoint: string, data?: unknown) => {
|
|
try {
|
|
const res = await fetch(`${API_BASE}${endpoint}`, {
|
|
method,
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: data ? JSON.stringify(data) : undefined,
|
|
});
|
|
if (!res.ok) {
|
|
let errText = res.statusText;
|
|
try {
|
|
const errData = await res.json();
|
|
if (errData && errData.error) errText = errData.error;
|
|
} catch {
|
|
// ignore json parse error
|
|
}
|
|
throw new Error(`API error: ${errText}`);
|
|
}
|
|
const text = await res.text();
|
|
try {
|
|
return JSON.parse(text);
|
|
} catch {
|
|
return { ok: true };
|
|
}
|
|
} catch (err) {
|
|
console.error(`API call failed: ${method} ${endpoint}`, err);
|
|
throw err;
|
|
}
|
|
}, []);
|
|
|
|
// Utility functions
|
|
const getCamaGrupoId = useCallback((camaId: string): string | null => {
|
|
const cama = state.camas.find(c => c.id === camaId);
|
|
return cama?.grupoId || null;
|
|
}, [state.camas]);
|
|
|
|
const getInternacionGrupoId = useCallback((internacionId: string): string | null => {
|
|
const internacion = state.internaciones.find(i => i.id === internacionId);
|
|
if (!internacion) return null;
|
|
return internacion.grupoId || getCamaGrupoId(internacion.camaId) || null;
|
|
}, [state.internaciones, getCamaGrupoId]);
|
|
|
|
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 getCamaGrupoId(anyInternacion.camaId);
|
|
return null;
|
|
}
|
|
return internacion.grupoId || getCamaGrupoId(internacion.camaId) || null;
|
|
}, [state.internaciones, getCamaGrupoId]);
|
|
|
|
// Permission functions
|
|
const canAccessGrupo = useCallback((grupoId: string | null | undefined): boolean => {
|
|
const user = state.currentUser;
|
|
if (!user) return false;
|
|
if (user.rol === 'admin') return true;
|
|
if (!grupoId) return true;
|
|
if (!user.grupoId) return true;
|
|
return user.grupoId === grupoId;
|
|
}, [state.currentUser]);
|
|
|
|
const checkGrupoPermission = useCallback((grupoId: string | null | undefined): boolean => {
|
|
const allowed = canAccessGrupo(grupoId);
|
|
if (!allowed) {
|
|
toast.error("no pertenecen al grupo de trabajo por la que se encuentra internado el paciente");
|
|
}
|
|
return allowed;
|
|
}, [canAccessGrupo]);
|
|
|
|
const canChangeBed = useCallback((internacionId: string): boolean => {
|
|
const internacion = state.internaciones.find(i => i.id === internacionId);
|
|
if (!internacion) return false;
|
|
return canAccessGrupo(internacion.grupoId);
|
|
}, [state.internaciones, canAccessGrupo]);
|
|
|
|
const canEditInternacion = useCallback((internacionId: string): boolean => {
|
|
const grupoId = getInternacionGrupoId(internacionId);
|
|
return canAccessGrupo(grupoId);
|
|
}, [getInternacionGrupoId, canAccessGrupo]);
|
|
|
|
const canEditIngreso = useCallback((internacionId: string): boolean => {
|
|
const internacion = state.internaciones.find(i => i.id === internacionId);
|
|
if (!internacion) return false;
|
|
const normalizeMedicoName = (name?: string) => {
|
|
return (name || '').trim().toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '');
|
|
};
|
|
const userProfesionalName = getNombreProfesional(state.currentUser);
|
|
const grupoId = getInternacionGrupoId(internacionId);
|
|
return state.currentUser?.rol === 'admin' ||
|
|
state.currentUser?.rol === 'medico' ||
|
|
canAccessGrupo(grupoId) ||
|
|
!internacion.medicoIngresante ||
|
|
(normalizeMedicoName(internacion.medicoIngresante) === normalizeMedicoName(userProfesionalName));
|
|
}, [state.internaciones, state.currentUser, getInternacionGrupoId, canAccessGrupo]);
|
|
|
|
const canEditCama = useCallback((camaId: string): boolean => {
|
|
const grupoId = getCamaGrupoId(camaId);
|
|
return canAccessGrupo(grupoId);
|
|
}, [getCamaGrupoId, canAccessGrupo]);
|
|
|
|
const canEditPaciente = useCallback((pacienteId: string): boolean => {
|
|
const grupoId = getPacienteGrupoId(pacienteId);
|
|
return canAccessGrupo(grupoId);
|
|
}, [getPacienteGrupoId, canAccessGrupo]);
|
|
|
|
const hasPermission = useCallback((permission: 'read' | 'write', section: string): boolean => {
|
|
const user = state.currentUser;
|
|
if (!user) return false;
|
|
if (user.rol === 'admin') return true;
|
|
if (user.rol === 'enfermero') {
|
|
if (section === 'glucemias' || section === 'signosvitales') return permission === 'read' || permission === 'write';
|
|
return permission === 'read';
|
|
}
|
|
if (user.rol === 'medico') {
|
|
if (section === 'miGrupo') return permission === 'read' || permission === 'write';
|
|
return permission === 'read';
|
|
}
|
|
return false;
|
|
}, [state.currentUser]);
|
|
|
|
// Acciones de navegación
|
|
const setVista = useCallback((vista: Vista) => {
|
|
setState(prev => ({ ...prev, vistaActual: vista }));
|
|
}, []);
|
|
|
|
// Acciones de pacientes
|
|
const agregarPaciente = useCallback(async (paciente: Omit<Paciente, 'id' | 'fechaRegistro'>) => {
|
|
const nuevoPaciente: Paciente = {
|
|
...paciente,
|
|
id: generateUUID(),
|
|
fechaRegistro: new Date().toISOString().split('T')[0],
|
|
};
|
|
try {
|
|
await apiCall('POST', '/pacientes', nuevoPaciente);
|
|
setState(prev => ({
|
|
...prev,
|
|
pacientes: [...prev.pacientes, nuevoPaciente],
|
|
}));
|
|
return nuevoPaciente.id;
|
|
} catch (err) {
|
|
console.error('Error al agregar paciente:', err);
|
|
throw err;
|
|
}
|
|
}, [apiCall]);
|
|
|
|
const actualizarPaciente = useCallback(async (id: string, datos: Partial<Paciente>) => {
|
|
const grupoId = getPacienteGrupoId(id);
|
|
if (!checkGrupoPermission(grupoId)) return;
|
|
try {
|
|
await apiCall('PUT', `/pacientes/${id}`, datos);
|
|
setState(prev => ({
|
|
...prev,
|
|
pacientes: prev.pacientes.map(p => p.id === id ? { ...p, ...datos } : p),
|
|
}));
|
|
} catch (err) {
|
|
console.error('Error al actualizar paciente:', err);
|
|
throw err;
|
|
}
|
|
}, [apiCall, checkGrupoPermission, getPacienteGrupoId]);
|
|
|
|
const eliminarPaciente = useCallback(async (id: string) => {
|
|
const grupoId = getPacienteGrupoId(id);
|
|
if (!checkGrupoPermission(grupoId)) return;
|
|
try {
|
|
await apiCall('DELETE', `/pacientes/${id}`);
|
|
setState(prev => ({
|
|
...prev,
|
|
pacientes: prev.pacientes.filter(p => p.id !== id),
|
|
}));
|
|
} catch (err) {
|
|
console.error('Error al eliminar paciente:', err);
|
|
throw err;
|
|
}
|
|
}, [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 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;
|
|
}
|
|
try {
|
|
if (datos.numero !== undefined) {
|
|
datos.sector = computeSector(datos.numero);
|
|
}
|
|
await apiCall('PUT', `/camas/${id}`, datos);
|
|
setState(prev => ({
|
|
...prev,
|
|
camas: prev.camas.map(c => c.id === id ? { ...c, ...datos } : c),
|
|
}));
|
|
} catch (err) {
|
|
console.error('Error al actualizar cama:', err);
|
|
throw err;
|
|
}
|
|
}, [state, apiCall]);
|
|
|
|
const agregarCama = useCallback(async (cama: Omit<Cama, 'id'>) => {
|
|
const nuevaCama: Cama = {
|
|
...cama,
|
|
id: generateUUID(),
|
|
sector: computeSector(cama.numero),
|
|
} as Cama;
|
|
try {
|
|
await apiCall('POST', '/camas', nuevaCama);
|
|
setState(prev => ({
|
|
...prev,
|
|
camas: [...prev.camas, nuevaCama],
|
|
}));
|
|
return nuevaCama.id;
|
|
} catch (err) {
|
|
console.error('Error al agregar cama:', err);
|
|
throw err;
|
|
}
|
|
}, [apiCall]);
|
|
|
|
const eliminarCama = useCallback(async (id: string) => {
|
|
try {
|
|
await apiCall('DELETE', `/camas/${id}`);
|
|
setState(prev => ({
|
|
...prev,
|
|
camas: prev.camas.filter(c => c.id !== id),
|
|
internaciones: prev.internaciones.map(i => i.camaId === id ? { ...i, activa: false } : i),
|
|
}));
|
|
} catch (err) {
|
|
console.error('Error al eliminar cama:', err);
|
|
throw err;
|
|
}
|
|
}, [apiCall]);
|
|
|
|
// Acciones de internaciones
|
|
const iniciarInternacion = useCallback(async (internacion: Omit<Internacion, 'id' | 'activa'>) => {
|
|
if (!checkGrupoPermission(internacion.grupoId)) {
|
|
return null;
|
|
}
|
|
const nuevaInternacion: Internacion = {
|
|
...internacion,
|
|
id: generateUUID(),
|
|
activa: true,
|
|
};
|
|
try {
|
|
// API call inmediata para crear internación
|
|
await apiCall('POST', '/internaciones', nuevaInternacion);
|
|
|
|
// Actualizar estado de la cama en la base de datos
|
|
if (internacion.camaId) {
|
|
await apiCall('PUT', `/camas/${internacion.camaId}`, {
|
|
estado: 'Ocupada',
|
|
pacienteId: internacion.pacienteId,
|
|
internacionId: nuevaInternacion.id
|
|
});
|
|
}
|
|
|
|
// Actualizar estado local después del éxito
|
|
setState(prev => ({
|
|
...prev,
|
|
internaciones: [...prev.internaciones, nuevaInternacion],
|
|
camas: prev.camas.map(c =>
|
|
c.id === internacion.camaId
|
|
? { ...c, estado: 'Ocupada' as const, pacienteId: internacion.pacienteId, internacionId: nuevaInternacion.id }
|
|
: c
|
|
),
|
|
}));
|
|
|
|
return nuevaInternacion.id;
|
|
} catch (err) {
|
|
console.error('Error al crear internación:', err);
|
|
throw err;
|
|
}
|
|
}, [apiCall, checkGrupoPermission]);
|
|
|
|
const finalizarInternacion = useCallback(async (internacionId: string, datos: {
|
|
fechaEgreso: string;
|
|
diagnosticoEgreso: string;
|
|
motivoEgreso: Internacion['motivoEgreso']
|
|
}) => {
|
|
const internacion = state.internaciones.find(i => i.id === internacionId);
|
|
if (!internacion) return;
|
|
|
|
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 {
|
|
// API call inmediata para finalizar internación
|
|
await apiCall('PUT', `/internaciones/${internacionId}`, { ...datos, activa: false });
|
|
|
|
// Eliminar o actualizar la cama según el área
|
|
if (camaId) {
|
|
if (esFueraDeGrupo) {
|
|
// Eliminar la cama si es "Fuera de área"
|
|
await apiCall('DELETE', `/camas/${camaId}`);
|
|
} else {
|
|
// Marcar como disponible si es un área normal
|
|
await apiCall('PUT', `/camas/${camaId}`, {
|
|
estado: 'Disponible',
|
|
pacienteId: null,
|
|
internacionId: null
|
|
});
|
|
}
|
|
}
|
|
|
|
// Actualizar estado local después del éxito
|
|
setState(prev => {
|
|
return {
|
|
...prev,
|
|
internaciones: prev.internaciones.map(i =>
|
|
i.id === internacionId
|
|
? { ...i, ...datos, activa: false }
|
|
: i
|
|
),
|
|
camas: esFueraDeGrupo
|
|
? prev.camas.filter(c => c.id !== camaId)
|
|
: prev.camas.map(c =>
|
|
c.id === camaId
|
|
? { ...c, estado: 'Disponible' as const, pacienteId: undefined, internacionId: undefined }
|
|
: c
|
|
),
|
|
};
|
|
});
|
|
} catch (err) {
|
|
console.error('Error al finalizar internación:', err);
|
|
throw err;
|
|
}
|
|
}, [state, apiCall]);
|
|
|
|
const eliminarInternacion = useCallback(async (internacionId: string) => {
|
|
const internacion = state.internaciones.find(i => i.id === internacionId);
|
|
if (!internacion) return;
|
|
const grupoId = internacion.grupoId || null;
|
|
if (!checkGrupoPermission(grupoId)) {
|
|
console.warn('No tiene permisos para eliminar internación en esta área');
|
|
toast.error('No tiene permisos para eliminar internación en esta área');
|
|
return;
|
|
}
|
|
|
|
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 {
|
|
await apiCall('DELETE', `/internaciones/${internacionId}`);
|
|
if (camaId) {
|
|
if (esFueraDeGrupo) {
|
|
await apiCall('DELETE', `/camas/${camaId}`);
|
|
} else {
|
|
await apiCall('PUT', `/camas/${camaId}`, {
|
|
estado: 'Disponible',
|
|
pacienteId: null,
|
|
internacionId: null
|
|
});
|
|
}
|
|
}
|
|
|
|
setState(prev => ({
|
|
...prev,
|
|
internaciones: prev.internaciones.filter(i => i.id !== internacionId),
|
|
camas: esFueraDeGrupo
|
|
? prev.camas.filter(c => c.id !== camaId)
|
|
: prev.camas.map(c =>
|
|
c.id === camaId
|
|
? { ...c, estado: 'Disponible' as const, pacienteId: undefined, internacionId: undefined }
|
|
: c
|
|
),
|
|
evoluciones: prev.evoluciones.filter(e => e.internacionId !== internacionId),
|
|
laboratorios: prev.laboratorios.filter(l => l.internacionId !== internacionId),
|
|
glucemias: prev.glucemias.filter(g => g.internacionId !== internacionId),
|
|
acidosBase: prev.acidosBase.filter(a => a.internacionId !== internacionId),
|
|
cultivos: prev.cultivos.filter(c => c.internacionId !== internacionId),
|
|
estudiosComplementarios: prev.estudiosComplementarios.filter(e => e.internacionId !== internacionId),
|
|
interconsultas: (prev.interconsultas || []).filter(ic => ic.internacionId !== internacionId),
|
|
atb: (prev.atb || []).filter(a => a.internacionId !== internacionId),
|
|
indicaciones: (prev.indicaciones || []).filter(i => i.internacionId !== internacionId),
|
|
}));
|
|
toast.success('Historia clínica de internación eliminada correctamente');
|
|
} catch (err) {
|
|
console.error('Error al eliminar internación:', err);
|
|
toast.error('Error al eliminar internación');
|
|
throw err;
|
|
}
|
|
}, [state, checkGrupoPermission, apiCall]);
|
|
|
|
const actualizarInternacion = useCallback(async (internacionId: string, datos: Partial<Internacion>) => {
|
|
const internacion = state.internaciones.find(i => i.id === internacionId);
|
|
if (!internacion) return;
|
|
|
|
// Check permissions
|
|
if (!canEditIngreso(internacionId)) {
|
|
toast.error(`No tiene permisos para modificar este ingreso.`);
|
|
return;
|
|
}
|
|
|
|
const oldCamaId = internacion.camaId;
|
|
const newCamaId = datos.camaId;
|
|
const cambioDeCama = newCamaId && newCamaId !== oldCamaId;
|
|
|
|
if (cambioDeCama && !canChangeBed(internacionId)) {
|
|
console.warn('No tiene permisos para cambiar la cama de esta internación');
|
|
checkGrupoPermission(null); // triggers toast
|
|
return;
|
|
}
|
|
|
|
if (!cambioDeCama && !checkGrupoPermission(internacion.grupoId)) {
|
|
console.warn('No tiene permisos para actualizar esta internación');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
// API call inmediata
|
|
await apiCall('PUT', `/internaciones/${internacionId}`, datos);
|
|
|
|
// Si hay cambio de cama, actualizar estados en la base de datos
|
|
if (cambioDeCama && newCamaId && oldCamaId) {
|
|
await apiCall('PUT', `/camas/${newCamaId}`, {
|
|
estado: 'Ocupada'
|
|
});
|
|
await apiCall('PUT', `/camas/${oldCamaId}`, {
|
|
estado: 'Disponible'
|
|
});
|
|
}
|
|
|
|
// Actualizar estado local después del éxito
|
|
setState(prev => {
|
|
const result = {
|
|
...prev,
|
|
internaciones: prev.internaciones.map(i =>
|
|
i.id === internacionId
|
|
? { ...i, ...datos }
|
|
: i
|
|
),
|
|
camas: prev.camas.map(c => {
|
|
if (c.id === newCamaId && newCamaId !== oldCamaId) {
|
|
return { ...c, estado: 'Ocupada' as const };
|
|
}
|
|
if (c.id === oldCamaId && oldCamaId !== newCamaId) {
|
|
return { ...c, estado: 'Disponible' as const };
|
|
}
|
|
return c;
|
|
}),
|
|
};
|
|
return result;
|
|
});
|
|
} catch (err) {
|
|
console.error('Error al actualizar internación:', err);
|
|
throw err;
|
|
}
|
|
}, [state, canChangeBed, canEditIngreso, checkGrupoPermission, apiCall]);
|
|
|
|
// Acciones de evoluciones
|
|
const agregarEvolucion = useCallback(async (evolucion: Omit<Evolucion, 'id'>) => {
|
|
const internacion = state.internaciones.find(i => i.id === evolucion.internacionId);
|
|
const grupoId = internacion?.grupoId || null;
|
|
if (!checkGrupoPermission(grupoId)) {
|
|
console.warn('No tiene permisos para agregar evolución en esta área');
|
|
return null;
|
|
}
|
|
const nuevaEvolucion: Evolucion = {
|
|
...evolucion,
|
|
id: generateUUID(),
|
|
};
|
|
|
|
try {
|
|
await apiCall('POST', '/evoluciones', nuevaEvolucion);
|
|
setState(prev => ({
|
|
...prev,
|
|
evoluciones: [...prev.evoluciones, nuevaEvolucion],
|
|
}));
|
|
return nuevaEvolucion.id;
|
|
} catch (err) {
|
|
console.error('Error al agregar evolución:', err);
|
|
throw err;
|
|
}
|
|
}, [state, 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 grupoId = internacion?.grupoId || null;
|
|
if (!checkGrupoPermission(grupoId)) {
|
|
console.warn('No tiene permisos para eliminar evolución en esta área');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
await apiCall('DELETE', `/evoluciones/${id}`);
|
|
setState(prev => ({
|
|
...prev,
|
|
evoluciones: prev.evoluciones.filter(e => e.id !== id),
|
|
}));
|
|
} catch (err) {
|
|
console.error('Error al eliminar evolución:', err);
|
|
throw err;
|
|
}
|
|
}, [state, 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 grupoId = internacion?.grupoId || null;
|
|
if (!checkGrupoPermission(grupoId)) {
|
|
console.warn('No tiene permisos para actualizar evolución en esta área');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
await apiCall('PUT', `/evoluciones/${id}`, datos);
|
|
setState(prev => ({
|
|
...prev,
|
|
evoluciones: prev.evoluciones.map(e => e.id === id ? { ...e, ...datos } : e),
|
|
}));
|
|
} catch (err) {
|
|
console.error('Error al actualizar evolución:', err);
|
|
throw err;
|
|
}
|
|
}, [state, checkGrupoPermission, apiCall]);
|
|
|
|
// Acciones de laboratorios
|
|
const agregarLaboratorio = useCallback(async (laboratorio: Omit<Laboratorio, 'id'>) => {
|
|
const internacion = state.internaciones.find(i => i.id === laboratorio.internacionId);
|
|
const grupoId = internacion?.grupoId || null;
|
|
if (!checkGrupoPermission(grupoId)) {
|
|
console.warn('No tiene permisos para agregar laboratorio en esta área');
|
|
return null;
|
|
}
|
|
const nuevoLaboratorio: Laboratorio = {
|
|
...laboratorio,
|
|
id: generateUUID(),
|
|
};
|
|
try {
|
|
await apiCall('POST', '/laboratorios', nuevoLaboratorio);
|
|
setState(prev => ({
|
|
...prev,
|
|
laboratorios: [...prev.laboratorios, nuevoLaboratorio],
|
|
}));
|
|
return nuevoLaboratorio.id;
|
|
} catch (err) {
|
|
console.error('Error al agregar laboratorio:', err);
|
|
throw err;
|
|
}
|
|
}, [state, 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 grupoId = internacion?.grupoId || null;
|
|
if (!checkGrupoPermission(grupoId)) {
|
|
console.warn('No tiene permisos para eliminar laboratorio en esta área');
|
|
return;
|
|
}
|
|
try {
|
|
await apiCall('DELETE', `/laboratorios/${id}`);
|
|
setState(prev => ({
|
|
...prev,
|
|
laboratorios: prev.laboratorios.filter(l => l.id !== id),
|
|
}));
|
|
} catch (err) {
|
|
console.error('Error al eliminar laboratorio:', err);
|
|
throw err;
|
|
}
|
|
}, [state, 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 grupoId = internacion?.grupoId || null;
|
|
if (!checkGrupoPermission(grupoId)) {
|
|
console.warn('No tiene permisos para actualizar laboratorio en esta área');
|
|
return;
|
|
}
|
|
try {
|
|
await apiCall('PUT', `/laboratorios/${id}`, datos);
|
|
setState(prev => ({
|
|
...prev,
|
|
laboratorios: prev.laboratorios.map(l => l.id === id ? { ...l, ...datos } : l),
|
|
}));
|
|
} catch (err) {
|
|
console.error('Error al actualizar laboratorio:', err);
|
|
throw err;
|
|
}
|
|
}, [state, checkGrupoPermission, apiCall]);
|
|
|
|
// Acciones de glucemias
|
|
const agregarGlucemia = useCallback(async (glucemia: Omit<Glucemia, 'id'>) => {
|
|
const internacion = state.internaciones.find(i => i.id === glucemia.internacionId);
|
|
const grupoId = internacion?.grupoId || null;
|
|
if (!checkGrupoPermission(grupoId)) {
|
|
console.warn('No tiene permisos para agregar glucemia en esta área');
|
|
return null;
|
|
}
|
|
const nuevaGlucemia: Glucemia = {
|
|
...glucemia,
|
|
id: generateUUID(),
|
|
};
|
|
try {
|
|
await apiCall('POST', '/glucemias', nuevaGlucemia);
|
|
setState(prev => ({
|
|
...prev,
|
|
glucemias: [...prev.glucemias, nuevaGlucemia],
|
|
}));
|
|
return nuevaGlucemia.id;
|
|
} catch (err) {
|
|
console.error('Error al agregar glucemia:', err);
|
|
throw err;
|
|
}
|
|
}, [state, 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 grupoId = internacion?.grupoId || null;
|
|
if (!checkGrupoPermission(grupoId)) {
|
|
console.warn('No tiene permisos para eliminar glucemia en esta área');
|
|
return;
|
|
}
|
|
try {
|
|
await apiCall('DELETE', `/glucemias/${id}`);
|
|
setState(prev => ({
|
|
...prev,
|
|
glucemias: prev.glucemias.filter(g => g.id !== id),
|
|
}));
|
|
} catch (err) {
|
|
console.error('Error al eliminar glucemia:', err);
|
|
throw err;
|
|
}
|
|
}, [state, 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 grupoId = internacion?.grupoId || null;
|
|
if (!checkGrupoPermission(grupoId)) {
|
|
console.warn('No tiene permisos para actualizar glucemia en esta área');
|
|
return;
|
|
}
|
|
try {
|
|
await apiCall('PUT', `/glucemias/${id}`, datos);
|
|
setState(prev => ({
|
|
...prev,
|
|
glucemias: prev.glucemias.map(g => g.id === id ? { ...g, ...datos } : g),
|
|
}));
|
|
} catch (err) {
|
|
console.error('Error al actualizar glucemia:', err);
|
|
throw err;
|
|
}
|
|
}, [state, 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 grupoId = internacion?.grupoId || null;
|
|
if (!checkGrupoPermission(grupoId)) {
|
|
console.warn('No tiene permisos para agregar ácido-base en esta área');
|
|
return null;
|
|
}
|
|
const nuevoAcidoBase: AcidoBase = {
|
|
...acidoBase,
|
|
id: generateUUID(),
|
|
};
|
|
try {
|
|
await apiCall('POST', '/acid-os-base', nuevoAcidoBase);
|
|
setState(prev => ({
|
|
...prev,
|
|
acidosBase: [...prev.acidosBase, nuevoAcidoBase],
|
|
}));
|
|
return nuevoAcidoBase.id;
|
|
} catch (err) {
|
|
console.error('Error al agregar ácido-base:', err);
|
|
throw err;
|
|
}
|
|
}, [state, 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 grupoId = internacion?.grupoId || null;
|
|
if (!checkGrupoPermission(grupoId)) {
|
|
console.warn('No tiene permisos para actualizar ácido-base en esta área');
|
|
return;
|
|
}
|
|
try {
|
|
await apiCall('PUT', `/acid-os-base/${id}`, datos);
|
|
setState(prev => ({
|
|
...prev,
|
|
acidosBase: prev.acidosBase.map(a => a.id === id ? { ...a, ...datos } : a),
|
|
}));
|
|
} catch (err) {
|
|
console.error('Error al actualizar ácido-base:', err);
|
|
throw err;
|
|
}
|
|
}, [state, 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 grupoId = internacion?.grupoId || null;
|
|
if (!checkGrupoPermission(grupoId)) {
|
|
console.warn('No tiene permisos para eliminar ácido-base en esta área');
|
|
return;
|
|
}
|
|
try {
|
|
await apiCall('DELETE', `/acid-os-base/${id}`);
|
|
setState(prev => ({
|
|
...prev,
|
|
acidosBase: prev.acidosBase.filter(a => a.id !== id),
|
|
}));
|
|
} catch (err) {
|
|
console.error('Error al eliminar ácido-base:', err);
|
|
throw err;
|
|
}
|
|
}, [state, checkGrupoPermission, apiCall]);
|
|
|
|
// Acciones de cultivos
|
|
const agregarCultivo = useCallback(async (cultivo: Omit<Cultivo, 'id'>) => {
|
|
const internacion = state.internaciones.find(i => i.id === cultivo.internacionId);
|
|
const grupoId = internacion?.grupoId || null;
|
|
if (!checkGrupoPermission(grupoId)) {
|
|
console.warn('No tiene permisos para agregar cultivo en esta área');
|
|
return null;
|
|
}
|
|
const nuevoCultivo: Cultivo = {
|
|
...cultivo,
|
|
id: generateUUID(),
|
|
};
|
|
try {
|
|
await apiCall('POST', '/cultivos', nuevoCultivo);
|
|
setState(prev => ({
|
|
...prev,
|
|
cultivos: [...prev.cultivos, nuevoCultivo],
|
|
}));
|
|
return nuevoCultivo.id;
|
|
} catch (err) {
|
|
console.error('Error al agregar cultivo:', err);
|
|
throw err;
|
|
}
|
|
}, [state, 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 grupoId = internacion?.grupoId || null;
|
|
if (!checkGrupoPermission(grupoId)) {
|
|
console.warn('No tiene permisos para actualizar cultivo en esta área');
|
|
return;
|
|
}
|
|
try {
|
|
await apiCall('PUT', `/cultivos/${id}`, datos);
|
|
setState(prev => ({
|
|
...prev,
|
|
cultivos: prev.cultivos.map(c => c.id === id ? { ...c, ...datos } : c),
|
|
}));
|
|
} catch (err) {
|
|
console.error('Error al actualizar cultivo:', err);
|
|
throw err;
|
|
}
|
|
}, [state, 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 grupoId = internacion?.grupoId || null;
|
|
if (!checkGrupoPermission(grupoId)) {
|
|
console.warn('No tiene permisos para eliminar cultivo en esta área');
|
|
return;
|
|
}
|
|
try {
|
|
await apiCall('DELETE', `/cultivos/${id}`);
|
|
setState(prev => ({
|
|
...prev,
|
|
cultivos: prev.cultivos.filter(c => c.id !== id),
|
|
}));
|
|
} catch (err) {
|
|
console.error('Error al eliminar cultivo:', err);
|
|
throw err;
|
|
}
|
|
}, [state, 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 grupoId = internacion?.grupoId || null;
|
|
if (!checkGrupoPermission(grupoId)) {
|
|
console.warn('No tiene permisos para agregar estudio complementario en esta área');
|
|
return null;
|
|
}
|
|
const nuevoEstudio: EstudioComplementario = {
|
|
...estudio,
|
|
id: generateUUID(),
|
|
};
|
|
try {
|
|
await apiCall('POST', '/estudios-complementarios', nuevoEstudio);
|
|
setState(prev => ({
|
|
...prev,
|
|
estudiosComplementarios: [...prev.estudiosComplementarios, nuevoEstudio],
|
|
}));
|
|
return nuevoEstudio.id;
|
|
} catch (err) {
|
|
console.error('Error al agregar estudio:', err);
|
|
throw err;
|
|
}
|
|
}, [state, 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 grupoId = internacion?.grupoId || null;
|
|
if (!checkGrupoPermission(grupoId)) {
|
|
console.warn('No tiene permisos para actualizar estudio complementario en esta área');
|
|
return;
|
|
}
|
|
try {
|
|
await apiCall('PUT', `/estudios-complementarios/${id}`, datos);
|
|
setState(prev => ({
|
|
...prev,
|
|
estudiosComplementarios: prev.estudiosComplementarios.map(e => e.id === id ? { ...e, ...datos } : e),
|
|
}));
|
|
} catch (err) {
|
|
console.error('Error al actualizar estudio:', err);
|
|
throw err;
|
|
}
|
|
}, [state, 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 grupoId = internacion?.grupoId || null;
|
|
if (!checkGrupoPermission(grupoId)) {
|
|
console.warn('No tiene permisos para eliminar estudio complementario en esta área');
|
|
return;
|
|
}
|
|
try {
|
|
await apiCall('DELETE', `/estudios-complementarios/${id}`);
|
|
setState(prev => ({
|
|
...prev,
|
|
estudiosComplementarios: prev.estudiosComplementarios.filter(e => e.id !== id),
|
|
}));
|
|
} catch (err) {
|
|
console.error('Error al eliminar estudio:', err);
|
|
throw err;
|
|
}
|
|
}, [state, checkGrupoPermission, apiCall]);
|
|
|
|
// Acciones de interconsultas
|
|
const agregarInterconsulta = useCallback(async (interconsulta: Omit<Interconsulta, 'id'>) => {
|
|
const internacion = state.internaciones.find(i => i.id === interconsulta.internacionId);
|
|
const grupoId = internacion?.grupoId || null;
|
|
if (!checkGrupoPermission(grupoId)) {
|
|
console.warn('No tiene permisos para agregar interconsulta en esta área');
|
|
return null;
|
|
}
|
|
const nuevaInterconsulta: Interconsulta = { ...interconsulta, id: generateUUID() };
|
|
try {
|
|
await apiCall('POST', '/interconsultas', nuevaInterconsulta);
|
|
setState(prev => ({
|
|
...prev,
|
|
interconsultas: [...(prev.interconsultas || []), nuevaInterconsulta],
|
|
}));
|
|
return nuevaInterconsulta.id;
|
|
} catch (err) {
|
|
console.error('Error al agregar interconsulta:', err);
|
|
throw err;
|
|
}
|
|
}, [state, 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 grupoId = internacion?.grupoId || null;
|
|
if (!checkGrupoPermission(grupoId)) {
|
|
console.warn('No tiene permisos para actualizar interconsulta en esta área');
|
|
return;
|
|
}
|
|
try {
|
|
await apiCall('PUT', `/interconsultas/${id}`, datos);
|
|
setState(prev => ({
|
|
...prev,
|
|
interconsultas: (prev.interconsultas || []).map(ic => ic.id === id ? { ...ic, ...datos } : ic),
|
|
}));
|
|
} catch (err) {
|
|
console.error('Error al actualizar interconsulta:', err);
|
|
throw err;
|
|
}
|
|
}, [state, 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 grupoId = internacion?.grupoId || null;
|
|
if (!checkGrupoPermission(grupoId)) {
|
|
console.warn('No tiene permisos para eliminar interconsulta en esta área');
|
|
return;
|
|
}
|
|
try {
|
|
await apiCall('DELETE', `/interconsultas/${id}`);
|
|
setState(prev => ({
|
|
...prev,
|
|
interconsultas: (prev.interconsultas || []).filter(ic => ic.id !== id),
|
|
}));
|
|
} catch (err) {
|
|
console.error('Error al eliminar interconsulta:', err);
|
|
throw err;
|
|
}
|
|
}, [state, checkGrupoPermission, apiCall]);
|
|
|
|
const agregarATB = useCallback(async (atb: Omit<ATB, 'id'>) => {
|
|
const internacion = state.internaciones.find(i => i.id === atb.internacionId);
|
|
const grupoId = internacion?.grupoId || null;
|
|
if (!checkGrupoPermission(grupoId)) {
|
|
console.warn('No tiene permisos para agregar ATB en esta área');
|
|
return null;
|
|
}
|
|
const nuevoATB: ATB = { ...atb, id: generateUUID() };
|
|
try {
|
|
await apiCall('POST', '/atb', nuevoATB);
|
|
setState(prev => ({
|
|
...prev,
|
|
atb: [...prev.atb, nuevoATB],
|
|
}));
|
|
return nuevoATB.id;
|
|
} catch (err) {
|
|
console.error('Error al agregar ATB:', err);
|
|
throw err;
|
|
}
|
|
}, [state, 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 grupoId = internacion?.grupoId || null;
|
|
if (!checkGrupoPermission(grupoId)) {
|
|
console.warn('No tiene permisos para actualizar ATB en esta área');
|
|
return;
|
|
}
|
|
try {
|
|
await apiCall('PUT', `/atb/${id}`, datos);
|
|
setState(prev => ({
|
|
...prev,
|
|
atb: prev.atb.map(a => a.id === id ? { ...a, ...datos } : a),
|
|
}));
|
|
} catch (err) {
|
|
console.error('Error al actualizar ATB:', err);
|
|
throw err;
|
|
}
|
|
}, [state, 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 grupoId = internacion?.grupoId || null;
|
|
if (!checkGrupoPermission(grupoId)) {
|
|
console.warn('No tiene permisos para eliminar ATB en esta área');
|
|
return;
|
|
}
|
|
try {
|
|
await apiCall('DELETE', `/atb/${id}`);
|
|
setState(prev => ({
|
|
...prev,
|
|
atb: prev.atb.filter(a => a.id !== id),
|
|
}));
|
|
} catch (err) {
|
|
console.error('Error al eliminar ATB:', err);
|
|
throw err;
|
|
}
|
|
}, [state, checkGrupoPermission, apiCall]);
|
|
|
|
const agregarIndicacion = useCallback(async (indicacion: Omit<Indicacion, 'id'>) => {
|
|
const internacion = state.internaciones.find(i => i.id === indicacion.internacionId);
|
|
const grupoId = internacion?.grupoId || null;
|
|
if (!checkGrupoPermission(grupoId)) {
|
|
console.warn('No tiene permisos para agregar indicación en esta área');
|
|
return null;
|
|
}
|
|
const nuevaIndicacion: Indicacion = { ...indicacion, id: generateUUID() };
|
|
try {
|
|
await apiCall('POST', '/indicaciones', nuevaIndicacion);
|
|
setState(prev => ({
|
|
...prev,
|
|
indicaciones: [...prev.indicaciones, nuevaIndicacion],
|
|
}));
|
|
return nuevaIndicacion.id;
|
|
} catch (err) {
|
|
console.error('Error al agregar indicación:', err);
|
|
throw err;
|
|
}
|
|
}, [state.internaciones, 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 grupoId = internacion?.grupoId || null;
|
|
if (!checkGrupoPermission(grupoId)) {
|
|
console.warn('No tiene permisos para actualizar indicación en esta área');
|
|
return;
|
|
}
|
|
try {
|
|
await apiCall('PUT', `/indicaciones/${id}`, datos);
|
|
setState(prev => ({
|
|
...prev,
|
|
indicaciones: prev.indicaciones.map(i => i.id === id ? { ...i, ...datos } : i),
|
|
}));
|
|
} catch (err) {
|
|
console.error('Error al actualizar indicación:', err);
|
|
throw err;
|
|
}
|
|
}, [state.indicaciones, state.internaciones, 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 grupoId = internacion?.grupoId || null;
|
|
if (!checkGrupoPermission(grupoId)) {
|
|
console.warn('No tiene permisos para eliminar indicación en esta área');
|
|
return;
|
|
}
|
|
try {
|
|
await apiCall('DELETE', `/indicaciones/${id}`);
|
|
setState(prev => ({
|
|
...prev,
|
|
indicaciones: prev.indicaciones.filter(i => i.id !== id),
|
|
}));
|
|
} catch (err) {
|
|
console.error('Error al eliminar indicación:', err);
|
|
throw err;
|
|
}
|
|
}, [state.indicaciones, state.internaciones, checkGrupoPermission, apiCall]);
|
|
|
|
const agregarMovimientoIndicacion = useCallback(async (movimiento: MovimientoIndicacion) => {
|
|
const internacion = state.internaciones.find(i => i.id === movimiento.internacionId);
|
|
const grupoId = internacion?.grupoId || null;
|
|
if (!checkGrupoPermission(grupoId)) {
|
|
console.warn('No tiene permisos para agregar movimiento de indicación en esta área');
|
|
return;
|
|
}
|
|
const nuevoMovimiento = { ...movimiento, id: generateUUID() };
|
|
try {
|
|
await apiCall('POST', '/movimientos-indicaciones', nuevoMovimiento);
|
|
setState(prev => ({
|
|
...prev,
|
|
movimientosIndicaciones: [...(prev.movimientosIndicaciones || []), nuevoMovimiento],
|
|
}));
|
|
} catch (err) {
|
|
console.error('Error al agregar movimiento:', err);
|
|
throw err;
|
|
}
|
|
}, [state, checkGrupoPermission, apiCall]);
|
|
|
|
const getMovimientosByInternacion = useCallback((internacionId: string) => {
|
|
return (state.movimientosIndicaciones || [])
|
|
.filter((m: MovimientoIndicacion) => m.internacionId === internacionId)
|
|
.sort((a: MovimientoIndicacion, b: MovimientoIndicacion) => new Date(b.fecha).getTime() - new Date(a.fecha).getTime());
|
|
}, [state.movimientosIndicaciones]);
|
|
|
|
// Acciones de grupos
|
|
const agregarGrupo = useCallback(async (grupo: Omit<Grupo, 'id'>) => {
|
|
const nuevaGrupo: Grupo = { ...grupo, id: generateUUID() };
|
|
try {
|
|
await apiCall('POST', '/grupos', nuevaGrupo);
|
|
setState(prev => ({
|
|
...prev,
|
|
grupos: [...prev.grupos, nuevaGrupo],
|
|
}));
|
|
return nuevaGrupo.id;
|
|
} catch (err) {
|
|
console.error('Error al agregar área:', err);
|
|
throw err;
|
|
}
|
|
}, [apiCall]);
|
|
|
|
const actualizarGrupo = useCallback(async (id: string, datos: Partial<Grupo>) => {
|
|
try {
|
|
await apiCall('PUT', `/grupos/${id}`, datos);
|
|
setState(prev => ({
|
|
...prev,
|
|
grupos: prev.grupos.map(a => a.id === id ? { ...a, ...datos } : a),
|
|
}));
|
|
} catch (err) {
|
|
console.error('Error al actualizar área:', err);
|
|
throw err;
|
|
}
|
|
}, [apiCall]);
|
|
|
|
const eliminarGrupo = useCallback(async (id: string) => {
|
|
try {
|
|
await apiCall('DELETE', `/grupos/${id}`);
|
|
setState(prev => ({
|
|
...prev,
|
|
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);
|
|
throw err;
|
|
}
|
|
}, [apiCall]);
|
|
|
|
// Funciones de utilidad para consultas
|
|
const getPacienteById = useCallback((id: string) => {
|
|
if (!id) return undefined;
|
|
const target = String(id).trim().toLowerCase();
|
|
return state.pacientes.find(p =>
|
|
(p.id && String(p.id).trim().toLowerCase() === target) ||
|
|
(p.dni && String(p.dni).trim().toLowerCase() === target)
|
|
);
|
|
}, [state.pacientes]);
|
|
|
|
const getCamaById = useCallback((id: string) => {
|
|
if (!id) return undefined;
|
|
const target = String(id).trim().toLowerCase();
|
|
return state.camas.find(c => c.id && String(c.id).trim().toLowerCase() === target);
|
|
}, [state.camas]);
|
|
|
|
const getInternacionById = useCallback((id: string) => {
|
|
if (!id) return undefined;
|
|
const target = String(id).trim().toLowerCase();
|
|
return state.internaciones.find(i => i.id && String(i.id).trim().toLowerCase() === target);
|
|
}, [state.internaciones]);
|
|
|
|
const getInternacionActivaByPaciente = useCallback((pacienteId: string) => {
|
|
return state.internaciones.find(i => i.pacienteId === pacienteId && i.activa);
|
|
}, [state.internaciones]);
|
|
|
|
const getEvolucionesByInternacion = useCallback((internacionId: string) => {
|
|
return state.evoluciones
|
|
.filter(e => e.internacionId === internacionId)
|
|
.sort((a, b) => new Date(b.fecha + 'T' + b.hora).getTime() - new Date(a.fecha + 'T' + a.hora).getTime());
|
|
}, [state.evoluciones]);
|
|
|
|
const getLaboratoriosByInternacion = useCallback((internacionId: string) => {
|
|
return state.laboratorios
|
|
.filter(l => l.internacionId === internacionId)
|
|
.sort((a, b) => new Date(b.fecha).getTime() - new Date(a.fecha).getTime());
|
|
}, [state.laboratorios]);
|
|
|
|
const getGlucemiasByInternacion = useCallback((internacionId: string) => {
|
|
return state.glucemias
|
|
.filter(g => g.internacionId === internacionId)
|
|
.sort((a, b) => new Date(b.fecha + 'T' + (b.hora || '00:00')).getTime() - new Date(a.fecha + 'T' + (a.hora || '00:00')).getTime());
|
|
}, [state.glucemias]);
|
|
|
|
const getAcidosBaseByInternacion = useCallback((internacionId: string) => {
|
|
return state.acidosBase
|
|
.filter(a => a.internacionId === internacionId)
|
|
.sort((a, b) => new Date(b.fecha + 'T' + b.hora).getTime() - new Date(a.fecha + 'T' + a.hora).getTime());
|
|
}, [state.acidosBase]);
|
|
|
|
const getCultivosByInternacion = useCallback((internacionId: string) => {
|
|
return state.cultivos
|
|
.filter(c => c.internacionId === internacionId)
|
|
.sort((a, b) => new Date(b.fechaToma).getTime() - new Date(a.fechaToma).getTime());
|
|
}, [state.cultivos]);
|
|
|
|
const agregarPendiente = useCallback(async (datos: Omit<Pendiente, 'id'>) => {
|
|
const nuevoPendiente: Pendiente = {
|
|
...datos,
|
|
id: generateUUID(),
|
|
fechaCreacion: datos.fechaCreacion || new Date().toISOString().split('T')[0],
|
|
horaCreacion: datos.horaCreacion || new Date().toTimeString().slice(0, 5),
|
|
estado: datos.estado || 'pendiente',
|
|
prioridad: datos.prioridad || 'media',
|
|
};
|
|
try {
|
|
await apiCall('POST', '/pendientes', nuevoPendiente);
|
|
setState(prev => ({
|
|
...prev,
|
|
pendientes: [...(prev.pendientes || []), nuevoPendiente],
|
|
}));
|
|
return nuevoPendiente.id;
|
|
} catch (err) {
|
|
console.error('Error al agregar pendiente:', err);
|
|
throw err;
|
|
}
|
|
}, [apiCall]);
|
|
|
|
const actualizarPendiente = useCallback(async (id: string, datos: Partial<Pendiente>) => {
|
|
try {
|
|
await apiCall('PUT', `/pendientes/${id}`, datos);
|
|
setState(prev => ({
|
|
...prev,
|
|
pendientes: (prev.pendientes || []).map(p => p.id === id ? { ...p, ...datos } : p),
|
|
}));
|
|
} catch (err) {
|
|
console.error('Error al actualizar pendiente:', err);
|
|
throw err;
|
|
}
|
|
}, [apiCall]);
|
|
|
|
const eliminarPendiente = useCallback(async (id: string) => {
|
|
try {
|
|
await apiCall('DELETE', `/pendientes/${id}`);
|
|
setState(prev => ({
|
|
...prev,
|
|
pendientes: (prev.pendientes || []).filter(p => p.id !== id),
|
|
}));
|
|
} catch (err) {
|
|
console.error('Error al eliminar pendiente:', err);
|
|
throw err;
|
|
}
|
|
}, [apiCall]);
|
|
|
|
const getPendientesByPaciente = useCallback((pacienteId: string) => {
|
|
return (state.pendientes || [])
|
|
.filter(p => p.pacienteId === pacienteId)
|
|
.sort((a, b) => new Date(`${b.fechaCreacion}T${b.horaCreacion || '00:00'}`).getTime() - new Date(`${a.fechaCreacion}T${a.horaCreacion || '00:00'}`).getTime());
|
|
}, [state.pendientes]);
|
|
|
|
const getEstadisticas = useCallback(() => {
|
|
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 {
|
|
camasOcupadas,
|
|
camasDisponibles,
|
|
camasMantenimiento,
|
|
totalCamas: state.camas.length,
|
|
totalCamasActivas: camasEnArea.length,
|
|
camasFueraDeArea: camasFueraDeArea.length,
|
|
internacionesActivas,
|
|
totalPacientes,
|
|
cultivosPendientes,
|
|
porcentajeOcupacion: camasEnArea.length > 0 ? Math.round((camasOcupadas / camasEnArea.length) * 100) : 0,
|
|
};
|
|
}, [state]);
|
|
|
|
// Current internacion selection (for HC page)
|
|
const setCurrentInternacion = useCallback((id?: string | null) => {
|
|
if (id) {
|
|
sessionStorage.setItem('hospital_current_internacion_id', id);
|
|
} else {
|
|
sessionStorage.removeItem('hospital_current_internacion_id');
|
|
}
|
|
setState(prev => ({ ...prev, currentInternacionId: id ?? null }));
|
|
}, []);
|
|
|
|
// Auth functions
|
|
const login = useCallback(async (dni: string, password: string) => {
|
|
const res = await fetch(`${API_BASE}/auth/login`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ dni, password }),
|
|
});
|
|
if (!res.ok) {
|
|
const err = await res.json();
|
|
throw new Error(err.error || 'Error en autenticación');
|
|
}
|
|
const user = await res.json();
|
|
sessionStorage.setItem('hospital_user', JSON.stringify(user));
|
|
setState(prev => ({ ...prev, currentUser: user, isAuthenticated: true }));
|
|
return user;
|
|
}, []);
|
|
|
|
const logout = useCallback(() => {
|
|
sessionStorage.removeItem('hospital_user');
|
|
setState(prev => {
|
|
const newState = { ...prev, currentUser: null, isAuthenticated: false };
|
|
return newState;
|
|
});
|
|
}, []);
|
|
|
|
const changePassword = useCallback(async (dni: string, oldPassword: string, newPassword: string) => {
|
|
const res = await fetch(`${API_BASE}/auth/change-password`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ dni, oldPassword, newPassword }),
|
|
});
|
|
if (!res.ok) {
|
|
const err = await res.json();
|
|
throw new Error(err.error || 'Error al cambiar contraseña');
|
|
}
|
|
return true;
|
|
}, []);
|
|
|
|
const updateEmail = useCallback(async (dni: string, newEmail: string) => {
|
|
const res = await fetch(`${API_BASE}/auth/update-email`, {
|
|
method: 'PUT',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ dni, newEmail }),
|
|
});
|
|
if (!res.ok) {
|
|
const err = await res.json();
|
|
throw new Error(err.error || 'Error al actualizar email');
|
|
}
|
|
return true;
|
|
}, []);
|
|
|
|
return {
|
|
...state,
|
|
isLoaded,
|
|
setVista,
|
|
agregarPaciente,
|
|
actualizarPaciente,
|
|
eliminarPaciente,
|
|
actualizarCama,
|
|
iniciarInternacion,
|
|
finalizarInternacion,
|
|
actualizarInternacion,
|
|
eliminarInternacion,
|
|
agregarCama,
|
|
eliminarCama,
|
|
agregarEvolucion,
|
|
actualizarEvolucion,
|
|
eliminarEvolucion,
|
|
agregarLaboratorio,
|
|
actualizarLaboratorio,
|
|
eliminarLaboratorio,
|
|
agregarGlucemia,
|
|
actualizarGlucemia,
|
|
eliminarGlucemia,
|
|
agregarAcidoBase,
|
|
actualizarAcidoBase,
|
|
eliminarAcidoBase,
|
|
agregarCultivo,
|
|
actualizarCultivo,
|
|
eliminarCultivo,
|
|
agregarEstudioComplementario,
|
|
actualizarEstudioComplementario,
|
|
eliminarEstudioComplementario,
|
|
agregarInterconsulta,
|
|
actualizarInterconsulta,
|
|
eliminarInterconsulta,
|
|
agregarATB,
|
|
actualizarATB,
|
|
eliminarATB,
|
|
agregarIndicacion,
|
|
actualizarIndicacion,
|
|
eliminarIndicacion,
|
|
agregarMovimientoIndicacion,
|
|
getMovimientosByInternacion,
|
|
agregarGrupo,
|
|
actualizarGrupo,
|
|
eliminarGrupo,
|
|
getPacienteById,
|
|
getCamaById,
|
|
getInternacionById,
|
|
getInternacionActivaByPaciente,
|
|
getEvolucionesByInternacion,
|
|
getLaboratoriosByInternacion,
|
|
getGlucemiasByInternacion,
|
|
getAcidosBaseByInternacion,
|
|
getCultivosByInternacion,
|
|
agregarPendiente,
|
|
actualizarPendiente,
|
|
eliminarPendiente,
|
|
getPendientesByPaciente,
|
|
setCurrentInternacion,
|
|
getEstadisticas,
|
|
login,
|
|
logout,
|
|
changePassword,
|
|
updateEmail,
|
|
hasPermission,
|
|
canAccessGrupo,
|
|
canChangeBed,
|
|
canEditInternacion,
|
|
canEditIngreso,
|
|
canEditCama,
|
|
canEditPaciente,
|
|
getCamaGrupoId,
|
|
getInternacionGrupoId,
|
|
getPacienteGrupoId,
|
|
isLoaded,
|
|
};
|
|
}
|