- {children}
+
+
+
{children}
+ {Boolean(footer) && (
+
{footer}
+ )}
);
diff --git a/src/app/(protected)/workorders/_components/list/table/wo-table.tsx b/src/app/(protected)/workorders/_components/list/table/wo-table.tsx
index 4706ce02..0d170a5d 100644
--- a/src/app/(protected)/workorders/_components/list/table/wo-table.tsx
+++ b/src/app/(protected)/workorders/_components/list/table/wo-table.tsx
@@ -12,6 +12,7 @@ import type {
import { isUnassignedQueueReady } from "@/domain/work-orders/utils/week-day-nav-utils";
import { DuplicateWoNumberDialog } from "@/app/(protected)/workorders/_components/list/duplicate-wo-number-dialog";
import { WoTableSkeleton } from "@/app/(protected)/workorders/_components/loading/wo-table-skeleton";
+import { WoDayPaginationFooter } from "./wo-day-pagination-footer";
import type { ReturnTypeOfUseWorkOrdersTableData } from "./wo-table-types";
import { buildSitePlaceLookups, resolveSitePlace } from "./site-place-lookup";
import { useWoTableInlineCreate } from "./use-wo-table-inline-create";
@@ -69,6 +70,24 @@ function WoTableEmptyShell({ message, actionLabel, onAction }: WoTableEmptyShell
);
}
+function WoTableDayFooter({ tableData }: { tableData: ReturnTypeOfUseWorkOrdersTableData }) {
+ if (!tableData.showDayPagination) {
+ return undefined;
+ }
+ return (
+
+ );
+}
+
export function WoTable({
tableData,
users,
@@ -188,7 +207,7 @@ export function WoTable({
return (
<>
-
+
void;
+};
+
+export function useWorkOrdersDayPagination({
+ weekMonday,
+ selectedDayIso,
+ advActive,
+ dayItems,
+ onRevealed,
+}: UseWorkOrdersDayPaginationInput) {
+ const [pageSize, setPageSizeState] = useState(DEFAULT_DAY_PAGE_SIZE);
+ const [page, setPage] = useState(0);
+ const [pendingRevealId, setPendingRevealId] = useState(null);
+
+ useEffect(() => {
+ setPage(0);
+ }, [weekMonday, selectedDayIso, advActive]);
+
+ useEffect(() => {
+ if (pendingRevealId == null) {
+ return;
+ }
+ const nextPage = findItemPageIndex(dayItems, pendingRevealId, pageSize);
+ if (nextPage == null) {
+ return;
+ }
+ setPage(nextPage);
+ const revealedId = pendingRevealId;
+ setPendingRevealId(null);
+ onRevealed(revealedId);
+ }, [pendingRevealId, dayItems, pageSize, onRevealed]);
+
+ const setPageSize = useCallback((next: DayPageSize) => {
+ setPageSizeState(next);
+ setPage(0);
+ }, []);
+
+ const goToPrevPage = useCallback(() => {
+ setPage((current) => Math.max(0, current - 1));
+ }, []);
+
+ const goToNextPage = useCallback(() => {
+ setPage((current) => current + 1);
+ }, []);
+
+ const revealRow = useCallback((id: string | number) => {
+ setPendingRevealId(id);
+ }, []);
+
+ return {
+ pageSize,
+ page,
+ setPageSize,
+ goToPrevPage,
+ goToNextPage,
+ revealRow,
+ };
+}
diff --git a/src/app/(protected)/workorders/_hooks/use-work-orders-table-data.ts b/src/app/(protected)/workorders/_hooks/use-work-orders-table-data.ts
index f56409f9..0b02f8a5 100644
--- a/src/app/(protected)/workorders/_hooks/use-work-orders-table-data.ts
+++ b/src/app/(protected)/workorders/_hooks/use-work-orders-table-data.ts
@@ -1,10 +1,15 @@
import { useMemo } from "react";
import type { useWorkOrdersListFilters } from "@/app/(protected)/workorders/_hooks/use-work-orders-list-filters";
import { useWorkOrdersBoardSource } from "@/app/(protected)/workorders/_hooks/use-work-orders-board-source";
+import { useWorkOrdersDayPagination } from "@/app/(protected)/workorders/_hooks/use-work-orders-day-pagination";
import { useWorkOrdersTableLocalState } from "@/app/(protected)/workorders/_hooks/use-work-orders-table-local-state";
import { currentWeekMonday } from "@/domain/work-orders/utils/list-week-utils";
import type { WorkOrderTableRow } from "@/domain/work-orders/types/work-order-table-row";
import { deriveDayFields } from "@/domain/work-orders/utils/table-day-utils";
+import {
+ pageSelectedDayGroups,
+ shouldShowDayPagination,
+} from "@/domain/work-orders/utils/day-pagination";
import {
buildSelectedDayGroup,
isDayScopedSearchEmpty,
@@ -51,7 +56,7 @@ export function useWorkOrdersTableData(filters: FiltersReturn) {
advActive,
isFetching,
});
- const { displayRows } = local;
+ const { displayRows, ...localUi } = local;
const advResults = useMemo(() => (advActive ? displayRows : []), [advActive, displayRows]);
@@ -85,16 +90,27 @@ export function useWorkOrdersTableData(filters: FiltersReturn) {
: [buildSelectedDayGroup(filters.weekMonday, filters.selectedDayIso, scheduled)],
[advActive, filters.selectedDayIso, filters.weekMonday, scheduled],
);
+ const pagination = useWorkOrdersDayPagination({
+ weekMonday: filters.weekMonday,
+ selectedDayIso: filters.selectedDayIso,
+ advActive,
+ dayItems: dayGroups[0]?.items ?? EMPTY_WEEKLY_ITEMS,
+ onRevealed: local.triggerFlash,
+ });
+ const pagedDay = useMemo(
+ () => pageSelectedDayGroups(dayGroups, pagination.page, pagination.pageSize),
+ [dayGroups, pagination.page, pagination.pageSize],
+ );
const searchActive = filters.search.trim() !== "";
- const displayGroups = dayGroups;
- const dayVisibleCount = displayGroups[0]?.items.length ?? 0;
+ const displayGroups = pagedDay.groups;
+ const dayTotalCount = pagedDay.totalCount;
const noSearchResults =
!advActive &&
isDayScopedSearchEmpty({
searchActive,
unassignedCount: unassigned.length,
- dayItemCount: dayVisibleCount,
+ dayItemCount: dayTotalCount,
unassignedQueueReady: isUnassignedQueueReady(unassignedLoading, unassignedError),
});
const isEmptyWeek =
@@ -127,30 +143,24 @@ export function useWorkOrdersTableData(filters: FiltersReturn) {
noSearchResults,
isEmptyWeek,
todayKey,
- draftDayKey: local.draftDayKey,
- draft: local.draft,
- setDraft: local.setDraft,
- unassignedOpen: local.unassignedOpen,
- setUnassignedOpen: local.setUnassignedOpen,
- unschedOpen: local.unschedOpen,
- setUnschedOpen: local.setUnschedOpen,
- selectedId: local.selectedId,
- setSelectedId: local.setSelectedId,
+ ...localUi,
selectedRow,
- flashId: local.flashId,
- triggerFlash: local.triggerFlash,
- dragViz: local.dragViz,
- setDragViz: local.setDragViz,
- dragState: local.dragState,
- patchRow: local.patchRow,
- clearRowPatch: local.clearRowPatch,
- reorderRows: local.reorderRows,
- endDrag: local.endDrag,
- startDayDraft: local.startDayDraft,
- cancelDraft: local.cancelDraft,
- addRow: local.addRow,
scopeTotalCount: data?.totalCount ?? 0,
- totalCount: advActive ? (data?.totalCount ?? advResults.length) : dayVisibleCount,
+ totalCount: advActive ? (data?.totalCount ?? advResults.length) : dayTotalCount,
search: filters.search,
+ showDayPagination: shouldShowDayPagination({
+ flatListMode: advActive,
+ isLoading,
+ noSearchResults,
+ }),
+ dayPageSize: pagination.pageSize,
+ dayPageIndex: pagedDay.pageIndex,
+ dayPageCount: pagedDay.pageCount,
+ dayItemCount: pagedDay.totalCount,
+ dayFooterLabel: displayGroups[0]?.label ?? "",
+ setDayPageSize: pagination.setPageSize,
+ goToPrevDayPage: pagination.goToPrevPage,
+ goToNextDayPage: pagination.goToNextPage,
+ revealScheduledRow: pagination.revealRow,
};
}
diff --git a/src/domain/work-orders/types/work-order-table-row.ts b/src/domain/work-orders/types/work-order-table-row.ts
index 4b066382..4594bb49 100644
--- a/src/domain/work-orders/types/work-order-table-row.ts
+++ b/src/domain/work-orders/types/work-order-table-row.ts
@@ -138,6 +138,7 @@ export type WorkOrderDayGroup = {
label: string;
date: string;
items: WorkOrderTableRow[];
+ totalCount?: number;
};
export type WorkOrderTablePatch = Partial;
diff --git a/src/domain/work-orders/utils/day-pagination.ts b/src/domain/work-orders/utils/day-pagination.ts
new file mode 100644
index 00000000..8caab266
--- /dev/null
+++ b/src/domain/work-orders/utils/day-pagination.ts
@@ -0,0 +1,80 @@
+import type { WorkOrderDayGroup } from "@/domain/work-orders/types/work-order-table-row";
+
+export const DAY_PAGE_SIZE_OPTIONS = [25, 50, 100, 200] as const;
+export const DEFAULT_DAY_PAGE_SIZE = 50;
+
+export type DayPageSize = (typeof DAY_PAGE_SIZE_OPTIONS)[number];
+
+export type PaginatedSlice = {
+ visible: T[];
+ pageCount: number;
+ pageIndex: number;
+};
+
+export function pageIndexForItem(itemIndex: number, pageSize: number): number {
+ if (itemIndex < 0) {
+ return 0;
+ }
+ const size = pageSize > 0 ? pageSize : DEFAULT_DAY_PAGE_SIZE;
+ return Math.floor(itemIndex / size);
+}
+
+export function findItemPageIndex(
+ items: readonly T[],
+ id: string | number,
+ pageSize: number,
+): number | null {
+ const index = items.findIndex((item) => String(item.id) === String(id));
+ if (index < 0) {
+ return null;
+ }
+ return pageIndexForItem(index, pageSize);
+}
+
+export function paginateItems(
+ items: readonly T[],
+ pageIndex: number,
+ pageSize: number,
+): PaginatedSlice {
+ const size = pageSize > 0 ? pageSize : DEFAULT_DAY_PAGE_SIZE;
+ const pageCount = Math.max(1, Math.ceil(items.length / size) || 1);
+ const page = Math.min(Math.max(0, pageIndex), pageCount - 1);
+ const start = page * size;
+ return {
+ visible: items.slice(start, start + size),
+ pageCount,
+ pageIndex: page,
+ };
+}
+
+export function shouldShowDayPagination(input: {
+ flatListMode: boolean;
+ isLoading: boolean;
+ noSearchResults: boolean;
+}): boolean {
+ return !input.flatListMode && !input.isLoading && !input.noSearchResults;
+}
+
+export function formatDayPaginationSummary(dayLabel: string, itemCount: number): string {
+ const label = dayLabel.trim().toUpperCase();
+ const noun = itemCount === 1 ? "item" : "items";
+ return `${label} · ${itemCount} ${noun}`;
+}
+
+export function pageSelectedDayGroups(
+ dayGroups: WorkOrderDayGroup[],
+ pageIndex: number,
+ pageSize: number,
+): { groups: WorkOrderDayGroup[]; pageIndex: number; pageCount: number; totalCount: number } {
+ const group = dayGroups[0];
+ if (!group) {
+ return { groups: dayGroups, pageIndex: 0, pageCount: 1, totalCount: 0 };
+ }
+ const slice = paginateItems(group.items, pageIndex, pageSize);
+ return {
+ groups: [{ ...group, items: slice.visible, totalCount: group.items.length }],
+ pageIndex: slice.pageIndex,
+ pageCount: slice.pageCount,
+ totalCount: group.items.length,
+ };
+}
diff --git a/src/test/app/(protected)/workorders/use-wo-table-row-handlers-duplicate.test.ts b/src/test/app/(protected)/workorders/use-wo-table-row-handlers-duplicate.test.ts
index e9b52a4a..daad10bd 100644
--- a/src/test/app/(protected)/workorders/use-wo-table-row-handlers-duplicate.test.ts
+++ b/src/test/app/(protected)/workorders/use-wo-table-row-handlers-duplicate.test.ts
@@ -13,6 +13,7 @@ function buildTableData() {
endDrag: vi.fn(),
setUnschedOpen: vi.fn(),
triggerFlash: vi.fn(),
+ revealScheduledRow: vi.fn(),
setSelectedId: vi.fn(),
} as never;
}
diff --git a/src/test/app/(protected)/workorders/use-wo-table-row-handlers-schedule.test.ts b/src/test/app/(protected)/workorders/use-wo-table-row-handlers-schedule.test.ts
index afbf434c..0f0ed39a 100644
--- a/src/test/app/(protected)/workorders/use-wo-table-row-handlers-schedule.test.ts
+++ b/src/test/app/(protected)/workorders/use-wo-table-row-handlers-schedule.test.ts
@@ -13,13 +13,13 @@ vi.mock("@/app/(protected)/workorders/_components/list/table/reschedule-notify",
weekMoveNotify,
}));
-function buildTableData(triggerFlash = vi.fn()) {
+function buildTableData(revealScheduledRow = vi.fn()) {
return {
dragState: { current: { dragId: null, overId: null } },
setDragViz: vi.fn(),
reorderRows: vi.fn(),
endDrag: vi.fn(),
- triggerFlash,
+ revealScheduledRow,
setSelectedId: vi.fn(),
} as never;
}
@@ -28,11 +28,11 @@ describe("useWoTableRowHandlers schedule navigation (SH-240)", () => {
it("selects the scheduled weekday in the same week so the row stays visible", () => {
const onNavigateToDay = vi.fn();
const onPatch = vi.fn();
- const triggerFlash = vi.fn();
+ const revealScheduledRow = vi.fn();
const { result } = renderHook(() =>
useWoTableRowHandlers({
- tableData: buildTableData(triggerFlash),
+ tableData: buildTableData(revealScheduledRow),
weekMonday: "2026-05-18",
onNavigateToDay,
onOpenSlideOver: vi.fn(),
@@ -46,16 +46,17 @@ describe("useWoTableRowHandlers schedule navigation (SH-240)", () => {
expect(onPatch).toHaveBeenCalledWith("wo-1", applySchedulePatch("2026-05-21", false));
expect(onNavigateToDay).toHaveBeenCalledWith("2026-05-21");
- expect(triggerFlash).toHaveBeenCalledWith("wo-1");
+ expect(revealScheduledRow).toHaveBeenCalledWith("wo-1");
expect(rescheduleNotify).not.toHaveBeenCalled();
});
it("sends cross-week view-it navigation to the target day, not Monday", () => {
const onNavigateToDay = vi.fn();
+ const revealScheduledRow = vi.fn();
const { result } = renderHook(() =>
useWoTableRowHandlers({
- tableData: buildTableData(),
+ tableData: buildTableData(revealScheduledRow),
weekMonday: "2026-05-18",
onNavigateToDay,
onOpenSlideOver: vi.fn(),
@@ -76,6 +77,7 @@ describe("useWoTableRowHandlers schedule navigation (SH-240)", () => {
const { onNavigate } = rescheduleNotify.mock.calls[0][1] as { onNavigate: () => void };
onNavigate();
expect(onNavigateToDay).toHaveBeenCalledWith("2026-05-27");
+ expect(revealScheduledRow).toHaveBeenCalledWith("wo-1");
});
it("opens Advanced Filters for week-only moves instead of the removed Unscheduled section", () => {
diff --git a/src/test/app/(protected)/workorders/use-work-orders-day-pagination.test.tsx b/src/test/app/(protected)/workorders/use-work-orders-day-pagination.test.tsx
new file mode 100644
index 00000000..01e98569
--- /dev/null
+++ b/src/test/app/(protected)/workorders/use-work-orders-day-pagination.test.tsx
@@ -0,0 +1,75 @@
+import { act, renderHook } from "@testing-library/react";
+import { describe, expect, it, vi } from "vitest";
+import { useWorkOrdersDayPagination } from "@/app/(protected)/workorders/_hooks/use-work-orders-day-pagination";
+import { DEFAULT_DAY_PAGE_SIZE } from "@/domain/work-orders/utils/day-pagination";
+
+describe("useWorkOrdersDayPagination (SH-241)", () => {
+ const onRevealed = vi.fn();
+ const base = {
+ weekMonday: "2026-08-17",
+ selectedDayIso: "2026-08-17",
+ advActive: false,
+ dayItems: [] as { id: string }[],
+ onRevealed,
+ };
+
+ it("defaults to 50 rows per page", () => {
+ const { result } = renderHook(() => useWorkOrdersDayPagination(base));
+ expect(result.current.pageSize).toBe(DEFAULT_DAY_PAGE_SIZE);
+ expect(result.current.page).toBe(0);
+ });
+
+ it("resets to page 1 when switching days", () => {
+ const { result, rerender } = renderHook(
+ (props: typeof base) => useWorkOrdersDayPagination(props),
+ { initialProps: base },
+ );
+ act(() => result.current.goToNextPage());
+ expect(result.current.page).toBe(1);
+ rerender({ ...base, selectedDayIso: "2026-08-18" });
+ expect(result.current.page).toBe(0);
+ });
+
+ it("resets to page 1 when the week changes", () => {
+ const { result, rerender } = renderHook(
+ (props: typeof base) => useWorkOrdersDayPagination(props),
+ { initialProps: base },
+ );
+ act(() => result.current.goToNextPage());
+ rerender({ ...base, weekMonday: "2026-08-10" });
+ expect(result.current.page).toBe(0);
+ });
+
+ it("resets to page 1 when rows-per-page changes", () => {
+ const { result } = renderHook(() => useWorkOrdersDayPagination(base));
+ act(() => result.current.goToNextPage());
+ act(() => result.current.setPageSize(25));
+ expect(result.current.page).toBe(0);
+ expect(result.current.pageSize).toBe(25);
+ });
+
+ it("resets to page 1 when a global filter is applied", () => {
+ const { result, rerender } = renderHook(
+ (props: typeof base) => useWorkOrdersDayPagination(props),
+ { initialProps: base },
+ );
+ act(() => result.current.goToNextPage());
+ rerender({ ...base, advActive: true });
+ expect(result.current.page).toBe(0);
+ });
+
+ it("selects the page that contains a revealed row beyond the first page", () => {
+ const dayItems = Array.from({ length: 60 }, (_, index) => ({ id: `wo-${index}` }));
+ const revealed = vi.fn();
+ const { result, rerender } = renderHook(
+ (props: typeof base) => useWorkOrdersDayPagination(props),
+ { initialProps: { ...base, onRevealed: revealed } },
+ );
+
+ act(() => result.current.revealRow("wo-55"));
+ rerender({ ...base, dayItems, onRevealed: revealed, selectedDayIso: "2026-08-18" });
+
+ expect(result.current.page).toBe(1);
+ expect(revealed).toHaveBeenCalledWith("wo-55");
+ });
+});
diff --git a/src/test/app/(protected)/workorders/wo-day-pagination-footer.test.tsx b/src/test/app/(protected)/workorders/wo-day-pagination-footer.test.tsx
new file mode 100644
index 00000000..37965136
--- /dev/null
+++ b/src/test/app/(protected)/workorders/wo-day-pagination-footer.test.tsx
@@ -0,0 +1,31 @@
+import { render, screen } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import { describe, expect, it, vi } from "vitest";
+import { WoDayPaginationFooter } from "@/app/(protected)/workorders/_components/list/table/wo-day-pagination-footer";
+
+describe("WoDayPaginationFooter (SH-241)", () => {
+ it("changes rows-per-page and navigates pages", async () => {
+ const user = userEvent.setup();
+ const onPageSizeChange = vi.fn();
+ const onNext = vi.fn();
+ render(
+ ,
+ );
+ expect(screen.getByText("MON · 06/01 · 60 items")).toBeInTheDocument();
+ expect(screen.getByText("Page 1 of 2")).toBeInTheDocument();
+ expect(screen.getByRole("button", { name: "Previous page" })).toBeDisabled();
+ await user.selectOptions(screen.getByLabelText("Rows per page"), "25");
+ expect(onPageSizeChange).toHaveBeenCalledWith(25);
+ await user.click(screen.getByRole("button", { name: "Next page" }));
+ expect(onNext).toHaveBeenCalled();
+ });
+});
diff --git a/src/test/app/(protected)/workorders/wo-table-search-empty.test.tsx b/src/test/app/(protected)/workorders/wo-table-search-empty.test.tsx
index 410f0c8d..db7e5685 100644
--- a/src/test/app/(protected)/workorders/wo-table-search-empty.test.tsx
+++ b/src/test/app/(protected)/workorders/wo-table-search-empty.test.tsx
@@ -43,6 +43,7 @@ function tableData(
selectedRow: null,
flashId: null,
triggerFlash: vi.fn(),
+ revealScheduledRow: vi.fn(),
dragViz: null,
setDragViz: vi.fn(),
dragState: { current: { dragId: null, overId: null } },
@@ -56,6 +57,15 @@ function tableData(
scopeTotalCount: 0,
totalCount: 0,
search: "no-match",
+ showDayPagination: false,
+ dayPageSize: 50,
+ dayPageIndex: 0,
+ dayPageCount: 1,
+ dayItemCount: 0,
+ dayFooterLabel: "Mon · 05/18",
+ setDayPageSize: vi.fn(),
+ goToPrevDayPage: vi.fn(),
+ goToNextDayPage: vi.fn(),
...overrides,
} as ReturnTypeOfUseWorkOrdersTableData;
}
@@ -79,7 +89,7 @@ function renderTable(data: ReturnTypeOfUseWorkOrdersTableData) {
);
}
-describe("WoTable search empty vs Unassigned queue (SH-165/SH-240)", () => {
+describe("WoTable search empty vs Unassigned queue (SH-165/SH-241)", () => {
it("shows empty search only after the Unassigned queue has settled empty", () => {
const { getByText, queryByText } = renderTable(tableData());
diff --git a/src/test/domain/work-orders/utils/day-pagination.test.ts b/src/test/domain/work-orders/utils/day-pagination.test.ts
new file mode 100644
index 00000000..0a71ba3c
--- /dev/null
+++ b/src/test/domain/work-orders/utils/day-pagination.test.ts
@@ -0,0 +1,84 @@
+import { describe, expect, it } from "vitest";
+import {
+ DAY_PAGE_SIZE_OPTIONS,
+ DEFAULT_DAY_PAGE_SIZE,
+ findItemPageIndex,
+ formatDayPaginationSummary,
+ pageIndexForItem,
+ paginateItems,
+ shouldShowDayPagination,
+} from "@/domain/work-orders/utils/day-pagination";
+
+describe("day pagination utils (SH-241)", () => {
+ it("defaults to 50 and exposes 25/50/100/200", () => {
+ expect(DEFAULT_DAY_PAGE_SIZE).toBe(50);
+ expect(DAY_PAGE_SIZE_OPTIONS).toEqual([25, 50, 100, 200]);
+ });
+
+ it("paginates 60 items at 50 per page", () => {
+ const items = Array.from({ length: 60 }, (_, index) => index);
+ const first = paginateItems(items, 0, 50);
+ expect(first.visible).toHaveLength(50);
+ expect(first.pageCount).toBe(2);
+ const second = paginateItems(items, 1, 50);
+ expect(second.visible).toEqual(items.slice(50));
+ });
+
+ it("re-paginates immediately when page size changes", () => {
+ const items = Array.from({ length: 60 }, (_, index) => index);
+ expect(paginateItems(items, 0, 25).visible).toHaveLength(25);
+ expect(paginateItems(items, 0, 25).pageCount).toBe(3);
+ });
+
+ it("clamps an out-of-range page to the last page", () => {
+ const paged = paginateItems([1, 2, 3], 9, 2);
+ expect(paged.pageIndex).toBe(1);
+ expect(paged.visible).toEqual([3]);
+ });
+
+ it("shows pagination in day view even when the page is not full", () => {
+ expect(
+ shouldShowDayPagination({
+ flatListMode: false,
+ isLoading: false,
+ noSearchResults: false,
+ }),
+ ).toBe(true);
+ });
+
+ it("hides pagination in flat-list / loading / empty search", () => {
+ expect(
+ shouldShowDayPagination({
+ flatListMode: true,
+ isLoading: false,
+ noSearchResults: false,
+ }),
+ ).toBe(false);
+ expect(
+ shouldShowDayPagination({
+ flatListMode: false,
+ isLoading: true,
+ noSearchResults: false,
+ }),
+ ).toBe(false);
+ expect(
+ shouldShowDayPagination({
+ flatListMode: false,
+ isLoading: false,
+ noSearchResults: true,
+ }),
+ ).toBe(false);
+ });
+
+ it("maps a row past the first page onto page 2 at the default size", () => {
+ const items = Array.from({ length: 60 }, (_, index) => ({ id: `wo-${index}` }));
+ expect(pageIndexForItem(50, 50)).toBe(1);
+ expect(findItemPageIndex(items, "wo-55", 50)).toBe(1);
+ expect(findItemPageIndex(items, "missing", 50)).toBeNull();
+ });
+
+ it("formats the AAP footer summary", () => {
+ expect(formatDayPaginationSummary("Mon · 06/01", 9)).toBe("MON · 06/01 · 9 items");
+ expect(formatDayPaginationSummary("Tue · 06/02", 1)).toBe("TUE · 06/02 · 1 item");
+ });
+});