import { createFileRoute, useNavigate } from '@tanstack/react-router' import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' import { useState } from 'react' import { permissionListOptions, rbacKeys, rbacMutations } from '@/api/rbac' 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 { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Separator } from '@/components/ui/separator' import { toast } from 'sonner' export const Route = createFileRoute('/_authenticated/roles/new')({ component: NewRolePage, }) function NewRolePage() { const navigate = useNavigate() const queryClient = useQueryClient() const { data: permsData } = useQuery(permissionListOptions()) const [name, setName] = useState('') const [slug, setSlug] = useState('') const [description, setDescription] = useState('') const [selectedPerms, setSelectedPerms] = useState>(new Set()) const mutation = useMutation({ mutationFn: rbacMutations.createRole, onSuccess: () => { queryClient.invalidateQueries({ queryKey: rbacKeys.roles }) toast.success('Role created') navigate({ to: '/roles', search: { page: 1, limit: 25, q: undefined, sort: undefined, order: 'asc' as const } }) }, onError: (err) => toast.error(err.message), }) function togglePermission(permSlug: string) { const next = new Set(selectedPerms) if (next.has(permSlug)) next.delete(permSlug) else next.add(permSlug) setSelectedPerms(next) } function toggleDomain(domain: string, allSlugs: string[]) { const allSelected = allSlugs.every((s) => selectedPerms.has(s)) const next = new Set(selectedPerms) for (const s of allSlugs) { if (allSelected) next.delete(s) else next.add(s) } setSelectedPerms(next) } function handleNameChange(value: string) { setName(value) if (!slug || slug === nameToSlug(name)) { setSlug(nameToSlug(value)) } } function nameToSlug(n: string) { return n.toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_|_$/g, '') } function handleSubmit() { if (!name || !slug) { toast.error('Name and slug are required') return } mutation.mutate({ name, slug, description: description || undefined, permissionSlugs: Array.from(selectedPerms), }) } const allPerms = permsData?.data ?? [] const domains = new Map() for (const p of allPerms) { const list = domains.get(p.domain) ?? [] list.push(p) domains.set(p.domain, list) } return (

New Role

Details
handleNameChange(e.target.value)} placeholder="e.g. School Sales Rep" />
setSlug(e.target.value)} placeholder="auto-generated" className="font-mono" />