Implement inline expandable flight-card details
Clicking a row on the board search results page now toggles an inline
details panel instead of immediately navigating away. The layout
matches Angular's board-flight-header:
- Aircraft model ('Sukhoi SuperJet 100') appears below the flight
number when expanded.
- 'Время' detail row: По расписанию / Фактическое times with UTC
offsets for both the departure and the arrival sides.
- 'Посадка' detail row: boarding status (через the
BOARDING-STATUSES.* keys), start and end times.
- 'Детали рейса' button (blue) in the bottom-right navigates to the
full details page.
- Active rows get a blue left border + light-blue background.
- Chevron icon on the right rotates on expand.
Wire-up: FlightCard has two new props (expandable, onViewDetails).
FlightList automatically passes expandable=true when a click handler
is provided. Added SHARED.BOARDING-START / SHARED.BOARDING-END keys
across all nine locales for the time captions.
This commit is contained in:
@@ -389,7 +389,9 @@
|
||||
"A11Y-OPEN-PICKER": "Open city picker",
|
||||
"A11Y-BREADCRUMB": "Breadcrumb",
|
||||
"A11Y-PREV-LEGS": "Previous legs",
|
||||
"A11Y-NEXT-LEGS": "Next legs"
|
||||
"A11Y-NEXT-LEGS": "Next legs",
|
||||
"BOARDING-START": "Start time",
|
||||
"BOARDING-END": "End time"
|
||||
},
|
||||
"WARNING": {
|
||||
"IFLY_HIGHLIGHT": "Bitte beachten Sie:",
|
||||
|
||||
@@ -416,7 +416,9 @@
|
||||
"A11Y-OPEN-PICKER": "Open city picker",
|
||||
"A11Y-BREADCRUMB": "Breadcrumb",
|
||||
"A11Y-PREV-LEGS": "Previous legs",
|
||||
"A11Y-NEXT-LEGS": "Next legs"
|
||||
"A11Y-NEXT-LEGS": "Next legs",
|
||||
"BOARDING-START": "Start time",
|
||||
"BOARDING-END": "End time"
|
||||
},
|
||||
"WARNING": {
|
||||
"IFLY_HIGHLIGHT": "Please note:",
|
||||
|
||||
@@ -389,7 +389,9 @@
|
||||
"A11Y-OPEN-PICKER": "Open city picker",
|
||||
"A11Y-BREADCRUMB": "Breadcrumb",
|
||||
"A11Y-PREV-LEGS": "Previous legs",
|
||||
"A11Y-NEXT-LEGS": "Next legs"
|
||||
"A11Y-NEXT-LEGS": "Next legs",
|
||||
"BOARDING-START": "Start time",
|
||||
"BOARDING-END": "End time"
|
||||
},
|
||||
"WARNING": {
|
||||
"IFLY_HIGHLIGHT": "Nota:",
|
||||
|
||||
@@ -389,7 +389,9 @@
|
||||
"A11Y-OPEN-PICKER": "Open city picker",
|
||||
"A11Y-BREADCRUMB": "Breadcrumb",
|
||||
"A11Y-PREV-LEGS": "Previous legs",
|
||||
"A11Y-NEXT-LEGS": "Next legs"
|
||||
"A11Y-NEXT-LEGS": "Next legs",
|
||||
"BOARDING-START": "Start time",
|
||||
"BOARDING-END": "End time"
|
||||
},
|
||||
"WARNING": {
|
||||
"IFLY_HIGHLIGHT": "Remarque:",
|
||||
|
||||
@@ -389,7 +389,9 @@
|
||||
"A11Y-OPEN-PICKER": "Open city picker",
|
||||
"A11Y-BREADCRUMB": "Breadcrumb",
|
||||
"A11Y-PREV-LEGS": "Previous legs",
|
||||
"A11Y-NEXT-LEGS": "Next legs"
|
||||
"A11Y-NEXT-LEGS": "Next legs",
|
||||
"BOARDING-START": "Start time",
|
||||
"BOARDING-END": "End time"
|
||||
},
|
||||
"WARNING": {
|
||||
"IFLY_HIGHLIGHT": "Attenzione:",
|
||||
|
||||
@@ -389,7 +389,9 @@
|
||||
"A11Y-OPEN-PICKER": "Open city picker",
|
||||
"A11Y-BREADCRUMB": "Breadcrumb",
|
||||
"A11Y-PREV-LEGS": "Previous legs",
|
||||
"A11Y-NEXT-LEGS": "Next legs"
|
||||
"A11Y-NEXT-LEGS": "Next legs",
|
||||
"BOARDING-START": "Start time",
|
||||
"BOARDING-END": "End time"
|
||||
},
|
||||
"WARNING": {
|
||||
"IFLY_HIGHLIGHT": "ご注意:",
|
||||
|
||||
@@ -389,7 +389,9 @@
|
||||
"A11Y-OPEN-PICKER": "Open city picker",
|
||||
"A11Y-BREADCRUMB": "Breadcrumb",
|
||||
"A11Y-PREV-LEGS": "Previous legs",
|
||||
"A11Y-NEXT-LEGS": "Next legs"
|
||||
"A11Y-NEXT-LEGS": "Next legs",
|
||||
"BOARDING-START": "Start time",
|
||||
"BOARDING-END": "End time"
|
||||
},
|
||||
"WARNING": {
|
||||
"IFLY_HIGHLIGHT": "참고:",
|
||||
|
||||
@@ -416,7 +416,9 @@
|
||||
"A11Y-OPEN-PICKER": "Открыть список городов",
|
||||
"A11Y-BREADCRUMB": "Навигационная цепочка",
|
||||
"A11Y-PREV-LEGS": "Предыдущие сегменты",
|
||||
"A11Y-NEXT-LEGS": "Следующие сегменты"
|
||||
"A11Y-NEXT-LEGS": "Следующие сегменты",
|
||||
"BOARDING-START": "Время начала",
|
||||
"BOARDING-END": "Время окончания"
|
||||
},
|
||||
"SMOKE": {
|
||||
"HEADING": "Страница проверки"
|
||||
|
||||
@@ -389,7 +389,9 @@
|
||||
"A11Y-OPEN-PICKER": "Open city picker",
|
||||
"A11Y-BREADCRUMB": "Breadcrumb",
|
||||
"A11Y-PREV-LEGS": "Previous legs",
|
||||
"A11Y-NEXT-LEGS": "Next legs"
|
||||
"A11Y-NEXT-LEGS": "Next legs",
|
||||
"BOARDING-START": "Start time",
|
||||
"BOARDING-END": "End time"
|
||||
},
|
||||
"WARNING": {
|
||||
"IFLY_HIGHLIGHT": "请注意:",
|
||||
|
||||
+120
-11
@@ -4,24 +4,25 @@
|
||||
@use "../../styles/screen" as screen;
|
||||
|
||||
.flight-card {
|
||||
display: grid;
|
||||
grid-template-columns: 70px 100px 80px 1fr 90px 80px 1fr;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 18px vars.$space-xl;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: transparent;
|
||||
transition: background-color 120ms ease;
|
||||
min-height: 68px;
|
||||
|
||||
& + & {
|
||||
border-top: 1px dashed colors.$border;
|
||||
}
|
||||
|
||||
&--clickable {
|
||||
&--expanded {
|
||||
background: #f3f6fb;
|
||||
border-left: 3px solid colors.$blue;
|
||||
}
|
||||
|
||||
&--clickable .flight-card__row {
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: #eef3ff;
|
||||
background-color: rgba(46, 87, 255, 0.04);
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
@@ -30,12 +31,28 @@
|
||||
}
|
||||
}
|
||||
|
||||
&__row {
|
||||
display: grid;
|
||||
grid-template-columns: 70px 100px 80px 1fr 90px 80px 1fr auto;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 18px vars.$space-xl;
|
||||
min-height: 68px;
|
||||
}
|
||||
|
||||
&__number {
|
||||
font-weight: fonts.$font-medium;
|
||||
color: #222;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
&__aircraft {
|
||||
font-size: 11px;
|
||||
color: #8a8a8a;
|
||||
font-weight: normal;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
&__operator {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -70,17 +87,109 @@
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@include screen.mobile {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
&__chevron {
|
||||
color: colors.$blue;
|
||||
font-size: 18px;
|
||||
transition: transform 150ms ease;
|
||||
|
||||
&--open {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
|
||||
&__expanded {
|
||||
padding: 0 vars.$space-xl vars.$space-xl;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: vars.$space-m;
|
||||
background: #f8fafd;
|
||||
}
|
||||
|
||||
&__detail-row {
|
||||
display: grid;
|
||||
grid-template-columns: 140px 1fr 1fr;
|
||||
gap: vars.$space-xl;
|
||||
padding: vars.$space-m 0;
|
||||
border-bottom: 1px dashed #e0e6f0;
|
||||
align-items: flex-start;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
&__detail-label {
|
||||
color: #8a8a8a;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
&__detail-group {
|
||||
display: flex;
|
||||
gap: vars.$space-xl;
|
||||
flex-wrap: wrap;
|
||||
|
||||
> div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
&__detail-caption {
|
||||
font-size: 12px;
|
||||
color: #8a8a8a;
|
||||
}
|
||||
|
||||
&__detail-value {
|
||||
font-weight: 500;
|
||||
color: #222;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
&__detail-status {
|
||||
color: #2457ff;
|
||||
}
|
||||
|
||||
&__actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding-top: vars.$space-s;
|
||||
}
|
||||
|
||||
&__details-btn {
|
||||
background: colors.$blue;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
padding: 10px 24px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: background-color 150ms ease;
|
||||
|
||||
&:hover {
|
||||
background: #1c45cc;
|
||||
}
|
||||
}
|
||||
|
||||
@include screen.mobile {
|
||||
&__row {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: vars.$space-m;
|
||||
}
|
||||
|
||||
&__operator,
|
||||
&__status {
|
||||
&__status,
|
||||
&__chevron {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&__station--arrival {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
&__detail-row {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+244
-71
@@ -1,6 +1,11 @@
|
||||
import type { FC, KeyboardEvent } from "react";
|
||||
import { useState, type FC, type KeyboardEvent } from "react";
|
||||
import { useTranslation } from "@/i18n/provider.js";
|
||||
import type { ISimpleFlight, IFlightLeg } from "@/features/online-board/types.js";
|
||||
import { operatingCarrier } from "@/features/online-board/types.js";
|
||||
import {
|
||||
formatLocalTime,
|
||||
formatUtcOffset,
|
||||
} from "@/shared/utils/datetime/index.js";
|
||||
import { StationDisplay } from "./StationDisplay.js";
|
||||
import { TimeGroup } from "./TimeGroup.js";
|
||||
import { FlightStatus } from "./FlightStatus.js";
|
||||
@@ -9,7 +14,19 @@ import "./FlightCard.scss";
|
||||
|
||||
export interface FlightCardProps {
|
||||
flight: ISimpleFlight;
|
||||
/**
|
||||
* Legacy single-click navigation handler. Kept for callers that don't
|
||||
* need inline expansion (e.g. details-page summary row).
|
||||
*/
|
||||
onClick?: () => void;
|
||||
/**
|
||||
* When true, a single row click toggles an inline detail panel (time
|
||||
* row, boarding row, 'Детали рейса' button) and the bottom button
|
||||
* fires onViewDetails. Matches Angular's board-flight-header behaviour.
|
||||
*/
|
||||
expandable?: boolean;
|
||||
/** Fired when the user clicks 'Детали рейса' in the expanded panel. */
|
||||
onViewDetails?: () => void;
|
||||
}
|
||||
|
||||
/** Extract the primary leg from a flight (first leg for multi-leg) */
|
||||
@@ -28,13 +45,31 @@ function getFinalLeg(flight: ISimpleFlight): IFlightLeg {
|
||||
return last;
|
||||
}
|
||||
|
||||
/** Pretty "HH:mm UTC±HH:mm" string from an offset-aware ISO timestamp. */
|
||||
function timeWithOffset(iso: string | undefined): string {
|
||||
if (!iso) return "";
|
||||
const time = formatLocalTime(iso);
|
||||
const offset = formatUtcOffset(iso);
|
||||
return offset ? `${time} ${offset}` : time;
|
||||
}
|
||||
|
||||
/**
|
||||
* A single flight row in search results.
|
||||
*
|
||||
* Matches Angular's board-flight-header layout:
|
||||
* flight#+status | operator-logo | dep-time | dep-city/terminal | status-icon | arr-time | arr-city/terminal
|
||||
* Header row matches Angular's board-flight-header layout:
|
||||
* flight#+aircraft | operator-logo | dep-time | dep-city/terminal | status-icon | arr-time | arr-city/terminal | chevron
|
||||
*
|
||||
* When `expandable`, a row click toggles an inline details panel with
|
||||
* scheduled/expected time rows for departure + arrival, a boarding
|
||||
* status row, and a 'Детали рейса' navigation button.
|
||||
*/
|
||||
export const FlightCard: FC<FlightCardProps> = ({ flight, onClick }) => {
|
||||
export const FlightCard: FC<FlightCardProps> = ({
|
||||
flight,
|
||||
onClick,
|
||||
expandable,
|
||||
onViewDetails,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const departureLeg = getPrimaryLeg(flight);
|
||||
const arrivalLeg = getFinalLeg(flight);
|
||||
|
||||
@@ -45,82 +80,220 @@ export const FlightCard: FC<FlightCardProps> = ({ flight, onClick }) => {
|
||||
|
||||
const flightNumber = `${flight.flightId.carrier} ${flight.flightId.flightNumber}`;
|
||||
const carrier = operatingCarrier(flight.operatingBy) ?? flight.flightId.carrier;
|
||||
const clickable = Boolean(onClick);
|
||||
const aircraftName =
|
||||
departureLeg.equipment?.aircraft?.actual?.title ??
|
||||
departureLeg.equipment?.aircraft?.scheduled?.title ??
|
||||
null;
|
||||
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
const rowClickable = expandable || Boolean(onClick);
|
||||
const toggleExpanded = (): void => {
|
||||
if (expandable) {
|
||||
setExpanded((v) => !v);
|
||||
} else if (onClick) {
|
||||
onClick();
|
||||
}
|
||||
};
|
||||
|
||||
const depScheduled = timeWithOffset(depTimes.scheduledDeparture.local);
|
||||
const depActual = depTimes.actualBlockOff?.local
|
||||
? timeWithOffset(depTimes.actualBlockOff.local)
|
||||
: null;
|
||||
const arrScheduled = timeWithOffset(arrTimes.scheduledArrival.local);
|
||||
const arrActual = arrTimes.actualBlockOn?.local
|
||||
? timeWithOffset(arrTimes.actualBlockOn.local)
|
||||
: null;
|
||||
|
||||
const boarding = departureLeg.transition?.boarding;
|
||||
const BOARDING_STATUS_KEY: Record<string, string> = {
|
||||
Finished: "BOARDING-STATUSES.Finished",
|
||||
Expected: "BOARDING-STATUSES.Expected",
|
||||
InProgress: "BOARDING-STATUSES.InProgress",
|
||||
Specified: "BOARDING-STATUSES.Specified",
|
||||
Scheduled: "BOARDING-STATUSES.Scheduled",
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`flight-card${clickable ? " flight-card--clickable" : ""}`}
|
||||
className={`flight-card${rowClickable ? " flight-card--clickable" : ""}${expanded ? " flight-card--expanded" : ""}`}
|
||||
data-flight-id={flight.id}
|
||||
{...(clickable
|
||||
? {
|
||||
role: "button",
|
||||
tabIndex: 0,
|
||||
onClick,
|
||||
onKeyDown: (e: KeyboardEvent<HTMLDivElement>) => {
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
e.preventDefault();
|
||||
onClick!();
|
||||
}
|
||||
},
|
||||
}
|
||||
: {})}
|
||||
>
|
||||
<div className="flight-card__number" data-testid="flight-carrier-number">
|
||||
<div>{flightNumber}</div>
|
||||
<div
|
||||
className="flight-card__row"
|
||||
{...(rowClickable
|
||||
? {
|
||||
role: "button",
|
||||
tabIndex: 0,
|
||||
onClick: toggleExpanded,
|
||||
onKeyDown: (e: KeyboardEvent<HTMLDivElement>) => {
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
e.preventDefault();
|
||||
toggleExpanded();
|
||||
}
|
||||
},
|
||||
}
|
||||
: {})}
|
||||
>
|
||||
<div className="flight-card__number" data-testid="flight-carrier-number">
|
||||
<div>{flightNumber}</div>
|
||||
{expanded && aircraftName && (
|
||||
<div className="flight-card__aircraft">{aircraftName}</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flight-card__operator">
|
||||
<OperatorLogo carrier={carrier} locale="ru" />
|
||||
</div>
|
||||
|
||||
<div className="flight-card__time">
|
||||
<TimeGroup
|
||||
scheduled={depTimes.scheduledDeparture.local}
|
||||
actual={depTimes.actualBlockOff?.local}
|
||||
dayChange={
|
||||
depTimes.actualBlockOff?.dayChange.value ??
|
||||
depTimes.scheduledDeparture.dayChange?.value
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flight-card__station">
|
||||
<StationDisplay
|
||||
airportCode={depStation.scheduled.airportCode}
|
||||
airportName={depStation.scheduled.airport}
|
||||
cityName={depStation.scheduled.city}
|
||||
{...(depStation.terminal ? { terminal: depStation.terminal } : {})}
|
||||
cityFirst
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flight-card__status">
|
||||
<FlightStatus status={flight.status} />
|
||||
</div>
|
||||
|
||||
<div className="flight-card__time flight-card__time--arrival">
|
||||
<TimeGroup
|
||||
scheduled={arrTimes.scheduledArrival.local}
|
||||
actual={arrTimes.actualBlockOn?.local}
|
||||
dayChange={
|
||||
arrTimes.actualBlockOn?.dayChange.value ??
|
||||
arrTimes.scheduledArrival.dayChange?.value
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flight-card__station flight-card__station--arrival">
|
||||
<StationDisplay
|
||||
airportCode={arrStation.scheduled.airportCode}
|
||||
airportName={arrStation.scheduled.airport}
|
||||
cityName={arrStation.scheduled.city}
|
||||
{...(arrStation.terminal ? { terminal: arrStation.terminal } : {})}
|
||||
cityFirst
|
||||
/>
|
||||
</div>
|
||||
|
||||
{expandable && (
|
||||
<div
|
||||
className={`flight-card__chevron${expanded ? " flight-card__chevron--open" : ""}`}
|
||||
aria-hidden="true"
|
||||
>
|
||||
{"\u25BE"}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flight-card__operator">
|
||||
<OperatorLogo carrier={carrier} locale="ru" />
|
||||
</div>
|
||||
{expandable && expanded && (
|
||||
<div className="flight-card__expanded" data-testid="flight-card-expanded">
|
||||
<div className="flight-card__detail-row">
|
||||
<div className="flight-card__detail-label">{t("SHARED.TIME")}</div>
|
||||
<div className="flight-card__detail-group">
|
||||
<div>
|
||||
<span className="flight-card__detail-caption">
|
||||
{t("SHARED.SCHEDULED")}
|
||||
</span>
|
||||
<span className="flight-card__detail-value">{depScheduled}</span>
|
||||
</div>
|
||||
{depActual && (
|
||||
<div>
|
||||
<span className="flight-card__detail-caption">
|
||||
{t("SHARED.ACTUAL")}
|
||||
</span>
|
||||
<span className="flight-card__detail-value">{depActual}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="flight-card__detail-group">
|
||||
<div>
|
||||
<span className="flight-card__detail-caption">
|
||||
{t("SHARED.SCHEDULED")}
|
||||
</span>
|
||||
<span className="flight-card__detail-value">{arrScheduled}</span>
|
||||
</div>
|
||||
{arrActual && (
|
||||
<div>
|
||||
<span className="flight-card__detail-caption">
|
||||
{t("SHARED.ACTUAL")}
|
||||
</span>
|
||||
<span className="flight-card__detail-value">{arrActual}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flight-card__time">
|
||||
<TimeGroup
|
||||
scheduled={depTimes.scheduledDeparture.local}
|
||||
actual={depTimes.actualBlockOff?.local}
|
||||
// Prefer the actual day-offset but fall back to the scheduled one
|
||||
// so scheduled-only flights still show the '+1' marker when they
|
||||
// cross midnight (SU 6805 departs at 23:30 and arrives at 00:55+1).
|
||||
dayChange={
|
||||
depTimes.actualBlockOff?.dayChange.value ??
|
||||
depTimes.scheduledDeparture.dayChange?.value
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
{boarding && (
|
||||
<div className="flight-card__detail-row">
|
||||
<div className="flight-card__detail-label">
|
||||
{t("DETAILS.BOARDING")}
|
||||
</div>
|
||||
<div className="flight-card__detail-group">
|
||||
<div>
|
||||
<span className="flight-card__detail-caption">
|
||||
{t("DETAILS.STATUS")}
|
||||
</span>
|
||||
<span className="flight-card__detail-value flight-card__detail-status">
|
||||
{t(BOARDING_STATUS_KEY[boarding.status] ?? boarding.status)}
|
||||
</span>
|
||||
</div>
|
||||
{boarding.start?.local && (
|
||||
<div>
|
||||
<span className="flight-card__detail-caption">
|
||||
{t("SHARED.BOARDING-START")}
|
||||
</span>
|
||||
<span className="flight-card__detail-value">
|
||||
{formatLocalTime(boarding.start.local)}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{boarding.end?.local && (
|
||||
<div>
|
||||
<span className="flight-card__detail-caption">
|
||||
{t("SHARED.BOARDING-END")}
|
||||
</span>
|
||||
<span className="flight-card__detail-value">
|
||||
{formatLocalTime(boarding.end.local)}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flight-card__station">
|
||||
<StationDisplay
|
||||
airportCode={depStation.scheduled.airportCode}
|
||||
airportName={depStation.scheduled.airport}
|
||||
cityName={depStation.scheduled.city}
|
||||
{...(depStation.terminal ? { terminal: depStation.terminal } : {})}
|
||||
cityFirst
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flight-card__status">
|
||||
<FlightStatus status={flight.status} />
|
||||
</div>
|
||||
|
||||
<div className="flight-card__time flight-card__time--arrival">
|
||||
<TimeGroup
|
||||
scheduled={arrTimes.scheduledArrival.local}
|
||||
actual={arrTimes.actualBlockOn?.local}
|
||||
dayChange={
|
||||
arrTimes.actualBlockOn?.dayChange.value ??
|
||||
arrTimes.scheduledArrival.dayChange?.value
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flight-card__station flight-card__station--arrival">
|
||||
<StationDisplay
|
||||
airportCode={arrStation.scheduled.airportCode}
|
||||
airportName={arrStation.scheduled.airport}
|
||||
cityName={arrStation.scheduled.city}
|
||||
{...(arrStation.terminal ? { terminal: arrStation.terminal } : {})}
|
||||
cityFirst
|
||||
/>
|
||||
</div>
|
||||
{onViewDetails && (
|
||||
<div className="flight-card__actions">
|
||||
<button
|
||||
type="button"
|
||||
className="flight-card__details-btn"
|
||||
data-testid="flight-details-button"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onViewDetails();
|
||||
}}
|
||||
>
|
||||
{t("BOARD.DETAILS-TITLE")}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -47,7 +47,10 @@ export const FlightList: FC<FlightListProps> = ({
|
||||
<FlightCard
|
||||
key={flight.id}
|
||||
flight={flight}
|
||||
{...(onFlightClick ? { onClick: () => onFlightClick(flight) } : {})}
|
||||
expandable={Boolean(onFlightClick)}
|
||||
{...(onFlightClick
|
||||
? { onViewDetails: () => onFlightClick(flight) }
|
||||
: {})}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user