Files
cloudflare-domain-manager/apps/web/src/components/service-group-edit-sheet.tsx
T
Denozordec 9569c22e4d
Build, Test, and Push CFDM Docker Image / test (push) Successful in 4m5s
Build, Test, and Push CFDM Docker Image / build-and-push (push) Successful in 2m26s
Build, Test, and Push CFDM Docker Image / update-wiki (push) Successful in 8s
Build, Test, and Push CFDM Docker Image / create-release (push) Has been skipped
chore: Update package.json and pnpm-lock.yaml to add husky for Git hooks; enhance Docker workflow with pnpm setup and linting steps; refactor various components to utilize new form components and improve UI consistency.
2026-06-25 15:47:29 +07:00

156 lines
4.6 KiB
TypeScript

import { useEffect } from 'react'
import { useForm, Controller } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import {
createServiceGroupSchema,
type CreateServiceGroupInput,
type ServiceGroup,
} from '@/lib/schemas'
import type { z } from 'zod'
import { FormSheet } from '@/components/form-sheet'
import { FormFieldSimple } from '@/components/form-field'
import { LoadingButton } from '@/components/loading-button'
import { FieldGroup } from '@cfdm/ui/components/field'
import { Input } from '@cfdm/ui/components/input'
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@cfdm/ui/components/select'
const groupTypes = [
{ value: 'vpn', label: 'VPN' },
{ value: 'network', label: 'Сеть' },
{ value: 'internet', label: 'Интернет' },
{ value: 'bgp', label: 'BGP' },
{ value: 'custom', label: 'Другое' },
] as const
type ServiceGroupFormValues = z.input<typeof createServiceGroupSchema>
interface ServiceGroupEditSheetProps {
mode: 'create' | 'edit'
group: ServiceGroup | null
open: boolean
isSaving: boolean
onOpenChange: (open: boolean) => void
onCreate?: (body: CreateServiceGroupInput) => void
onSave?: (id: number, body: CreateServiceGroupInput) => void
}
export function ServiceGroupEditSheet({
mode,
group,
open,
isSaving,
onOpenChange,
onCreate,
onSave,
}: ServiceGroupEditSheetProps) {
const form = useForm<ServiceGroupFormValues>({
resolver: zodResolver(createServiceGroupSchema),
defaultValues: { name: '', type: 'custom', domain: null },
})
useEffect(() => {
if (!open) return
if (mode === 'edit' && group) {
form.reset({
name: group.name,
type: group.type,
domain: group.domain ?? null,
})
} else {
form.reset({ name: '', type: 'custom', domain: null })
}
}, [open, mode, group, form])
function handleSubmit(values: ServiceGroupFormValues) {
const body: CreateServiceGroupInput = {
name: values.name,
type: values.type ?? 'custom',
icon: values.icon,
domain: values.domain?.trim() || null,
}
if (mode === 'create') {
onCreate?.(body)
} else if (group) {
onSave?.(group.id, body)
}
}
return (
<FormSheet<ServiceGroupFormValues>
open={open}
onOpenChange={onOpenChange}
title={mode === 'create' ? 'Новая группа сервисов' : 'Редактировать группу'}
description="Домен группы необязателен. Если указан FQDN (gr.ivx.su, domain.new.ivx.su), он публикуется в Cloudflare отдельно от привязок сервисов."
form={form}
onSubmit={handleSubmit}
contentClassName="gap-6"
footer={
<LoadingButton
type="submit"
className="w-full"
isLoading={isSaving}
loadingLabel="Сохранение…"
>
{mode === 'create' ? 'Создать' : 'Сохранить'}
</LoadingButton>
}
>
<FieldGroup>
<FormFieldSimple
label="Название"
htmlFor="group-name"
error={form.formState.errors.name}
>
<Input
id="group-name"
placeholder="VPN"
{...form.register('name')}
aria-invalid={!!form.formState.errors.name}
/>
</FormFieldSimple>
<FormFieldSimple label="Тип" htmlFor="group-type">
<Controller
control={form.control}
name="type"
render={({ field }) => (
<Select
value={field.value}
onValueChange={(value) =>
field.onChange(value as CreateServiceGroupInput['type'])
}
>
<SelectTrigger id="group-type">
<SelectValue placeholder="Выберите тип" />
</SelectTrigger>
<SelectContent>
{groupTypes.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectContent>
</Select>
)}
/>
</FormFieldSimple>
<FormFieldSimple
label="Домен группы (FQDN, необязательно)"
htmlFor="group-domain"
>
<Input
id="group-domain"
placeholder="domain.new.ivx.su"
{...form.register('domain')}
/>
</FormFieldSimple>
</FieldGroup>
</FormSheet>
)
}