feat: implementar permisos por área de trabajo
- Agregar funciones de verificación de área en useHospitalStore - canEditInArea, canEditCama, canEditInternacion, canEditPaciente - Leer datos de tablas individuales en lugar de tabla kv - Usar sessionStorage para persistir sesión de usuario - Agregar prop canEdit a componentes de secciones en HC - Ocultar botones de edición para usuarios sin permisos en el área - MapaCamas: ocultar botones de edición para camas fuera del área
This commit is contained in:
@@ -88,6 +88,8 @@ export function useHospitalStore() {
|
||||
const body = await res.json();
|
||||
if (mounted && body) {
|
||||
const defaults = defaultState();
|
||||
const storedUser = sessionStorage.getItem('hospital_user');
|
||||
const currentUser = storedUser ? JSON.parse(storedUser) : null;
|
||||
const normalized = {
|
||||
...defaults,
|
||||
...body,
|
||||
@@ -95,6 +97,8 @@ export function useHospitalStore() {
|
||||
interconsultas: body.interconsultas || [],
|
||||
atb: body.atb || [],
|
||||
movimientosIndicaciones: body.movimientosIndicaciones || [],
|
||||
currentUser,
|
||||
isAuthenticated: !!currentUser,
|
||||
};
|
||||
setState(normalized);
|
||||
}
|
||||
@@ -108,15 +112,24 @@ export function useHospitalStore() {
|
||||
}, []);
|
||||
|
||||
// Persist state to backend when it changes (debounced)
|
||||
const [initialLoadComplete, setInitialLoadComplete] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isLoaded) return;
|
||||
if (isLoaded && !initialLoadComplete) {
|
||||
setInitialLoadComplete(true);
|
||||
}
|
||||
}, [isLoaded, initialLoadComplete]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!initialLoadComplete) return;
|
||||
const t = setTimeout(() => {
|
||||
(async () => {
|
||||
try {
|
||||
const { currentUser, isAuthenticated, ...stateToSave } = state;
|
||||
await fetch(`${API_BASE}/state`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(state),
|
||||
body: JSON.stringify(stateToSave),
|
||||
});
|
||||
} catch (err) {
|
||||
// ignore save errors for now
|
||||
@@ -124,7 +137,7 @@ export function useHospitalStore() {
|
||||
})();
|
||||
}, 300);
|
||||
return () => clearTimeout(t);
|
||||
}, [state, isLoaded]);
|
||||
}, [state, initialLoadComplete]);
|
||||
|
||||
// Acciones de navegación
|
||||
const setVista = useCallback((vista: Vista) => {
|
||||
@@ -570,6 +583,7 @@ const getEstadisticas = useCallback(() => {
|
||||
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;
|
||||
} catch (err) {
|
||||
@@ -578,13 +592,9 @@ const getEstadisticas = useCallback(() => {
|
||||
}, []);
|
||||
|
||||
const logout = useCallback(() => {
|
||||
sessionStorage.removeItem('hospital_user');
|
||||
setState(prev => {
|
||||
const newState = { ...prev, currentUser: null, isAuthenticated: false };
|
||||
fetch(`${API_BASE}/state`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ ...newState }),
|
||||
}).catch(() => {});
|
||||
return newState;
|
||||
});
|
||||
}, []);
|
||||
@@ -644,6 +654,50 @@ const getEstadisticas = useCallback(() => {
|
||||
return rol === 'admin';
|
||||
}, [state.currentUser, state.internaciones, state.camas]);
|
||||
|
||||
const getCamaAreaId = useCallback((camaId: string): string | null => {
|
||||
const cama = state.camas.find(c => c.id === camaId);
|
||||
return cama?.areaId || null;
|
||||
}, [state.camas]);
|
||||
|
||||
const getInternacionAreaId = useCallback((internacionId: string): string | null => {
|
||||
const internacion = state.internaciones.find(i => i.id === internacionId);
|
||||
if (!internacion) return null;
|
||||
return getCamaAreaId(internacion.camaId);
|
||||
}, [state.internaciones, getCamaAreaId]);
|
||||
|
||||
const getPacienteAreaId = useCallback((pacienteId: string): string | null => {
|
||||
const internacion = state.internaciones.find(i => i.pacienteId === pacienteId && i.activa);
|
||||
if (!internacion) {
|
||||
const anyInternacion = state.internaciones.find(i => i.pacienteId === pacienteId);
|
||||
if (anyInternacion) return getCamaAreaId(anyInternacion.camaId);
|
||||
return null;
|
||||
}
|
||||
return getCamaAreaId(internacion.camaId);
|
||||
}, [state.internaciones, getCamaAreaId]);
|
||||
|
||||
const canEditInArea = useCallback((areaId: string | null | undefined): boolean => {
|
||||
const user = state.currentUser;
|
||||
if (!user) return false;
|
||||
if (user.rol === 'admin') return true;
|
||||
if (!areaId) return false;
|
||||
return user.areaId === areaId;
|
||||
}, [state.currentUser]);
|
||||
|
||||
const canEditCama = useCallback((camaId: string): boolean => {
|
||||
const areaId = getCamaAreaId(camaId);
|
||||
return canEditInArea(areaId);
|
||||
}, [getCamaAreaId, canEditInArea]);
|
||||
|
||||
const canEditInternacion = useCallback((internacionId: string): boolean => {
|
||||
const areaId = getInternacionAreaId(internacionId);
|
||||
return canEditInArea(areaId);
|
||||
}, [getInternacionAreaId, canEditInArea]);
|
||||
|
||||
const canEditPaciente = useCallback((pacienteId: string): boolean => {
|
||||
const areaId = getPacienteAreaId(pacienteId);
|
||||
return canEditInArea(areaId);
|
||||
}, [getPacienteAreaId, canEditInArea]);
|
||||
|
||||
return {
|
||||
...state,
|
||||
isLoaded,
|
||||
@@ -702,5 +756,12 @@ const getEstadisticas = useCallback(() => {
|
||||
updateEmail,
|
||||
hasPermission,
|
||||
canAccessInternacion,
|
||||
canEditInArea,
|
||||
canEditCama,
|
||||
canEditInternacion,
|
||||
canEditPaciente,
|
||||
getCamaAreaId,
|
||||
getInternacionAreaId,
|
||||
getPacienteAreaId,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user