mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-09-30 09:13:11 +00:00
fix(vendors): use grouped directory endpoint
This commit is contained in:
parent
b1ae5085e7
commit
99253587ef
9 changed files with 389 additions and 71 deletions
|
|
@ -125,6 +125,7 @@ export const API_PATHS = {
|
|||
},
|
||||
vendor: {
|
||||
getList: "Vendor/GetVendorList",
|
||||
getDirectoryList: "Vendor/GetVendorDirectoryList",
|
||||
getById: "Vendor/GetById",
|
||||
create: "Vendor/Create",
|
||||
update: "Vendor/Update",
|
||||
|
|
|
|||
16
src/app/(protected)/vendors/index.tsx
vendored
16
src/app/(protected)/vendors/index.tsx
vendored
|
|
@ -15,7 +15,7 @@ import { useVendorListState } from "./_components/use-vendor-list-state";
|
|||
import type { VendorFilters } from "./_components/vendor-filters";
|
||||
import type { VendorListItem } from "@/domain/vendors/types/vendor";
|
||||
import { useVendorFacets } from "@/domain/vendors/use-cases/use-vendor-facets";
|
||||
import { useVendorsList } from "@/domain/vendors/use-cases/use-vendors-list";
|
||||
import { useVendorDirectoryList } from "@/domain/vendors/use-cases/use-vendor-directory-list";
|
||||
|
||||
interface AppliedChip {
|
||||
category: keyof VendorFilters;
|
||||
|
|
@ -125,9 +125,17 @@ export default function VendorsListPage() {
|
|||
const deactivation = useVendorDeactivation(closeDetail);
|
||||
|
||||
const { data: facets } = useVendorFacets(filters.isActive);
|
||||
const { data, isLoading, isFetching, error } = useVendorsList(filters.listParams);
|
||||
const { data: activeCountData } = useVendorsList({ isActive: true, page: 1, pageSize: 1 });
|
||||
const { data: inactiveCountData } = useVendorsList({ isActive: false, page: 1, pageSize: 1 });
|
||||
const { data, isLoading, isFetching, error } = useVendorDirectoryList(filters.listParams);
|
||||
const { data: activeCountData } = useVendorDirectoryList({
|
||||
isActive: true,
|
||||
page: 1,
|
||||
pageSize: 1,
|
||||
});
|
||||
const { data: inactiveCountData } = useVendorDirectoryList({
|
||||
isActive: false,
|
||||
page: 1,
|
||||
pageSize: 1,
|
||||
});
|
||||
|
||||
const rows = data?.items ?? [];
|
||||
const totalCount = data?.totalCount ?? 0;
|
||||
|
|
|
|||
18
src/domain/vendors/api/vendors-api.ts
vendored
18
src/domain/vendors/api/vendors-api.ts
vendored
|
|
@ -76,6 +76,24 @@ export const vendorsApi = {
|
|||
};
|
||||
},
|
||||
|
||||
// SH-281: grouped company rows come from the dedicated directory endpoint;
|
||||
// Vendor/GetVendorList stays on the legacy technician-level contract.
|
||||
getDirectoryList: async (params: VendorsListParams = {}): Promise<VendorsListResult> => {
|
||||
const data = await apiGet<unknown>(API_PATHS.vendor.getDirectoryList, {
|
||||
searchParams: buildListParams(params),
|
||||
});
|
||||
const paginated = handlePaginatedResponse<unknown>(data, {
|
||||
page: params.page,
|
||||
pageSize: params.pageSize,
|
||||
});
|
||||
return {
|
||||
items: mapVendorListItems(paginated.items),
|
||||
totalCount: paginated.totalCount,
|
||||
page: paginated.page,
|
||||
pageSize: paginated.pageSize,
|
||||
};
|
||||
},
|
||||
|
||||
getFacets: async (params?: VendorFacetsParams): Promise<VendorFacets> => {
|
||||
const data = await apiGet<unknown>(API_PATHS.vendor.facets, {
|
||||
searchParams: buildFacetsParams(params),
|
||||
|
|
|
|||
14
src/domain/vendors/use-cases/use-vendor-directory-list.ts
vendored
Normal file
14
src/domain/vendors/use-cases/use-vendor-directory-list.ts
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import { keepPreviousData, useQuery, type UseQueryResult } from "@tanstack/react-query";
|
||||
import { vendorsApi } from "@/domain/vendors/api/vendors-api";
|
||||
import type { VendorsListParams, VendorsListResult } from "@/domain/vendors/types/vendor";
|
||||
import { queryKeys } from "@/infra/query-key/query-key";
|
||||
|
||||
export function useVendorDirectoryList(
|
||||
params: VendorsListParams,
|
||||
): UseQueryResult<VendorsListResult, Error> {
|
||||
return useQuery({
|
||||
queryKey: queryKeys.vendors.directoryList(params as Record<string, unknown>),
|
||||
queryFn: () => vendorsApi.getDirectoryList(params),
|
||||
placeholderData: keepPreviousData,
|
||||
});
|
||||
}
|
||||
|
|
@ -68,6 +68,8 @@ export const queryKeys = {
|
|||
all: ["vendors"] as const,
|
||||
list: (params?: Record<string, unknown>) =>
|
||||
[...queryKeys.vendors.all, "list", params ?? {}] as const,
|
||||
directoryList: (params?: Record<string, unknown>) =>
|
||||
[...queryKeys.vendors.all, "directoryList", params ?? {}] as const,
|
||||
detail: (id: string | number) => [...queryKeys.vendors.all, "detail", id] as const,
|
||||
facets: (isActive?: boolean) => [...queryKeys.vendors.all, "facets", isActive ?? null] as const,
|
||||
dropdown: (trade?: string, siteZip?: string) =>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
import { describe, expect, it, vi } from "vitest";
|
||||
import { screen } from "@testing-library/react";
|
||||
import VendorPosListPage from "@/app/(protected)/vendor-pos/index";
|
||||
import { renderWithProviders } from "@/test/test-utils";
|
||||
|
||||
const useVendorPosList = vi.fn();
|
||||
const useVendorsList = vi.fn();
|
||||
const useVendorDirectoryList = vi.fn();
|
||||
|
||||
vi.mock("@/domain/vendor-pos/use-cases/use-vendor-pos-list", () => ({
|
||||
useVendorPosList: (...args: unknown[]) => useVendorPosList(...args),
|
||||
}));
|
||||
|
||||
vi.mock("@/domain/vendors/use-cases/use-vendors-list", () => ({
|
||||
useVendorsList: (...args: unknown[]) => useVendorsList(...args),
|
||||
}));
|
||||
|
||||
vi.mock("@/domain/vendors/use-cases/use-vendor-directory-list", () => ({
|
||||
useVendorDirectoryList: (...args: unknown[]) => useVendorDirectoryList(...args),
|
||||
}));
|
||||
|
||||
describe("VendorPosListPage vendor source", () => {
|
||||
it("keeps the legacy technician-level vendors list with pageSize 500", () => {
|
||||
useVendorPosList.mockReturnValue({
|
||||
data: { items: [], totalCount: 0, page: 1, pageSize: 12 },
|
||||
isLoading: false,
|
||||
isFetching: false,
|
||||
error: null,
|
||||
});
|
||||
useVendorsList.mockReturnValue({
|
||||
data: { items: [], totalCount: 0, page: 1, pageSize: 500 },
|
||||
isLoading: false,
|
||||
isFetching: false,
|
||||
error: null,
|
||||
});
|
||||
useVendorDirectoryList.mockReturnValue({
|
||||
data: { items: [], totalCount: 0, page: 1, pageSize: 500 },
|
||||
isLoading: false,
|
||||
isFetching: false,
|
||||
error: null,
|
||||
});
|
||||
|
||||
renderWithProviders(<VendorPosListPage />, { route: "/vendor-pos", withAuth: false });
|
||||
|
||||
expect(useVendorsList).toHaveBeenCalledWith({ page: 1, pageSize: 500 });
|
||||
expect(useVendorsList).toHaveBeenCalledTimes(1);
|
||||
expect(useVendorDirectoryList).not.toHaveBeenCalled();
|
||||
expect(screen.getByRole("table")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
|
@ -5,12 +5,12 @@ import VendorsListPage from "@/app/(protected)/vendors/index";
|
|||
import type { VendorCompanyRoster, VendorListItem } from "@/domain/vendors/types/vendor";
|
||||
import { renderWithProviders } from "@/test/test-utils";
|
||||
|
||||
const useVendorsList = vi.fn();
|
||||
const useVendorDirectoryList = vi.fn();
|
||||
const useVendorCompanyRoster = vi.fn();
|
||||
const useVendorDeactivationImpact = vi.fn();
|
||||
const mutate = vi.fn();
|
||||
vi.mock("@/domain/vendors/use-cases/use-vendors-list", () => ({
|
||||
useVendorsList: (...args: unknown[]) => useVendorsList(...args),
|
||||
vi.mock("@/domain/vendors/use-cases/use-vendor-directory-list", () => ({
|
||||
useVendorDirectoryList: (...args: unknown[]) => useVendorDirectoryList(...args),
|
||||
}));
|
||||
|
||||
vi.mock("@/domain/vendors/use-cases/use-vendor-company-roster", () => ({
|
||||
|
|
@ -108,10 +108,12 @@ function setupDefaults() {
|
|||
describe("VendorsListPage", () => {
|
||||
it("renders prototype-aligned status and two row actions in both tabs", async () => {
|
||||
setupDefaults();
|
||||
useVendorsList.mockImplementation((params: { isActive?: boolean; pageSize?: number }) => {
|
||||
if (params.pageSize === 1) return result([], params.isActive ? 1 : 1);
|
||||
return params.isActive ? result([activeVendor], 1) : result([inactiveVendor], 1);
|
||||
});
|
||||
useVendorDirectoryList.mockImplementation(
|
||||
(params: { isActive?: boolean; pageSize?: number }) => {
|
||||
if (params.pageSize === 1) return result([], params.isActive ? 1 : 1);
|
||||
return params.isActive ? result([activeVendor], 1) : result([inactiveVendor], 1);
|
||||
},
|
||||
);
|
||||
|
||||
renderWithProviders(<VendorsListPage />, { route: "/vendors", withAuth: false });
|
||||
|
||||
|
|
@ -169,10 +171,12 @@ describe("VendorsListPage", () => {
|
|||
},
|
||||
],
|
||||
};
|
||||
useVendorsList.mockImplementation((params: { isActive?: boolean; pageSize?: number }) => {
|
||||
if (params.pageSize === 1) return result([], 1);
|
||||
return params.isActive ? result([groupedVendor], 1) : result([], 0);
|
||||
});
|
||||
useVendorDirectoryList.mockImplementation(
|
||||
(params: { isActive?: boolean; pageSize?: number }) => {
|
||||
if (params.pageSize === 1) return result([], 1);
|
||||
return params.isActive ? result([groupedVendor], 1) : result([], 0);
|
||||
},
|
||||
);
|
||||
|
||||
renderWithProviders(<VendorsListPage />, { route: "/vendors", withAuth: false });
|
||||
|
||||
|
|
@ -198,10 +202,12 @@ describe("VendorsListPage", () => {
|
|||
state: " MO ",
|
||||
phone: " (314) 555-0198 ",
|
||||
};
|
||||
useVendorsList.mockImplementation((params: { isActive?: boolean; pageSize?: number }) => {
|
||||
if (params.pageSize === 1) return result([], 1);
|
||||
return params.isActive ? result([vendorWithAllFields], 1) : result([], 0);
|
||||
});
|
||||
useVendorDirectoryList.mockImplementation(
|
||||
(params: { isActive?: boolean; pageSize?: number }) => {
|
||||
if (params.pageSize === 1) return result([], 1);
|
||||
return params.isActive ? result([vendorWithAllFields], 1) : result([], 0);
|
||||
},
|
||||
);
|
||||
|
||||
renderWithProviders(<VendorsListPage />, { route: "/vendors", withAuth: false });
|
||||
|
||||
|
|
@ -228,10 +234,12 @@ describe("VendorsListPage", () => {
|
|||
state: "",
|
||||
phone: " ",
|
||||
};
|
||||
useVendorsList.mockImplementation((params: { isActive?: boolean; pageSize?: number }) => {
|
||||
if (params.pageSize === 1) return result([], 1);
|
||||
return params.isActive ? result([fallbackVendor], 1) : result([], 0);
|
||||
});
|
||||
useVendorDirectoryList.mockImplementation(
|
||||
(params: { isActive?: boolean; pageSize?: number }) => {
|
||||
if (params.pageSize === 1) return result([], 1);
|
||||
return params.isActive ? result([fallbackVendor], 1) : result([], 0);
|
||||
},
|
||||
);
|
||||
|
||||
renderWithProviders(<VendorsListPage />, { route: "/vendors", withAuth: false });
|
||||
|
||||
|
|
@ -260,10 +268,12 @@ describe("VendorsListPage", () => {
|
|||
city: "",
|
||||
state: "",
|
||||
};
|
||||
useVendorsList.mockImplementation((params: { isActive?: boolean; pageSize?: number }) => {
|
||||
if (params.pageSize === 1) return result([], 1);
|
||||
return params.isActive ? result([fallbackVendor], 1) : result([], 0);
|
||||
});
|
||||
useVendorDirectoryList.mockImplementation(
|
||||
(params: { isActive?: boolean; pageSize?: number }) => {
|
||||
if (params.pageSize === 1) return result([], 1);
|
||||
return params.isActive ? result([fallbackVendor], 1) : result([], 0);
|
||||
},
|
||||
);
|
||||
|
||||
renderWithProviders(<VendorsListPage />, { route: "/vendors", withAuth: false });
|
||||
|
||||
|
|
@ -319,10 +329,12 @@ describe("VendorsListPage", () => {
|
|||
...activeVendor,
|
||||
tradeSpecialties: "Backflow Preventers, Water Heaters, Drain Cleaning",
|
||||
};
|
||||
useVendorsList.mockImplementation((params: { isActive?: boolean; pageSize?: number }) => {
|
||||
if (params.pageSize === 1) return result([], 1);
|
||||
return params.isActive ? result([multiTradeVendor], 1) : result([], 0);
|
||||
});
|
||||
useVendorDirectoryList.mockImplementation(
|
||||
(params: { isActive?: boolean; pageSize?: number }) => {
|
||||
if (params.pageSize === 1) return result([], 1);
|
||||
return params.isActive ? result([multiTradeVendor], 1) : result([], 0);
|
||||
},
|
||||
);
|
||||
|
||||
renderWithProviders(<VendorsListPage />, { route: "/vendors", withAuth: false });
|
||||
|
||||
|
|
@ -346,10 +358,12 @@ describe("VendorsListPage", () => {
|
|||
|
||||
it("does not show the +N badge when the vendor has a single trade", () => {
|
||||
setupDefaults();
|
||||
useVendorsList.mockImplementation((params: { isActive?: boolean; pageSize?: number }) => {
|
||||
if (params.pageSize === 1) return result([], 1);
|
||||
return params.isActive ? result([activeVendor], 1) : result([], 0);
|
||||
});
|
||||
useVendorDirectoryList.mockImplementation(
|
||||
(params: { isActive?: boolean; pageSize?: number }) => {
|
||||
if (params.pageSize === 1) return result([], 1);
|
||||
return params.isActive ? result([activeVendor], 1) : result([], 0);
|
||||
},
|
||||
);
|
||||
|
||||
renderWithProviders(<VendorsListPage />, { route: "/vendors", withAuth: false });
|
||||
|
||||
|
|
@ -370,10 +384,12 @@ describe("VendorsListPage", () => {
|
|||
...activeVendor,
|
||||
tradeSpecialties: "Backflow Preventers, Water Heaters, Drain Cleaning",
|
||||
};
|
||||
useVendorsList.mockImplementation((params: { isActive?: boolean; pageSize?: number }) => {
|
||||
if (params.pageSize === 1) return result([], 1);
|
||||
return params.isActive ? result([multiTradeVendor], 1) : result([], 0);
|
||||
});
|
||||
useVendorDirectoryList.mockImplementation(
|
||||
(params: { isActive?: boolean; pageSize?: number }) => {
|
||||
if (params.pageSize === 1) return result([], 1);
|
||||
return params.isActive ? result([multiTradeVendor], 1) : result([], 0);
|
||||
},
|
||||
);
|
||||
|
||||
renderWithProviders(<VendorsListPage />, { route: "/vendors", withAuth: false });
|
||||
|
||||
|
|
@ -394,10 +410,12 @@ describe("VendorsListPage", () => {
|
|||
...activeVendor,
|
||||
tradeSpecialties: "Backflow Preventers, Water Heaters",
|
||||
};
|
||||
useVendorsList.mockImplementation((params: { isActive?: boolean; pageSize?: number }) => {
|
||||
if (params.pageSize === 1) return result([], 1);
|
||||
return params.isActive ? result([multiTradeVendor], 1) : result([], 0);
|
||||
});
|
||||
useVendorDirectoryList.mockImplementation(
|
||||
(params: { isActive?: boolean; pageSize?: number }) => {
|
||||
if (params.pageSize === 1) return result([], 1);
|
||||
return params.isActive ? result([multiTradeVendor], 1) : result([], 0);
|
||||
},
|
||||
);
|
||||
|
||||
renderWithProviders(<VendorsListPage />, { route: "/vendors", withAuth: false });
|
||||
|
||||
|
|
@ -414,10 +432,12 @@ describe("VendorsListPage", () => {
|
|||
companyName: `Vendor ${index + 1}`,
|
||||
}));
|
||||
|
||||
useVendorsList.mockImplementation((params: { isActive?: boolean; pageSize?: number }) => {
|
||||
if (params.pageSize === 1) return result([], params.isActive ? 25 : 0);
|
||||
return result(pageVendors, 25);
|
||||
});
|
||||
useVendorDirectoryList.mockImplementation(
|
||||
(params: { isActive?: boolean; pageSize?: number }) => {
|
||||
if (params.pageSize === 1) return result([], params.isActive ? 25 : 0);
|
||||
return result(pageVendors, 25);
|
||||
},
|
||||
);
|
||||
|
||||
renderWithProviders(<VendorsListPage />, { route: "/vendors", withAuth: false });
|
||||
|
||||
|
|
@ -434,10 +454,12 @@ describe("VendorsListPage", () => {
|
|||
error: null,
|
||||
refetch: vi.fn(),
|
||||
});
|
||||
useVendorsList.mockImplementation((params: { isActive?: boolean; pageSize?: number }) => {
|
||||
if (params.pageSize === 1) return result([], 1);
|
||||
return params.isActive ? result([activeVendor], 1) : result([], 0);
|
||||
});
|
||||
useVendorDirectoryList.mockImplementation(
|
||||
(params: { isActive?: boolean; pageSize?: number }) => {
|
||||
if (params.pageSize === 1) return result([], 1);
|
||||
return params.isActive ? result([activeVendor], 1) : result([], 0);
|
||||
},
|
||||
);
|
||||
|
||||
renderWithProviders(<VendorsListPage />, { route: "/vendors", withAuth: false });
|
||||
|
||||
|
|
@ -475,10 +497,12 @@ describe("VendorsListPage", () => {
|
|||
isLoading: false,
|
||||
error: null,
|
||||
});
|
||||
useVendorsList.mockImplementation((params: { isActive?: boolean; pageSize?: number }) => {
|
||||
if (params.pageSize === 1) return result([], 1);
|
||||
return params.isActive ? result([activeVendor], 1) : result([], 0);
|
||||
});
|
||||
useVendorDirectoryList.mockImplementation(
|
||||
(params: { isActive?: boolean; pageSize?: number }) => {
|
||||
if (params.pageSize === 1) return result([], 1);
|
||||
return params.isActive ? result([activeVendor], 1) : result([], 0);
|
||||
},
|
||||
);
|
||||
|
||||
renderWithProviders(<VendorsListPage />, { route: "/vendors", withAuth: false });
|
||||
|
||||
|
|
@ -516,10 +540,12 @@ describe("VendorsListPage", () => {
|
|||
isLoading: false,
|
||||
error: null,
|
||||
});
|
||||
useVendorsList.mockImplementation((params: { isActive?: boolean; pageSize?: number }) => {
|
||||
if (params.pageSize === 1) return result([], 1);
|
||||
return params.isActive ? result([activeVendor], 1) : result([], 0);
|
||||
});
|
||||
useVendorDirectoryList.mockImplementation(
|
||||
(params: { isActive?: boolean; pageSize?: number }) => {
|
||||
if (params.pageSize === 1) return result([], 1);
|
||||
return params.isActive ? result([activeVendor], 1) : result([], 0);
|
||||
},
|
||||
);
|
||||
|
||||
renderWithProviders(<VendorsListPage />, { route: "/vendors", withAuth: false });
|
||||
|
||||
|
|
@ -546,10 +572,12 @@ describe("VendorsListPage", () => {
|
|||
isLoading: false,
|
||||
error: null,
|
||||
});
|
||||
useVendorsList.mockImplementation((params: { isActive?: boolean; pageSize?: number }) => {
|
||||
if (params.pageSize === 1) return result([], 1);
|
||||
return params.isActive ? result([activeVendor], 1) : result([], 0);
|
||||
});
|
||||
useVendorDirectoryList.mockImplementation(
|
||||
(params: { isActive?: boolean; pageSize?: number }) => {
|
||||
if (params.pageSize === 1) return result([], 1);
|
||||
return params.isActive ? result([activeVendor], 1) : result([], 0);
|
||||
},
|
||||
);
|
||||
|
||||
renderWithProviders(<VendorsListPage />, { route: "/vendors", withAuth: false });
|
||||
|
||||
|
|
@ -577,10 +605,12 @@ describe("VendorsListPage", () => {
|
|||
error: null,
|
||||
refetch: vi.fn(),
|
||||
});
|
||||
useVendorsList.mockImplementation((params: { isActive?: boolean; pageSize?: number }) => {
|
||||
if (params.pageSize === 1) return result([], 1);
|
||||
return params.isActive ? result([activeVendor], 1) : result([], 0);
|
||||
});
|
||||
useVendorDirectoryList.mockImplementation(
|
||||
(params: { isActive?: boolean; pageSize?: number }) => {
|
||||
if (params.pageSize === 1) return result([], 1);
|
||||
return params.isActive ? result([activeVendor], 1) : result([], 0);
|
||||
},
|
||||
);
|
||||
|
||||
renderWithProviders(<VendorsListPage />, { route: "/vendors", withAuth: false });
|
||||
|
||||
|
|
@ -602,10 +632,12 @@ describe("VendorsListPage", () => {
|
|||
error: null,
|
||||
refetch: vi.fn(),
|
||||
});
|
||||
useVendorsList.mockImplementation((params: { isActive?: boolean; pageSize?: number }) => {
|
||||
if (params.pageSize === 1) return result([], 1);
|
||||
return params.isActive ? result([companyOnlyVendor], 1) : result([], 0);
|
||||
});
|
||||
useVendorDirectoryList.mockImplementation(
|
||||
(params: { isActive?: boolean; pageSize?: number }) => {
|
||||
if (params.pageSize === 1) return result([], 1);
|
||||
return params.isActive ? result([companyOnlyVendor], 1) : result([], 0);
|
||||
},
|
||||
);
|
||||
|
||||
renderWithProviders(<VendorsListPage />, { route: "/vendors", withAuth: false });
|
||||
|
||||
|
|
@ -616,4 +648,24 @@ describe("VendorsListPage", () => {
|
|||
"Gateway Plumbing",
|
||||
);
|
||||
});
|
||||
|
||||
it("loads rows and status counts through the directory hook", async () => {
|
||||
setupDefaults();
|
||||
useVendorDirectoryList.mockImplementation(
|
||||
(params: { isActive?: boolean; pageSize?: number }) => {
|
||||
if (params.pageSize === 1) return result([], params.isActive ? 3 : 2);
|
||||
return result([activeVendor], 3);
|
||||
},
|
||||
);
|
||||
|
||||
renderWithProviders(<VendorsListPage />, { route: "/vendors", withAuth: false });
|
||||
|
||||
expect(useVendorDirectoryList).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ page: 1, pageSize: 48 }),
|
||||
);
|
||||
expect(useVendorDirectoryList).toHaveBeenCalledWith({ isActive: true, page: 1, pageSize: 1 });
|
||||
expect(useVendorDirectoryList).toHaveBeenCalledWith({ isActive: false, page: 1, pageSize: 1 });
|
||||
expect(screen.getByRole("tab", { name: "Active (3)" })).toBeInTheDocument();
|
||||
expect(screen.getByRole("tab", { name: "Inactive (2)" })).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
93
src/test/domain/vendors/api/vendors-api.test.ts
vendored
93
src/test/domain/vendors/api/vendors-api.test.ts
vendored
|
|
@ -326,3 +326,96 @@ describe("vendorsApi.getList", () => {
|
|||
await expect(vendorsApi.delete(8)).rejects.toThrow("Conflict");
|
||||
});
|
||||
});
|
||||
|
||||
describe("vendorsApi.getDirectoryList", () => {
|
||||
beforeEach(() => {
|
||||
apiGet.mockReset();
|
||||
apiGet.mockResolvedValue({
|
||||
Data: [
|
||||
{
|
||||
Id: 7,
|
||||
CompanyId: "co-1",
|
||||
CompanyName: "Gateway Plumbing",
|
||||
ContactName: "Adam Whyte",
|
||||
Email: "dispatch@gateway.test",
|
||||
Phone: "314-555-0198",
|
||||
Address: "1 Market St",
|
||||
City: "St. Louis",
|
||||
State: "MO",
|
||||
IsActive: false,
|
||||
PreferredContact: "Email",
|
||||
Technicians: [
|
||||
{
|
||||
Id: 7,
|
||||
ContactName: "Adam Whyte",
|
||||
Email: "adam@gateway.test",
|
||||
Phone: "314-555-0198",
|
||||
TradeSpecialties: "Plumbing",
|
||||
IsActive: false,
|
||||
TotalJobs: 3,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
TotalCount: 1,
|
||||
});
|
||||
});
|
||||
|
||||
it("targets the dedicated directory endpoint while getList keeps the legacy route", async () => {
|
||||
await vendorsApi.getDirectoryList({ search: "gateway", isActive: false, page: 1 });
|
||||
await vendorsApi.getList({ search: "gateway", isActive: false, page: 1 });
|
||||
|
||||
expect(API_PATHS.vendor.getDirectoryList).toBe("Vendor/GetVendorDirectoryList");
|
||||
expect(API_PATHS.vendor.getList).toBe("Vendor/GetVendorList");
|
||||
expect(apiGet).toHaveBeenNthCalledWith(1, API_PATHS.vendor.getDirectoryList, {
|
||||
searchParams: { search: "gateway", isActive: "false", page: 1, pageSize: 12 },
|
||||
});
|
||||
expect(apiGet).toHaveBeenNthCalledWith(2, API_PATHS.vendor.getList, {
|
||||
searchParams: { search: "gateway", isActive: "false", page: 1, pageSize: 12 },
|
||||
});
|
||||
});
|
||||
|
||||
it("builds directory query parameters with the same repeated facet encoding", async () => {
|
||||
await vendorsApi.getDirectoryList({
|
||||
companies: ["Gateway Plumbing", "Metro HVAC"],
|
||||
trades: ["Plumbing"],
|
||||
locations: ["St. Louis, MO"],
|
||||
jobBuckets: ["50-99"],
|
||||
});
|
||||
|
||||
expect(apiGet).toHaveBeenCalledWith(API_PATHS.vendor.getDirectoryList, {
|
||||
searchParams: {
|
||||
search: "",
|
||||
page: 1,
|
||||
pageSize: 12,
|
||||
"companies[0]": "Gateway Plumbing",
|
||||
"companies[1]": "Metro HVAC",
|
||||
"trades[0]": "Plumbing",
|
||||
"locations[0]": "St. Louis, MO",
|
||||
"jobBuckets[0]": "50-99",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("maps grouped company rows with the shared grouped-row mapper", async () => {
|
||||
const result = await vendorsApi.getDirectoryList({ isActive: false, page: 1 });
|
||||
|
||||
expect(result.items[0]).toMatchObject({
|
||||
companyId: "co-1",
|
||||
companyName: "Gateway Plumbing",
|
||||
address: "1 Market St",
|
||||
city: "St. Louis",
|
||||
state: "MO",
|
||||
isActive: false,
|
||||
technicians: [
|
||||
expect.objectContaining({
|
||||
id: 7,
|
||||
contactName: "Adam Whyte",
|
||||
email: "adam@gateway.test",
|
||||
phone: "314-555-0198",
|
||||
totalJobs: 3,
|
||||
}),
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
80
src/test/domain/vendors/use-cases/use-vendor-directory-list.test.tsx
vendored
Normal file
80
src/test/domain/vendors/use-cases/use-vendor-directory-list.test.tsx
vendored
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { renderHook, waitFor } from "@testing-library/react";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
const getDirectoryList = vi.fn();
|
||||
const getList = vi.fn();
|
||||
|
||||
vi.mock("@/domain/vendors/api/vendors-api", () => ({
|
||||
vendorsApi: {
|
||||
getDirectoryList: (...args: unknown[]) => getDirectoryList(...args),
|
||||
getList: (...args: unknown[]) => getList(...args),
|
||||
},
|
||||
}));
|
||||
|
||||
import { useVendorDirectoryList } from "@/domain/vendors/use-cases/use-vendor-directory-list";
|
||||
import { useVendorsList } from "@/domain/vendors/use-cases/use-vendors-list";
|
||||
import { queryKeys } from "@/infra/query-key/query-key";
|
||||
|
||||
const emptyResult = { items: [], totalCount: 0, page: 1, pageSize: 12 };
|
||||
|
||||
function createClient(): QueryClient {
|
||||
return new QueryClient({
|
||||
defaultOptions: { queries: { retry: false } },
|
||||
});
|
||||
}
|
||||
|
||||
function makeWrapper(client: QueryClient) {
|
||||
return function Wrapper({ children }: { children: ReactNode }) {
|
||||
return <QueryClientProvider client={client}>{children}</QueryClientProvider>;
|
||||
};
|
||||
}
|
||||
|
||||
describe("useVendorDirectoryList", () => {
|
||||
beforeEach(() => {
|
||||
getDirectoryList.mockReset();
|
||||
getList.mockReset();
|
||||
getDirectoryList.mockResolvedValue(emptyResult);
|
||||
getList.mockResolvedValue(emptyResult);
|
||||
});
|
||||
|
||||
it("fetches through the directory endpoint, never the legacy list", async () => {
|
||||
const { result } = renderHook(() => useVendorDirectoryList({ isActive: true, page: 1 }), {
|
||||
wrapper: makeWrapper(createClient()),
|
||||
});
|
||||
|
||||
await waitFor(() => expect(result.current.isSuccess).toBe(true));
|
||||
|
||||
expect(getDirectoryList).toHaveBeenCalledWith({ isActive: true, page: 1 });
|
||||
expect(getList).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("keeps a query key distinct from the legacy list key", () => {
|
||||
const params = { isActive: true, page: 1, pageSize: 12 };
|
||||
|
||||
expect(queryKeys.vendors.directoryList(params)).not.toEqual(queryKeys.vendors.list(params));
|
||||
expect(queryKeys.vendors.directoryList(params)).toEqual(
|
||||
queryKeys.vendors.directoryList(params),
|
||||
);
|
||||
expect(queryKeys.vendors.directoryList(params)[1]).toBe("directoryList");
|
||||
expect(queryKeys.vendors.list(params)[1]).toBe("list");
|
||||
});
|
||||
|
||||
it("caches directory and legacy results independently for the same params", async () => {
|
||||
const params = { isActive: true, page: 1 } as const;
|
||||
const client = createClient();
|
||||
const directory = renderHook(() => useVendorDirectoryList({ ...params }), {
|
||||
wrapper: makeWrapper(client),
|
||||
});
|
||||
const legacy = renderHook(() => useVendorsList({ ...params }), {
|
||||
wrapper: makeWrapper(client),
|
||||
});
|
||||
|
||||
await waitFor(() => expect(directory.result.current.isSuccess).toBe(true));
|
||||
await waitFor(() => expect(legacy.result.current.isSuccess).toBe(true));
|
||||
|
||||
expect(getDirectoryList).toHaveBeenCalledTimes(1);
|
||||
expect(getList).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Reference in a new issue