diff --git a/src/app/(protected)/vendors/_components/vendors-table.tsx b/src/app/(protected)/vendors/_components/vendors-table.tsx index e524630c..57e8a243 100644 --- a/src/app/(protected)/vendors/_components/vendors-table.tsx +++ b/src/app/(protected)/vendors/_components/vendors-table.tsx @@ -61,7 +61,10 @@ function VendorTableRow({ row, onOpenDetail, onOpenEdit }: VendorTableRowProps) const trades = splitTrades(row.tradeSpecialties); const primaryTrade = trades[0] ?? "—"; const extraTrades = trades.length > 1 ? trades.length - 1 : 0; - const locationText = [row.city, row.state].filter(Boolean).join(", ") || "—"; + // Vendors captured through the roster form keep their location in the free-text + // address field, so fall back to it the way the detail drawer already does. + const locationText = + [row.city, row.state].filter(Boolean).join(", ").trim() || (row.address ?? "").trim() || "—"; const rowKey = String(row.id ?? `company-${row.companyId ?? ""}`); const handleKeyDown = (event: KeyboardEvent) => { diff --git a/src/domain/vendors/mappers/vendor-mapper.ts b/src/domain/vendors/mappers/vendor-mapper.ts index 33a31223..321e4542 100644 --- a/src/domain/vendors/mappers/vendor-mapper.ts +++ b/src/domain/vendors/mappers/vendor-mapper.ts @@ -119,6 +119,7 @@ export function mapVendorListItem(raw: unknown): VendorListItem { googleMapsUrl: readString(item, "googleMapsUrl", "GoogleMapsUrl"), notes: readString(item, "notes", "Notes"), totalJobs: readNumber(item, "totalJobs", "TotalJobs"), + address: readString(item, "address", "Address"), city: readString(item, "city", "City"), state: readString(item, "state", "State"), tradeSpecialties: readString(item, "tradeSpecialties", "TradeSpecialties"), diff --git a/src/domain/vendors/types/vendor.ts b/src/domain/vendors/types/vendor.ts index d4140afa..74e6519e 100644 --- a/src/domain/vendors/types/vendor.ts +++ b/src/domain/vendors/types/vendor.ts @@ -13,6 +13,7 @@ export interface VendorListItem { googleMapsUrl: string; notes: string; totalJobs: number; + address: string; city: string; state: string; tradeSpecialties: string; diff --git a/src/test/app/(protected)/vendors/vendor-detail-drawer.test.tsx b/src/test/app/(protected)/vendors/vendor-detail-drawer.test.tsx index a882b91f..cf38b5bb 100644 --- a/src/test/app/(protected)/vendors/vendor-detail-drawer.test.tsx +++ b/src/test/app/(protected)/vendors/vendor-detail-drawer.test.tsx @@ -33,6 +33,7 @@ const vendor: VendorListItem = { googleMapsUrl: "", notes: "", totalJobs: 0, + address: "", city: "", state: "", tradeSpecialties: "", diff --git a/src/test/app/(protected)/vendors/vendors-list.test.tsx b/src/test/app/(protected)/vendors/vendors-list.test.tsx index ae5a18d3..ec0b1389 100644 --- a/src/test/app/(protected)/vendors/vendors-list.test.tsx +++ b/src/test/app/(protected)/vendors/vendors-list.test.tsx @@ -40,6 +40,7 @@ const activeVendor: VendorListItem = { googleMapsUrl: "", notes: "", totalJobs: 0, + address: "", city: "St. Louis", state: "MO", tradeSpecialties: "Backflow Preventers", @@ -152,6 +153,48 @@ describe("VendorsListPage", () => { expect(screen.queryByText(/3 active technicians/)).not.toBeInTheDocument(); }); + it("falls back to the free-text address when city and state are blank", () => { + setupDefaults(); + const addressOnly = { + ...activeVendor, + id: 900, + companyName: "Vinewood LLC", + address: "Santa Monica, CA", + city: "", + state: "", + }; + + useVendorsList.mockImplementation((params: { isActive?: boolean; pageSize?: number }) => { + if (params.pageSize === 1) return result([], params.isActive ? 1 : 0); + return result([addressOnly], 1); + }); + + renderWithProviders(, { route: "/vendors", withAuth: false }); + + expect(screen.getByText("Santa Monica, CA")).toBeInTheDocument(); + }); + + it("prefers structured city and state over the free-text address", () => { + setupDefaults(); + const both = { + ...activeVendor, + id: 901, + address: "Santa Monica, CA", + city: "St. Louis", + state: "MO", + }; + + useVendorsList.mockImplementation((params: { isActive?: boolean; pageSize?: number }) => { + if (params.pageSize === 1) return result([], params.isActive ? 1 : 0); + return result([both], 1); + }); + + renderWithProviders(, { route: "/vendors", withAuth: false }); + + expect(screen.getByText("St. Louis, MO")).toBeInTheDocument(); + expect(screen.queryByText("Santa Monica, CA")).not.toBeInTheDocument(); + }); + it("opens the detail drawer when a row is clicked or activated by keyboard", async () => { setupDefaults(); useVendorCompanyRoster.mockReturnValue({