shoc-frontend-new/src/domain/work-orders/utils/day-pagination.ts

172 lines
4.6 KiB
TypeScript

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<T> = {
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<T extends { id: string | number }>(
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 totalPageCount(totalCount: number, pageSize: number): number {
const size = pageSize > 0 ? pageSize : DEFAULT_DAY_PAGE_SIZE;
return Math.max(1, Math.ceil(Math.max(0, totalCount) / size) || 1);
}
export function asDayPageSize(value: number): DayPageSize {
return (DAY_PAGE_SIZE_OPTIONS as readonly number[]).includes(value)
? (value as DayPageSize)
: DEFAULT_DAY_PAGE_SIZE;
}
export function paginateItems<T>(
items: readonly T[],
pageIndex: number,
pageSize: number,
): PaginatedSlice<T> {
const size = pageSize > 0 ? pageSize : DEFAULT_DAY_PAGE_SIZE;
const pageCount = totalPageCount(items.length, size);
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 const SEARCH_PAGER_FOOTER_LABEL = "Results";
export function shouldShowDayPagination(input: {
flatListMode: boolean;
isLoading: boolean;
noSearchResults: boolean;
}): boolean {
return !input.flatListMode && !input.isLoading && !input.noSearchResults;
}
export function shouldShowSearchPagination(input: {
isLoading: boolean;
hasResults: boolean;
}): boolean {
return !input.isLoading && input.hasResults;
}
export function resolveSearchPager(input: { page: number; pageSize: number; totalCount: number }): {
pageSize: DayPageSize;
pageIndex: number;
pageCount: number;
itemCount: number;
} {
const pageSize = asDayPageSize(input.pageSize);
const pageCount = totalPageCount(input.totalCount, pageSize);
return {
pageSize,
pageIndex: Math.min(Math.max(0, input.page), pageCount - 1),
pageCount,
itemCount: input.totalCount,
};
}
export function nextSearchPageIfOutOfRange(input: {
page: number;
pageSize: number;
totalCount: number;
}): number | null {
if (input.totalCount <= 0) {
return null;
}
const pageCount = totalPageCount(input.totalCount, asDayPageSize(input.pageSize));
if (input.page < pageCount) {
return null;
}
return pageCount - 1;
}
export function pickBoardPager(input: {
advActive: boolean;
isLoading: boolean;
noSearchResults: boolean;
advResultCount: number;
search: { page: number; pageSize: number; totalCount: number };
day: {
pageSize: DayPageSize;
pageIndex: number;
pageCount: number;
itemCount: number;
footerLabel: string;
};
}): {
show: boolean;
pageSize: DayPageSize;
pageIndex: number;
pageCount: number;
itemCount: number;
footerLabel: string;
} {
if (input.advActive) {
return {
show: shouldShowSearchPagination({
isLoading: input.isLoading,
hasResults: input.search.totalCount > 0,
}),
...resolveSearchPager(input.search),
footerLabel: SEARCH_PAGER_FOOTER_LABEL,
};
}
return {
show: shouldShowDayPagination({
flatListMode: false,
isLoading: input.isLoading,
noSearchResults: input.noSearchResults,
}),
...input.day,
};
}
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,
};
}