'use client'; export const dynamic = 'force-dynamic'; import React, { useState, useEffect, useRef } from 'react'; import { useAuth } from '../../../../contexts/AuthContext'; import ProtectedRoute from '../../../../components/auth/ProtectedRoute'; import { Card } from 'primereact/card'; import { Button } from 'primereact/button'; import { DataTable } from 'primereact/datatable'; import { Column } from 'primereact/column'; import { Toast } from 'primereact/toast'; import { Toolbar } from 'primereact/toolbar'; import { InputText } from 'primereact/inputtext'; import { Dialog } from 'primereact/dialog'; import { Dropdown } from 'primereact/dropdown'; import { InputTextarea } from 'primereact/inputtextarea'; import { Tag } from 'primereact/tag'; import { Checkbox } from 'primereact/checkbox'; import { Tree } from 'primereact/tree'; import { TabView, TabPanel } from 'primereact/tabview'; import { Panel } from 'primereact/panel'; import { Badge } from 'primereact/badge'; import { Chip } from 'primereact/chip'; interface Permission { id: string; nom: string; description: string; module: string; action: 'CREATE' | 'READ' | 'UPDATE' | 'DELETE' | 'EXECUTE'; ressource: string; cle: string; } interface Role { id: string; nom: string; description: string; type: 'SYSTEM' | 'CUSTOM'; permissions: string[]; utilisateursAssignes: number; dateCreation: Date; dateModification: Date; actif: boolean; couleur: string; priorite: number; heriteDe?: string; } interface ModulePermission { module: string; permissions: Permission[]; } const RolesPermissionsPage = () => { const [roles, setRoles] = useState([]); const [permissions, setPermissions] = useState([]); const [modulesPermissions, setModulesPermissions] = useState([]); const [selectedRoles, setSelectedRoles] = useState([]); const [loading, setLoading] = useState(true); const [globalFilter, setGlobalFilter] = useState(''); const [roleDialog, setRoleDialog] = useState(false); const [permissionDialog, setPermissionDialog] = useState(false); const [deleteRoleDialog, setDeleteRoleDialog] = useState(false); const [activeIndex, setActiveIndex] = useState(0); const [role, setRole] = useState({ id: '', nom: '', description: '', type: 'CUSTOM', permissions: [], utilisateursAssignes: 0, dateCreation: new Date(), dateModification: new Date(), actif: true, couleur: '#2196F3', priorite: 0 }); const [permission, setPermission] = useState({ id: '', nom: '', description: '', module: '', action: 'READ', ressource: '', cle: '' }); const [submitted, setSubmitted] = useState(false); const [selectedPermissions, setSelectedPermissions] = useState([]); const toast = useRef(null); const dt = useRef>(null); const modules = [ 'Dashboard', 'Utilisateurs', 'Clients', 'Chantiers', 'Devis', 'Factures', 'Stock', 'Planning', 'Rapports', 'Administration', 'Système' ]; const actions = [ { label: 'Créer', value: 'CREATE' }, { label: 'Lire', value: 'READ' }, { label: 'Modifier', value: 'UPDATE' }, { label: 'Supprimer', value: 'DELETE' }, { label: 'Exécuter', value: 'EXECUTE' } ]; const couleurs = [ { label: 'Bleu', value: '#2196F3' }, { label: 'Vert', value: '#4CAF50' }, { label: 'Orange', value: '#FF9800' }, { label: 'Rouge', value: '#F44336' }, { label: 'Violet', value: '#9C27B0' }, { label: 'Indigo', value: '#3F51B5' } ]; useEffect(() => { loadData(); }, []); const loadData = async () => { try { setLoading(true); // TODO: Remplacer par un appel API réel pour charger les permissions depuis le backend // Exemple: const response = await fetch('/api/admin/permissions'); // const permissions = await response.json(); const mockPermissions: Permission[] = []; // TODO: Remplacer par un appel API réel pour charger les rôles depuis le backend // Exemple: const response = await fetch('/api/admin/roles'); // const roles = await response.json(); const mockRoles: Role[] = []; // Groupement par modules const groupedPermissions: ModulePermission[] = modules.map(module => ({ module, permissions: mockPermissions.filter(p => p.module === module) })).filter(group => group.permissions.length > 0); setPermissions(mockPermissions); setRoles(mockRoles); setModulesPermissions(groupedPermissions); } catch (error) { console.error('Erreur lors du chargement:', error); toast.current?.show({ severity: 'error', summary: 'Erreur', detail: 'Impossible de charger les données', life: 3000 }); } finally { setLoading(false); } }; const openNewRole = () => { setRole({ id: '', nom: '', description: '', type: 'CUSTOM', permissions: [], utilisateursAssignes: 0, dateCreation: new Date(), dateModification: new Date(), actif: true, couleur: '#2196F3', priorite: 0 }); setSelectedPermissions([]); setSubmitted(false); setRoleDialog(true); }; const editRole = (role: Role) => { setRole({ ...role }); setSelectedPermissions([...role.permissions]); setRoleDialog(true); }; const confirmDeleteRole = (role: Role) => { setRole(role); setDeleteRoleDialog(true); }; const deleteRole = () => { if (role.type === 'SYSTEM') { toast.current?.show({ severity: 'error', summary: 'Erreur', detail: 'Impossible de supprimer un rôle système', life: 3000 }); return; } const updatedRoles = roles.filter(r => r.id !== role.id); setRoles(updatedRoles); setDeleteRoleDialog(false); toast.current?.show({ severity: 'success', summary: 'Succès', detail: 'Rôle supprimé', life: 3000 }); }; const saveRole = () => { setSubmitted(true); if (role.nom.trim() && role.description.trim()) { let updatedRoles = [...roles]; const roleToSave = { ...role, permissions: selectedPermissions }; if (role.id) { // Mise à jour const index = roles.findIndex(r => r.id === role.id); updatedRoles[index] = { ...roleToSave, dateModification: new Date() }; toast.current?.show({ severity: 'success', summary: 'Succès', detail: 'Rôle mis à jour', life: 3000 }); } else { // Création const newRole = { ...roleToSave, id: Date.now().toString(), dateCreation: new Date(), dateModification: new Date() }; updatedRoles.push(newRole); toast.current?.show({ severity: 'success', summary: 'Succès', detail: 'Rôle créé', life: 3000 }); } setRoles(updatedRoles); setRoleDialog(false); } }; const duplicateRole = (role: Role) => { const newRole = { ...role, id: Date.now().toString(), nom: `${role.nom} (Copie)`, type: 'CUSTOM' as const, utilisateursAssignes: 0, dateCreation: new Date(), dateModification: new Date() }; setRoles([...roles, newRole]); toast.current?.show({ severity: 'success', summary: 'Succès', detail: 'Rôle dupliqué', life: 3000 }); }; const onPermissionToggle = (permissionId: string, checked: boolean) => { if (checked) { setSelectedPermissions([...selectedPermissions, permissionId]); } else { setSelectedPermissions(selectedPermissions.filter(id => id !== permissionId)); } }; const selectAllPermissionsForModule = (module: string, checked: boolean) => { const modulePermissions = permissions.filter(p => p.module === module).map(p => p.id); if (checked) { const newPermissions = [...selectedPermissions]; modulePermissions.forEach(permId => { if (!newPermissions.includes(permId)) { newPermissions.push(permId); } }); setSelectedPermissions(newPermissions); } else { setSelectedPermissions(selectedPermissions.filter(id => !modulePermissions.includes(id))); } }; const exportCSV = () => { dt.current?.exportCSV(); }; const leftToolbarTemplate = () => { return (
); }; const rightToolbarTemplate = () => { return (
); }; const actionBodyTemplate = (rowData: Role) => { return (
); }; const typeBodyTemplate = (rowData: Role) => { return ( ); }; const utilisateursBodyTemplate = (rowData: Role) => { return ; }; const permissionsBodyTemplate = (rowData: Role) => { return ; }; const couleurBodyTemplate = (rowData: Role) => { return (
{rowData.nom}
); }; const prioriteBodyTemplate = (rowData: Role) => { const getPriorityColor = (priority: number) => { if (priority >= 90) return 'danger'; if (priority >= 70) return 'warning'; if (priority >= 50) return 'info'; return 'success'; }; return ; }; const header = (
Gestion des Rôles et Permissions
r.actif).length} className="mr-2" /> rôles actifs
); return (
setActiveIndex(e.index)}> setSelectedRoles(e.value)} selectionMode="multiple" dataKey="id" paginator rows={10} rowsPerPageOptions={[5, 10, 25]} className="datatable-responsive" paginatorTemplate="FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink CurrentPageReport RowsPerPageDropdown" currentPageReportTemplate="Affichage de {first} à {last} sur {totalRecords} rôles" globalFilter={globalFilter} emptyMessage="Aucun rôle trouvé." header={header} loading={loading} > rowData.dateModification.toLocaleDateString()} sortable />
{modulesPermissions.map((moduleGroup, index) => (
{moduleGroup.permissions.map((permission) => (
{permission.nom}
{permission.description}
))}
))}
{roles.map(role => ( ))} {modulesPermissions.map((moduleGroup, moduleIndex) => ( {moduleGroup.permissions.map((permission) => ( {roles.map(role => ( ))} ))} ))}
Permission
{role.nom}
{moduleGroup.module}
{permission.nom}
{permission.action}
{role.permissions.includes(permission.id) ? ( ) : ( )}
{/* Dialog rôle */}
} onHide={() => setRoleDialog(false)} >
setRole({...role, nom: e.target.value})} required className={submitted && !role.nom ? 'p-invalid' : ''} /> {submitted && !role.nom && Le nom est requis.}
setRole({...role, couleur: e.value})} itemTemplate={(option) => (
{option.label}
)} />
setRole({...role, description: e.target.value})} rows={3} required className={submitted && !role.description ? 'p-invalid' : ''} /> {submitted && !role.description && La description est requise.}
setRole({...role, priorite: parseInt(e.target.value) || 0})} />
{modulesPermissions.map((moduleGroup, index) => (
{moduleGroup.module} selectedPermissions.includes(p.id))} onChange={(e) => selectAllPermissionsForModule(moduleGroup.module, e.checked || false)} />
} className="mb-3" >
{moduleGroup.permissions.map((permission) => (
onPermissionToggle(permission.id, e.checked || false)} />
{permission.nom}
{permission.description}
))}
))}
Résumé des permissions sélectionnées:
permissions sélectionnées
{/* Dialog suppression */} ); }; const ProtectedRolesPermissionsPage = () => { return ( ); }; export default ProtectedRolesPermissionsPage;