mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-07 16:35:42 +00:00
89 lines
2.7 KiB
TypeScript
89 lines
2.7 KiB
TypeScript
/**
|
|
* Shared helpers for the staff shipment-day / export-train pickers (the
|
|
* operation reschedule modal and the GL "returned for changes" resubmit).
|
|
*/
|
|
|
|
export const EAT_TIMEZONE = "Africa/Addis_Ababa";
|
|
|
|
/** YYYY-MM-DD of an instant in East Africa Time — the booking day key. */
|
|
export function eatDay(value: string | Date): string {
|
|
const date = typeof value === "string" ? new Date(value) : value;
|
|
return new Intl.DateTimeFormat("en-CA", {
|
|
timeZone: EAT_TIMEZONE,
|
|
year: "numeric",
|
|
month: "2-digit",
|
|
day: "2-digit",
|
|
}).format(date);
|
|
}
|
|
|
|
/** "Mon, 07 Sep, 09:00" in EAT; "—" for a missing or invalid value. */
|
|
export function formatEat(value: string | Date | null | undefined): string {
|
|
if (!value) return "—";
|
|
const date = typeof value === "string" ? new Date(value) : value;
|
|
if (Number.isNaN(date.getTime())) return "—";
|
|
return new Intl.DateTimeFormat("en-GB", {
|
|
timeZone: EAT_TIMEZONE,
|
|
weekday: "short",
|
|
day: "2-digit",
|
|
month: "short",
|
|
hour: "2-digit",
|
|
minute: "2-digit",
|
|
}).format(date);
|
|
}
|
|
|
|
/** "Wed, 09 Sep 2026" for a YYYY-MM-DD EAT day key. */
|
|
export function formatEatDay(dayKey: string): string {
|
|
const date = new Date(`${dayKey}T12:00:00.000Z`);
|
|
if (Number.isNaN(date.getTime())) return dayKey;
|
|
return new Intl.DateTimeFormat("en-GB", {
|
|
timeZone: EAT_TIMEZONE,
|
|
weekday: "short",
|
|
day: "2-digit",
|
|
month: "short",
|
|
year: "numeric",
|
|
}).format(date);
|
|
}
|
|
|
|
/** Mirrors the API road-service rule: ServiceType.code ROAD, TRUCK, ROAD_*, TRUCK_* */
|
|
export function isRoadServiceCode(code: string | null | undefined): boolean {
|
|
const c = (code ?? "").toUpperCase();
|
|
return (
|
|
c === "ROAD" ||
|
|
c === "TRUCK" ||
|
|
c.startsWith("ROAD_") ||
|
|
c.startsWith("TRUCK_")
|
|
);
|
|
}
|
|
|
|
/** Export rail bookings are the only ones that carry a train pick. */
|
|
export function isExportRailBooking(booking: {
|
|
tradeDirection?: string | null;
|
|
serviceType?: { code?: string | null } | null;
|
|
}): boolean {
|
|
return (
|
|
booking.tradeDirection === "EXPORT" &&
|
|
!isRoadServiceCode(booking.serviceType?.code)
|
|
);
|
|
}
|
|
|
|
/** Select option for one export train; closed or too-small trains are disabled. */
|
|
export function exportTrainOption(t: {
|
|
scheduleId: string;
|
|
trainNumber: string | null;
|
|
trainName: string | null;
|
|
departure: string;
|
|
isOpen: boolean;
|
|
fits: boolean;
|
|
freeWagons: number;
|
|
neededWagons: number;
|
|
}): { value: string; label: string; disabled: boolean } {
|
|
return {
|
|
value: t.scheduleId,
|
|
label:
|
|
`${t.trainNumber ?? t.trainName ?? "Train"} · departs ${formatEat(t.departure)} · ` +
|
|
`${t.freeWagons} free / needs ${t.neededWagons}` +
|
|
(!t.isOpen ? " · closed" : !t.fits ? " · no room" : ""),
|
|
disabled: !t.isOpen || !t.fits,
|
|
};
|
|
}
|