Add IFlyWarning component shown on details pages for SU5801-5948 flights (Angular parity)
This commit is contained in:
@@ -12,6 +12,7 @@ import { useNavigate, useSearchParams } from "@modern-js/runtime/router";
|
||||
import { useTranslation } from "@/i18n/provider.js";
|
||||
import "./OnlineBoardDetailsPage.scss";
|
||||
import { FlightListSkeleton } from "@/ui/flights/FlightListSkeleton.js";
|
||||
import { IFlyWarning } from "@/ui/flights/IFlyWarning.js";
|
||||
import { JsonLdRenderer } from "@/shared/seo/json-ld.js";
|
||||
import { PageLayout } from "@/ui/layout/PageLayout.js";
|
||||
import { useAppSettings } from "@/shared/hooks/useAppSettings.js";
|
||||
@@ -561,6 +562,11 @@ export const OnlineBoardDetailsPage: FC<OnlineBoardDetailsPageProps> = ({
|
||||
|
||||
<BoardDetailsHeader flight={displayFlight} locale={locale} />
|
||||
|
||||
{/* iFly operator warning (SU5801-5948) — Angular embeds
|
||||
this inside flight-schedule-details.component.html via
|
||||
a flightNumber range guard. */}
|
||||
<IFlyWarning flightNumber={displayFlight.flightId.flightNumber} />
|
||||
|
||||
{displayFlight.routeType === "MultiLeg" && (
|
||||
<FullRouteTimeline legs={displayFlight.legs} viewType="Onlineboard" />
|
||||
)}
|
||||
|
||||
@@ -15,6 +15,7 @@ import { useTranslation } from "@/i18n/provider.js";
|
||||
import { localeToLanguage, normalizeLocaleParam, DEFAULT_LANGUAGE } from "@/i18n/resolver.js";
|
||||
import { FlightCard } from "@/ui/flights/FlightCard.js";
|
||||
import { FlightListSkeleton } from "@/ui/flights/FlightListSkeleton.js";
|
||||
import { IFlyWarning } from "@/ui/flights/IFlyWarning.js";
|
||||
import { SeoHead } from "@/ui/seo/SeoHead.js";
|
||||
import { PageLayout } from "@/ui/layout/PageLayout.js";
|
||||
import { PageTabs } from "@/ui/layout/PageTabs.js";
|
||||
@@ -230,6 +231,10 @@ export const ScheduleDetailsPage: FC<ScheduleDetailsPageProps> = ({
|
||||
|
||||
{/* Collapsed summary row, then the rich per-leg body. */}
|
||||
<FlightCard flight={flight} direction="schedule" />
|
||||
{/* iFly operator warning (SU5801-5948) — Angular
|
||||
renders this inside flight-schedule-details between
|
||||
the header and the route strip. */}
|
||||
<IFlyWarning flightNumber={flight.flightId.flightNumber} />
|
||||
{renderBody(flight)}
|
||||
|
||||
{/* Angular's flight-schedule-details renders the weekly
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
@use "../../styles/colors" as colors;
|
||||
@use "../../styles/variables" as vars;
|
||||
@use "../../styles/fonts" as fonts;
|
||||
|
||||
// Mirrors Angular `warning-ifly-carrier-detail.component.scss`:
|
||||
// a narrow orange vertical bar + highlighted leading caption, used
|
||||
// on details pages for flights in the iFly-operated SU5801–5948 range.
|
||||
.ifly-warning {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: vars.$space-m vars.$space-xl;
|
||||
|
||||
&__bar {
|
||||
width: 0.3rem;
|
||||
height: 80px;
|
||||
background-color: colors.$orange--hover;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
&__text {
|
||||
text-align: left;
|
||||
padding: vars.$space-xl;
|
||||
font-size: fonts.$font-size-m;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
&__highlight {
|
||||
font-weight: fonts.$font-bold;
|
||||
color: colors.$orange--hover;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* @vitest-environment jsdom
|
||||
*/
|
||||
import { describe, it, expect, vi } from "vitest";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { IFlyWarning } from "./IFlyWarning.js";
|
||||
|
||||
vi.mock("@/i18n/provider.js", () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string) => key,
|
||||
i18n: { language: "ru" },
|
||||
}),
|
||||
}));
|
||||
|
||||
describe("IFlyWarning", () => {
|
||||
it("renders warning for flights in the iFly range (5801-5948)", () => {
|
||||
const { container } = render(<IFlyWarning flightNumber="5825" />);
|
||||
expect(container.querySelector(".ifly-warning")).toBeTruthy();
|
||||
expect(screen.getByText("WARNING.IFLY_HIGHLIGHT")).toBeTruthy();
|
||||
});
|
||||
|
||||
it("accepts numeric flight numbers", () => {
|
||||
const { container } = render(<IFlyWarning flightNumber={5900} />);
|
||||
expect(container.querySelector(".ifly-warning")).toBeTruthy();
|
||||
});
|
||||
|
||||
it("does not render for flights below the iFly range", () => {
|
||||
const { container } = render(<IFlyWarning flightNumber="5800" />);
|
||||
expect(container.querySelector(".ifly-warning")).toBeNull();
|
||||
});
|
||||
|
||||
it("does not render for flights above the iFly range", () => {
|
||||
const { container } = render(<IFlyWarning flightNumber="5949" />);
|
||||
expect(container.querySelector(".ifly-warning")).toBeNull();
|
||||
});
|
||||
|
||||
it("does not render for regular flights (SU100)", () => {
|
||||
const { container } = render(<IFlyWarning flightNumber="100" />);
|
||||
expect(container.querySelector(".ifly-warning")).toBeNull();
|
||||
});
|
||||
|
||||
it("does not render for non-numeric input", () => {
|
||||
const { container } = render(<IFlyWarning flightNumber="abc" />);
|
||||
expect(container.querySelector(".ifly-warning")).toBeNull();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,33 @@
|
||||
import type { FC } from "react";
|
||||
import { useTranslation } from "@/i18n/provider.js";
|
||||
import "./IFlyWarning.scss";
|
||||
|
||||
export interface IFlyWarningProps {
|
||||
flightNumber: string | number;
|
||||
}
|
||||
|
||||
function isIFlyRange(num: string | number): boolean {
|
||||
const n = typeof num === "string" ? parseInt(num, 10) : num;
|
||||
if (!Number.isFinite(n)) return false;
|
||||
return n > 5800 && n < 5949;
|
||||
}
|
||||
|
||||
export const IFlyWarning: FC<IFlyWarningProps> = ({ flightNumber }) => {
|
||||
const { t } = useTranslation();
|
||||
if (!isIFlyRange(flightNumber)) return null;
|
||||
return (
|
||||
<div className="ifly-warning" data-testid="ifly-warning">
|
||||
<div className="ifly-warning__bar" aria-hidden="true" />
|
||||
<div className="ifly-warning__text">
|
||||
<span className="ifly-warning__highlight">
|
||||
{t("WARNING.IFLY_HIGHLIGHT")}
|
||||
</span>{" "}
|
||||
{t("WARNING.IFLY_BODY")}
|
||||
<br />
|
||||
<span
|
||||
dangerouslySetInnerHTML={{ __html: t("WARNING.IFLY_INFO") }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -21,3 +21,6 @@ export type { FlightListSkeletonProps } from "./FlightListSkeleton.js";
|
||||
|
||||
export { FlightList } from "./FlightList.js";
|
||||
export type { FlightListProps } from "./FlightList.js";
|
||||
|
||||
export { IFlyWarning } from "./IFlyWarning.js";
|
||||
export type { IFlyWarningProps } from "./IFlyWarning.js";
|
||||
|
||||
Reference in New Issue
Block a user