Commit Graph

714 Commits

Author SHA1 Message Date
gnezim 63fc6060f2 Verify day-change algorithm per TZ 4.1.17 (per-time-type badges, query-date baseline)
R4 gap fixed: TimeGroup now accepts scheduledDayChange + actualDayChange props
separately so each time type renders its own independent badge. FlightCard
updated to pass them independently (scheduled vs actual/estimated); expanded
row time block also now shows per-type badges.

R5 tooltip fixed: dayChangeBadgeTooltip() uses string-based date extraction
(no TZ reprojection via new Date()) — avoids viewer-TZ shift for SSR and
cross-TZ correctness. Returns "День" for ±1, DD.MM.YYYY for ±2+.

New shared helper dayChange.ts exports computeDayChange(), dayChangeBadgeTooltip(),
formatDayChangeBadge(). 27 unit tests cover +0/+1/+2/-1/-2, null, malformed
input, month/year boundaries, and per-time-type independence (R4).

R1–R3, R6 confirmed correct (API supplies dayChange per ITimesSet; badge
adjacent to time; hidden when 0). R8 (mobile tooltip suppression) deferred.
2026-04-22 00:01:30 +03:00
gnezim 5d31f4389e Add operator icon mapping helper per TZ §4.1.22
Extracts the 35-carrier logo path table from OperatorLogo into a shared
pure module (src/shared/operatorIcon.ts) so the mapping can be tested and
reused independently. Adds the 7-range SU flight-number fallback that the
TZ requires when OperatingBy is null — SU5000-5399 shows Pobeda (DP),
SU5400-5799 shows Aurora (HZ), SU6000-6999 shows Rossiya (FV), and the
3000-4999 / 5800-5999 bands explicitly render no logo.

63 table-driven tests lock in every range boundary and carrier entry.
FlightCard and ScheduleFlightBody both apply the range resolution before
falling back to the flight's own carrier code.
2026-04-21 23:54:00 +03:00
gnezim b43c341fcb Add "Уточняется" fallback helper + orange styling per TZ 4.1.23 2026-04-21 23:49:10 +03:00
gnezim df83a587c2 Populate rule rows for P5 subsections 4.1.15/16/17/22/23 in TZ audit spec 2026-04-21 23:45:57 +03:00
gnezim 27fd4ac601 Add P5 implementation plan: flight cards + timeline + aircraft icons + Уточняется 2026-04-21 23:36:46 +03:00
gnezim 8c8022780f Mark P4 (results lists) rules Done in TZ audit spec
32 rules Done + ~142 Implemented across §4.1.13/14. 4 Partial (multi-seg
status-switching, check-in counter, airport-as-link on segment dep/arr).
7 TBD(P5) deferred (airport-as-link OB+Schedule collapsed/expanded,
online check-in button). C8 registered and resolved (week-tabs active
range +210→+330 days). Coverage: 317 Done, ~191 Implemented, 6 Partial,
~138 TBD.
2026-04-21 23:35:11 +03:00
gnezim f6def717b5 Verify sticky behavior + scroll-up button per TZ Table 22
PageLayout.test: assert header/breadcrumbs/title stay outside sticky
wrapper, filter column carries __column-left (CSS sticky on desktop),
stickyContent (day-tabs) gets __sticky-content wrapper, overlay only
when stickyContent present.

ScrollUpButton.test: assert button hidden below 300px threshold, visible
above it, disappears on scroll-back, correct aria-label/type, listener
cleaned up on unmount.

