Add area assignment to internaciones and permission controls

- Add areaId field to Internacion type and database schema
- Add area selection in NuevoIngreso, EditIngreso, and Internaciones forms
- Filter out 'Fuera de area' from area selection dropdowns
- Add permission controls for users to only edit internaciones in their area
- Add canEdit check to hide 'Editar Ingreso' button in HistoriaClinica
- Fix getInternacionAreaId to use new areaId field first, fallback to cama area
- Add INSERT OR IGNORE to prevent duplicate errors
This commit is contained in:
2026-04-23 17:49:07 -03:00
parent 6611258ce9
commit 56402563fb
9 changed files with 345 additions and 47 deletions
+2 -2
View File
@@ -82,8 +82,8 @@ app.put('/api/state', async (req, res) => {
if (state.internaciones?.length) { if (state.internaciones?.length) {
for (const i of state.internaciones) { for (const i of state.internaciones) {
await db.run( await db.run(
'INSERT INTO internaciones (id, pacienteId, camaId, fechaIngresoHospital, fechaIngresoClinica, fechaEgreso, diagnosticoIngreso, motivoConsulta, enfermedadActual, antecedentesEnfermedadActual, diagnosticoEgreso, medicoIngresante, motivoEgreso, activa, apache, derivacion) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', 'INSERT OR IGNORE INTO internaciones (id, pacienteId, camaId, areaId, fechaIngresoHospital, fechaIngresoClinica, fechaEgreso, diagnosticoIngreso, motivoConsulta, enfermedadActual, antecedentesEnfermedadActual, diagnosticoEgreso, medicoIngresante, motivoEgreso, activa, apache, derivacion) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
[i.id, i.pacienteId, i.camaId, i.fechaIngresoHospital || null, i.fechaIngresoClinica || null, i.fechaEgreso || null, i.diagnosticoIngreso || null, i.motivoConsulta || null, i.enfermedadActual || null, i.antecedentesEnfermedadActual || null, i.diagnosticoEgreso || null, i.medicoIngresante || null, i.motivoEgreso || null, i.activa ? 1 : 0, i.apache || null, i.derivacion || null] [i.id, i.pacienteId, i.camaId, i.areaId || null, i.fechaIngresoHospital || null, i.fechaIngresoClinica || null, i.fechaEgreso || null, i.diagnosticoIngreso || null, i.motivoConsulta || null, i.enfermedadActual || null, i.antecedentesEnfermedadActual || null, i.diagnosticoEgreso || null, i.medicoIngresante || null, i.motivoEgreso || null, i.activa ? 1 : 0, i.apache || null, i.derivacion || null]
); );
} }
} }
+11 -4
View File
@@ -16,6 +16,12 @@ if (!existsSync(join(__dirname, 'data'))) {
const db = new Database(DB_PATH); const db = new Database(DB_PATH);
try {
db.exec("ALTER TABLE internaciones ADD COLUMN areaId TEXT;");
} catch (e) {
// Ignore errors - column might already exist or other issues
}
db.exec(` db.exec(`
CREATE TABLE IF NOT EXISTS pacientes ( CREATE TABLE IF NOT EXISTS pacientes (
id TEXT PRIMARY KEY, id TEXT PRIMARY KEY,
@@ -52,6 +58,7 @@ db.exec(`
id TEXT PRIMARY KEY, id TEXT PRIMARY KEY,
pacienteId TEXT NOT NULL, pacienteId TEXT NOT NULL,
camaId TEXT, camaId TEXT,
areaId TEXT,
fechaIngresoHospital TEXT, fechaIngresoHospital TEXT,
fechaIngresoClinica TEXT, fechaIngresoClinica TEXT,
fechaEgreso TEXT, fechaEgreso TEXT,
@@ -378,21 +385,21 @@ app.put('/api/state', (req, res) => {
} }
if (state.camas?.length) { if (state.camas?.length) {
const stmt = db.prepare('INSERT INTO camas (id, numero, areaId, tipo, estado) VALUES (?, ?, ?, ?, ?)'); const stmt = db.prepare('INSERT OR IGNORE INTO camas (id, numero, areaId, tipo, estado) VALUES (?, ?, ?, ?, ?)');
for (const c of state.camas) { for (const c of state.camas) {
stmt.run(c.id, c.numero, c.areaId, c.tipo, c.estado); stmt.run(c.id, c.numero, c.areaId, c.tipo, c.estado);
} }
} }
if (state.internaciones?.length) { if (state.internaciones?.length) {
const stmt = db.prepare('INSERT INTO internaciones (id, pacienteId, camaId, fechaIngresoHospital, fechaIngresoClinica, fechaEgreso, diagnosticoIngreso, motivoConsulta, enfermedadActual, antecedentesEnfermedadActual, diagnosticoEgreso, medicoIngresante, motivoEgreso, activa, apache, derivacion) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'); const stmt = db.prepare('INSERT OR IGNORE INTO internaciones (id, pacienteId, camaId, areaId, fechaIngresoHospital, fechaIngresoClinica, fechaEgreso, diagnosticoIngreso, motivoConsulta, enfermedadActual, antecedentesEnfermedadActual, diagnosticoEgreso, medicoIngresante, motivoEgreso, activa, apache, derivacion) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
for (const i of state.internaciones) { for (const i of state.internaciones) {
stmt.run(i.id, i.pacienteId, i.camaId, i.fechaIngresoHospital || null, i.fechaIngresoClinica || null, i.fechaEgreso || null, i.diagnosticoIngreso || null, i.motivoConsulta || null, i.enfermedadActual || null, i.antecedentesEnfermedadActual || null, i.diagnosticoEgreso || null, i.medicoIngresante || null, i.motivoEgreso || null, i.activa ? 1 : 0, i.apache || null, i.derivacion || null); stmt.run(i.id, i.pacienteId, i.camaId, i.areaId || null, i.fechaIngresoHospital || null, i.fechaIngresoClinica || null, i.fechaEgreso || null, i.diagnosticoIngreso || null, i.motivoConsulta || null, i.enfermedadActual || null, i.antecedentesEnfermedadActual || null, i.diagnosticoEgreso || null, i.medicoIngresante || null, i.motivoEgreso || null, i.activa ? 1 : 0, i.apache || null, i.derivacion || null);
} }
} }
if (state.evoluciones?.length) { if (state.evoluciones?.length) {
const stmt = db.prepare('INSERT INTO evoluciones (id, internacionId, fecha, hora, medico, signosVitales, examenFisico, novedades, comentarios, pendientes) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'); const stmt = db.prepare('INSERT OR IGNORE INTO evoluciones (id, internacionId, fecha, hora, medico, signosVitales, examenFisico, novedades, comentarios, pendientes) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
for (const e of state.evoluciones) { for (const e of state.evoluciones) {
stmt.run(e.id, e.internacionId, e.fecha, e.hora || '', e.medico || '', JSON.stringify(e.signosVitales || {}), JSON.stringify(e.examenFisico || {}), e.novedades || '', e.comentario || '', e.pendientes || ''); stmt.run(e.id, e.internacionId, e.fecha, e.hora || '', e.medico || '', JSON.stringify(e.signosVitales || {}), JSON.stringify(e.examenFisico || {}), e.novedades || '', e.comentario || '', e.pendientes || '');
} }
+234 -27
View File
@@ -174,11 +174,19 @@ export function useHospitalStore() {
// Acciones de camas // Acciones de camas
const actualizarCama = useCallback((id: string, datos: Partial<Cama>) => { const actualizarCama = useCallback((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) {
console.warn('No tiene permisos para actualizar cama en esta área');
return;
}
setState(prev => ({ setState(prev => ({
...prev, ...prev,
camas: prev.camas.map(c => c.id === id ? { ...c, ...datos } : c), camas: prev.camas.map(c => c.id === id ? { ...c, ...datos } : c),
})); }));
}, []); }, [state.camas, state.currentUser]);
const agregarCama = useCallback((cama: Omit<Cama, 'id'>) => { const agregarCama = useCallback((cama: Omit<Cama, 'id'>) => {
const nuevaCama: Cama = { const nuevaCama: Cama = {
@@ -202,6 +210,12 @@ export function useHospitalStore() {
// Acciones de internaciones // Acciones de internaciones
const iniciarInternacion = useCallback((internacion: Omit<Internacion, 'id' | 'activa'>) => { const iniciarInternacion = useCallback((internacion: Omit<Internacion, 'id' | 'activa'>) => {
const user = state.currentUser;
const areaId = internacion.areaId || null;
if (user && user.rol !== 'admin' && areaId && user.areaId !== areaId) {
console.warn('No tiene permisos para iniciar internación en esta área');
return null;
}
const nuevaInternacion: Internacion = { const nuevaInternacion: Internacion = {
...internacion, ...internacion,
id: generateUUID(), id: generateUUID(),
@@ -217,7 +231,7 @@ export function useHospitalStore() {
), ),
})); }));
return nuevaInternacion.id; return nuevaInternacion.id;
}, []); }, [state.currentUser]);
const finalizarInternacion = useCallback((internacionId: string, datos: { const finalizarInternacion = useCallback((internacionId: string, datos: {
fechaEgreso: string; fechaEgreso: string;
@@ -245,6 +259,14 @@ const finalizarInternacion = useCallback((internacionId: string, datos: {
}, []); }, []);
const actualizarInternacion = useCallback((internacionId: string, datos: Partial<Internacion>) => { const actualizarInternacion = useCallback((internacionId: string, datos: Partial<Internacion>) => {
const internacion = state.internaciones.find(i => i.id === internacionId);
if (!internacion) return;
const user = state.currentUser;
const areaId = internacion.areaId || null;
if (user && user.rol !== 'admin' && areaId && user.areaId !== areaId) {
console.warn('No tiene permisos para actualizar internación en esta área');
return;
}
setState(prev => ({ setState(prev => ({
...prev, ...prev,
internaciones: prev.internaciones.map(i => internaciones: prev.internaciones.map(i =>
@@ -253,10 +275,16 @@ const finalizarInternacion = useCallback((internacionId: string, datos: {
: i : i
), ),
})); }));
}, []); }, [state.internaciones, state.currentUser]);
// Acciones de evoluciones // Acciones de evoluciones
const agregarEvolucion = useCallback((evolucion: Omit<Evolucion, 'id'>) => { const agregarEvolucion = useCallback((evolucion: Omit<Evolucion, 'id'>) => {
const internacion = state.internaciones.find(i => i.id === evolucion.internacionId);
const areaId = internacion?.areaId || null;
if (!canEditInArea(areaId)) {
console.warn('No tiene permisos para agregar evolución en esta área');
return null;
}
const nuevaEvolucion: Evolucion = { const nuevaEvolucion: Evolucion = {
...evolucion, ...evolucion,
id: generateUUID(), id: generateUUID(),
@@ -266,9 +294,17 @@ const finalizarInternacion = useCallback((internacionId: string, datos: {
evoluciones: [...prev.evoluciones, nuevaEvolucion], evoluciones: [...prev.evoluciones, nuevaEvolucion],
})); }));
return nuevaEvolucion.id; return nuevaEvolucion.id;
}, []); }, [state.internaciones, state.currentUser]);
const eliminarEvolucion = useCallback((id: string) => { const eliminarEvolucion = useCallback((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 (!canEditInArea(areaId)) {
console.warn('No tiene permisos para eliminar evolución en esta área');
return;
}
setState(prev => ({ setState(prev => ({
...prev, ...prev,
evoluciones: prev.evoluciones.filter(e => e.id !== id), evoluciones: prev.evoluciones.filter(e => e.id !== id),
@@ -276,14 +312,28 @@ const finalizarInternacion = useCallback((internacionId: string, datos: {
}, []); }, []);
const actualizarEvolucion = useCallback((id: string, datos: Partial<Evolucion>) => { const actualizarEvolucion = useCallback((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 (!canEditInArea(areaId)) {
console.warn('No tiene permisos para actualizar evolución en esta área');
return;
}
setState(prev => ({ setState(prev => ({
...prev, ...prev,
evoluciones: prev.evoluciones.map(e => e.id === id ? { ...e, ...datos } : e), evoluciones: prev.evoluciones.map(e => e.id === id ? { ...e, ...datos } : e),
})); }));
}, []); }, [state.internaciones, state.currentUser]);
// Acciones de laboratorios // Acciones de laboratorios
const agregarLaboratorio = useCallback((laboratorio: Omit<Laboratorio, 'id'>) => { const agregarLaboratorio = useCallback((laboratorio: Omit<Laboratorio, 'id'>) => {
const internacion = state.internaciones.find(i => i.id === laboratorio.internacionId);
const areaId = internacion?.areaId || null;
if (!canEditInArea(areaId)) {
console.warn('No tiene permisos para agregar laboratorio en esta área');
return null;
}
const nuevoLaboratorio: Laboratorio = { const nuevoLaboratorio: Laboratorio = {
...laboratorio, ...laboratorio,
id: generateUUID(), id: generateUUID(),
@@ -293,24 +343,46 @@ const finalizarInternacion = useCallback((internacionId: string, datos: {
laboratorios: [...prev.laboratorios, nuevoLaboratorio], laboratorios: [...prev.laboratorios, nuevoLaboratorio],
})); }));
return nuevoLaboratorio.id; return nuevoLaboratorio.id;
}, []); }, [state.internaciones, state.currentUser]);
const eliminarLaboratorio = useCallback((id: string) => { const eliminarLaboratorio = useCallback((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 (!canEditInArea(areaId)) {
console.warn('No tiene permisos para eliminar laboratorio en esta área');
return;
}
setState(prev => ({ setState(prev => ({
...prev, ...prev,
laboratorios: prev.laboratorios.filter(l => l.id !== id), laboratorios: prev.laboratorios.filter(l => l.id !== id),
})); }));
}, []); }, [state.internaciones, state.currentUser]);
const actualizarLaboratorio = useCallback((id: string, datos: Partial<Laboratorio>) => { const actualizarLaboratorio = useCallback((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 (!canEditInArea(areaId)) {
console.warn('No tiene permisos para actualizar laboratorio en esta área');
return;
}
setState(prev => ({ setState(prev => ({
...prev, ...prev,
laboratorios: prev.laboratorios.map(l => l.id === id ? { ...l, ...datos } : l), laboratorios: prev.laboratorios.map(l => l.id === id ? { ...l, ...datos } : l),
})); }));
}, []); }, [state.internaciones, state.currentUser]);
// Acciones de ácido-base // Acciones de ácido-base
const agregarAcidoBase = useCallback((acidoBase: Omit<AcidoBase, 'id'>) => { const agregarAcidoBase = useCallback((acidoBase: Omit<AcidoBase, 'id'>) => {
const internacion = state.internaciones.find(i => i.id === acidoBase.internacionId);
const areaId = internacion?.areaId || null;
if (!canEditInArea(areaId)) {
console.warn('No tiene permisos para agregar ácido-base en esta área');
return null;
}
const nuevoAcidoBase: AcidoBase = { const nuevoAcidoBase: AcidoBase = {
...acidoBase, ...acidoBase,
id: generateUUID(), id: generateUUID(),
@@ -320,24 +392,46 @@ const finalizarInternacion = useCallback((internacionId: string, datos: {
acidosBase: [...prev.acidosBase, nuevoAcidoBase], acidosBase: [...prev.acidosBase, nuevoAcidoBase],
})); }));
return nuevoAcidoBase.id; return nuevoAcidoBase.id;
}, []); }, [state.internaciones, state.currentUser]);
const actualizarAcidoBase = useCallback((id: string, datos: Partial<AcidoBase>) => { const actualizarAcidoBase = useCallback((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 (!canEditInArea(areaId)) {
console.warn('No tiene permisos para actualizar ácido-base en esta área');
return;
}
setState(prev => ({ setState(prev => ({
...prev, ...prev,
acidosBase: prev.acidosBase.map(a => a.id === id ? { ...a, ...datos } : a), acidosBase: prev.acidosBase.map(a => a.id === id ? { ...a, ...datos } : a),
})); }));
}, []); }, [state.internaciones, state.currentUser]);
const eliminarAcidoBase = useCallback((id: string) => { const eliminarAcidoBase = useCallback((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 (!canEditInArea(areaId)) {
console.warn('No tiene permisos para eliminar ácido-base en esta área');
return;
}
setState(prev => ({ setState(prev => ({
...prev, ...prev,
acidosBase: prev.acidosBase.filter(a => a.id !== id), acidosBase: prev.acidosBase.filter(a => a.id !== id),
})); }));
}, []); }, [state.internaciones, state.currentUser]);
// Acciones de cultivos // Acciones de cultivos
const agregarCultivo = useCallback((cultivo: Omit<Cultivo, 'id'>) => { const agregarCultivo = useCallback((cultivo: Omit<Cultivo, 'id'>) => {
const internacion = state.internaciones.find(i => i.id === cultivo.internacionId);
const areaId = internacion?.areaId || null;
if (!canEditInArea(areaId)) {
console.warn('No tiene permisos para agregar cultivo en esta área');
return null;
}
const nuevoCultivo: Cultivo = { const nuevoCultivo: Cultivo = {
...cultivo, ...cultivo,
id: generateUUID(), id: generateUUID(),
@@ -347,24 +441,46 @@ const finalizarInternacion = useCallback((internacionId: string, datos: {
cultivos: [...prev.cultivos, nuevoCultivo], cultivos: [...prev.cultivos, nuevoCultivo],
})); }));
return nuevoCultivo.id; return nuevoCultivo.id;
}, []); }, [state.internaciones, state.currentUser]);
const actualizarCultivo = useCallback((id: string, datos: Partial<Cultivo>) => { const actualizarCultivo = useCallback((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 (!canEditInArea(areaId)) {
console.warn('No tiene permisos para actualizar cultivo en esta área');
return;
}
setState(prev => ({ setState(prev => ({
...prev, ...prev,
cultivos: prev.cultivos.map(c => c.id === id ? { ...c, ...datos } : c), cultivos: prev.cultivos.map(c => c.id === id ? { ...c, ...datos } : c),
})); }));
}, []); }, [state.internaciones, state.currentUser]);
const eliminarCultivo = useCallback((id: string) => { const eliminarCultivo = useCallback((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 (!canEditInArea(areaId)) {
console.warn('No tiene permisos para eliminar cultivo en esta área');
return;
}
setState(prev => ({ setState(prev => ({
...prev, ...prev,
cultivos: prev.cultivos.filter(c => c.id !== id), cultivos: prev.cultivos.filter(c => c.id !== id),
})); }));
}, []); }, [state.internaciones, state.currentUser]);
// Acciones de estudios complementarios // Acciones de estudios complementarios
const agregarEstudioComplementario = useCallback((estudio: Omit<EstudioComplementario, 'id'>) => { const agregarEstudioComplementario = useCallback((estudio: Omit<EstudioComplementario, 'id'>) => {
const internacion = state.internaciones.find(i => i.id === estudio.internacionId);
const areaId = internacion?.areaId || null;
if (!canEditInArea(areaId)) {
console.warn('No tiene permisos para agregar estudio complementario en esta área');
return null;
}
const nuevoEstudio: EstudioComplementario = { const nuevoEstudio: EstudioComplementario = {
...estudio, ...estudio,
id: generateUUID(), id: generateUUID(),
@@ -374,98 +490,186 @@ const finalizarInternacion = useCallback((internacionId: string, datos: {
estudiosComplementarios: [...prev.estudiosComplementarios, nuevoEstudio], estudiosComplementarios: [...prev.estudiosComplementarios, nuevoEstudio],
})); }));
return nuevoEstudio.id; return nuevoEstudio.id;
}, []); }, [state.internaciones, state.currentUser]);
const actualizarEstudioComplementario = useCallback((id: string, datos: Partial<EstudioComplementario>) => { const actualizarEstudioComplementario = useCallback((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 (!canEditInArea(areaId)) {
console.warn('No tiene permisos para actualizar estudio complementario en esta área');
return;
}
setState(prev => ({ setState(prev => ({
...prev, ...prev,
estudiosComplementarios: prev.estudiosComplementarios.map(e => e.id === id ? { ...e, ...datos } : e), estudiosComplementarios: prev.estudiosComplementarios.map(e => e.id === id ? { ...e, ...datos } : e),
})); }));
}, []); }, [state.internaciones, state.currentUser]);
const eliminarEstudioComplementario = useCallback((id: string) => { const eliminarEstudioComplementario = useCallback((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 (!canEditInArea(areaId)) {
console.warn('No tiene permisos para eliminar estudio complementario en esta área');
return;
}
setState(prev => ({ setState(prev => ({
...prev, ...prev,
estudiosComplementarios: prev.estudiosComplementarios.filter(e => e.id !== id), estudiosComplementarios: prev.estudiosComplementarios.filter(e => e.id !== id),
})); }));
}, []); }, [state.internaciones, state.currentUser]);
// Acciones de interconsultas // Acciones de interconsultas
const agregarInterconsulta = useCallback((interconsulta: Omit<Interconsulta, 'id'>) => { const agregarInterconsulta = useCallback((interconsulta: Omit<Interconsulta, 'id'>) => {
const internacion = state.internaciones.find(i => i.id === interconsulta.internacionId);
const areaId = internacion?.areaId || null;
if (!canEditInArea(areaId)) {
console.warn('No tiene permisos para agregar interconsulta en esta área');
return null;
}
const nuevaInterconsulta: Interconsulta = { ...interconsulta, id: generateUUID() }; const nuevaInterconsulta: Interconsulta = { ...interconsulta, id: generateUUID() };
setState(prev => ({ setState(prev => ({
...prev, ...prev,
interconsultas: [...(prev.interconsultas || []), nuevaInterconsulta], interconsultas: [...(prev.interconsultas || []), nuevaInterconsulta],
})); }));
return nuevaInterconsulta.id; return nuevaInterconsulta.id;
}, []); }, [state.internaciones, state.currentUser]);
const actualizarInterconsulta = useCallback((id: string, datos: Partial<Interconsulta>) => { const actualizarInterconsulta = useCallback((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 (!canEditInArea(areaId)) {
console.warn('No tiene permisos para actualizar interconsulta en esta área');
return;
}
setState(prev => ({ setState(prev => ({
...prev, ...prev,
interconsultas: (prev.interconsultas || []).map(ic => ic.id === id ? { ...ic, ...datos } : ic), interconsultas: (prev.interconsultas || []).map(ic => ic.id === id ? { ...ic, ...datos } : ic),
})); }));
}, []); }, [state.internaciones, state.currentUser]);
const eliminarInterconsulta = useCallback((id: string) => { const eliminarInterconsulta = useCallback((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 (!canEditInArea(areaId)) {
console.warn('No tiene permisos para eliminar interconsulta en esta área');
return;
}
setState(prev => ({ setState(prev => ({
...prev, ...prev,
interconsultas: (prev.interconsultas || []).filter(ic => ic.id !== id), interconsultas: (prev.interconsultas || []).filter(ic => ic.id !== id),
})); }));
}, []); }, [state.internaciones, state.currentUser]);
const agregarATB = useCallback((atb: Omit<ATB, 'id'>) => { const agregarATB = useCallback((atb: Omit<ATB, 'id'>) => {
const internacion = state.internaciones.find(i => i.id === atb.internacionId);
const areaId = internacion?.areaId || null;
if (!canEditInArea(areaId)) {
console.warn('No tiene permisos para agregar ATB en esta área');
return null;
}
const nuevoATB: ATB = { ...atb, id: generateUUID() }; const nuevoATB: ATB = { ...atb, id: generateUUID() };
setState(prev => ({ setState(prev => ({
...prev, ...prev,
atb: [...prev.atb, nuevoATB], atb: [...prev.atb, nuevoATB],
})); }));
return nuevoATB.id; return nuevoATB.id;
}, []); }, [state.internaciones, state.currentUser]);
const actualizarATB = useCallback((id: string, datos: Partial<ATB>) => { const actualizarATB = useCallback((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 (!canEditInArea(areaId)) {
console.warn('No tiene permisos para actualizar ATB en esta área');
return;
}
setState(prev => ({ setState(prev => ({
...prev, ...prev,
atb: prev.atb.map(a => a.id === id ? { ...a, ...datos } : a), atb: prev.atb.map(a => a.id === id ? { ...a, ...datos } : a),
})); }));
}, []); }, [state.internaciones, state.currentUser]);
const eliminarATB = useCallback((id: string) => { const eliminarATB = useCallback((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 (!canEditInArea(areaId)) {
console.warn('No tiene permisos para eliminar ATB en esta área');
return;
}
setState(prev => ({ setState(prev => ({
...prev, ...prev,
atb: prev.atb.filter(a => a.id !== id), atb: prev.atb.filter(a => a.id !== id),
})); }));
}, []); }, [state.internaciones, state.currentUser]);
const agregarIndicacion = useCallback((indicacion: Omit<Indicacion, 'id'>) => { const agregarIndicacion = useCallback((indicacion: Omit<Indicacion, 'id'>) => {
const internacion = state.internaciones.find(i => i.id === indicacion.internacionId);
const areaId = internacion?.areaId || null;
if (!canEditInArea(areaId)) {
console.warn('No tiene permisos para agregar indicación en esta área');
return null;
}
const nuevaIndicacion: Indicacion = { ...indicacion, id: generateUUID() }; const nuevaIndicacion: Indicacion = { ...indicacion, id: generateUUID() };
setState(prev => ({ setState(prev => ({
...prev, ...prev,
indicaciones: [...prev.indicaciones, nuevaIndicacion], indicaciones: [...prev.indicaciones, nuevaIndicacion],
})); }));
return nuevaIndicacion.id; return nuevaIndicacion.id;
}, []); }, [state.internaciones, state.currentUser]);
const actualizarIndicacion = useCallback((id: string, datos: Partial<Indicacion>) => { const actualizarIndicacion = useCallback((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 (!canEditInArea(areaId)) {
console.warn('No tiene permisos para actualizar indicación en esta área');
return;
}
setState(prev => ({ setState(prev => ({
...prev, ...prev,
indicaciones: prev.indicaciones.map(i => i.id === id ? { ...i, ...datos } : i), indicaciones: prev.indicaciones.map(i => i.id === id ? { ...i, ...datos } : i),
})); }));
}, []); }, [state.internaciones, state.currentUser]);
const eliminarIndicacion = useCallback((id: string) => { const eliminarIndicacion = useCallback((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 (!canEditInArea(areaId)) {
console.warn('No tiene permisos para eliminar indicación en esta área');
return;
}
setState(prev => ({ setState(prev => ({
...prev, ...prev,
indicaciones: prev.indicaciones.filter(i => i.id !== id), indicaciones: prev.indicaciones.filter(i => i.id !== id),
})); }));
}, []); }, [state.internaciones, state.currentUser]);
const agregarMovimientoIndicacion = useCallback((movimiento: any) => { const agregarMovimientoIndicacion = useCallback((movimiento: any) => {
const internacion = state.internaciones.find(i => i.id === movimiento.internacionId);
const areaId = internacion?.areaId || null;
if (!canEditInArea(areaId)) {
console.warn('No tiene permisos para agregar movimiento de indicación en esta área');
return;
}
setState(prev => ({ setState(prev => ({
...prev, ...prev,
movimientosIndicaciones: [...(prev.movimientosIndicaciones || []), { ...movimiento, id: generateUUID() }], movimientosIndicaciones: [...(prev.movimientosIndicaciones || []), { ...movimiento, id: generateUUID() }],
})); }));
}, []); }, [state.internaciones, state.currentUser]);
const getMovimientosByInternacion = useCallback((internacionId: string) => { const getMovimientosByInternacion = useCallback((internacionId: string) => {
return (state.movimientosIndicaciones || []) return (state.movimientosIndicaciones || [])
@@ -662,6 +866,9 @@ const getEstadisticas = useCallback(() => {
const getInternacionAreaId = useCallback((internacionId: string): string | null => { const getInternacionAreaId = useCallback((internacionId: string): string | null => {
const internacion = state.internaciones.find(i => i.id === internacionId); const internacion = state.internaciones.find(i => i.id === internacionId);
if (!internacion) return null; if (!internacion) return null;
// Use the new areaId field first
if (internacion.areaId) return internacion.areaId;
// Fallback to cama's area
return getCamaAreaId(internacion.camaId); return getCamaAreaId(internacion.camaId);
}, [state.internaciones, getCamaAreaId]); }, [state.internaciones, getCamaAreaId]);
+25 -3
View File
@@ -34,6 +34,7 @@ export function EditIngreso({
const [pacienteSeleccionado, setPacienteSeleccionado] = useState(internacion.pacienteId); const [pacienteSeleccionado, setPacienteSeleccionado] = useState(internacion.pacienteId);
const [busqueda, setBusqueda] = useState(''); const [busqueda, setBusqueda] = useState('');
const [camaSeleccionada, setCamaSeleccionada] = useState(internacion.camaId); const [camaSeleccionada, setCamaSeleccionada] = useState(internacion.camaId);
const [areaSeleccionada, setAreaSeleccionada] = useState(internacion.areaId);
const [medico, setMedico] = useState(internacion.medicoIngresante); const [medico, setMedico] = useState(internacion.medicoIngresante);
const [fechaIngresoHospital, setFechaIngresoHospital] = useState(internacion.fechaIngresoHospital || ''); const [fechaIngresoHospital, setFechaIngresoHospital] = useState(internacion.fechaIngresoHospital || '');
const [fechaIngresoClinica, setFechaIngresoClinica] = useState(internacion.fechaIngresoClinica || ''); const [fechaIngresoClinica, setFechaIngresoClinica] = useState(internacion.fechaIngresoClinica || '');
@@ -56,9 +57,13 @@ export function EditIngreso({
}; };
const selectedPaciente = pacientes.find(p => p.id === pacienteSeleccionado); const selectedPaciente = pacientes.find(p => p.id === pacienteSeleccionado);
const areasDisponibles = areas.filter(a => {
const nombre = (a.nombre || '').trim().toLowerCase();
return nombre !== 'fuera de area';
});
const handleSubmit = () => { const handleSubmit = () => {
if (!pacienteSeleccionado || !camaSeleccionada || !medico || !diagnosticoIngreso || !enfermedadActual) { if (!pacienteSeleccionado || !camaSeleccionada || !areaSeleccionada || !medico || !diagnosticoIngreso || !enfermedadActual) {
alert('Por favor complete los campos obligatorios'); alert('Por favor complete los campos obligatorios');
return; return;
} }
@@ -66,6 +71,7 @@ export function EditIngreso({
onActualizarInternacion(internacion.id, { onActualizarInternacion(internacion.id, {
pacienteId: pacienteSeleccionado, pacienteId: pacienteSeleccionado,
camaId: camaSeleccionada, camaId: camaSeleccionada,
areaId: areaSeleccionada,
medicoIngresante: medico, medicoIngresante: medico,
diagnosticoIngreso, diagnosticoIngreso,
motivoConsulta: motivoConsulta || undefined, motivoConsulta: motivoConsulta || undefined,
@@ -180,17 +186,33 @@ export function EditIngreso({
</Card> </Card>
</div> </div>
{/* Columna 2: Cama */} {/* Columna 2: Cama y Área */}
<div className="space-y-6"> <div className="space-y-6">
<Card className="min-h-[200px]"> <Card className="min-h-[200px]">
<CardContent className="pt-6 space-y-4"> <CardContent className="pt-6 space-y-4">
<h3 className="font-semibold text-gray-900 flex items-center gap-2"> <h3 className="font-semibold text-gray-900 flex items-center gap-2">
<Bed className="h-4 w-4" /> <Bed className="h-4 w-4" />
Asignación de Cama Asignación de Cama y Área
</h3> </h3>
<div> <div>
<Label>Área de Trabajo *</Label>
<Select value={areaSeleccionada} onValueChange={setAreaSeleccionada}>
<SelectTrigger>
<SelectValue placeholder="Seleccionar área" />
</SelectTrigger>
<SelectContent>
{areasDisponibles.map(a => (
<SelectItem key={a.id} value={a.id}>
{a.nombre}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div>
<Label>Cama</Label>
<Select value={camaSeleccionada} onValueChange={setCamaSeleccionada}> <Select value={camaSeleccionada} onValueChange={setCamaSeleccionada}>
<SelectTrigger> <SelectTrigger>
<SelectValue placeholder="Seleccionar cama" /> <SelectValue placeholder="Seleccionar cama" />
+2
View File
@@ -266,10 +266,12 @@ export function HistoriaClinica({
<ArrowLeft className="h-4 w-4 mr-2" /> <ArrowLeft className="h-4 w-4 mr-2" />
Volver Volver
</Button> </Button>
{canEdit && onEditarIngreso && (
<Button onClick={onEditarIngreso}> <Button onClick={onEditarIngreso}>
<Pencil className="h-4 w-4 mr-2" /> <Pencil className="h-4 w-4 mr-2" />
Editar Ingreso Editar Ingreso
</Button> </Button>
)}
</div> </div>
<Card> <Card>
+19 -1
View File
@@ -49,6 +49,7 @@ export function Internaciones({
const [busqueda, setBusqueda] = useState(''); const [busqueda, setBusqueda] = useState('');
const [pacienteSeleccionado, setPacienteSeleccionado] = useState<string>(''); const [pacienteSeleccionado, setPacienteSeleccionado] = useState<string>('');
const [camaSeleccionada, setCamaSeleccionada] = useState<string>(''); const [camaSeleccionada, setCamaSeleccionada] = useState<string>('');
const [areaSeleccionada, setAreaSeleccionada] = useState<string>('');
const [diagnosticoIngreso, setDiagnosticoIngreso] = useState(''); const [diagnosticoIngreso, setDiagnosticoIngreso] = useState('');
const [enfermedadActual, setEnfermedadActual] = useState(''); const [enfermedadActual, setEnfermedadActual] = useState('');
const [motivoConsulta, setMotivoConsulta] = useState(''); const [motivoConsulta, setMotivoConsulta] = useState('');
@@ -63,6 +64,7 @@ export function Internaciones({
const resetFormularioNueva = () => { const resetFormularioNueva = () => {
setPacienteSeleccionado(''); setPacienteSeleccionado('');
setCamaSeleccionada(''); setCamaSeleccionada('');
setAreaSeleccionada('');
setDiagnosticoIngreso(''); setDiagnosticoIngreso('');
setEnfermedadActual(''); setEnfermedadActual('');
setAntecedentesEnfermedadActual(''); setAntecedentesEnfermedadActual('');
@@ -77,10 +79,11 @@ export function Internaciones({
}; };
const handleIniciarInternacion = () => { const handleIniciarInternacion = () => {
if (pacienteSeleccionado && camaSeleccionada && motivoConsulta && enfermedadActual && medicoIngresante) { if (pacienteSeleccionado && camaSeleccionada && areaSeleccionada && motivoConsulta && enfermedadActual && medicoIngresante) {
onIniciarInternacion({ onIniciarInternacion({
pacienteId: pacienteSeleccionado, pacienteId: pacienteSeleccionado,
camaId: camaSeleccionada, camaId: camaSeleccionada,
areaId: areaSeleccionada,
diagnosticoIngreso: diagnosticoIngreso || motivoConsulta, diagnosticoIngreso: diagnosticoIngreso || motivoConsulta,
motivoConsulta, motivoConsulta,
enfermedadActual, enfermedadActual,
@@ -206,6 +209,21 @@ export function Internaciones({
</div> </div>
)} )}
</div> </div>
<div>
<Label>Área de Trabajo *</Label>
<Select value={areaSeleccionada} onValueChange={setAreaSeleccionada}>
<SelectTrigger>
<SelectValue placeholder="Seleccionar área" />
</SelectTrigger>
<SelectContent>
{areas.filter(a => a.nombre !== 'Fuera de area').map(a => (
<SelectItem key={a.id} value={a.id}>
{a.nombre}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div> <div>
<Label>Cama *</Label> <Label>Cama *</Label>
<Select value={camaSeleccionada} onValueChange={setCamaSeleccionada}> <Select value={camaSeleccionada} onValueChange={setCamaSeleccionada}>
+19 -1
View File
@@ -47,6 +47,7 @@ export function MapaCamas({
const [filtroTipo, setFiltroTipo] = useState<string>('todos'); const [filtroTipo, setFiltroTipo] = useState<string>('todos');
const [filtroEstado, setFiltroEstado] = useState<string>('todos'); const [filtroEstado, setFiltroEstado] = useState<string>('todos');
const [camaSeleccionada, setCamaSeleccionada] = useState<Cama | null>(null); const [camaSeleccionada, setCamaSeleccionada] = useState<Cama | null>(null);
const [areaSeleccionada, setAreaSeleccionada] = useState<string>('');
const [pacienteSeleccionado, setPacienteSeleccionado] = useState<string>(''); const [pacienteSeleccionado, setPacienteSeleccionado] = useState<string>('');
const [diagnostico, setDiagnostico] = useState(''); const [diagnostico, setDiagnostico] = useState('');
const [enfermedadActual, setEnfermedadActual] = useState(''); const [enfermedadActual, setEnfermedadActual] = useState('');
@@ -147,10 +148,11 @@ export function MapaCamas({
}); });
const handleOcuparCama = () => { const handleOcuparCama = () => {
if (camaSeleccionada && pacienteSeleccionado && diagnostico && enfermedadActual && medico) { if (camaSeleccionada && areaSeleccionada && pacienteSeleccionado && diagnostico && enfermedadActual && medico) {
onIniciarInternacion({ onIniciarInternacion({
pacienteId: pacienteSeleccionado, pacienteId: pacienteSeleccionado,
camaId: camaSeleccionada.id, camaId: camaSeleccionada.id,
areaId: areaSeleccionada,
diagnosticoIngreso: diagnostico, diagnosticoIngreso: diagnostico,
enfermedadActual, enfermedadActual,
antecedentesEnfermedadActual: antecedentesEnfermedadActual || undefined, antecedentesEnfermedadActual: antecedentesEnfermedadActual || undefined,
@@ -158,6 +160,7 @@ export function MapaCamas({
}); });
setDialogoAbierto(false); setDialogoAbierto(false);
setCamaSeleccionada(null); setCamaSeleccionada(null);
setAreaSeleccionada('');
setPacienteSeleccionado(''); setPacienteSeleccionado('');
setDiagnostico(''); setDiagnostico('');
setEnfermedadActual(''); setEnfermedadActual('');
@@ -360,6 +363,21 @@ export function MapaCamas({
</SelectContent> </SelectContent>
</Select> </Select>
</div> </div>
<div>
<Label>Área de Trabajo *</Label>
<Select value={areaSeleccionada} onValueChange={setAreaSeleccionada}>
<SelectTrigger>
<SelectValue placeholder="Seleccionar área" />
</SelectTrigger>
<SelectContent>
{areas.filter(a => a.nombre !== 'Fuera de area').map(a => (
<SelectItem key={a.id} value={a.id}>
{a.nombre}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div> <div>
<Label>Diagnóstico de Ingreso *</Label> <Label>Diagnóstico de Ingreso *</Label>
<textarea <textarea
+26 -3
View File
@@ -23,6 +23,7 @@ export function NuevoIngreso({ pacientes, camas, areas, onIniciarInternacion, on
const [pacienteSeleccionado, setPacienteSeleccionado] = useState<string>(''); const [pacienteSeleccionado, setPacienteSeleccionado] = useState<string>('');
const [busqueda, setBusqueda] = useState(''); const [busqueda, setBusqueda] = useState('');
const [camaSeleccionada, setCamaSeleccionada] = useState(''); const [camaSeleccionada, setCamaSeleccionada] = useState('');
const [areaSeleccionada, setAreaSeleccionada] = useState('');
const [medico, setMedico] = useState(''); const [medico, setMedico] = useState('');
const [fechaIngresoHospital, setFechaIngresoHospital] = useState(''); const [fechaIngresoHospital, setFechaIngresoHospital] = useState('');
const [fechaIngresoClinica, setFechaIngresoClinica] = useState(''); const [fechaIngresoClinica, setFechaIngresoClinica] = useState('');
@@ -37,6 +38,7 @@ export function NuevoIngreso({ pacientes, camas, areas, onIniciarInternacion, on
setPacienteSeleccionado(''); setPacienteSeleccionado('');
setBusqueda(''); setBusqueda('');
setCamaSeleccionada(''); setCamaSeleccionada('');
setAreaSeleccionada('');
setMedico(''); setMedico('');
setFechaIngresoHospital(''); setFechaIngresoHospital('');
setFechaIngresoClinica(''); setFechaIngresoClinica('');
@@ -48,10 +50,14 @@ export function NuevoIngreso({ pacientes, camas, areas, onIniciarInternacion, on
setDerivacion(''); setDerivacion('');
}; };
const areasDisponibles = areas.filter(a => {
const nombre = (a.nombre || '').trim().toLowerCase();
return nombre !== 'fuera de area';
});
const pacientesSinInternar = pacientes; const pacientesSinInternar = pacientes;
const handleSubmit = () => { const handleSubmit = () => {
if (!pacienteSeleccionado || !camaSeleccionada || !medico || !diagnosticoIngreso || !enfermedadActual) { if (!pacienteSeleccionado || !camaSeleccionada || !areaSeleccionada || !medico || !diagnosticoIngreso || !enfermedadActual) {
alert('Por favor complete los campos obligatorios'); alert('Por favor complete los campos obligatorios');
return; return;
} }
@@ -59,6 +65,7 @@ export function NuevoIngreso({ pacientes, camas, areas, onIniciarInternacion, on
onIniciarInternacion({ onIniciarInternacion({
pacienteId: pacienteSeleccionado, pacienteId: pacienteSeleccionado,
camaId: camaSeleccionada, camaId: camaSeleccionada,
areaId: areaSeleccionada,
medicoIngresante: medico, medicoIngresante: medico,
diagnosticoIngreso, diagnosticoIngreso,
motivoConsulta: motivoConsulta || undefined, motivoConsulta: motivoConsulta || undefined,
@@ -163,15 +170,31 @@ export function NuevoIngreso({ pacientes, camas, areas, onIniciarInternacion, on
</Card> </Card>
</div> </div>
{/* Columna 2: Cama */} {/* Columna 2: Cama y Área */}
<div className="space-y-6"> <div className="space-y-6">
<Card className="min-h-[200px]"> <Card className="min-h-[200px]">
<CardContent className="pt-6 space-y-4"> <CardContent className="pt-6 space-y-4">
<h3 className="font-semibold text-gray-900 flex items-center gap-2"> <h3 className="font-semibold text-gray-900 flex items-center gap-2">
<Bed className="h-4 w-4" /> <Bed className="h-4 w-4" />
Asignación de Cama Asignación de Cama y Área
</h3> </h3>
<div>
<Label>Área de Trabajo *</Label>
<Select value={areaSeleccionada} onValueChange={setAreaSeleccionada}>
<SelectTrigger>
<SelectValue placeholder="Seleccionar área" />
</SelectTrigger>
<SelectContent>
{areasDisponibles.map(a => (
<SelectItem key={a.id} value={a.id}>
{a.nombre}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div> <div>
<Label>Cama *</Label> <Label>Cama *</Label>
<Select value={camaSeleccionada} onValueChange={setCamaSeleccionada}> <Select value={camaSeleccionada} onValueChange={setCamaSeleccionada}>
+1
View File
@@ -40,6 +40,7 @@ export interface Internacion {
id: string; id: string;
pacienteId: string; pacienteId: string;
camaId: string; camaId: string;
areaId: string;
fechaIngresoHospital?: string; fechaIngresoHospital?: string;
fechaIngresoClinica?: string; fechaIngresoClinica?: string;
fechaEgreso?: string; fechaEgreso?: string;