/
t3
/
web-ui
Обзор
Документация
Войти
/
t3
/
web-ui
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
master
src/features/roles/components/CreateRoleDialog.tsx
124 строки
5 KB
Ivan Shibkikh
ui roles managment
23 июл 2026, 20:48
23 июл 2026, 20:48
dd7a244
Код
Авторство
О чём код?
import { useState } from "react"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { rolesApi, ApiError } from "@/api/client"; import { useMutation, useQueryClient } from "@tanstack/react-query"; interface CreateRoleDialogProps { open: boolean; onOpenChange: (open: boolean) => void; } export function CreateRoleDialog({ open, onOpenChange }: CreateRoleDialogProps) { const [name, setName] = useState(""); const [description, setDescription] = useState(""); const [error, setError] = useState<string | null>(null); const [fieldErrors, setFieldErrors] = useState<Record<string, string>>({}); const queryClient = useQueryClient(); const mutation = useMutation({ mutationFn: (data: { name: string; description?: string }) => rolesApi.create(data), onSuccess: () => { setName(""); setDescription(""); setError(null); setFieldErrors({}); queryClient.invalidateQueries({ queryKey: ["roles"] }); onOpenChange(false); }, onError: (err) => { if (err instanceof ApiError) { setError(err.detail ?? err.message); if (err.iamFields) { const fe: Record<string, string> = {}; for (const f of err.iamFields) { fe[f.field] = f.issue; } setFieldErrors(fe); } } else { setError(err instanceof Error ? err.message : "Ошибка создания роли"); } }, }); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); if (!name.trim()) { setError("Введите название роли"); return; } mutation.mutate({ name: name.trim(), description: description.trim() || undefined, }); }; const handleClose = () => { setName(""); setDescription(""); setError(null); setFieldErrors({}); mutation.reset(); onOpenChange(false); }; return ( <Dialog open={open} onOpenChange={handleClose}> <DialogContent className="sm:max-w-lg"> <DialogHeader> <DialogTitle>Создать роль</DialogTitle> <DialogDescription> Роль объединяет набор разрешений, которые можно назначить пользователям </DialogDescription> </DialogHeader> <form onSubmit={handleSubmit} className="space-y-4"> <div className="space-y-2"> <Label htmlFor="role_name">Название</Label> <Input id="role_name" placeholder="S3Administrator" value={name} onChange={(e) => { setName(e.target.value); setFieldErrors({}); }} autoFocus /> {fieldErrors.name && ( <p className="text-sm text-destructive">{fieldErrors.name}</p> )} </div> <div className="space-y-2"> <Label htmlFor="role_description">Описание (опционально)</Label> <Input id="role_description" placeholder="Полный доступ к S3" value={description} onChange={(e) => setDescription(e.target.value)} /> {fieldErrors.description && ( <p className="text-sm text-destructive">{fieldErrors.description}</p> )} </div> {error && !Object.keys(fieldErrors).length && ( <div className="rounded-md bg-destructive/10 p-3 text-sm text-destructive"> {error} </div> )} <div className="flex justify-end gap-2"> <Button type="button" variant="outline" onClick={handleClose}> Отмена </Button> <Button type="submit" disabled={mutation.isPending}> {mutation.isPending ? "Создание..." : "Создать"} </Button> </div> </form> </DialogContent> </Dialog> ); }