All 27 tests pass; no implementation changes needed — React matches
Angular reference behavior exactly.
2026-04-21 23:21:37 +03:00
gnezim 4290c819bb Audit Schedule expanded rows per TZ 4.1.14.4 (multi-segment + connecting)
Gate Buy button to the TZ §4.1.14.4.4 window: visible only when departure
UTC is > 2 hours ahead AND < 330 days ahead; first leg governs for multi/
connecting. Gate Status button (§4.1.14.4.5) to same-day departure only,
based on UTC calendar date. Add separate Details button (§4.1.14.4.6) that
is always visible when an onStatus handler is provided. Add SCSS for the
new details-btn outline style. Add 25-test ScheduleFlightBody.test.tsx
covering structure, transfer-box labels, buy gate, and status gate.
2026-04-21 23:18:16 +03:00
gnezim 6f67c06786 Audit Schedule week-tabs + collapsed row per TZ 4.1.14.1 + 4.1.14.3
WeekTabs (§4.1.14.1):
- Fix active range: derive weeks from scheduleWindowBounds() [-1,+330 days]
  instead of hardcoded WEEKS_AFTER=30 (≈210 days, less than required 330).
- Fix auto-scroll: sync page via useEffect when selectedMonday prop changes
  so navigating to a different week always reveals its tab.
- Add fill-to-7: pad last page with disabled placeholder tabs when the
  final active week does not end a complete group of 7; disable next arrow.

Collapsed row (§4.1.14.3): already implemented — add lock-in tests for
Tables 36–40 (direct / multi-leg / connecting) covering flight number,
operator logos (round for multi-leg per commit 3ae59da), dep/arr times,
day-change chips, duration column, expand chevron, and DayGroupedFlightList
day-grouping + column headers.
2026-04-21 23:11:32 +03:00
gnezim 9f6623786f Audit Online-Board expanded row per TZ 4.1.13.4
Gap audit against §4.1.13.4.3 (Tables 29/30) found that the inline
boarding/deboarding row in FlightCard's default expanded body was
missing three attributes:
- departure.gate / arrival.gate (boarding gate number)
- departure.dispatch (трап/автобус transfer type)
- arrival.bagBelt (baggage belt, deboarding only)

Add all three as conditional fields in the transition block, guarded
by the existing isArrival flag so departure shows gate+dispatch and
arrival shows gate+bagBelt. Add DETAILS.DISPATCH i18n label (ru + en).
Add 16 assertion tests covering time rows, transition status/times,
gate, dispatch, bagBelt, and the share/details buttons.

Deferred (DONE_WITH_CONCERNS):
- Check-in counter number: API type has checkingStatus string but no
  counter number field; requires backend extension.
- Aircraft tail number: field (aircraft.registration) exists in types
  but is only shown in the details-page AircraftPanel, not in the
  FlightCard expanded body; deferred to details-page parity task.
- Code-share chips in expanded segment body: currently merged into the
  collapsed header number column via _childFlightIds; per-segment
  expanded display deferred to multi-leg task.
2026-04-21 23:02:55 +03:00
gnezim 3b5ae9af85 Audit Online-Board collapsed row per TZ 4.1.13.3 Tables 23-27 2026-04-21 22:55:49 +03:00
gnezim 8b0d559df9 Implement Online-Board flight-list default sort per TZ §4.1.13.2
Departure/route/flight-number modes sort by scheduled departure time;
arrival mode sorts by scheduled arrival time (last leg for MultiLeg).
Day ordering (yesterday < today < tomorrow) emerges from absolute ISO
timestamps — no bespoke bucketing needed. Flights missing a timestamp
are pushed to the end. 18 unit tests lock the contract in.
2026-04-21 22:48:39 +03:00
gnezim 439624244d Audit DayTabs behavior per TZ 4.1.13.1 (7-day window, paging, padding, active range)
- Fix daysAfter: 7→14 in OnlineBoardSearchPage (TZ active range is today-1 to today+14)
- Add inactive padding tabs on the last page when it has fewer than 7 slots; right-arrow stays disabled on last page regardless (TZ §4.1.13.1)
- Add aria-current="date" to active DayTabButton for accessible highlight (TZ requires visual highlight + screen-reader signal)
- Add auto-scroll via scrollIntoView when selectedDate changes externally (URL-driven day navigation)
- Convert DayTabButton to forwardRef to support the activeBtnRef scroll anchor
- 9 new TZ-labelled tests locking in all the above behaviors
2026-04-21 22:45:08 +03:00
gnezim 38a512004f Add scroll-to-current-time + auto-expand-nearest on Online-Board today's tab per TZ 4.1.13
- New findNearestFlightIndex helper (scrollToCurrentTime.ts) with 5 unit tests
- FlightList: lock scroll-to-nearest behind a ref so live SignalR updates
  don't yank the viewport back to the auto-selected flight after the user
  has manually scrolled elsewhere
