112 lines
3.7 KiB
TypeScript
112 lines
3.7 KiB
TypeScript
/**
|
|
* Session-scoped store for cross-section filter state (TZ §4.1.8 Table 10).
|
|
* In-memory only — cleared on page reload. Projection functions implement
|
|
* the exact field mappings from Table 10 when a user navigates between
|
|
* Online-Board ↔ Schedule. Map filter is stored separately and is NEVER
|
|
* projected from / to Board or Schedule (per TZ §4.1.1 ¶12).
|
|
*/
|
|
|
|
export interface BoardFilterSnapshot {
|
|
mode: "route" | "flight-number" | "departure" | "arrival";
|
|
departure?: string;
|
|
arrival?: string;
|
|
flightNumber?: string;
|
|
date: string; // yyyyMMdd
|
|
timeFrom: string; // HHmm
|
|
timeTo: string; // HHmm
|
|
searchExecuted: boolean;
|
|
}
|
|
|
|
export interface ScheduleFilterSnapshot {
|
|
mode: "route";
|
|
departure?: string;
|
|
arrival?: string;
|
|
dateFrom: string; // yyyyMMdd
|
|
dateTo: string;
|
|
timeFrom: string;
|
|
timeTo: string;
|
|
onlyDirect: boolean;
|
|
showReturn: boolean;
|
|
returnDateFrom?: string;
|
|
returnDateTo?: string;
|
|
returnTimeFrom?: string;
|
|
returnTimeTo?: string;
|
|
searchExecuted: boolean;
|
|
}
|
|
|
|
export interface MapFilterSnapshot {
|
|
departure: string | null;
|
|
arrival: string | null;
|
|
date: string | null;
|
|
showInternal: boolean;
|
|
showInternational: boolean;
|
|
showTransfers: boolean;
|
|
}
|
|
|
|
// Module-level in-memory state
|
|
let board: BoardFilterSnapshot | null = null;
|
|
let schedule: ScheduleFilterSnapshot | null = null;
|
|
let map: MapFilterSnapshot | null = null;
|
|
|
|
export function setBoardFilter(s: BoardFilterSnapshot): void { board = s; }
|
|
export function getBoardFilter(): BoardFilterSnapshot | null { return board; }
|
|
export function setScheduleFilter(s: ScheduleFilterSnapshot): void { schedule = s; }
|
|
export function getScheduleFilter(): ScheduleFilterSnapshot | null { return schedule; }
|
|
export function setMapFilter(s: MapFilterSnapshot): void { map = s; }
|
|
export function getMapFilter(): MapFilterSnapshot | null { return map; }
|
|
|
|
export function resetCrossSectionStore(): void {
|
|
board = null; schedule = null; map = null;
|
|
}
|
|
|
|
function currentWeekBounds(base: Date): { start: string; end: string } {
|
|
const d = new Date(base);
|
|
d.setHours(0, 0, 0, 0);
|
|
const dow = (d.getDay() + 6) % 7; // 0 = Mon .. 6 = Sun
|
|
d.setDate(d.getDate() - dow);
|
|
const start = new Date(d);
|
|
const end = new Date(d);
|
|
end.setDate(end.getDate() + 6);
|
|
const y = (x: Date) =>
|
|
`${x.getFullYear()}${String(x.getMonth() + 1).padStart(2, "0")}${String(x.getDate()).padStart(2, "0")}`;
|
|
return { start: y(start), end: y(end) };
|
|
}
|
|
|
|
function todayYyyymmdd(): string {
|
|
const d = new Date();
|
|
return `${d.getFullYear()}${String(d.getMonth() + 1).padStart(2, "0")}${String(d.getDate()).padStart(2, "0")}`;
|
|
}
|
|
|
|
/** TZ Table 10: Board → Schedule projection. Preserves cities + dateFrom=current-week. */
|
|
export function projectBoardToSchedule(b: BoardFilterSnapshot): ScheduleFilterSnapshot {
|
|
const base = b.date && /^\d{8}$/.test(b.date)
|
|
? new Date(Number(b.date.slice(0, 4)), Number(b.date.slice(4, 6)) - 1, Number(b.date.slice(6, 8)))
|
|
: new Date();
|
|
const week = currentWeekBounds(base);
|
|
return {
|
|
mode: "route",
|
|
...(b.departure ? { departure: b.departure } : {}),
|
|
...(b.arrival ? { arrival: b.arrival } : {}),
|
|
dateFrom: week.start,
|
|
dateTo: week.end,
|
|
timeFrom: "0000",
|
|
timeTo: "2400",
|
|
onlyDirect: false,
|
|
showReturn: false,
|
|
searchExecuted: false,
|
|
};
|
|
}
|
|
|
|
/** TZ Table 10: Schedule → Board projection. Preserves cities + date=today. */
|
|
export function projectScheduleToBoard(s: ScheduleFilterSnapshot): BoardFilterSnapshot {
|
|
return {
|
|
mode: "route",
|
|
...(s.departure ? { departure: s.departure } : {}),
|
|
...(s.arrival ? { arrival: s.arrival } : {}),
|
|
date: todayYyyymmdd(),
|
|
timeFrom: "0000",
|
|
timeTo: "2400",
|
|
searchExecuted: false,
|
|
};
|
|
}
|