import React, { useState } from 'react'; import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout'; import { Head, router } from '@inertiajs/react'; import { PageProps } from '@/types'; import { Can } from '@/Components/Can'; import { Portal } from '@/Components/Portal'; import { swal } from '@/lib/swal'; interface RoleData { id: number; name: string; guard_name: string; permissions: string[]; users_count: number; } interface PermissionData { id: number; name: string; group: string; } interface RolesPageProps extends PageProps { roles: RoleData[]; permissions: PermissionData[]; } export default function RolesIndex({ roles, permissions }: RolesPageProps) { const groups = [...new Set(permissions.map(p => p.group))]; const [localMatrix, setLocalMatrix] = useState>(() => { const m: Record = {}; roles.forEach(r => { m[r.id] = [...r.permissions]; }); return m; }); const [dirty, setDirty] = useState>({}); const [saving, setSaving] = useState>({}); const [showCreateModal, setShowCreateModal] = useState(false); const [newRoleName, setNewRoleName] = useState(''); const togglePermission = (roleId: number, permName: string) => { setLocalMatrix(prev => { const current = prev[roleId] || []; const updated = current.includes(permName) ? current.filter(p => p !== permName) : [...current, permName]; return { ...prev, [roleId]: updated }; }); setDirty(prev => ({ ...prev, [roleId]: true })); }; const handleSaveRole = async (role: RoleData) => { setSaving(prev => ({ ...prev, [role.id]: true })); router.patch(`/roles/${role.id}/permissions`, { permissions: localMatrix[role.id] || [], }, { preserveScroll: true, onSuccess: () => { setDirty(prev => ({ ...prev, [role.id]: false })); setSaving(prev => ({ ...prev, [role.id]: false })); swal.success('Saved', `Permissions updated for "${role.name}"`); }, onError: () => { setSaving(prev => ({ ...prev, [role.id]: false })); swal.error('Error', 'Failed to update permissions.'); }, }); }; const handleCreateRole = (e: React.SyntheticEvent) => { e.preventDefault(); if (!newRoleName.trim()) return; router.post('/roles', { name: newRoleName.trim() }, { onSuccess: () => { setShowCreateModal(false); setNewRoleName(''); swal.success('Created', 'New role created successfully.'); }, onError: () => swal.error('Error', 'Failed to create role.'), }); }; const handleDeleteRole = async (role: RoleData) => { const result = await swal.confirmDelete(role.name); if (!result.isConfirmed) return; router.delete(`/roles/${role.id}`, { onSuccess: () => swal.success('Deleted', `Role "${role.name}" has been deleted.`), onError: () => swal.error('Error', 'Failed to delete role.'), }); }; return (

Access Control

Configure hierarchical roles and granular permissions

{/* Role Summary Grid */}
{roles.map((role, idx) => { const count = (localMatrix[role.id] || []).length; const isSuperAdmin = role.name === 'super-admin'; return (
{role.name} {!isSuperAdmin && ( )}
{count} / {permissions.length} perms
{role.users_count} Total Active Users
{dirty[role.id] && ( )}
); })}
{/* Permissions Matrix */}

Permissions Matrix

{roles.map(role => ( ))} {groups.map(group => ( {permissions.filter(p => p.group === group).map((perm) => ( {roles.map(role => { const isChecked = (localMatrix[role.id] || []).includes(perm.name); const isSuperAdmin = role.name === 'super-admin'; return ( ); })} ))} ))}
Functional Permission{role.name}
{group} Module
{perm.name.replace('.', ' ')}
{perm.name}
{/* Create Role Modal */} {showCreateModal && (

Provision New Role

setNewRoleName(e.target.value)} placeholder="e.g. auditor" className="input-field" required autoFocus />
)} ); }