Match Angular details layout when no parent request is present

- Drop the duplicate FlightCard summary between the header and the route
  strip — Angular's details page shows the route strip directly under the
  board-details-header, with no 'SU 6272 Russia 15:30/15:22 ...' row.
- Keep the mini-list sidebar visible even when allFlights has only one
  entry; fall back to rendering the current flight as a single item,
  matching Angular's flights-details-list-flight behavior.
This commit is contained in:
2026-04-18 16:41:35 +03:00
parent 583fe45c14
commit 2d77e86c88
5 changed files with 23 additions and 21 deletions
@@ -58,20 +58,23 @@ function makeFlight(id: string, date = "20260416"): ISimpleFlight {
}
describe("FlightsMiniList", () => {
it("returns null when flights array is empty", () => {
it("falls back to the current flight when the list is empty", () => {
// Angular parity: mini-list stays visible and shows the currently-viewed
// flight as a single item even when no sibling flights are available.
const current = makeFlight("SU0022-20260416");
const { container } = render(
render(
<FlightsMiniList flights={[]} currentFlight={current} lang="ru" />,
);
expect(container.firstChild).toBeNull();
expect(screen.getByTestId("flights-mini-list")).toBeTruthy();
expect(screen.getByTestId("mini-list-item-SU0022-20260416")).toBeTruthy();
});
it("returns null when flights array has only one flight", () => {
it("renders the single entry when flights array has only one flight", () => {
const current = makeFlight("SU0022-20260416");
const { container } = render(
render(
<FlightsMiniList flights={[current]} currentFlight={current} lang="ru" />,
);
expect(container.firstChild).toBeNull();
expect(screen.getByTestId("mini-list-item-SU0022-20260416")).toBeTruthy();
});
it("renders one item per flight when multiple flights", () => {
@@ -23,13 +23,14 @@ export const FlightsMiniList: FC<FlightsMiniListProps> = ({
}
}, [currentFlight.id]);
if (flights.length <= 1) {
return null;
}
// Angular parity: the sidebar renders even when the list is empty or
// has a single flight — it falls back to showing the current flight so
// the layout stays consistent with the stand-alone Angular details view.
const renderFlights = flights.length > 0 ? flights : [currentFlight];
return (
<section className="mini-list" data-testid="flights-mini-list">
{flights.map((flight) => (
{renderFlights.map((flight) => (
<FlightsMiniListItem
key={flight.id}
ref={(el) => {
@@ -251,10 +251,12 @@ describe("OnlineBoardDetailsPage", () => {
expect(screen.getByTestId("flights-mini-list")).toBeTruthy();
});
it("does not render mini-list when only one flight is returned", () => {
it("still renders mini-list with the current flight when only one flight is returned", () => {
// Angular parity: mini-list always visible, falling back to the current
// flight as a single entry when there are no sibling flights.
mockState = { flight: mockFlight, allFlights: [mockFlight], daysOfFlight: ["20250115"], loading: false, error: null };
render(<OnlineBoardDetailsPage flightId={mockFlightId} locale="ru" canonicalOrigin="https://example.com" />);
expect(screen.queryByTestId("flights-mini-list")).toBeNull();
expect(screen.getByTestId("flights-mini-list")).toBeTruthy();
});
it("renders inside PageLayout (has page-layout class)", () => {
@@ -11,7 +11,6 @@ import { Fragment, useCallback, useMemo, type FC } from "react";
import { useNavigate, useSearchParams } from "@modern-js/runtime/router";
import { useTranslation } from "@/i18n/provider.js";
import "./OnlineBoardDetailsPage.scss";
import { FlightCard } from "@/ui/flights/FlightCard.js";
import { FlightListSkeleton } from "@/ui/flights/FlightListSkeleton.js";
import { SeoHead } from "@/ui/seo/SeoHead.js";
import { JsonLdRenderer } from "@/shared/seo/json-ld.js";
@@ -568,9 +567,6 @@ export const OnlineBoardDetailsPage: FC<OnlineBoardDetailsPageProps> = ({
<FullRouteTimeline legs={displayFlight.legs} viewType="Onlineboard" />
)}
{/* Summary card */}
<FlightCard flight={displayFlight} />
{/* Angular's details page conveys the operating carrier
via the airline logo in the badge and, for code-share
flights, via the small 'KL 123, AF 456…' line under the
@@ -138,11 +138,11 @@ describe("Flight details page integration", () => {
canonicalOrigin="https://www.aeroflot.ru"
/>,
);
// FlightStatus renders STATUS_LABELS_RU in the embedded
// <FlightCard> summary row (the leg header only renders for
// multi-leg flights now). For a direct Scheduled flight that's
// the single Russian label 'Запланирован'.
expect(screen.getAllByText("Запланирован").length).toBeGreaterThanOrEqual(1);
// After removing the duplicate FlightCard summary for Angular parity,
// the status label is rendered by the LegRoute status-text inside the
// route strip — under the test's identity i18n mock that resolves to
// the raw 'FLIGHT-STATUSES.Scheduled' key.
expect(screen.getAllByText("FLIGHT-STATUSES.Scheduled").length).toBeGreaterThanOrEqual(1);
});
it("renders flight legs for direct flight", () => {