From 6bd17b047f37598b21deffa1274a0137bee0e6a4 Mon Sep 17 00:00:00 2001 From: gnezim Date: Thu, 16 Apr 2026 22:23:29 +0300 Subject: [PATCH] Add shared helpers and DETAILS i18n keys for flight details panels --- .../components/details-panels/shared.test.ts | 82 +++++++++++++++++++ .../components/details-panels/shared.ts | 68 +++++++++++++++ src/i18n/locales/en/common.json | 23 ++++++ src/i18n/locales/ru/common.json | 23 ++++++ 4 files changed, 196 insertions(+) create mode 100644 src/features/online-board/components/details-panels/shared.test.ts create mode 100644 src/features/online-board/components/details-panels/shared.ts diff --git a/src/features/online-board/components/details-panels/shared.test.ts b/src/features/online-board/components/details-panels/shared.test.ts new file mode 100644 index 00000000..32104ed6 --- /dev/null +++ b/src/features/online-board/components/details-panels/shared.test.ts @@ -0,0 +1,82 @@ +import { describe, it, expect } from "vitest"; +import { + shouldShowTransition, + shouldShowAircraft, + SERVICE_ICON_MAP, + MEAL_LINKS, +} from "./shared.js"; +import type { IFlightTransitionItem } from "../../types.js"; + +describe("shouldShowTransition", () => { + const validItem: IFlightTransitionItem = { + start: {} as never, + end: {} as never, + status: "InProgress", + isActual: true, + }; + + it("returns false for Schedule viewType", () => { + expect(shouldShowTransition(validItem, "Scheduled", "Schedule")).toBe(false); + }); + + it("returns false when leg is Cancelled", () => { + expect(shouldShowTransition(validItem, "Cancelled", "Onlineboard")).toBe(false); + }); + + it("returns false when item is undefined", () => { + expect(shouldShowTransition(undefined, "Scheduled", "Onlineboard")).toBe(false); + }); + + it("returns false when item.status is Scheduled", () => { + const scheduled = { ...validItem, status: "Scheduled" as const }; + expect(shouldShowTransition(scheduled, "Scheduled", "Onlineboard")).toBe(false); + }); + + it("returns true for active transition on Onlineboard", () => { + expect(shouldShowTransition(validItem, "Scheduled", "Onlineboard")).toBe(true); + }); +}); + +describe("shouldShowAircraft", () => { + it("returns true when actual.title exists", () => { + expect(shouldShowAircraft({ aircraft: { actual: { title: "A320" } } })).toBe(true); + }); + + it("returns true when scheduled.title exists", () => { + expect(shouldShowAircraft({ aircraft: { scheduled: { title: "A320" } } })).toBe(true); + }); + + it("returns true when configuration exists", () => { + expect(shouldShowAircraft({ aircraft: { configuration: "C12Y138" } })).toBe(true); + }); + + it("returns false when no aircraft info", () => { + expect(shouldShowAircraft({})).toBe(false); + expect(shouldShowAircraft({ aircraft: {} })).toBe(false); + }); + + it("returns false when titles are empty strings", () => { + expect(shouldShowAircraft({ aircraft: { actual: { title: "" }, scheduled: { title: "" } } })).toBe(false); + }); +}); + +describe("SERVICE_ICON_MAP", () => { + it("maps all 8 service IDs", () => { + expect(SERVICE_ICON_MAP[1]).toBe("shopping"); + expect(SERVICE_ICON_MAP[2]).toBe("space"); + expect(SERVICE_ICON_MAP[3]).toBe("taxi"); + expect(SERVICE_ICON_MAP[4]).toBe("wifi"); + expect(SERVICE_ICON_MAP[5]).toBe("gsm"); + expect(SERVICE_ICON_MAP[6]).toBe("entertaintment"); + expect(SERVICE_ICON_MAP[7]).toBe("entertaintment"); + expect(SERVICE_ICON_MAP[8]).toBe("seat_reservation"); + }); +}); + +describe("MEAL_LINKS", () => { + it("has links for Economy, Comfort, Business", () => { + expect(MEAL_LINKS.Economy).toContain("meal-type_0"); + expect(MEAL_LINKS.Comfort).toContain("meal-type_1"); + expect(MEAL_LINKS.Business).toContain("meal-type_2"); + }); +}); diff --git a/src/features/online-board/components/details-panels/shared.ts b/src/features/online-board/components/details-panels/shared.ts new file mode 100644 index 00000000..b316753b --- /dev/null +++ b/src/features/online-board/components/details-panels/shared.ts @@ -0,0 +1,68 @@ +import type { + FlightStatus, + IEquipmentFull, + IFlightTransitionItem, + MealType, +} from "../../types.js"; + +export type DetailsViewType = "Onlineboard" | "Schedule"; + +/** + * Matches Angular's `showBoardProperty` in flight-details-wrapper.component.ts. + * Transition panels are hidden for Schedule mode, Cancelled flights, + * missing data, or when the transition hasn't started. + */ +export function shouldShowTransition( + item: IFlightTransitionItem | undefined, + legStatus: FlightStatus, + viewType: DetailsViewType, +): boolean { + if (viewType === "Schedule") return false; + if (legStatus === "Cancelled") return false; + if (!item) return false; + if (item.status === "Scheduled") return false; + return true; +} + +/** + * Matches Angular's `showAircraft` getter. Shows when actual or scheduled + * title exists, or when configuration string is present. + */ +export function shouldShowAircraft(equipment: Pick): boolean { + const aircraft = equipment.aircraft; + if (!aircraft) return false; + const title = aircraft.actual?.title || aircraft.scheduled?.title; + if (title) return true; + if (aircraft.configuration) return true; + return false; +} + +/** + * Service ID → icon filename mapping. + * From Angular flight-details-services.component.ts. + * IDs 6 and 7 both use the entertaintment icon (typo in original is preserved + * because that's how Angular ships the filename). + */ +export const SERVICE_ICON_MAP: Record = { + 1: "shopping", + 2: "space", + 3: "taxi", + 4: "wifi", + 5: "gsm", + 6: "entertaintment", + 7: "entertaintment", + 8: "seat_reservation", +}; + +/** Fallback icon for unknown service IDs. */ +export const SERVICE_ICON_FALLBACK = "comfort-plus"; + +/** + * Meal type → aeroflot.ru info page link. + * From Angular flight-details-meal.component.ts. + */ +export const MEAL_LINKS: Record, string> = { + Economy: "https://www.aeroflot.ru/ru-ru/information/onboard/dining?0000#meal-type_0", + Comfort: "https://www.aeroflot.ru/ru-ru/information/onboard/dining?0000#meal-type_1", + Business: "https://www.aeroflot.ru/ru-ru/information/onboard/dining?0000#meal-type_2", +}; diff --git a/src/i18n/locales/en/common.json b/src/i18n/locales/en/common.json index f9b54e60..887fd6a7 100644 --- a/src/i18n/locales/en/common.json +++ b/src/i18n/locales/en/common.json @@ -37,6 +37,29 @@ "TITLE": "Online Timetable", "YOU_SEARCH": "You searched" }, + "DETAILS": { + "REGISTRATION": "Check-in", + "BOARDING": "Boarding", + "DEBOARDING": "Deboarding", + "AIRCRAFT": "Aircraft", + "MEAL": "Meal", + "ON_BOARD_SERVICES": "On-board services", + "SCHEDULED": "Scheduled", + "ACTUAL": "Actual", + "MEAL_ECONOMY": "Economy", + "MEAL_COMFORT": "Comfort", + "MEAL_BUSINESS": "Business", + "STATUS_FINISHED": "Finished", + "STATUS_EXPECTED": "Expected", + "STATUS_IN_PROGRESS": "In progress", + "STATUS_SPECIFIED": "Specified", + "STATUS_SCHEDULED": "Scheduled", + "TERMINAL": "Terminal", + "GATE": "Gate", + "BAG_BELT": "Baggage belt", + "CONFIGURATION": "Configuration", + "STATUS": "Status" + }, "BOARDING-STATUSES": { "Expected": "Expected", "Finished": "Completed", diff --git a/src/i18n/locales/ru/common.json b/src/i18n/locales/ru/common.json index 2b06b289..f4f6f09b 100644 --- a/src/i18n/locales/ru/common.json +++ b/src/i18n/locales/ru/common.json @@ -37,6 +37,29 @@ "TITLE": "Онлайн-Табло", "YOU_SEARCH": "Вы искали" }, + "DETAILS": { + "REGISTRATION": "Регистрация", + "BOARDING": "Посадка", + "DEBOARDING": "Высадка", + "AIRCRAFT": "Воздушное судно", + "MEAL": "Питание", + "ON_BOARD_SERVICES": "Услуги на борту", + "SCHEDULED": "По расписанию", + "ACTUAL": "Фактически", + "MEAL_ECONOMY": "Эконом", + "MEAL_COMFORT": "Комфорт", + "MEAL_BUSINESS": "Бизнес", + "STATUS_FINISHED": "Завершена", + "STATUS_EXPECTED": "Ожидается", + "STATUS_IN_PROGRESS": "В процессе", + "STATUS_SPECIFIED": "Назначена", + "STATUS_SCHEDULED": "По расписанию", + "TERMINAL": "Терминал", + "GATE": "Выход", + "BAG_BELT": "Лента выдачи багажа", + "CONFIGURATION": "Компоновка", + "STATUS": "Статус" + }, "BOARDING-STATUSES": { "Expected": "Ожидается", "Finished": "Закончена",