enhance booking windows section with pagination and improved UI

This commit is contained in:
Marshal
2026-07-04 00:41:28 +00:00
parent 61f70d5471
commit 97cc9d76b1
21 changed files with 805 additions and 285 deletions

View File

@@ -54,6 +54,7 @@ import type {
LocomotiveRecord,
PinWagonsPayload,
RecordCheckpointPayload,
StaffBookingWindow,
TrainScheduleDetail,
TrainScheduleFilters,
TrainScheduleListItem,
@@ -223,6 +224,13 @@ export const api = {
() => QUERY_KEYS.TRAIN_SCHEDULING.batchBoard(),
),
allBookingWindows: endpoint<void, StaffBookingWindow[]>(
"train-scheduling",
"all-booking-windows",
() => trainSchedulingService.getAllBookingWindows(),
() => ["train-scheduling", "all-booking-windows"],
),
batchBoardDetail: endpoint<
{ scheduleId: string },
BatchBoardScheduleDetail

View File

@@ -27,6 +27,39 @@ export interface PaginatedContracts {
total: number;
}
/** One line of the server-priced booking breakdown (mirrors PriceLineItemDto). */
export interface ShipmentPriceLine {
code: string;
description: string;
amount: number;
unitAmount: number;
/** Rate unit as stored: PER_CONTAINER | PER_WAGON | PER_TON | PER_KM | FLAT | … */
unit: string;
quantity: number;
currency: string;
}
/**
* Pre-create validation + authoritative price preview for a booking under a
* contract. `lineItems`/`totalAmount` are the full server-computed breakdown —
* the same pricing pass the booking persists at create (rail freight,
* first/last mile, overweight and every other surcharge). `pairingErrors` are
* HARD BLOCKS; `overweightLines` are warnings.
*/
export interface ShipmentValidation {
overweightLines: Array<{
containerTypeCode: string;
totalVgmTons: number;
maxAllowedTons: number;
excessTons: number;
}>;
overweightSurchargeAmount: number;
currency: string | null;
pairingErrors: string[];
lineItems?: ShipmentPriceLine[];
totalAmount?: number;
}
export interface ContractListSummaryMetrics {
inQueue: number;
needsAction: number;
@@ -471,6 +504,18 @@ export const contractsService = {
payload: Freight.CreateBookingUnderContractDto,
) => postContract<{ id: string; reference: string }>(C.BOOKINGS(id), payload),
/**
* Pre-create validation + authoritative price preview: the same
* BookingPricingService pass that prices the booking on create (rail +
* first/last mile + every surcharge), plus overweight warnings and 20ft
* pairing hard-blocks. Shown in the GL price-confirm modal.
*/
validateShipment: (
id: string,
payload: Freight.CreateBookingUnderContractDto,
) =>
postContract<ShipmentValidation>(C.VALIDATE_SHIPMENT(id), payload),
/** Remaining bookable quantity per cargo line (GENERAL draw-down cap). */
getCapacity: async (id: string): Promise<Freight.ContractCapacityLine[]> => {
const response = await client.get(C.CAPACITY(id));

View File

@@ -21,6 +21,7 @@ import type {
LocomotiveRecord,
PinWagonsPayload,
RecordCheckpointPayload,
StaffBookingWindow,
TrainScheduleDetail,
TrainScheduleFilters,
TrainScheduleListItem,
@@ -543,6 +544,13 @@ export const trainSchedulingService = {
return unwrap(response.data);
},
getAllBookingWindows: async (): Promise<StaffBookingWindow[]> => {
const response = await client.get<StaffBookingWindow[]>(
URL_CONSTANTS.TRAIN_SCHEDULING.BOOKING_WINDOWS,
);
return unwrap(response.data);
},
updateGlobalRules: async (
payload: Partial<Omit<TrainSchedulingGlobalRules, "id">>,
): Promise<TrainSchedulingGlobalRules> => {