import { ASSIGNEE_FILTER_UNASSIGNED } from "@/domain/work-orders/types/work-order-list"; import type { WorkOrderAdvancedFilters } from "@/domain/work-orders/types/work-order-advanced-filters"; import type { WorkOrderBarFilters } from "@/domain/work-orders/types/work-order-list-filters"; import { BOARD_DISPATCHER_UNASSIGNED, DATE_RANGE_TO_PRESET, DOC_STATUS_API, LIFECYCLE_STATUS_API, type WorkOrderBoardQueryParams, type WorkOrderBoardSearchQueryParams, } from "@/domain/work-orders/types/work-order-board"; import { mapWizardTypeToApi } from "@/domain/work-orders/mappers/work-order-board-mapper"; import { weekRange } from "@/domain/work-orders/utils/list-week-utils"; import type { CompletionDocFilter } from "@/domain/work-orders/types/work-order-advanced-filters"; import type { WizardWOStatus, WOType } from "@/domain/work-orders/types/work-order-wizard"; export const BOARD_SEARCH_MAX_PAGE_SIZE = 100; function toBoardDispatcherId(id: string): string { if (id === ASSIGNEE_FILTER_UNASSIGNED || id === BOARD_DISPATCHER_UNASSIGNED) { return BOARD_DISPATCHER_UNASSIGNED; } return id; } function mapDispatchers(ids: Iterable): string[] | undefined { const list = [...ids].map(toBoardDispatcherId); return list.length > 0 ? list : undefined; } /** Maps UI type filters to API `types` + separate `overdue` flag. Overdue is never sent as types=99. */ function mapWoTypeFilters(types: Iterable): { types?: number[]; overdue?: boolean; } { const list: number[] = []; let overdue = false; for (const type of types) { if (type === "All") { continue; } if (type === "Overdue") { overdue = true; continue; } const api = mapWizardTypeToApi(type as WOType); if (api != null) { list.push(api); } } return { types: list.length > 0 ? list : undefined, overdue: overdue || undefined, }; } function mapStatuses(statuses: Iterable): number[] | undefined { const list: number[] = []; for (const status of statuses) { const value = LIFECYCLE_STATUS_API[status as WizardWOStatus]; if (typeof value === "number") { list.push(value); } else if (status === "Canceled" || status === "Cancelled") { list.push(LIFECYCLE_STATUS_API.Canceled); } } return list.length > 0 ? list : undefined; } function mapDocStatuses(docs: Iterable): number[] | undefined { const list: number[] = []; for (const doc of docs) { if (doc === "Yes") list.push(DOC_STATUS_API.Yes); else if (doc === "No") list.push(DOC_STATUS_API.No); else if (doc === "NN") list.push(DOC_STATUS_API.NotNeeded); } return list.length > 0 ? list : undefined; } /** Build GET /board query from weekly filter bar. */ export function toBoardQueryParams( bar: WorkOrderBarFilters, search: string, ): WorkOrderBoardQueryParams { const [, weekTo] = weekRange(bar.weekMonday); const typeFilters = bar.type !== "All" ? mapWoTypeFilters([bar.type]) : {}; return { weekStart: bar.weekMonday, weekEnd: weekTo, dispatchers: mapDispatchers(bar.dispatcherIds), types: typeFilters.types, overdue: typeFilters.overdue, search: search.trim().length >= 2 ? search.trim() : undefined, }; } /** Build GET /board/search query from advanced filters (+ optional bar/search). */ export function toBoardSearchQueryParams(input: { filters: WorkOrderAdvancedFilters; search?: string; page?: number; pageSize?: number; sortBy?: string; sortDir?: string; /** Optional company-name → vendorId resolution. */ vendorIdsByCompanyName?: Map; }): WorkOrderBoardSearchQueryParams { const { filters } = input; const datePreset = DATE_RANGE_TO_PRESET[filters.dateRange]; const pageSize = Math.min( input.pageSize ?? BOARD_SEARCH_MAX_PAGE_SIZE, BOARD_SEARCH_MAX_PAGE_SIZE, ); const vendorIds: number[] = []; if (input.vendorIdsByCompanyName && filters.vendorTechs.size > 0) { for (const name of filters.vendorTechs) { const id = input.vendorIdsByCompanyName.get(name); if (typeof id === "number") { vendorIds.push(id); } } } const typeFilters = mapWoTypeFilters(filters.types); const params: WorkOrderBoardSearchQueryParams = { page: input.page ?? 0, pageSize, search: input.search?.trim() && input.search.trim().length >= 2 ? input.search.trim() : undefined, datePreset, sites: filters.sites.size > 0 ? [...filters.sites] : undefined, types: typeFilters.types, overdue: typeFilters.overdue, dispatchers: mapDispatchers(filters.dispatchers), statuses: mapStatuses(filters.statuses), pmTypes: filters.pmTypes.size > 0 ? [...filters.pmTypes] : undefined, vendorIds: vendorIds.length > 0 ? vendorIds : undefined, docStatuses: mapDocStatuses(filters.docs), sortBy: input.sortBy || "scheduledDate", sortDir: input.sortDir === "desc" ? "desc" : "asc", }; if (datePreset === "Custom") { params.dateFrom = filters.customFrom || undefined; params.dateTo = filters.customTo || undefined; } return params; } /** ky/URLSearchParams-friendly object; arrays become repeated keys. */ export function buildBoardSearchParamsRecord( params: WorkOrderBoardQueryParams | WorkOrderBoardSearchQueryParams, ): Record { const out: Record = {}; for (const [key, value] of Object.entries(params)) { if (value === undefined || value === null || value === "") { continue; } if (Array.isArray(value)) { if (value.length === 0) continue; out[key] = value; continue; } out[key] = value as string | number | boolean; } return out; } export function woTypeFilterIsOverdue(type: string): boolean { return type === "Overdue"; }