- OnlineBoardSearchPage integration tests: verify today/future/past tab
  selection logic via findClosestFlightId (the id-based variant already
  wired to FlightList.initialCurrentFlightId)
2026-04-21 22:39:33 +03:00
gnezim 4fd1b054a4 Populate rule rows for P4 subsections 4.1.13/14 in TZ audit spec 2026-04-21 22:34:32 +03:00
gnezim 890d575e88 Add P4 implementation plan: results lists (Online-Board + Schedule) 2026-04-21 22:25:06 +03:00
gnezim 793637ffc3 Mark P3 (filter + validation + history + search execution) rules Done in TZ audit spec 2026-04-21 22:21:09 +03:00
gnezim a5c64a2270 Search execution, cancellation, and error handling per TZ §4.1.10/11/12
- AbortController wired through ApiClient → api functions → hooks so a
  new search immediately aborts the previous in-flight request (§4.1.12)
- cancel() exposed from useOnlineBoard / useScheduleSearch; Escape key
  triggers it while the loader is showing (§4.1.12)
- «Отменить поиск» button rendered during loading; hides when idle (§4.1.12)
- data-searching attribute on search pages disables filter/tabs/breadcrumbs
  via pointer-events:none CSS while a search is running (§4.1.10/11)
- Submit buttons disabled for 30 s after each search (hardcoded, per TZ
  §4.1.10/11: «не должно выноситься в конфигурационный файл»)
- Per-status error messages: BOARD.ERROR-TIMEOUT / ERROR-4XX / ERROR-5XX
  replace the generic LOAD-FAILED-MESSAGE (§4.1.10.1/11.1)
- Error messages added to all 9 locales
- 8 new tests: 3 for AbortController wiring, 5 for error banners + cancel
  button visibility
2026-04-21 22:08:11 +03:00
gnezim 2b0a7ecbe7 Audit «Вы искали» search history per TZ 4.1.9.5
TZ §4.1.9.5 requires session-scoped history ("в рамках одной сессии").
Migrate useSearchHistory from localStorage to sessionStorage so history
clears on tab close / page reload.

Add schema-validated get/set/deleteNs helpers to sessionStore in storage.ts
so the hook stays under no-restricted-globals constraints.

Fix hover style in SearchHistory.scss: TZ specifies голубая подложка with
white text/icon on hover — replace the near-white tint with the full blue.

Add TZ §4.1.9.5 assertion tests: session storage target, dedup + bump-to-top,
most-recent-first ordering, item types, empty initial state.
2026-04-21 21:55:30 +03:00
gnezim c509131649 Tighten filter validation per TZ 4.1.9.3 + 4.1.9.4 2026-04-21 21:50:46 +03:00
gnezim d173159018 Audit CityPickerPopup dictionary-picker behavior per TZ 4.1.9.2
Add keyboard navigation (ArrowDown/Up + Enter to commit highlighted item),
Escape closes the popup without committing, role=dialog + aria-activedescendant
for a11y, and city-highlighted visual feedback. All §4.1.9.2 structural rules
(grouping, RU/CIS-first, MOW-first, alpha ordering, scrollable panel, selected
highlight) confirmed by assertion tests. 14 new assertion tests added across
CityPickerPopup.test.tsx and CityAutocomplete.test.tsx.
2026-04-21 21:44:43 +03:00
gnezim dc3ee10ae8 Audit CityAutocomplete manual-entry behavior per TZ 4.1.9.1
Two gaps filled vs the Angular reference:
1. EN→RU keyboard layout translit fallback in searchCities (TZ §4.1.9.1:
   retry query converted from EN layout, e.g. "vjc" → "мос" → Москва).
