mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-10-02 02:43:12 +00:00
172 lines
4.6 KiB
TypeScript
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,
|
|
};
|
|
}
|