Add canViewFlightStatus visibility logic

This commit is contained in:
2026-04-17 01:22:56 +03:00
parent 9234dcd2e1
commit 51bc2f6acc
2 changed files with 105 additions and 0 deletions
@@ -0,0 +1,73 @@
import { describe, it, expect } from "vitest";
import { canViewFlightStatus } from "./flightStatusVisibility.js";
import { AIRLINES_WITH_STATUS } from "../airlines.js";
import type { ISimpleFlight } from "../../../types.js";
function makeFlight(carrier: string, depUtc: string): ISimpleFlight {
return {
id: "X-1",
routeType: "Direct",
flyingTime: "1h",
status: "Scheduled",
flightId: { carrier, flightNumber: "0022", suffix: "", date: "20260417" },
operatingBy: { carrier, flightNumber: "0022" },
leg: {
arrival: {
scheduled: { airport: "", airportCode: "", city: "", cityCode: "", countryCode: "" },
latest: { airport: "", airportCode: "", city: "", cityCode: "", countryCode: "" },
dispatch: "", gate: "", terminal: "",
times: { scheduledArrival: { dayChange: { value: 0, title: "" }, local: "", localTime: "", tzOffset: 0, utc: "" } },
},
dayChange: 0,
departure: {
scheduled: { airport: "", airportCode: "", city: "", cityCode: "", countryCode: "" },
latest: { airport: "", airportCode: "", city: "", cityCode: "", countryCode: "" },
dispatch: "", gate: "", terminal: "", checkingStatus: "Scheduled", parkingStand: "",
times: { scheduledDeparture: { dayChange: { value: 0, title: "" }, local: "", localTime: "", tzOffset: 0, utc: depUtc } },
},
equipment: {},
flags: { checkinAvailable: false, returnToAirport: false, routeChanged: false },
flyingTime: "1h",
index: 0,
operatingBy: {},
status: "Scheduled",
updated: "",
},
} as ISimpleFlight;
}
describe("canViewFlightStatus", () => {
it("returns false for carrier not in AIRLINES_WITH_STATUS", () => {
const now = new Date("2026-04-17T10:00:00Z");
expect(
canViewFlightStatus(makeFlight("AF", "2026-04-17T12:00:00Z"), now, 24, AIRLINES_WITH_STATUS),
).toBe(false);
});
it("returns false when departure is not same day as now (UTC)", () => {
const now = new Date("2026-04-17T23:59:59Z");
expect(
canViewFlightStatus(makeFlight("SU", "2026-04-18T00:30:00Z"), now, 24, AIRLINES_WITH_STATUS),
).toBe(false);
});
it("returns true when SU same-day and within availableFromHours before departure", () => {
const now = new Date("2026-04-17T08:00:00Z");
expect(
canViewFlightStatus(makeFlight("SU", "2026-04-17T10:00:00Z"), now, 24, AIRLINES_WITH_STATUS),
).toBe(true);
});
it("returns false when now is before availableFrom window", () => {
const now = new Date("2026-04-17T00:00:00Z");
// Departure 23:00 same day, availableFromHours=1 → available only from 22:00
expect(
canViewFlightStatus(makeFlight("SU", "2026-04-17T23:00:00Z"), now, 1, AIRLINES_WITH_STATUS),
).toBe(false);
});
it("returns false when departure UTC is empty", () => {
const now = new Date();
expect(canViewFlightStatus(makeFlight("SU", ""), now, 24, AIRLINES_WITH_STATUS)).toBe(false);
});
});
@@ -0,0 +1,32 @@
import { parseISO, subHours, isAfter, isSameDay } from "date-fns";
import type { ISimpleFlight } from "../../../types.js";
/**
* Flight Status button is visible when:
* - the operating carrier is in airlinesWithStatus
* - departure is same-day as now
* - now is within `availableFromHours` before departure
*/
export function canViewFlightStatus(
flight: ISimpleFlight,
now: Date,
availableFromHours: number,
airlinesWithStatus: Set<string>,
): boolean {
const carrier = flight.operatingBy.carrier;
if (!carrier || !airlinesWithStatus.has(carrier)) return false;
const leg = flight.routeType === "Direct" ? flight.leg : flight.legs[0];
if (!leg) return false;
const depUtc = leg.departure.times.scheduledDeparture.utc;
if (!depUtc) return false;
const departure = parseISO(depUtc);
if (isNaN(departure.getTime())) return false;
if (!isSameDay(now, departure)) return false;
const availableFrom = subHours(departure, availableFromHours);
return isAfter(now, availableFrom);
}