import { useState, useEffect } from "react"; import { Plus, Trash2, Pencil, RefreshCcw, AlertCircle, Loader2 } from "lucide-react"; import MaterialTable from "@material-table/core"; import { getAllRoles, createRole, updateRole, deleteRole, type Role } from "../api/roles"; import ConfirmModal from "../components/layout/common/ConfirmModal"; interface RoleForm { name: string; description: string; permissions?: Record>; } export default function RolesPage() { const [roles, setRoles] = useState([]); const [activeRole, setActiveRole] = useState(null); const [search, setSearch] = useState(""); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [showModal, setShowModal] = useState(false); const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); const [editingId, setEditingId] = useState(null); const emptyForm: RoleForm = { name: "", description: "", permissions: {}, }; const [form, setForm] = useState(emptyForm); useEffect(() => { fetchRoles(); }, []); const fetchRoles = async () => { setLoading(true); setError(null); try { const data = await getAllRoles(); setRoles(data); } catch (err) { setError(err instanceof Error ? err.message : "Failed to load roles"); console.error("Error fetching roles:", err); } finally { setLoading(false); } }; const handleSave = async () => { if (!form.name.trim()) { setError("Role name is required"); return; } setLoading(true); setError(null); try { if (editingId) { const updated = await updateRole(editingId, form); setRoles(prev => prev.map(r => r.id === editingId ? updated : r)); } else { const created = await createRole(form); setRoles(prev => [...prev, created]); } setShowModal(false); setEditingId(null); setForm(emptyForm); setActiveRole(null); } catch (err) { setError(err instanceof Error ? err.message : "Failed to save role"); console.error("Error saving role:", err); } finally { setLoading(false); } }; const handleDelete = async () => { if (!activeRole) return; setLoading(true); setError(null); try { await deleteRole(activeRole.id); setRoles(prev => prev.filter(r => r.id !== activeRole.id)); setActiveRole(null); setShowDeleteConfirm(false); } catch (err) { setError(err instanceof Error ? err.message : "Failed to delete role"); console.error("Error deleting role:", err); } finally { setLoading(false); } }; const openEditModal = () => { if (!activeRole) return; setEditingId(activeRole.id); setForm({ name: activeRole.name, description: activeRole.description, permissions: activeRole.permissions, }); setShowModal(true); }; const filtered = roles.filter(r => r.name.toLowerCase().includes(search.toLowerCase()) || r.description?.toLowerCase().includes(search.toLowerCase()) ); return (
{/* LEFT INFO SIDEBAR */}

Role Information

Manage system roles and their permissions. Roles define what actions users can perform.

{activeRole && (

Selected Role

Name

{activeRole.name}

Description

{activeRole.description || "No description"}

Created

{new Date(activeRole.created_at).toLocaleDateString()}

{activeRole.permissions && Object.keys(activeRole.permissions).length > 0 && (

Permissions

{Object.keys(activeRole.permissions).length} permission groups

)}
)}
{/* MAIN */}
{/* HEADER */}

Role Management

{roles.length} roles registered

{/* ERROR ALERT */} {error && (

Error

{error}

)} {/* SEARCH */} setSearch(e.target.value)} /> {/* TABLE */}
{loading && roles.length === 0 ? (
) : ( ( {rowData.name} ) }, { title: "Description", field: "description", render: (rowData) => ( {rowData.description || "—"} ) }, { title: "Permissions", field: "permissions", render: (rowData) => { const count = rowData.permissions ? Object.keys(rowData.permissions).length : 0; return ( {count > 0 ? `${count} groups` : "No permissions"} ); } }, { title: "Created", field: "created_at", type: "date", render: (rowData) => ( {new Date(rowData.created_at).toLocaleDateString()} ) } ]} data={filtered} onRowClick={(_, rowData) => setActiveRole(rowData as Role)} options={{ actionsColumnIndex: -1, search: false, paging: true, pageSize: 10, pageSizeOptions: [10, 20, 50], sorting: true, rowStyle: (rowData) => ({ backgroundColor: activeRole?.id === (rowData as Role).id ? "#EEF2FF" : "#FFFFFF", cursor: "pointer" }) }} /> )}
{/* ADD/EDIT MODAL */} {showModal && (

{editingId ? "Edit Role" : "Add New Role"}

setForm({...form, name: e.target.value})} disabled={loading} />