2. ESC key cancels manual entry and restores the last committed value's
   display (TZ §4.1.9.1 / mirrors Angular focusOut behaviour on Escape).

All other §4.1.9.1 rules (case-insensitive search, substring match, city+
airports grouping, 3-letter code lookup, top-10 cap, alpha sort, no auto-
submit on typing, exact-match auto-commit) were already present; assertion
tests lock them in.
2026-04-21 21:40:23 +03:00
gnezim 66518a6f0c Enforce 1h minimum gap on time-range slider per TZ 4.1.9 Tables 12/14 2026-04-21 21:36:07 +03:00
gnezim 83951d4292 Add clear-button (X) to filter fields per TZ 4.1.9 Tables 11/12/14
- OB flight-number: X was always visible; now conditionally rendered only
  when the field has a value (hides when empty)
- OB flight-date and route-date: add X button next to calendar icon,
  clears date state and hides itself when empty
- Schedule outbound and return date-range calendars: same inline X pattern
- CSS: .calendar-input-wrapper + .calendar-clear-btn added to both SCSS
  files (absolute-positioned left of the calendar icon)
- CityAutocomplete: already correct (CSS show/hide via has-value class)
- 21 new tests across OnlineBoardFilter, ScheduleFilter, CityAutocomplete
  (aria-label, visibility toggling, click-to-clear); all 640 pass
2026-04-21 20:05:53 +03:00
gnezim 8f4d5fcaa2 Add Current-Week label substitution to Schedule date-range picker per TZ 4.1.9 Table 14 2026-04-21 19:59:27 +03:00
gnezim 04a3d9cd7c Add Today/Tomorrow label substitution to Online-Board date picker per TZ 4.1.9 Tables 11+12 2026-04-21 19:55:36 +03:00
gnezim ae061bcaab Populate rule rows for P3 subsections 4.1.9/10/11/12 in TZ audit spec
159 net-new concrete rules extracted from TZ Tables 11-17, §4.1.9.3-4,
§4.1.10/10.1/11/11.1/12, replacing 27 skeleton placeholder rows.
Coverage total: 283 → 494 rules. All new rows Status=TBD, Plan=P3.
2026-04-21 19:48:13 +03:00
gnezim 3b32233b88 Add P3 implementation plan: filter + validation + search history + search execution 2026-04-21 19:40:04 +03:00
gnezim 268205fc2f Stub geolocation + matchMedia in OB start-page integration test (P2 regression fix) 2026-04-21 19:35:39 +03:00
gnezim 5362d8d6c4 Mark P2 (start pages + first-entry + popular) rules Done in TZ audit spec 2026-04-21 19:32:14 +03:00
gnezim b27ee2ae8b Verify start-page info-section content per TZ Table 8 + Table 9
Add assertion tests confirming both OnlineBoardStartPage and ScheduleStartPage
render the required info-section headings and content blocks per TZ specifications.

OnlineBoardStartPage (TZ Table 8):
- Heading: 'Что такое Онлайн-табло и что я могу в нем увидеть?'
- 4 info blocks: Актуальная информация, Информация об услугах, Купить билет, Расписание

ScheduleStartPage (TZ Table 9):
- First heading: 'Как пользоваться расписанием?' + 4 info blocks
- Second heading: 'Возможности расписания' + 2 capabilities blocks
- Blocks 5-6 (Купить билет, Расписание) now rendered under capabilities heading

