Schedule heading + column header row
- ScheduleSearchPage: H1 now reads `Расписание по маршруту: …` using SCHEDULE.SCHEDULE-BY-ROUTE — the existing onlineboard variant was leaking through. Matches Angular's schedule-search title-bar verbatim. - DayGroupedFlightList: render a non-sortable column header bar above the list with `Рейс / Авиакомпания, борт / Вылет / Время в пути / Прилет`. Mirrors Angular's schedule-list-flight-header column row. Sort arrows still TBD. - New i18n keys: SCHEDULE.COL-FLIGHT, COL-AIRLINE, COL-DEPARTURE, COL-DURATION, COL-ARRIVAL (RU + EN both filled). Schedule-route mismatch now 11.99% (was 12.47% pre-heading fix).
This commit is contained in:
@@ -3,6 +3,19 @@
|
||||
flex-direction: column;
|
||||
gap: 18px;
|
||||
|
||||
&__column-headers {
|
||||
display: grid;
|
||||
grid-template-columns: 80px 1fr 100px 120px 1fr;
|
||||
gap: 12px;
|
||||
padding: 8px 16px;
|
||||
color: #6b7280;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
border-bottom: 1px solid #e8edf3;
|
||||
}
|
||||
|
||||
&__group {
|
||||
border: 1px solid #e8edf3;
|
||||
border-radius: 6px;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
*/
|
||||
|
||||
import { type FC, useMemo } from "react";
|
||||
import { useTranslation } from "@/i18n/provider.js";
|
||||
import { FlightList } from "@/ui/flights/FlightList.js";
|
||||
import { FlightListSkeleton } from "@/ui/flights/FlightListSkeleton.js";
|
||||
import { useLocale } from "@/i18n/useLocale.js";
|
||||
@@ -72,8 +73,25 @@ export const DayGroupedFlightList: FC<DayGroupedFlightListProps> = ({
|
||||
initialCurrentFlightId,
|
||||
}) => {
|
||||
const { language } = useLocale();
|
||||
const { t } = useTranslation();
|
||||
const groups = useMemo(() => groupFlightsByDay(flights), [flights]);
|
||||
|
||||
/** Angular's schedule renders a sortable column header row above the
|
||||
* list. We render the same labels as a non-sortable bar — sortable
|
||||
* headers are tracked separately. Skipped while loading or empty. */
|
||||
const headerRow = (
|
||||
<div
|
||||
className="day-grouped-flight-list__column-headers"
|
||||
data-testid="schedule-column-headers"
|
||||
>
|
||||
<span>{t("SCHEDULE.COL-FLIGHT") || "РЕЙС"}</span>
|
||||
<span>{t("SCHEDULE.COL-AIRLINE") || "АВИАКОМПАНИЯ, БОРТ"}</span>
|
||||
<span>{t("SCHEDULE.COL-DEPARTURE") || "ВЫЛЕТ"}</span>
|
||||
<span>{t("SCHEDULE.COL-DURATION") || "ВРЕМЯ В ПУТИ"}</span>
|
||||
<span>{t("SCHEDULE.COL-ARRIVAL") || "ПРИЛЕТ"}</span>
|
||||
</div>
|
||||
);
|
||||
|
||||
if (loading) return <FlightListSkeleton count={5} />;
|
||||
|
||||
if (groups.length === 0) {
|
||||
@@ -83,13 +101,16 @@ export const DayGroupedFlightList: FC<DayGroupedFlightListProps> = ({
|
||||
// Single-day result: skip grouping noise and render the flat list.
|
||||
if (groups.length === 1) {
|
||||
return (
|
||||
<FlightList
|
||||
flights={flights}
|
||||
loading={false}
|
||||
direction="schedule"
|
||||
{...(onFlightClick ? { onFlightClick } : {})}
|
||||
{...(initialCurrentFlightId ? { initialCurrentFlightId } : {})}
|
||||
/>
|
||||
<div className="day-grouped-flight-list">
|
||||
{headerRow}
|
||||
<FlightList
|
||||
flights={flights}
|
||||
loading={false}
|
||||
direction="schedule"
|
||||
{...(onFlightClick ? { onFlightClick } : {})}
|
||||
{...(initialCurrentFlightId ? { initialCurrentFlightId } : {})}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -103,6 +124,7 @@ export const DayGroupedFlightList: FC<DayGroupedFlightListProps> = ({
|
||||
|
||||
return (
|
||||
<div className="day-grouped-flight-list" data-testid="day-grouped-flight-list">
|
||||
{headerRow}
|
||||
{groups.map((g) => {
|
||||
const weekday = weekdayFmt.format(g.parsed);
|
||||
const dayMonth = dayMonthFmt.format(g.parsed);
|
||||
|
||||
@@ -97,7 +97,10 @@ export const ScheduleSearchPage: FC<ScheduleSearchPageProps> = ({ params }) => {
|
||||
};
|
||||
const depName = describeStation(outbound.departure);
|
||||
const arrName = describeStation(outbound.arrival);
|
||||
const routeHeading = `${t("BOARD.ROUTE-TEXT")}${depName} - ${arrName}`;
|
||||
// Angular's schedule pages render the heading as
|
||||
// `Расписание по маршруту: Москва - Самара` (SCHEDULE.SCHEDULE-BY-ROUTE);
|
||||
// the onlineboard variant uses the shorter `Маршрут:` (BOARD.ROUTE-TEXT).
|
||||
const routeHeading = `${t("SCHEDULE.SCHEDULE-BY-ROUTE")}: ${depName} - ${arrName}`;
|
||||
|
||||
// Fetch outbound flights
|
||||
const outboundRequest = toSearchRequest(outbound);
|
||||
|
||||
@@ -177,6 +177,11 @@
|
||||
"TO-HOME": "HOME"
|
||||
},
|
||||
"SCHEDULE": {
|
||||
"COL-FLIGHT": "Flight",
|
||||
"COL-AIRLINE": "Airline, aircraft",
|
||||
"COL-DEPARTURE": "Departure",
|
||||
"COL-DURATION": "Duration",
|
||||
"COL-ARRIVAL": "Arrival",
|
||||
"DOWNLOAD-SCHEDULE": "Download schedule",
|
||||
"DOWNLOAD-SCHEDULE-FOR-DAY": "For the day",
|
||||
"DOWNLOAD-SCHEDULE-FOR-THE-CURRENT-MONTH": "For the current month",
|
||||
|
||||
@@ -177,6 +177,11 @@
|
||||
"TO-HOME": "НА ГЛАВНУЮ"
|
||||
},
|
||||
"SCHEDULE": {
|
||||
"COL-FLIGHT": "Рейс",
|
||||
"COL-AIRLINE": "Авиакомпания, борт",
|
||||
"COL-DEPARTURE": "Вылет",
|
||||
"COL-DURATION": "Время в пути",
|
||||
"COL-ARRIVAL": "Прилет",
|
||||
"DOWNLOAD-SCHEDULE": "Выгрузить расписание",
|
||||
"DOWNLOAD-SCHEDULE-FOR-DAY": "На день",
|
||||
"DOWNLOAD-SCHEDULE-FOR-THE-CURRENT-MONTH": "На текущий месяц",
|
||||
|
||||
Reference in New Issue
Block a user