'use client'; import { useEffect } from 'react'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { zodResolver } from '@hookform/resolvers/zod'; import { useForm } from 'react-hook-form'; import { Loader2 } from 'lucide-react'; import { toast } from 'sonner'; import { z } from 'zod'; 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 { Textarea } from '@/components/ui/textarea'; import { type OriginItem, type OriginMutationPayload, OriginService, } from '@/lib/services/openflare'; import { useTranslations } from 'next-intl'; type OriginFormValues = { name: string; address: string; remark: string; }; const originsQueryKey = ['openflare', 'origins'] as const; function toFormValues(origin?: OriginItem | null): OriginFormValues { if (!origin) return { name: '', address: '', remark: '' }; return { name: origin.name, address: origin.address, remark: origin.remark || '', }; } function toPayload(values: OriginFormValues): OriginMutationPayload { return { name: values.name.trim(), address: values.address.trim(), remark: values.remark.trim(), }; } interface OriginEditorDialogProps { open: boolean; onOpenChange: (open: boolean) => void; origin?: OriginItem | null; onSaved?: () => void; } export function OriginEditorDialog({ open, onOpenChange, origin, onSaved, }: OriginEditorDialogProps) { const t = useTranslations('origins'); const tc = useTranslations('common'); const queryClient = useQueryClient(); const originSchema = z.object({ name: z.string().max(255), address: z .string() .trim() .min(1, t('addressRequired')) .refine( (value) => !/[/?#]/.test(value) && !value.includes('://'), t('addressInvalid'), ), remark: z.string().max(255), }); const form = useForm({ resolver: zodResolver(originSchema), defaultValues: toFormValues(origin), }); useEffect(() => { if (open) form.reset(toFormValues(origin)); }, [form, origin, open]); const mutation = useMutation({ mutationFn: async (values: OriginFormValues) => { const payload = toPayload(values); return origin ? OriginService.update(origin.id, payload) : OriginService.create(payload); }, onSuccess: async () => { toast.success(origin ? t('updated') : t('created')); await queryClient.invalidateQueries({ queryKey: originsQueryKey }); if (origin) { await queryClient.invalidateQueries({ queryKey: ['openflare', 'origins', String(origin.id)], }); } onSaved?.(); onOpenChange(false); }, onError: (error) => { toast.error(error instanceof Error ? error.message : t('saveFailed')); }, }); return ( {origin ? t('editOrigin') : t('create')} {t('editorDesc')}
mutation.mutate(values))} >
{form.formState.errors.address ? (

{form.formState.errors.address.message}

) : null}