Add IFlyWarning component shown on details pages for SU5801-5948 flights (Angular parity)

This commit is contained in:
2026-04-20 20:02:45 +03:00
parent 28c88873a5
commit d942cb55bc
6 changed files with 124 additions and 0 deletions
+31
View File
@@ -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 SU58015948 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;
}
}
+46
View File
@@ -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();
});
});
+33
View File
@@ -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>
);
};
+3
View File
@@ -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";