From db3ae2ca3fe967e6f76fb035567986411e99063c Mon Sep 17 00:00:00 2001 From: Alexandre Brandizzi Date: Wed, 22 Jul 2026 11:30:02 -0300 Subject: [PATCH] fix(vendors): keep company input in sync --- .../_components/vendor-form-fields.tsx | 7 +- .../vendors/vendor-form-fields.test.tsx | 151 ++++++++++++++++++ 2 files changed, 152 insertions(+), 6 deletions(-) create mode 100644 src/test/app/(protected)/vendors/vendor-form-fields.test.tsx diff --git a/src/app/(protected)/vendors/_components/vendor-form-fields.tsx b/src/app/(protected)/vendors/_components/vendor-form-fields.tsx index fefc696e..f88d0505 100644 --- a/src/app/(protected)/vendors/_components/vendor-form-fields.tsx +++ b/src/app/(protected)/vendors/_components/vendor-form-fields.tsx @@ -46,7 +46,6 @@ export function VendorFormFields({ onCompanySelected, showTotalJobs = false, }: VendorFormFieldsProps) { - const [companyInput, setCompanyInput] = useState(""); const [tradeInput, setTradeInput] = useState(""); return ( @@ -99,28 +98,24 @@ export function VendorFormFields({ : option.name === value.name } value={field.value ?? ""} - inputValue={companyInput || (typeof field.value === "string" ? field.value : "")} + inputValue={field.value ?? ""} onInputChange={(_event, value, reason) => { if (reason === "input") { - setCompanyInput(value); field.onChange(value); } }} onChange={(_event, value, reason) => { if (typeof value === "string") { field.onChange(value); - setCompanyInput(value); return; } if (value) { field.onChange(value.name); - setCompanyInput(value.name); if (reason === "selectOption") { onCompanySelected(value); } } else { field.onChange(""); - setCompanyInput(""); } }} renderInput={(params) => ( diff --git a/src/test/app/(protected)/vendors/vendor-form-fields.test.tsx b/src/test/app/(protected)/vendors/vendor-form-fields.test.tsx new file mode 100644 index 00000000..eb197115 --- /dev/null +++ b/src/test/app/(protected)/vendors/vendor-form-fields.test.tsx @@ -0,0 +1,151 @@ +import { screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { useForm, type FieldErrors } from "react-hook-form"; +import { describe, expect, it } from "vitest"; +import { VendorFormFields } from "@/app/(protected)/vendors/_components/vendor-form-fields"; +import { vendorSchema, type VendorFormValues } from "@/domain/vendors/schemas/vendor-schema"; +import type { VendorFacetCompany } from "@/domain/vendors/types/vendor"; +import { renderWithProviders } from "@/test/test-utils"; + +const companies: VendorFacetCompany[] = [ + { + name: "Gateway Plumbing", + companyPhone: "(314) 555-0198", + email: "dispatch@gatewayplumbing.com", + address: "1 Main St", + city: "St. Louis", + state: "MO", + zip: "63101", + googleMapsUrl: "https://maps.google.com/gateway", + }, +]; + +const emptyForm: VendorFormValues = { + companyName: "", + contactName: "Tech Person", + email: "", + phone: "", + companyPhone: "", + googleMapsUrl: "", + notes: "", + totalJobs: 0, + address: "", + city: "", + state: "", + zip: "", + tradeSpecialties: "", + isActive: true, +}; + +function Harness({ + defaultValues, + resetTarget, +}: { + defaultValues: VendorFormValues; + resetTarget: VendorFormValues; +}) { + const { control, reset, setValue } = useForm({ + resolver: zodResolver(vendorSchema), + defaultValues, + }); + + const onCompanySelected = (company: VendorFacetCompany | null) => { + if (!company) return; + setValue("companyPhone", company.companyPhone); + setValue("email", company.email); + setValue("address", company.address); + setValue("city", company.city); + setValue("state", company.state); + setValue("zip", company.zip); + setValue("googleMapsUrl", company.googleMapsUrl); + }; + + return ( + <> + } + companies={companies} + tradeOptions={[]} + onCompanySelected={onCompanySelected} + /> + + + ); +} + +const companyField = () => screen.getByRole("combobox", { name: "Company" }) as HTMLInputElement; + +describe("VendorFormFields company autocomplete state", () => { + it("clears a previously typed company when the form is reset (create-form reopen)", async () => { + renderWithProviders(, { + withAuth: false, + }); + + await userEvent.type(companyField(), "Leftover Co"); + expect(companyField()).toHaveValue("Leftover Co"); + + await userEvent.click(screen.getByRole("button", { name: "reset-form" })); + + expect(companyField()).toHaveValue(""); + }); + + it("shows the switched company value instead of previously typed text when the form is reset", async () => { + renderWithProviders( + , + { withAuth: false }, + ); + + await userEvent.type(companyField(), "Acme"); + expect(companyField()).toHaveValue("Acme"); + + await userEvent.click(screen.getByRole("button", { name: "reset-form" })); + + expect(companyField()).toHaveValue("Beta LLC"); + }); + + it("reflects the company provided by an external reset even when nothing was typed", async () => { + renderWithProviders( + , + { withAuth: false }, + ); + + expect(companyField()).toHaveValue("Acme Corp"); + + await userEvent.click(screen.getByRole("button", { name: "reset-form" })); + + expect(companyField()).toHaveValue("Beta LLC"); + }); + + it("updates the displayed company as the user types (freeSolo)", async () => { + renderWithProviders(, { + withAuth: false, + }); + + await userEvent.type(companyField(), "Acme"); + + expect(companyField()).toHaveValue("Acme"); + }); + + it("selects a company option, autofills company details, and shows the company name", async () => { + renderWithProviders(, { + withAuth: false, + }); + + await userEvent.type(companyField(), "Gate"); + const option = await screen.findByRole("option", { name: "Gateway Plumbing" }); + await userEvent.click(option); + + expect(companyField()).toHaveValue("Gateway Plumbing"); + expect(screen.getByRole("textbox", { name: "Company Phone" })).toHaveValue("(314) 555-0198"); + }); +});