Commit Graph

90 Commits

Author SHA1 Message Date
gnezim ea25f5c017 Replace 4 rgba(46,87,255,0.04/0.06/0.08) hover tints with $blue-extra-light / $blue-icon (brand palette) 2026-04-20 15:50:30 +03:00
gnezim d063281b09 ScheduleFlightBody share-btn: hover uses $blue-icon (Angular share-button parity) 2026-04-20 15:48:13 +03:00
gnezim 15f3356a75 ScheduleSearchPage: add Angular page-footer-notes to results frame 2026-04-20 15:17:34 +03:00
gnezim d7a9ae5d79 FlightCard schedule grid: match Angular schedule-list-flight-header (80px number, minmax(45,240)px stations) 2026-04-20 13:52:59 +03:00
gnezim 21a557b875 ScheduleFilter: search button uses Angular blue-light 48px pill styling (Angular parity) 2026-04-20 13:28:30 +03:00
gnezim e4c8948cdc ScheduleFilter: add return-flight date range + time slider when round-trip (Angular parity) 2026-04-20 13:26:35 +03:00
gnezim 9134a830da ScheduleStartPage: add validation-tooltip SCSS for same-cities error 2026-04-20 13:23:08 +03:00
gnezim d44eb2fe71 ScheduleStartPage: add departure===arrival same-cities validation (Angular parity) 2026-04-20 13:21:51 +03:00
gnezim 02c6003225 ScheduleStartPage: Calendar min/max ±1/+330 days, return dates as single range picker (Angular parity) 2026-04-20 13:20:29 +03:00
gnezim 922e41e5c9 ScheduleStartPage: use shared CityAutocomplete (adds clear button + regional picker parity) 2026-04-20 13:18:29 +03:00
gnezim 0e74d9d196 FlightCard schedule mode + DayGroupedFlightList headers: number column 80→60px (Angular parity) 2026-04-20 13:00:51 +03:00
gnezim a361eeb7a5 ScheduleSearchPage: direction-switch exact Angular styles (130×40, extra-blue segmented) 2026-04-20 12:53:39 +03:00
gnezim 85deac7b54 ScheduleStartPage: bottom-description matches Angular's plain styling (no gray text, no link restyle) 2026-04-20 12:51:48 +03:00
gnezim 3d29c93eb6 DayGroupedFlightList: day header padding 12px 18px → 20px (Angular parity) 2026-04-20 12:50:11 +03:00
gnezim 13926314d0 ScheduleFilter: add validation-tooltip SCSS style for inline errors 2026-04-20 12:36:16 +03:00
gnezim fc27e6c476 ScheduleFilter: validate departure===arrival mismatch with inline error (Angular parity) 2026-04-20 12:34:59 +03:00
gnezim 3a3a7cda5f DayGroupedFlightList: auto-expand first flight of today's group (Angular expandDefaultFlight parity) 2026-04-20 12:31:15 +03:00
gnezim 6d87521634 ScheduleFilter: constrain Calendar to ±1/+330 day window (Angular scheduleMin/MaxDate parity) 2026-04-20 12:24:57 +03:00
gnezim 62d3d68c1b ScheduleFilter: wire time range slider to schedule URL + seed from URL 2026-04-20 12:21:04 +03:00
gnezim 0c1701086d Upgrade Schedule prefill codes to CitySuggestion objects once dictionaries load
ScheduleStartPage previously stored the raw IATA code from the prefill
in departureAirport / arrivalAirport state, so PrimeReact's AutoComplete
would render 'MOW' (or 'SVO' before the prior commit) literally in the
input. Now, once dictionaries resolve, the effect replaces each string
slot with a { code, name } object so the autocomplete shows 'Москва'.

Mirrors Angular CityAutocomplete.writeValue → getCityOrAirport, which
upgrades the bound string to a CityModel for display while keeping the
code as the outbound form value.
2026-04-20 11:44:38 +03:00
gnezim af473f9877 Resolve popular-request airport codes to city codes before prefill
Popular-requests API returns mixed airport (SVO) and city (MOW) IATA
codes. Clicking a "Шереметьево → Санкт-Петербург" entry used to paste
SVO into the departure field, leaving a specific airport pinned even
though the visible label already resolves to the owning city name.

