159 lines
6.0 KiB
TypeScript
159 lines
6.0 KiB
TypeScript
|
|
import React, { useState, useEffect, useCallback } from 'react';
|
||
|
|
import { useParams, useNavigate } from 'react-router-dom';
|
||
|
|
import {
|
||
|
|
Box, Typography, Button, Paper, CircularProgress, Alert,
|
||
|
|
Checkbox, FormControlLabel, FormGroup // Para el caso sin componente checklist
|
||
|
|
} from '@mui/material';
|
||
|
|
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
|
||
|
|
import SaveIcon from '@mui/icons-material/Save';
|
||
|
|
import perfilService from '../../services/Usuarios/perfilService';
|
||
|
|
import type { PermisoAsignadoDto } from '../../models/dtos/Usuarios/PermisoAsignadoDto';
|
||
|
|
import type { PerfilDto } from '../../models/dtos/Usuarios/PerfilDto';
|
||
|
|
import { usePermissions } from '../../hooks/usePermissions'; // Para verificar si el usuario actual puede estar aquí
|
||
|
|
import axios from 'axios';
|
||
|
|
import PermisosChecklist from '../../components/Modals/Usuarios/PermisosChecklist'; // Importar el componente
|
||
|
|
|
||
|
|
const AsignarPermisosAPerfilPage: React.FC = () => {
|
||
|
|
const { idPerfil } = useParams<{ idPerfil: string }>();
|
||
|
|
const navigate = useNavigate();
|
||
|
|
const { tienePermiso, isSuperAdmin } = usePermissions();
|
||
|
|
|
||
|
|
const puedeAsignar = isSuperAdmin || tienePermiso("PU004");
|
||
|
|
|
||
|
|
const [perfil, setPerfil] = useState<PerfilDto | null>(null);
|
||
|
|
const [permisosDisponibles, setPermisosDisponibles] = useState<PermisoAsignadoDto[]>([]);
|
||
|
|
// Usamos un Set para los IDs de los permisos seleccionados para eficiencia
|
||
|
|
const [permisosSeleccionados, setPermisosSeleccionados] = useState<Set<number>>(new Set());
|
||
|
|
const [loading, setLoading] = useState(true);
|
||
|
|
const [saving, setSaving] = useState(false);
|
||
|
|
const [error, setError] = useState<string | null>(null);
|
||
|
|
const [successMessage, setSuccessMessage] = useState<string | null>(null);
|
||
|
|
|
||
|
|
const idPerfilNum = Number(idPerfil);
|
||
|
|
|
||
|
|
const cargarDatos = useCallback(async () => {
|
||
|
|
if (!puedeAsignar) {
|
||
|
|
setError("Acceso denegado. No tiene permiso para asignar permisos.");
|
||
|
|
setLoading(false);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (isNaN(idPerfilNum)) {
|
||
|
|
setError("ID de Perfil inválido.");
|
||
|
|
setLoading(false);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
setLoading(true); setError(null); setSuccessMessage(null);
|
||
|
|
try {
|
||
|
|
const [perfilData, permisosData] = await Promise.all([
|
||
|
|
perfilService.getPerfilById(idPerfilNum),
|
||
|
|
perfilService.getPermisosPorPerfil(idPerfilNum)
|
||
|
|
]);
|
||
|
|
setPerfil(perfilData);
|
||
|
|
setPermisosDisponibles(permisosData);
|
||
|
|
// Inicializar los permisos seleccionados basados en los que vienen 'asignado: true'
|
||
|
|
setPermisosSeleccionados(new Set(permisosData.filter(p => p.asignado).map(p => p.id)));
|
||
|
|
} catch (err) {
|
||
|
|
console.error(err);
|
||
|
|
setError('Error al cargar datos del perfil o permisos.');
|
||
|
|
if (axios.isAxiosError(err) && err.response?.status === 404) {
|
||
|
|
setError(`Perfil con ID ${idPerfilNum} no encontrado.`);
|
||
|
|
}
|
||
|
|
} finally {
|
||
|
|
setLoading(false);
|
||
|
|
}
|
||
|
|
}, [idPerfilNum, puedeAsignar]);
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
cargarDatos();
|
||
|
|
}, [cargarDatos]);
|
||
|
|
|
||
|
|
const handlePermisoChange = (permisoId: number, asignado: boolean) => {
|
||
|
|
setPermisosSeleccionados(prev => {
|
||
|
|
const next = new Set(prev);
|
||
|
|
if (asignado) {
|
||
|
|
next.add(permisoId);
|
||
|
|
} else {
|
||
|
|
next.delete(permisoId);
|
||
|
|
}
|
||
|
|
return next;
|
||
|
|
});
|
||
|
|
// Limpiar mensajes al cambiar selección
|
||
|
|
if (successMessage) setSuccessMessage(null);
|
||
|
|
if (error) setError(null);
|
||
|
|
};
|
||
|
|
|
||
|
|
const handleGuardarCambios = async () => {
|
||
|
|
if (!puedeAsignar || !perfil) return;
|
||
|
|
setSaving(true); setError(null); setSuccessMessage(null);
|
||
|
|
try {
|
||
|
|
await perfilService.updatePermisosPorPerfil(perfil.id, {
|
||
|
|
permisosIds: Array.from(permisosSeleccionados)
|
||
|
|
});
|
||
|
|
setSuccessMessage('Permisos actualizados correctamente.');
|
||
|
|
// Opcional: recargar datos, aunque el estado local ya está actualizado
|
||
|
|
// cargarDatos();
|
||
|
|
} catch (err: any) {
|
||
|
|
console.error(err);
|
||
|
|
const message = axios.isAxiosError(err) && err.response?.data?.message
|
||
|
|
? err.response.data.message
|
||
|
|
: 'Error al guardar los permisos.';
|
||
|
|
setError(message);
|
||
|
|
} finally {
|
||
|
|
setSaving(false);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
if (loading) {
|
||
|
|
return <Box sx={{ display: 'flex', justifyContent: 'center', p: 3 }}><CircularProgress /></Box>;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (error && !perfil) { // Si hay un error crítico al cargar el perfil
|
||
|
|
return <Alert severity="error" sx={{ m: 2 }}>{error}</Alert>;
|
||
|
|
}
|
||
|
|
if (!puedeAsignar) {
|
||
|
|
return <Alert severity="error" sx={{ m: 2 }}>Acceso denegado.</Alert>;
|
||
|
|
}
|
||
|
|
if (!perfil) { // Si no hay error, pero el perfil es null después de cargar (no debería pasar si no hay error)
|
||
|
|
return <Alert severity="warning" sx={{ m: 2 }}>Perfil no encontrado.</Alert>;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
return (
|
||
|
|
<Box sx={{ p: 2 }}>
|
||
|
|
<Button startIcon={<ArrowBackIcon />} onClick={() => navigate('/usuarios/perfiles')} sx={{ mb: 2 }}>
|
||
|
|
Volver a Perfiles
|
||
|
|
</Button>
|
||
|
|
<Typography variant="h4" gutterBottom>
|
||
|
|
Asignar Permisos al Perfil: {perfil?.nombrePerfil || 'Cargando...'}
|
||
|
|
</Typography>
|
||
|
|
<Typography variant="body2" color="textSecondary" gutterBottom>
|
||
|
|
ID Perfil: {perfil?.id}
|
||
|
|
</Typography>
|
||
|
|
|
||
|
|
{error && <Alert severity="error" sx={{ mb: 2 }}>{error}</Alert>}
|
||
|
|
{successMessage && <Alert severity="success" sx={{ mb: 2 }}>{successMessage}</Alert>}
|
||
|
|
|
||
|
|
<Paper sx={{ p: 2, mt: 2 }}>
|
||
|
|
<PermisosChecklist
|
||
|
|
permisosDisponibles={permisosDisponibles}
|
||
|
|
permisosSeleccionados={permisosSeleccionados}
|
||
|
|
onPermisoChange={handlePermisoChange}
|
||
|
|
disabled={saving}
|
||
|
|
/>
|
||
|
|
<Box sx={{ mt: 3, display: 'flex', justifyContent: 'flex-end' }}>
|
||
|
|
<Button
|
||
|
|
variant="contained"
|
||
|
|
color="primary"
|
||
|
|
startIcon={saving ? <CircularProgress size={20} color="inherit" /> : <SaveIcon />}
|
||
|
|
onClick={handleGuardarCambios}
|
||
|
|
disabled={saving || !puedeAsignar}
|
||
|
|
>
|
||
|
|
Guardar Cambios
|
||
|
|
</Button>
|
||
|
|
</Box>
|
||
|
|
</Paper>
|
||
|
|
</Box>
|
||
|
|
);
|
||
|
|
};
|
||
|
|
|
||
|
|
export default AsignarPermisosAPerfilPage;
|