'use client' import { useState } from 'react' import { toast } from 'sonner' import { setRolePermissions } from '@/lib/actions' import { PERMISSIONS, PERMISSION_GROUPS } from '@/lib/permissions-catalog' import { BUILTIN_ROLES } from '@/lib/role-labels' import { Card } from './card' import type { CustomRole } from './types' interface Props { isAdmin: boolean customRoles: CustomRole[] rolePerms: Array<{ subject: string; permission: string }> } export function PermissionsPanel({ isAdmin, customRoles, rolePerms }: Props) { // subjects: built-in roles except admin (implicit-all), plus custom roles. const subjects = [ ...BUILTIN_ROLES.filter(r => r !== 'admin').map(r => ({ key: r, label: r })), ...customRoles.map(c => ({ key: c.slug, label: c.name })), ] const initial: Record> = {} for (const s of subjects) initial[s.key] = new Set() for (const rp of rolePerms) { if (!initial[rp.subject]) initial[rp.subject] = new Set() initial[rp.subject].add(rp.permission) } const [grants, setGrants] = useState(initial) const [savingSubject, setSavingSubject] = useState(null) async function toggle(subject: string, permission: string, on: boolean) { const next = new Set(grants[subject] ?? []) if (on) next.add(permission) else next.delete(permission) setGrants(g => ({ ...g, [subject]: next })) setSavingSubject(subject) const result = await setRolePermissions({ subject, permissions: Array.from(next) }) setSavingSubject(null) if (result.error) { toast.error(result.error) // revert setGrants(g => { const back = new Set(g[subject] ?? []) if (on) back.delete(permission) else back.add(permission) return { ...g, [subject]: back } }) } } return (
admin holds all permissions (implicit, locked)
{!isAdmin && (

View only. Only an admin can change permissions.

)}
{subjects.map(s => ( ))} {PERMISSION_GROUPS.map(group => ( ))}
Permission {s.label}{savingSubject === s.key && …}
) } function PermGroup({ group, subjects, grants, isAdmin, onToggle, }: { group: string subjects: { key: string; label: string }[] grants: Record> isAdmin: boolean onToggle: (subject: string, permission: string, on: boolean) => void }) { const perms = PERMISSIONS.filter(p => p.group === group) return ( <> {group} {perms.map(p => ( {p.label} {p.code} {subjects.map(s => ( onToggle(s.key, p.code, e.target.checked)} /> ))} ))} ) }