From cb25d2e5fdaafd50ce17ce8a7433bd69ed0ddfc9 Mon Sep 17 00:00:00 2001 From: "Claude (auto-fix)" Date: Sun, 21 Jun 2026 12:43:21 +0530 Subject: [PATCH] feat(vendors): search by vendor ID and show it next to the name On /inventory/vendors, include vendorId in the search filter and render it as a muted mono badge beside the vendor name. The vendorId data was already passed to the client component, so this is a presentation/filter change only. Unverified vendors (no vendorId) render unchanged. Fixes #57 Co-Authored-By: Claude Opus 4.8 (1M context) --- .../inventory/vendors/vendors-table.tsx | 6 +- App/tests/unit/vendors-table.test.tsx | 64 +++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 App/tests/unit/vendors-table.test.tsx diff --git a/App/app/(portal)/inventory/vendors/vendors-table.tsx b/App/app/(portal)/inventory/vendors/vendors-table.tsx index 5eeaeb5..01d9226 100644 --- a/App/app/(portal)/inventory/vendors/vendors-table.tsx +++ b/App/app/(portal)/inventory/vendors/vendors-table.tsx @@ -41,6 +41,7 @@ export function VendorsTable({ ? vendors.filter( (v) => v.name.toLowerCase().includes(q) || + (v.vendorId && v.vendorId.toLowerCase().includes(q)) || (v.gstin && v.gstin.toLowerCase().includes(q)) || (v.address && v.address.toLowerCase().includes(q)) ) @@ -89,7 +90,7 @@ export function VendorsTable({ setQuery(e.target.value)} - placeholder="Search by name, GSTIN or address…" + placeholder="Search by name, ID, GSTIN or address…" className="w-full rounded-lg border border-neutral-200 py-2 pl-8 pr-8 text-sm focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-primary-500/20" /> {query && ( @@ -151,6 +152,9 @@ export function VendorsTable({ {vendor.name} + {vendor.vendorId && ( + {vendor.vendorId} + )} {vendor.isVerified && ( Verified )} diff --git a/App/tests/unit/vendors-table.test.tsx b/App/tests/unit/vendors-table.test.tsx new file mode 100644 index 0000000..c75c5f2 --- /dev/null +++ b/App/tests/unit/vendors-table.test.tsx @@ -0,0 +1,64 @@ +import { describe, it, expect, vi } from "vitest"; +import { render, screen, fireEvent } from "@testing-library/react"; +import { VendorsTable } from "@/app/(portal)/inventory/vendors/vendors-table"; + +vi.mock("next/navigation", () => ({ + useRouter: () => ({ push: vi.fn() }), +})); + +type Row = Parameters[0]["vendors"][number]; + +const makeRow = (over: Partial = {}): Row => ({ + id: "v1", + name: "Acme Marine Supplies", + vendorId: "VND-001", + gstin: null, + address: null, + isVerified: false, + itemCount: 0, + primaryContact: null, + distanceKm: null, + ...over, +}); + +describe("VendorsTable — vendor id (issue #57)", () => { + it("renders the vendorId next to the name when present", () => { + render(); + expect(screen.getByText("Acme Marine Supplies")).toBeTruthy(); + expect(screen.getByText("VND-001")).toBeTruthy(); + }); + + it("omits the id (no placeholder) when vendorId is null", () => { + render(); + expect(screen.queryByText("VND-001")).toBeNull(); + }); + + it("filters by vendorId", () => { + const rows = [ + makeRow({ id: "v1", name: "Acme Marine Supplies", vendorId: "VND-001" }), + makeRow({ id: "v2", name: "Beta Traders", vendorId: "VND-999" }), + ]; + render(); + const search = screen.getByPlaceholderText(/Search by name/i); + fireEvent.change(search, { target: { value: "VND-999" } }); + expect(screen.queryByText("Acme Marine Supplies")).toBeNull(); + expect(screen.getByText("Beta Traders")).toBeTruthy(); + }); + + it("still filters by name", () => { + const rows = [ + makeRow({ id: "v1", name: "Acme Marine Supplies", vendorId: "VND-001" }), + makeRow({ id: "v2", name: "Beta Traders", vendorId: "VND-999" }), + ]; + render(); + const search = screen.getByPlaceholderText(/Search by name/i); + fireEvent.change(search, { target: { value: "beta" } }); + expect(screen.getByText("Beta Traders")).toBeTruthy(); + expect(screen.queryByText("Acme Marine Supplies")).toBeNull(); + }); + + it("advertises ID search in the placeholder", () => { + render(); + expect(screen.getByPlaceholderText(/Search by name, ID, GSTIN or address/i)).toBeTruthy(); + }); +});