Tests added:
- OnlineBoardStartPage: 6 new assertions (4.1.6-R-info-heading through 4.1.6-R-popular)
- ScheduleStartPage: 8 new assertions (4.1.7-R-info-heading-1 through 4.1.7-R-popular)
2026-04-21 19:25:45 +03:00
gnezim fbb84fc0da Align Flight-Map first-entry toggle defaults with TZ 4.1.1-R14/R21 2026-04-21 19:22:16 +03:00
gnezim 4b6cb5bc40 Audit popular-requests Top-4 click-prefill against TZ §4.1.5 (6 kinds)
Board kinds (Arrival, Departure, Route, FlightNumber): buildOnlineBoardPrefillState
now emits date=today in every case; OnlineBoardStartPage wires it through to
OnlineBoardFilter via initialDate.

Schedule one-way (Route/Schedule): click handler now includes dateFrom/dateTo
= current ISO week (Mon-Sun) in the transient prefill written to sessionStorage.

Schedule round-trip (RouteWithBack/Schedule): additionally includes
returnDateFrom/returnDateTo = next ISO week.

SchedulePrefillState extended with the four new optional date fields;
yyyymmddToDate helper added to ScheduleStartPage; currentWeekBounds /
nextWeekBounds helpers implement the TZ week-boundary logic.

Nine new §4.1.5-labeled tests (4 unit + 5 integration) added; existing
prefill-state tests updated to expect the new date fields. All 55 tests pass.
2026-04-21 19:19:38 +03:00
gnezim 53b5359ad5 Align Board tab tooltip preposition to TZ-exact 'в ближайшие дни' 2026-04-21 19:14:41 +03:00
gnezim c3c1f830b9 Wire first-entry geolocation into Schedule start page (TZ 4.1.1-R8) 2026-04-21 19:11:57 +03:00
gnezim b023cb922a Wire first-entry geolocation + mobile time default into Online-Board start page (TZ 4.1.1) 2026-04-21 19:09:34 +03:00
gnezim 9aed10c281 Add useIsMobileViewport hook + Online-Board mobile time defaults per TZ 4.1.1-R4/R5 2026-04-21 19:03:54 +03:00
gnezim bc0b10bd8e Migrate flights-map to shared useGeoCityDefault hook 2026-04-21 19:01:07 +03:00
gnezim b31204c543 Add shared useGeoCityDefault hook (generalized from flights-map) 2026-04-21 18:58:23 +03:00
gnezim 2aa831e198 Populate rule rows for P2 subsections 4.1.5/6/7 in TZ audit spec 2026-04-21 18:54:13 +03:00
gnezim a6d8f43e94 Add P2 implementation plan: start pages + first-entry geo + popular sections 2026-04-21 18:50:01 +03:00
gnezim ef33b557f6 Clamp projectScheduleToBoard.date to today only when schedule dateFrom is out-of-window 2026-04-21 18:34:20 +03:00
gnezim b910fd058c Add aria-current="page" to clickable last breadcrumb (a11y fix per WAI-ARIA) 2026-04-21 18:34:16 +03:00
gnezim 8f573c15b8 Mark P1 (URLs/breadcrumbs/names/nav) rules Done in TZ audit spec 2026-04-21 18:21:51 +03:00
gnezim e935596813 Add P1 e2e coverage: URL guards + breadcrumbs + cross-section nav per TZ 4.1.2/4/8 2026-04-21 18:13:24 +03:00
gnezim ef0e1e38e5 Assert date-window clamp on Board ← Schedule projection per TZ 4.1.8-R2 2026-04-21 18:08:42 +03:00
gnezim a6454dc07f Fix exactOptionalPropertyTypes errors in cross-section store hydration initializers 2026-04-21 18:04:36 +03:00
gnezim 47fee9d7b5 Wire cross-section filter hydration into Board/Schedule/Map per TZ 4.1.8 Table 10 2026-04-21 18:03:27 +03:00
gnezim 986313248e Add cross-section navigation store with Board↔Schedule projection per TZ 4.1.8 Table 10 2026-04-21 17:57:06 +03:00
gnezim 2fe5364187 Verify TZ Table 7 Карта полетов breadcrumb = [Главная] only 2026-04-21 17:53:16 +03:00