mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-10-02 17:53:12 +00:00
fix(work-orders): wire Advanced Search sheet and cover SH-121 flow
This commit is contained in:
parent
4550acf1ea
commit
7df076f011
3 changed files with 192 additions and 4 deletions
|
|
@ -3,6 +3,7 @@ import { Box } from "@mui/material";
|
|||
import { useNavigate } from "react-router";
|
||||
import { PageHeader } from "@/components/ui/page-header";
|
||||
import { MediaUploadModal } from "@/app/(protected)/workorders/_components/media/media-upload-modal";
|
||||
import { WorkOrdersAdvancedSearchSheet } from "@/app/(protected)/workorders/_components/list/advanced-search/work-orders-advanced-search-sheet";
|
||||
import { WorkOrdersAdvancedFiltersBanner } from "@/app/(protected)/workorders/_components/list/work-orders-advanced-filters-banner";
|
||||
import { WorkOrdersFilterBar } from "@/app/(protected)/workorders/_components/list/filter-bar/work-orders-filter-bar";
|
||||
import { WorkOrdersListHeader } from "@/app/(protected)/workorders/_components/list/work-orders-list-header";
|
||||
|
|
@ -44,6 +45,11 @@ export default function WorkOrdersListPage() {
|
|||
[problemOptions],
|
||||
);
|
||||
|
||||
const vendorTechs = useMemo(
|
||||
() => [...new Set(vendors.map((vendor) => vendor.companyName).filter(Boolean))],
|
||||
[vendors],
|
||||
);
|
||||
|
||||
const totalCount = tableData.totalCount;
|
||||
const scopeTotalCount = tableData.scopeTotalCount;
|
||||
|
||||
|
|
@ -62,6 +68,7 @@ export default function WorkOrdersListPage() {
|
|||
<WorkOrdersListHeader
|
||||
search={filters.search}
|
||||
onSearchChange={filters.handleSearchChange}
|
||||
onOpenAdvancedFilters={() => filters.setAdvOpen(true)}
|
||||
activeFilterCount={filters.activeFilterCount}
|
||||
isFetching={tableData.isFetching && !tableData.isLoading}
|
||||
/>
|
||||
|
|
@ -104,6 +111,19 @@ export default function WorkOrdersListPage() {
|
|||
}}
|
||||
onOpenMedia={setMediaRow}
|
||||
onClearSearch={() => filters.handleSearchChange("")}
|
||||
onOpenAdvancedFilters={() => filters.setAdvOpen(true)}
|
||||
/>
|
||||
|
||||
<WorkOrdersAdvancedSearchSheet
|
||||
open={filters.advOpen}
|
||||
onOpenChange={filters.setAdvOpen}
|
||||
initial={filters.advInitial}
|
||||
onApply={filters.applyAdvancedFilters}
|
||||
onClearAll={filters.clearAdvancedFilters}
|
||||
sites={locations}
|
||||
users={users}
|
||||
pmTypes={pmTypes}
|
||||
vendorTechs={vendorTechs}
|
||||
/>
|
||||
|
||||
{activeMediaRow && (
|
||||
|
|
|
|||
|
|
@ -0,0 +1,154 @@
|
|||
import { fireEvent, screen, within } from "@testing-library/react";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import WorkOrdersListPage from "@/app/(protected)/workorders/index";
|
||||
import { EMPTY_ADVANCED_FILTERS } from "@/domain/work-orders/types/work-order-advanced-filters";
|
||||
import { renderWithProviders } from "@/test/test-utils";
|
||||
|
||||
const setAdvOpen = vi.fn();
|
||||
const applyAdvancedFilters = vi.fn();
|
||||
const clearAdvancedFilters = vi.fn();
|
||||
let advOpen = false;
|
||||
let advApplied: typeof EMPTY_ADVANCED_FILTERS | null = null;
|
||||
|
||||
vi.mock("react-router", async () => {
|
||||
const actual = await vi.importActual<typeof import("react-router")>("react-router");
|
||||
return {
|
||||
...actual,
|
||||
useNavigate: () => vi.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("@/providers/auth-context", () => ({
|
||||
useAuthContext: () => ({ user: { id: "u1" } }),
|
||||
}));
|
||||
|
||||
vi.mock("@/app/(protected)/workorders/_hooks/use-work-orders-list-filters", () => ({
|
||||
useWorkOrdersListFilters: () => ({
|
||||
search: "",
|
||||
handleSearchChange: vi.fn(),
|
||||
advOpen,
|
||||
setAdvOpen: (open: boolean) => {
|
||||
advOpen = open;
|
||||
setAdvOpen(open);
|
||||
},
|
||||
advApplied,
|
||||
advInitial: advApplied ?? EMPTY_ADVANCED_FILTERS,
|
||||
applyAdvancedFilters: (filters: typeof EMPTY_ADVANCED_FILTERS) => {
|
||||
advApplied = filters;
|
||||
applyAdvancedFilters(filters);
|
||||
},
|
||||
clearAdvancedFilters: () => {
|
||||
advApplied = null;
|
||||
clearAdvancedFilters();
|
||||
},
|
||||
clearAdvancedFilterChip: vi.fn(),
|
||||
activeFilterCount: advApplied ? 1 : 0,
|
||||
weekMonday: "2026-07-20",
|
||||
setWeekMonday: vi.fn(),
|
||||
dispatcherIds: new Set<string>(),
|
||||
setDispatcherIds: vi.fn(),
|
||||
typeFilter: "All",
|
||||
setTypeFilter: vi.fn(),
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock("@/app/(protected)/workorders/_hooks/use-work-orders-table-data", () => ({
|
||||
useWorkOrdersTableData: () => ({
|
||||
rows: [],
|
||||
totalCount: 0,
|
||||
scopeTotalCount: 0,
|
||||
isFetching: false,
|
||||
isLoading: false,
|
||||
setSelectedId: vi.fn(),
|
||||
patchRow: vi.fn(),
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock("@/domain/work-orders/use-cases/use-work-order-table-mutations", () => ({
|
||||
useWorkOrderTableMutations: () => ({ patchField: vi.fn() }),
|
||||
}));
|
||||
|
||||
vi.mock("@/domain/work-orders/use-cases/use-work-orders-list", () => ({
|
||||
useWorkOrderUsers: () => ({
|
||||
data: [{ id: "u1", name: "Dispatcher One" }],
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock("@/domain/work-orders/use-cases/use-work-order-detail", () => ({
|
||||
useWorkOrderLocations: () => ({
|
||||
data: [{ id: "loc-1", name: "Seattle" }],
|
||||
}),
|
||||
useWorkOrderVendors: () => ({
|
||||
data: [{ companyName: "Vendor Co", email: "real@vendor.com" }],
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock("@/domain/settings/dropdown-options/use-cases/use-dropdown-options-by-category", () => ({
|
||||
useDropdownOptionsByCategory: () => ({ data: [{ value: "HVAC" }] }),
|
||||
}));
|
||||
|
||||
vi.mock("@/domain/work-orders/mocks/is-wo-table-mock-enabled", () => ({
|
||||
isWoTableMockEnabled: () => false,
|
||||
}));
|
||||
|
||||
vi.mock("@/app/(protected)/workorders/_components/list/table/wo-table", () => ({
|
||||
WoTable: () => null,
|
||||
}));
|
||||
|
||||
vi.mock("@/app/(protected)/workorders/_components/list/filter-bar/work-orders-filter-bar", () => ({
|
||||
WorkOrdersFilterBar: () => null,
|
||||
}));
|
||||
|
||||
vi.mock("@/app/(protected)/workorders/_components/media/media-upload-modal", () => ({
|
||||
MediaUploadModal: () => null,
|
||||
}));
|
||||
|
||||
describe("WorkOrders Advanced Search page wiring (SH-121)", () => {
|
||||
beforeEach(() => {
|
||||
advOpen = false;
|
||||
advApplied = null;
|
||||
setAdvOpen.mockClear();
|
||||
applyAdvancedFilters.mockClear();
|
||||
clearAdvancedFilters.mockClear();
|
||||
});
|
||||
|
||||
it("opens the sheet from Advanced Filters, applies, then clears", () => {
|
||||
const view = renderWithProviders(<WorkOrdersListPage />, {
|
||||
route: "/workorders",
|
||||
withAuth: false,
|
||||
});
|
||||
|
||||
expect(screen.queryByRole("button", { name: /apply filters/i })).not.toBeInTheDocument();
|
||||
|
||||
fireEvent.click(screen.getByRole("button", { name: "Advanced Filters" }));
|
||||
expect(setAdvOpen).toHaveBeenCalledWith(true);
|
||||
|
||||
advOpen = true;
|
||||
view.rerender(<WorkOrdersListPage />);
|
||||
|
||||
const sheet = screen.getByRole("dialog", { name: "Advanced Filters" });
|
||||
expect(within(sheet).getByRole("button", { name: /apply filters/i })).toBeInTheDocument();
|
||||
|
||||
// Expand filter sections that start collapsed and assert option inputs are wired.
|
||||
for (const label of ["Site", "Assigned to", "PM type", "Vendor / tech"]) {
|
||||
fireEvent.click(within(sheet).getByRole("button", { name: new RegExp(label, "i") }));
|
||||
}
|
||||
expect(within(sheet).getByText("Seattle")).toBeInTheDocument();
|
||||
expect(within(sheet).getByText("Dispatcher One")).toBeInTheDocument();
|
||||
expect(within(sheet).getByText("HVAC")).toBeInTheDocument();
|
||||
expect(within(sheet).getByText("Vendor Co")).toBeInTheDocument();
|
||||
|
||||
fireEvent.click(within(sheet).getByRole("button", { name: /apply filters/i }));
|
||||
expect(applyAdvancedFilters).toHaveBeenCalled();
|
||||
expect(setAdvOpen).toHaveBeenCalledWith(false);
|
||||
|
||||
advOpen = true;
|
||||
view.rerender(<WorkOrdersListPage />);
|
||||
fireEvent.click(
|
||||
within(screen.getByRole("dialog", { name: "Advanced Filters" })).getByRole("button", {
|
||||
name: /clear all/i,
|
||||
}),
|
||||
);
|
||||
expect(clearAdvancedFilters).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
|
@ -25,10 +25,24 @@ vi.mock("@/app/(protected)/workorders/_hooks/use-work-orders-list-filters", () =
|
|||
search: "",
|
||||
handleSearchChange: vi.fn(),
|
||||
setAdvOpen: vi.fn(),
|
||||
activeFilterCount: 0,
|
||||
advOpen: false,
|
||||
advApplied: null,
|
||||
clearAdvancedFilterChip: vi.fn(),
|
||||
advInitial: {
|
||||
dateRange: "this-week",
|
||||
customFrom: "",
|
||||
customTo: "",
|
||||
sites: new Set(),
|
||||
types: new Set(),
|
||||
dispatchers: new Set(),
|
||||
statuses: new Set(),
|
||||
pmTypes: new Set(),
|
||||
vendorTechs: new Set(),
|
||||
docs: new Set(),
|
||||
},
|
||||
applyAdvancedFilters: vi.fn(),
|
||||
clearAdvancedFilters: vi.fn(),
|
||||
clearAdvancedFilterChip: vi.fn(),
|
||||
activeFilterCount: 0,
|
||||
weekMonday: "2026-07-20",
|
||||
setWeekMonday: vi.fn(),
|
||||
dispatcherIds: new Set<string>(),
|
||||
|
|
@ -165,15 +179,15 @@ describe("WorkOrdersListHeader slice affordances", () => {
|
|||
});
|
||||
|
||||
describe("WorkOrdersListPage board-core public interface", () => {
|
||||
it("does not render New WO or Advanced Filters, and View navigates to detail", () => {
|
||||
it("does not render New WO, and View navigates to detail", () => {
|
||||
navigate.mockReset();
|
||||
|
||||
renderWithProviders(<WorkOrdersListPage />, { route: "/workorders", withAuth: false });
|
||||
|
||||
expect(screen.queryByRole("button", { name: /new wo/i })).not.toBeInTheDocument();
|
||||
expect(screen.queryByLabelText("Advanced Filters")).not.toBeInTheDocument();
|
||||
expect(screen.queryByRole("button", { name: /view doc|draft/i })).not.toBeInTheDocument();
|
||||
|
||||
|
||||
fireEvent.click(screen.getByRole("button", { name: /view canceled row/i }));
|
||||
expect(navigate).toHaveBeenCalledWith("/workorders/77");
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue