import { zodResolver } from '@hookform/resolvers/zod' import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { Plus, Trash2 } from 'lucide-react' import { useState } from 'react' import { useForm } from 'react-hook-form' import { useTranslation } from 'react-i18next' import { z } from 'zod' import { qk } from '@/shared/api/query-keys' import { useApiError } from '@/shared/lib/use-api-error' import { Badge } from '@/shared/ui/badge' import { Button } from '@/shared/ui/button' import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from '@/shared/ui/dialog' import { Input } from '@/shared/ui/input' import { Label } from '@/shared/ui/label' import { sortRows, useTableSort } from '@/shared/lib/table-sort' import { SortHeader } from '@/shared/ui/sortable' import { createRole, deleteRole, listRoles, updateRole } from './api' const schema = z.object({ name: z.string().min(1).max(64) }) export function RolesPanel() { const { t } = useTranslation() const queryClient = useQueryClient() const { data: roles, isLoading } = useQuery({ queryKey: qk.roles.all, queryFn: listRoles }) const { sort, toggle } = useTableSort('name', false) const sortedRoles = sortRows(roles ?? [], sort, { name: (r) => r.name.toLowerCase(), system: (r) => r.isSystem, }) const invalidate = () => queryClient.invalidateQueries({ queryKey: qk.roles.all }) const onError = useApiError() const createMutation = useMutation({ mutationFn: (name: string) => createRole(name), onSuccess: invalidate, }) const deleteMutation = useMutation({ mutationFn: (id: string) => deleteRole(id), onSuccess: invalidate, onError, }) const renameMutation = useMutation({ mutationFn: ({ id, name }: Readonly<{ id: string; name: string }>) => updateRole(id, name), onSuccess: invalidate, onError, }) const [open, setOpen] = useState(false) const { register, handleSubmit, reset } = useForm>({ resolver: zodResolver(schema) }) const onCreate = async (values: z.infer) => { try { await createMutation.mutateAsync(values.name) reset() setOpen(false) } catch (error) { onError(error) } } return (

{t('admin.roles.title')}

{t('admin.roles.create')}
{isLoading && ( )} {sortedRoles.map((role) => ( ))}
{t('common.actions')}
{t('common.loading')}
{role.name} {role.isSystem ? {t('common.yes')} : t('common.no')}
) }