import { useActionMutation } from "@agent-native/core/client/hooks"; import { useT } from "@agent-native/core/client/i18n"; import { zodResolver } from "@hookform/resolvers/zod"; import type { Weight } from "@shared/types"; import { IconPlus, IconScale } from "@tabler/icons-react"; import { useState, useEffect } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; import { z } from "zod"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; import { formatLocalDate } from "@/lib/utils"; const formSchema = z.object({ weight: z.string().transform((val) => parseFloat(val)), date: z.string(), notes: z.string().optional(), }); type FormData = z.input; interface AddWeightDialogProps { editingWeight?: Weight | null; onOpenChange?: (open: boolean) => void; isOpen?: boolean; currentDate?: Date; } export function AddWeightDialog({ editingWeight, onOpenChange, isOpen: controlledOpen, currentDate, }: AddWeightDialogProps) { const t = useT(); const [uncontrolledOpen, setUncontrolledOpen] = useState(false); const open = controlledOpen !== undefined ? controlledOpen : uncontrolledOpen; const setOpen = controlledOpen !== undefined ? (v: boolean) => onOpenChange?.(v) : setUncontrolledOpen; const isEditing = !!editingWeight; const form = useForm({ // zod resolves at multiple minor versions across the workspace; cast the // schema so @hookform/resolvers v5's zod-v4 overload doesn't reject a // v4.3-internal schema under CI's frozen lockfile. Runtime is unaffected. resolver: zodResolver(formSchema as any) as any, defaultValues: { weight: editingWeight?.weight?.toString() || "", date: editingWeight?.date || formatLocalDate(currentDate || new Date()), notes: editingWeight?.notes || "", }, }); const createMutation = useActionMutation("log-weight", { onSuccess: () => { toast.success(t("weight.logged")); setOpen(false); form.reset(); }, onError: () => toast.error(t("weight.logFailed")), }); const updateMutation = useActionMutation("update-weight", { onSuccess: () => { toast.success(t("weight.updated")); setOpen(false); form.reset(); }, onError: () => toast.error(t("weight.updateFailed")), }); const onSubmit = (data: FormData) => { const date = isEditing ? editingWeight!.date : formatLocalDate(currentDate || new Date()); if (isEditing) { updateMutation.mutate({ id: String(editingWeight!.id), weight: String(data.weight), date, notes: data.notes || undefined, }); } else { createMutation.mutate({ weight: String(data.weight), date, notes: data.notes || undefined, }); } }; const handleOpenChange = (newOpen: boolean) => { setOpen(newOpen); onOpenChange?.(newOpen); if (!newOpen) form.reset(); }; useEffect(() => { if (editingWeight) { form.reset({ weight: editingWeight.weight.toString(), date: editingWeight.date, notes: editingWeight.notes || "", }); } else if (currentDate) { form.setValue("date", formatLocalDate(currentDate)); } }, [editingWeight, currentDate, form]); return ( {!isEditing && ( )} {isEditing ? t("weight.edit") : t("weight.log")} {isEditing ? t("weight.updateDescription") : t("weight.logDescription")}
{form.formState.errors.weight && (

{form.formState.errors.weight.message}

)}