'use client'; import {zodResolver} from '@hookform/resolvers/zod'; import {useMutation, useQueryClient} from '@tanstack/react-query'; import {useEffect} from 'react'; import {useForm, useWatch} from 'react-hook-form'; import {Loader2} from 'lucide-react'; import {Button} from '@/components/ui/button'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import {Input} from '@/components/ui/input'; import {Label} from '@/components/ui/label'; import {Select, SelectContent, SelectItem, SelectTrigger, SelectValue,} from '@/components/ui/select'; import {Switch} from '@/components/ui/switch'; import type {ManagedDomainItem, TlsCertificateItem} from '@/lib/services/openflare'; import {WebsiteService} from '@/lib/services/openflare'; import {defaultManagedDomainValues, type ManagedDomainFormValues, managedDomainSchema,} from './schemas'; import {WebsiteStatusBadge} from './status-badge'; import { buildCertificateLabel, getErrorMessage, getMatchTypeMeta, toManagedDomainFormValues, toManagedDomainPayload, } from './website-utils'; const domainsQueryKey = ['openflare', 'managed-domains']; interface WebsiteEditorDialogProps { open: boolean; onOpenChange: (open: boolean) => void; onSaved?: (domain: ManagedDomainItem, mode: 'create' | 'update') => void; onRequestImportCertificate: () => void; certificates: TlsCertificateItem[]; certificatesLoading?: boolean; initialDomain?: ManagedDomainItem | null; preferredCertificateId?: number | null; } export function WebsiteEditorDialog({ open, onOpenChange, onSaved, onRequestImportCertificate, certificates, certificatesLoading = false, initialDomain = null, preferredCertificateId = null, }: WebsiteEditorDialogProps) { const queryClient = useQueryClient(); const form = useForm({ resolver: zodResolver(managedDomainSchema), defaultValues: defaultManagedDomainValues, }); const watchedDomain = useWatch({control: form.control, name: 'domain'}); const watchedCertId = useWatch({control: form.control, name: 'cert_id'}); const watchedEnabled = useWatch({control: form.control, name: 'enabled'}); const saveMutation = useMutation({ mutationFn: async (values: ManagedDomainFormValues) => { const payload = toManagedDomainPayload(values); return initialDomain ? WebsiteService.update(initialDomain.id, payload) : WebsiteService.create(payload); }, onSuccess: async (domain) => { await queryClient.invalidateQueries({queryKey: domainsQueryKey}); onSaved?.(domain, initialDomain ? 'update' : 'create'); handleClose(); }, }); const currentCertificate = watchedCertId ? (certificates.find((item) => item.id === Number(watchedCertId)) ?? null) : null; const handleSubmit = form.handleSubmit((values) => { saveMutation.mutate(values); }); const handleClose = () => { saveMutation.reset(); form.reset(defaultManagedDomainValues); onOpenChange(false); }; useEffect(() => { if (!open) return; form.reset( initialDomain ? toManagedDomainFormValues(initialDomain) : defaultManagedDomainValues, ); }, [form, initialDomain, open]); useEffect(() => { if (!open || !preferredCertificateId) return; form.setValue('cert_id', String(preferredCertificateId), { shouldDirty: true, shouldValidate: true, }); }, [form, open, preferredCertificateId]); return ( !next && handleClose()}> {initialDomain ? '编辑网站' : '新增网站'} 录入域名并选择绑定证书。证书可在弹窗内直接新增,导入成功后会自动回填。
{saveMutation.isError ? (

{getErrorMessage(saveMutation.error)}

) : null}
{form.formState.errors.domain ? (

{form.formState.errors.domain.message}

) : null}

当前域名

{watchedDomain?.trim() || '未填写域名'}

匹配类型

{watchedDomain?.trim() ? ( ) : ( )}

当前证书

启用网站

停用后该网站不会参与自动匹配,但记录会保留。

form.setValue('enabled', checked, {shouldDirty: true, shouldValidate: true}) } />
); }