Both start pages now route request.departure/arrival through
getCityCodeByAirportCode(dictionaries, code), so the filter form seeds
with MOW instead of SVO (and falls back to the raw code when
dictionaries aren't loaded yet). buildOnlineBoardPrefillState takes
an optional dictionaries arg for the same reason.

ScheduleStartPage.test mocks @/shared/dictionaries/index.js to preserve
the existing assertions (which expect unresolved codes).
2026-04-20 11:37:27 +03:00
gnezim 706b8f444b Clear the last 19 lint warnings — make check now passes clean
- BuyTicketButton / FlightsMiniListItem: narrow firstLeg/lastLeg with
  explicit null guards (throw / return '').
- FlightSchedule.tsx: `match?.[1] ?? iso` for the regex capture.
- OnlineBoardSearchPage + schedule/api: `split('T')[0] ?? iso` for the
  date-prefix extraction.
- ServicesPanel: icon lookup uses a third '' fallback instead of `!`.
- buildCountryCityRows: explicit `break` if cities[i] is undefined.
- useAppSettings: `match?.[1]` null-check before parseInt.
- datetime/index.ts: guard bare HH:MM capture groups together.
- ScheduleDetailsCatchAllRoute: drop unused `t` + useTranslation import.
- ScheduleDetailsPage.tsx: prefix unused `getLegs` with underscore.
- 4 seo/json-ld tests: drop now-redundant eslint-disable comments.
- calendarRange.test + api.test: prefix unused helper names with `_`.

Warning count: 19 → 0. make check (typecheck + lint + test) exits 0.
2026-04-20 09:30:34 +03:00
gnezim 298f007463 Drop 11 non-null assertions in api.ts, DayGroupedFlightList, FlightCard
Regex capture groups and array boundary accesses replaced with nullish
fallbacks / explicit guards. Warning count: 41 → 30.
2026-04-20 09:19:14 +03:00
gnezim 1fc96b603e Drop 14 non-null assertions in ScheduleFlightBody + CityPickerPopup
- ScheduleFlightBody.tsx: hms regex capture uses `?? "0"` fallback;
  inline IIFEs expose last-leg and transfer-to-next in narrowed scope.
- CityPickerPopup.tsx: row.city1/city2/city1Airports are lifted into
  locals so the narrowing survives into JSX event handler closures.

Warning count: 55 → 41.
2026-04-20 08:33:33 +03:00
gnezim a982d9a669 Fix lint: route sessionStorage through shared storage module, drop dead imports
- storage.ts: add sessionStore wrapper (getRaw/setRaw/delete/clear) so
  transientPrefill + ScheduleStartPage tests don't trip the
  no-restricted-globals rule.
- transientPrefill.ts + ScheduleStartPage.test.tsx: use sessionStore.
- closestFlight.ts: hoist bracket-index key so no newline-before-[ ASI.
- Test files: hoist typeof import(...) into named type alias with
  type-only namespace import.
- Drop unused imports: FlightCard (Link, languageToLocale),
  OnlineBoardDetailsPage (operatingCarrier),
  ScheduleSearchPage (FlightList, inline import() types),
  PageLayout (FeedbackButton).
- Drop react-hooks/exhaustive-deps disable comments for a rule not
  registered in eslint.config.js.
2026-04-20 08:15:21 +03:00
gnezim 68e7b3e9ec Normalize 4/6/8px radii to vars.$border-radius (3px) across 5 SCSS files 2026-04-20 07:10:12 +03:00
gnezim ef845f587f Final token sweep: pastel blues, blues, greys to design tokens (8 files) 2026-04-20 06:14:55 +03:00
gnezim 94e7180a2f Use colors.$white token across schedule components (6 files) 2026-04-20 05:16:56 +03:00
gnezim d960e469ed Use colors.$white token for ScheduleFlightBody backgrounds/button text 2026-04-20 04:53:23 +03:00
gnezim c8257baf26 Replace border-radius: 4px with vars.$border-radius (3px) to match Angular 2026-04-20 04:26:19 +03:00
gnezim 627f155f87 Replace #022040/#1a3a5c navy hex with colors.$blue-dark token 2026-04-20 04:21:47 +03:00
gnezim 2d7646d793 Replace custom brand hex with design tokens ($blue, $orange, $green, $red) across 13 SCSS files 2026-04-20 04:19:43 +03:00
gnezim fb82fc6ad1 Replace pastel-blue dividers/bg with $border and $blue-extra-light tokens (6 files) 2026-04-20 03:58:13 +03:00
gnezim 4aadab25e9 Normalize body-text #222 to colors.$text-color across 10 SCSS files 2026-04-20 03:50:54 +03:00
gnezim 1156dd6f90 Replace hardcoded #6b7280/#1c2330/#8a8a8a greys with design tokens ($light-gray/$text-color) 2026-04-20 03:02:10 +03:00
gnezim 353bd62296 Render branded 404 page on invalid URLs and malformed params
Replace the inline 'Invalid parameters' fallbacks and the framework's
default '404' text with the existing Aeroflot 404 screen. Unknown
locale, malformed flight/route/station params, and unmatched URLs
(including bad paths like onlineboard//route/...) now all land on the
same ErrorPage component.
2026-04-20 02:23:16 +03:00
gnezim 4095344b7b Revert "Convert schedule WeekTabs to day-of-week strip"
This reverts commit c097ab21fe.
2026-04-20 01:38:12 +03:00
gnezim c097ab21fe Convert schedule WeekTabs to day-of-week strip
Angular's schedule renders 7 day pills ("20 пн … 26 вс") spanning the
active week, not weekly date ranges. Match that: tabs now render the
seven days of selectedMonday's week with day-num + weekday-abbr stack.
Prev/next arrows shift by full weeks. Day clicks scroll to the
matching day group in DayGroupedFlightList for the schedule UX.
2026-04-20 01:29:53 +03:00
gnezim f1f0030b69 Auto-expand today's day group + dynamic dates in visual diff
Schedule list day accordion stays collapsed by default but auto-
opens the day matching today's date when it's in the visible week
window — mirrors Angular's p-accordion default-active behaviour
where today's flights are visible without a click. The user can
still collapse it; we never re-open after that for the same date.

Visual-diff URLs were hardcoded to a past date with the wrong React
URL format (Angular path-style /AAQ/16042026 instead of React's
single-segment /AAQ-20260420-00002400). Switch to dynamic
yyyyMMdd of today for onlineboard pages and Mon→Sun of the current
week for schedule. Schedule-route diff dropped from ~91% to ~28%
on desktop after these two fixes.
2026-04-20 01:17:58 +03:00
gnezim 9cdc8fd75b Default schedule day groups to collapsed
Match Angular's p-accordion default-collapsed state on the schedule
results page. State now tracks expanded days (default empty)
instead of collapsed days (default empty), so the initial render
shows day headers only and the user clicks to reveal flights.
2026-04-20 00:35:44 +03:00
gnezim e05ef1ca20 Render rich Schedule details page + fix broken SEO key
Schedule details page used to show only a one-line FlightCard and
stop. Reuse ScheduleFlightBody so each flight in the chain renders
the same per-leg layout the schedule results page uses (route
summary, leg cards, transit pill, share/Купить/Детали рейса
actions). Add a `Вернуться к Расписанию` back link to the header.

While here, fix the SEO title key — buildScheduleDetailsSeo was
calling SEO.SCHEDULE.DETAILS.TITLE with `flights={...}`, but the
i18n bundle only defines SEO.SCHEDULE.FLIGHT-DETAILS.TITLE with
`flightNumber={...}`. The unresolved key was leaking into the
document title as "SEO.SCHEDULE.DETAILS.TITLE".
2026-04-20 00:30:39 +03:00
gnezim b21ae2638b Add Туда/Обратно direction switch to round-trip schedule page
Round-trip schedules used to render outbound and inbound lists
stacked. Mirror Angular's schedule-direction-switch: keep both
fetches running, but render only the active direction's list and add
a button group to the sticky header that swaps which one is shown.
WeekTabs track the active direction's week independently, and tab
navigation updates whichever direction is currently active.
2026-04-20 00:21:20 +03:00
gnezim ddc8e9f6dc Wire Вы искали sidebar accordion to live search history
Each schedule + onlineboard search now records itself into the
existing useSearchHistory localStorage hook, with a structured
params payload (departure/arrival/dates/flightNumber). The
SearchHistory sidebar renders the rich Angular layout: clock or
plane icon, optional sub-title (e.g. "Расписание рейсов, в одну
сторону"), city pair, and date range, with inbound dates appended
for round-trip searches.
2026-04-20 00:12:58 +03:00
gnezim d6ef3c8433 Render Angular schedule expanded body in React
Schedule flight cards now expand into the rich Angular layout instead
of the online-board time/transition rows. Mirrors connecting-flight-
body / multi-flight-body: horizontal timeline summary, per-leg card
with section number + flight number + operator + aircraft + dep/arr
times + leg duration + stations, transfer-inline-extended pill
between legs (Пересадка, ground time, transit city), and the actions
row (share, Купить, Детали рейса).

Wired via a renderExpandedBody render prop on FlightCard/FlightList so
ui/flights doesn't need to know about schedule-specific bodies.
2026-04-20 00:01:24 +03:00
gnezim 8bf672f3fa Schedule-specific sidebar (ScheduleFilter)
Replace OnlineBoardFilter on schedule pages with a dedicated
ScheduleFilter that matches Angular's schedule-filter:
- Город вылета / Город прилета with swap arrows
- 'Показать расписание на' date range picker
- 'Время вылета' time slider
- 'Только прямые рейсы' checkbox (sets connections=0)
- 'Показать обратные рейсы' checkbox
- 'Показать расписание' submit button (blue, full-width)

The OnlineBoardFilter accordion (Номер рейса + Маршрут tabs) is no
longer rendered on schedule pages — Angular only ships flight-number
search on the online-board side.
2026-04-19 23:36:05 +03:00
gnezim d74061e03b Sortable schedule columns + collapsible day accordion
Add sort arrows on ВЫЛЕТ / ВРЕМЯ В ПУТИ / ПРИЛЕТ headers — clicking
toggles ascending/descending order; clicking again clears the sort.

Day groups (Понедельник 20 апреля, etc.) are now collapsible via the
header chevron — matches Angular's p-accordion structure where each
day is an accordionTab. Default state expanded.
2026-04-19 23:29:48 +03:00
gnezim 4c487ab1b2 Render Connecting flights + Angular grid for schedule rows
- Connecting (multi-leg via transit) flights are now folded into a
  synthetic MultiLeg shape with combined flight numbers (SU 6188,
  SU 6233) and per-leg airline logos, matching Angular's
  schedule-list-flight-header.

- Schedule grid now uses Angular's 8-column layout
  (80/120/100/240/100/100/240/16). The middle status icon is
  replaced by a duration column with the blue clock icon and
  '3ч. 48мин.' / '4h 19m' formatting.

- Multi-leg airline logos use the round badge variant (separate
  round.png assets) so two carriers fit side-by-side without overlap.

- Action buttons removed from collapsed rows — Angular only shows
  flight-actions in the expanded body. Added chevron column for
  every schedule card and made schedule cards expandable by default.

- Removed 'Туда: MOW → KUF' subhead from outbound section, matching
  Angular's bare flight list under the column header.
2026-04-19 23:24:06 +03:00
gnezim 27b1ab1329 Schedule start: empty date-range placeholder
ScheduleStartPage now starts dateFrom/dateTo as null so the input
shows the `ДД.ММ.ГГГГ - ДД.ММ.ГГГГ` placeholder Angular ships
instead of pre-filling with the current week. The submit handler
defaults to current-week range when the user submits without
picking dates, preserving the legacy "find this week" UX.

Same pattern as the onlineboard date fix.
2026-04-19 21:52:03 +03:00
gnezim 71d0eef3e2 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).
2026-04-19 21:44:19 +03:00
gnezim 69706e023d Schedule + flights-map structural parity
- flights-map: default departure to Москва (MOW) when geolocation
  doesn't yield a city. Mirrors Angular which seeds the orange
  marker on Moscow regardless of geo permission. Hook now has two
  effects — a synchronous MOW fallback that fires once dictionaries
  load, and the existing geo callback that may upgrade to a closer
  city when permission is granted.
- Schedule: introduce DayGroupedFlightList. Buckets the flat result
  list by scheduled-departure date and renders each group under a
  `Воскресенье 19 Апреля`-style header (Intl-driven, weekday +
  genitive month). Single-day result skips the grouping noise.
- Schedule: introduce WeekTabs. Replaces the daily DayTabs in the
  schedule sticky-content with Monday-anchored 7-day windows like
  `13 апр - 19 апр`, matching Angular's week-tabs component.
  handleWeekChange recomputes both dateFrom (Monday) and dateTo
  (Sunday) when the tab changes.
- Schedule: aircraft model now visible in the collapsed FlightCard
  row when `direction === "schedule"` (Sukhoi SuperJet 100 / Airbus
  A321 etc., per Angular's operator-logo-and-model column).
- FlightCard / FlightList: extend `direction` union with `"schedule"`.

Tests updated: useGeolocationDefault tests now assert the MOW
fallback fires when permission is denied / API missing / arrival
already set (was previously expected to no-op).
2026-04-19 20:52:41 +03:00