import React, { useEffect, useState } from 'react'; import api from '../../utils/api'; import { Card } from '../../components/ui/card'; import { Button } from '../../components/ui/button'; import { Input } from '../../components/ui/input'; import { Label } from '../../components/ui/label'; import { Textarea } from '../../components/ui/textarea'; import { Checkbox } from '../../components/ui/checkbox'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '../../components/ui/dialog'; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from '../../components/ui/alert-dialog'; import { toast } from 'sonner'; import { Shield, Plus, Edit, Trash2, Lock, ChevronDown, ChevronUp } from 'lucide-react'; const AdminRoles = () => { const [roles, setRoles] = useState([]); const [permissions, setPermissions] = useState([]); const [selectedRole, setSelectedRole] = useState(null); const [rolePermissions, setRolePermissions] = useState([]); const [selectedPermissions, setSelectedPermissions] = useState([]); const [loading, setLoading] = useState(true); const [showCreateModal, setShowCreateModal] = useState(false); const [showEditModal, setShowEditModal] = useState(false); const [showDeleteDialog, setShowDeleteDialog] = useState(false); const [showPermissionsModal, setShowPermissionsModal] = useState(false); const [expandedModules, setExpandedModules] = useState({}); const [formData, setFormData] = useState({ code: '', name: '', description: '', permissions: [] }); useEffect(() => { fetchRoles(); fetchPermissions(); }, []); const fetchRoles = async () => { try { const response = await api.get('/admin/roles'); setRoles(response.data); setLoading(false); } catch (error) { toast.error('Failed to fetch roles'); setLoading(false); } }; const fetchPermissions = async () => { try { const response = await api.get('/admin/permissions'); setPermissions(response.data); // Expand all modules by default const modules = [...new Set(response.data.map(p => p.module))]; const expanded = {}; modules.forEach(module => { expanded[module] = true; }); setExpandedModules(expanded); } catch (error) { toast.error('Failed to fetch permissions'); } }; const fetchRolePermissions = async (roleId) => { try { const response = await api.get(`/admin/roles/${roleId}/permissions`); setRolePermissions(response.data.permissions); setSelectedPermissions(response.data.permissions.map(p => p.code)); } catch (error) { toast.error('Failed to fetch role permissions'); } }; const handleCreateRole = async () => { try { await api.post('/admin/roles', { code: formData.code, name: formData.name, description: formData.description, permission_codes: formData.permissions }); toast.success('Role created successfully'); setShowCreateModal(false); setFormData({ code: '', name: '', description: '', permissions: [] }); fetchRoles(); } catch (error) { toast.error(error.response?.data?.detail || 'Failed to create role'); } }; const handleUpdateRole = async () => { try { await api.put(`/admin/roles/${selectedRole.id}`, { name: formData.name, description: formData.description }); toast.success('Role updated successfully'); setShowEditModal(false); fetchRoles(); } catch (error) { toast.error(error.response?.data?.detail || 'Failed to update role'); } }; const handleDeleteRole = async () => { try { await api.delete(`/admin/roles/${selectedRole.id}`); toast.success('Role deleted successfully'); setShowDeleteDialog(false); setSelectedRole(null); fetchRoles(); } catch (error) { toast.error(error.response?.data?.detail || 'Failed to delete role'); } }; const handleSavePermissions = async () => { try { await api.put(`/admin/roles/${selectedRole.id}/permissions`, { permission_codes: selectedPermissions }); toast.success('Permissions updated successfully'); setShowPermissionsModal(false); fetchRoles(); } catch (error) { toast.error('Failed to update permissions'); } }; const togglePermission = (permissionCode) => { setSelectedPermissions(prev => { if (prev.includes(permissionCode)) { return prev.filter(p => p !== permissionCode); } else { return [...prev, permissionCode]; } }); }; const toggleModule = (module) => { setExpandedModules(prev => ({ ...prev, [module]: !prev[module] })); }; const groupPermissionsByModule = () => { const grouped = {}; permissions.forEach(perm => { if (!grouped[perm.module]) { grouped[perm.module] = []; } grouped[perm.module].push(perm); }); return grouped; }; if (loading) { return (
Loading roles...
); } const groupedPermissions = groupPermissionsByModule(); return (
{/* Header */}

Role Management

Create and manage custom roles with specific permissions

{/* Roles Grid */}
{roles.map(role => (

{role.name}

{role.code}

{role.is_system_role && ( )}

{role.description || 'No description'}

{role.permission_count} permissions
{!role.is_system_role && ( <> )}
))}
{/* Create Role Modal */} Create New Role Create a custom role with specific permissions for your team members.
setFormData({ ...formData, code: e.target.value })} />

Lowercase, no spaces. Used internally to identify the role.

setFormData({ ...formData, name: e.target.value })} />