"use client" import { useEffect, useMemo, useRef, useState } from "react" import { zodResolver } from "@hookform/resolvers/zod" import { Controller, useFieldArray, useForm, type Resolver, type UseFormReturn, } from "react-hook-form" import { PlusIcon, Trash2Icon } from "lucide-react" import { z } from "zod/v4" import { CompanyPicker } from "@/components/company-picker" import { OptionCombobox } from "@/components/option-combobox" import { Button } from "@/components/ui/button" import { Field, FieldContent, FieldError, FieldLabel, } from "@/components/ui/field" import { Input } from "@/components/ui/input" import { Textarea } from "@/components/ui/textarea" import { fetchCustomerContacts, type AdminCustomerContact } from "@/lib/api/customer-contact" import { fetchCustomer, type AdminCustomer, type SaveCustomerProfilePayload, } from "@/lib/api/customer" import { ContactType, Gender } from "@/lib/generated/enums" import { useI18n } from "@/i18n/provider" const genderValueOptions = [ String(Gender.Unknown), String(Gender.Male), String(Gender.Female), ] as const const contactTypeValues = [ ContactType.Mobile, ContactType.Email, ContactType.Other, ] as const const contactRowSchema = z.object({ id: z.number().optional(), contactType: z.enum(contactTypeValues), contactValue: z.string(), remark: z.string(), isPrimary: z.boolean(), }) export type CustomerFormValues = { name: string gender: (typeof genderValueOptions)[number] companyId: string remark: string contacts: CustomerContactFormRow[] } export type CustomerContactFormRow = { id?: number contactType: (typeof contactTypeValues)[number] contactValue: string remark: string isPrimary: boolean } function defaultContactRow(isPrimary: boolean): CustomerContactFormRow { return { contactType: ContactType.Mobile, contactValue: "", remark: "", isPrimary, } } const emptyCustomerForm: CustomerFormValues = { name: "", gender: "0", companyId: "0", remark: "", contacts: [defaultContactRow(true)], } function buildCustomerMainFromAdmin(item: AdminCustomer | null): Omit { if (!item) { return { name: "", gender: "0", companyId: "0", remark: "", } } return { name: item.name, gender: String(item.gender) as "0" | "1" | "2", companyId: String(item.companyId ?? 0), remark: item.remark ?? "", } } function buildContactsFromApi(list: AdminCustomerContact[]): CustomerContactFormRow[] { if (list.length === 0) { return [defaultContactRow(true)] } return list.map((c) => ({ id: c.id, contactType: c.contactType as CustomerContactFormRow["contactType"], contactValue: c.contactValue ?? "", remark: c.remark ?? "", isPrimary: c.isPrimary, })) } /** Filters empty rows and keeps at most one primary contact. */ export function normalizeContactsForSubmit(rows: CustomerContactFormRow[]): CustomerContactFormRow[] { const withValue = rows.filter((r) => r.contactValue.trim() !== "") if (withValue.length === 0) { return [] } const primaryIdx = withValue.findIndex((r) => r.isPrimary) if (primaryIdx < 0) { return withValue.map((r, i) => ({ ...r, isPrimary: i === 0 })) } return withValue.map((r, i) => ({ ...r, isPrimary: i === primaryIdx, })) } export type CustomerFormSavePayload = SaveCustomerProfilePayload type CustomerFormFieldsProps = { form: UseFormReturn fieldIdPrefix?: string remarkRows?: number } function CustomerFormFields({ form, fieldIdPrefix = "customer", remarkRows = 4, }: CustomerFormFieldsProps) { const t = useI18n() const { control, register, formState: { errors }, watch, setValue, getValues, } = form const { fields, append, remove } = useFieldArray({ control, name: "contacts" }) const genderOptions = useMemo( () => [ { value: String(Gender.Unknown), label: t("customerForm.genderUnknown") }, { value: String(Gender.Male), label: t("customerForm.genderMale") }, { value: String(Gender.Female), label: t("customerForm.genderFemale") }, ], [t] ) const contactTypeOptions = useMemo( () => [ { value: ContactType.Mobile, label: t("customerForm.contactMobile") }, { value: ContactType.Email, label: t("customerForm.contactEmail") }, { value: ContactType.Other, label: t("customerForm.contactOther") }, ], [t] ) const id = (suffix: string) => `${fieldIdPrefix}-${suffix}` function setPrimaryIndex(index: number) { fields.forEach((_, i) => { setValue(`contacts.${i}.isPrimary`, i === index) }) } function addContactRow() { append(defaultContactRow(fields.length === 0)) } function removeContactRow(index: number) { const wasPrimary = watch(`contacts.${index}.isPrimary`) remove(index) if (wasPrimary) { requestAnimationFrame(() => { const list = getValues("contacts") if (list.length > 0) { list.forEach((_, i) => setValue(`contacts.${i}.isPrimary`, i === 0)) } }) } } return (

{t("customerForm.sectionCustomer")}

{t("customerForm.name")}
{t("customerForm.gender")} ( )} /> {t("customerForm.company")} ( )} />
{t("customerForm.remark")}