import { A, useNavigate } from '@solidjs/router'; import { createResource, createSignal, For, Show } from 'solid-js'; import { Search } from 'lucide-solid'; import AdminShell from '~/components/AdminShell'; const API = '/api/gateway'; type Role = { id: string; key: string; name: string; audience: string; description?: string; department_name?: string; is_active: boolean; users_assigned: number; permissions_count: number; created_at: string; }; type ListResponse = { roles: Role[]; total: number; page: number; per_page: number; }; async function loadRoles(params: { q: string; page: number }): Promise { try { const qs = new URLSearchParams({ audience: 'INTERNAL', q: params.q, page: String(params.page), per_page: '8', }); const res = await fetch(`${API}/api/admin/roles?${qs}`); if (!res.ok) throw new Error('Failed'); const data = await res.json(); if (data.roles) return data; // flat array fallback return { roles: Array.isArray(data) ? data : [], total: 0, page: 1, per_page: 8 }; } catch { return { roles: [], total: 0, page: 1, per_page: 8 }; } } function formatDate(iso: string) { try { const d = new Date(iso); return d.toISOString().slice(0, 10); } catch { return '—'; } } export default function InternalRolesListPage() { const navigate = useNavigate(); const [search, setSearch] = createSignal(''); const [debouncedSearch, setDebouncedSearch] = createSignal(''); const [page, setPage] = createSignal(1); const [deleting, setDeleting] = createSignal(''); let debounceTimer: ReturnType; const handleSearch = (val: string) => { setSearch(val); clearTimeout(debounceTimer); debounceTimer = setTimeout(() => { setDebouncedSearch(val); setPage(1); }, 300); }; const [data, { refetch }] = createResource( () => ({ q: debouncedSearch(), page: page() }), loadRoles, ); const totalPages = () => { const d = data(); if (!d || d.per_page === 0) return 1; return Math.max(1, Math.ceil(d.total / d.per_page)); }; const handleDelete = async (id: string, name: string) => { if (!confirm(`Delete role "${name}"? This cannot be undone.`)) return; setDeleting(id); try { const res = await fetch(`${API}/api/admin/roles/${id}`, { method: 'DELETE' }); if (!res.ok) throw new Error('Failed'); refetch(); } finally { setDeleting(''); } }; return (
{/* Page title */}

Internal Role Management

Manage internal roles and permissions

{/* Card */}
{/* Tabs */}
Create Role
{/* Toolbar */}
handleSearch(e.currentTarget.value)} class="w-full pl-9 pr-3 py-2 text-[13px] border border-[#e5e7eb] rounded-lg outline-none focus:border-[#fa5014] focus:ring-1 focus:ring-[#fa5014] bg-white" />
{/* Table */}
{(role) => ( )}
Role Name Department Users Assigned Permissions Count Status Created Date Actions
Loading roles…
No internal roles found.{' '} Create your first role.

{role.name}

{role.key}

{role.department_name || '—'} {role.users_assigned} {role.permissions_count} Permissions Inactive } > Active {formatDate(role.created_at)}
View | Edit |
{/* Pagination */} 0}>

Showing {((page() - 1) * (data()?.per_page ?? 8)) + 1}– {Math.min(page() * (data()?.per_page ?? 8), data()?.total ?? 0)} of {data()?.total ?? 0} roles

i + 1)}> {(p) => ( )}
); }