Commit Graph

552 Commits

Author SHA1 Message Date
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 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 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 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 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
gnezim 266a6f910c Fix ScheduleDetailsPage happy-path breadcrumb + add missing breadcrumb tests
The final (success) return branch was passing a hardcoded 1-item breadcrumb
array instead of the computed `breadcrumbs` variable, so the leaf crumb built
from ?request= was silently dropped for loaded flights. Loading/error/empty
branches were already correct. Adds 3 unit tests to lock the wiring.
2026-04-21 17:50:57 +03:00
gnezim 5728861c5c Schedule search → details links emit ?request= + details page shows leaf breadcrumb (TZ §4.1.2 row 11, §4.1.4 rows 11-13) 2026-04-21 17:45:36 +03:00
gnezim 12807cf085 Extend detailsRequestParam codec for area:schedule (one-way + round-trip + connections) 2026-04-21 17:42:54 +03:00
gnezim 1821f7f78e Add TZ Table 7 mode-specific leaf breadcrumb + clickable back-to-search link on Online-Board details
Per TZ §4.1.4 Table 7 rows 6–8, the details page now builds a 3-item
breadcrumb trail [Home, Онлайн-Табло, <leaf>] where <leaf> is mode-aware:
- flight: "Номер рейса: SU-1234" (hyphen per TZ)
- departure: "Вылет: {station}"
- arrival: "Прилет: {station}"
- route: "Маршрут: {dep}-{arr}"

The leaf crumb is a clickable link back to the source search page with
time-range preserved in the URL. Share-link entries (no ?request=) get
only [Home, Онлайн-Табло] with no leaf.

Breadcrumbs component updated to allow last-item links (was suppressed),
since TZ explicitly requires the leaf to be navigatable.

CONFLICT (deferred to Task 16): TZ row 6 says departure/arrival leaf
should show both dep+arr cities; parentRequest only carries one station,
so only that station is shown. Departure/arrival search returns flights
to many arrival cities — "both cities" makes no sense at search-mode level.
2026-04-21 17:35:49 +03:00
gnezim bcaf3ab503 Verify Flight-Map title 'Карта полетов' per TZ Table 6 rows 1-3 2026-04-21 17:27:18 +03:00
gnezim df4ac19f7d Branch schedule details title by direct vs connecting per TZ Table 6 rows 11-13 2026-04-21 17:24:16 +03:00
gnezim f03562e4cd Align Online-Board page titles with TZ Table 6 (сегодня/завтра/ДД.ММ.ГГГГ date display)
- Add formatDateForTitle helper: returns today/tomorrow labels or dd.MM.yyyy
- Switch all search page title builders to use formatDateForTitle; descriptions keep dd.MM.yyyy
- FLIGHT-DETAILS title now uses routeCities (no date) per TZ rows 6-8; adds TITLE-NO-ROUTE fallback for SSR when cities not yet loaded
- buildFlightDetailsSeoFromId accepts optional cityNames param
- Update ru/en i18n TITLE strings to TZ Table 6 format; add TITLE-NO-ROUTE to all 9 locales
- Tests: 32 cases covering today/tomorrow/arbitrary-date branches and routeCities logic
2026-04-21 17:18:59 +03:00
gnezim 4f840486b8 Consolidate scattered +330/+6mo date-window literals into shared dateWindow module 2026-04-21 17:09:17 +03:00
gnezim ead18fc5e5 Enforce [-1, +330] schedule window redirect guard per TZ 4.1.2-R11 2026-04-21 17:07:24 +03:00
gnezim 57d21f6a42 Enforce [-1, +14] date-window guard on Online-Board details route per TZ 4.1.2-R11
Out-of-window dates now redirect to /{locale}/onlineboard instead of rendering
stale data. Parse failures (malformed URLs) continue to 404 unchanged.
2026-04-21 17:00:22 +03:00
gnezim d633b2daa0 Enforce [-1, +14] date-window guard on Online-Board arrival route per TZ 4.1.2-R11
Out-of-window dates now redirect to /{locale}/onlineboard instead of rendering
stale data. Parse failures (malformed URLs) continue to 404 unchanged.
2026-04-21 17:00:17 +03:00
gnezim 7d6b23b5af Enforce [-1, +14] date-window guard on Online-Board departure route per TZ 4.1.2-R11
Out-of-window dates now redirect to /{locale}/onlineboard instead of rendering
stale data. Parse failures (malformed URLs) continue to 404 unchanged.
2026-04-21 17:00:12 +03:00
gnezim f2c52ca988 Enforce [-1, +14] date-window guard on Online-Board route route per TZ 4.1.2-R11
Out-of-window dates now redirect to /{locale}/onlineboard instead of rendering
stale data. Parse failures (malformed URLs) continue to 404 unchanged.
2026-04-21 17:00:07 +03:00
gnezim f5304e200e Enforce [-1, +14] date-window guard on Online-Board flight route per TZ 4.1.2-R11
Out-of-window dates now redirect to /{locale}/onlineboard instead of rendering
stale data. Parse failures (malformed URLs) continue to 404 unchanged.
2026-04-21 16:50:17 +03:00
gnezim fbd4438da0 Add boardDateRedirect guard utility for Online-Board date-window per TZ 4.1.2-R11
Shared single-purpose helper: returns redirect path when a parsed yyyymmdd
date falls outside the [-1, +14] day window, null otherwise. Six unit tests
cover both bounds, the in-window case, and locale propagation.
2026-04-21 16:44:03 +03:00
gnezim 8b22f0601f Use shared detailsRequestParam codec for mini-list parent-request (route + flight kinds) 2026-04-21 16:37:32 +03:00
gnezim 531ace6abc Add ?request= query-param codec for Online-Board details URLs per TZ 4.1.2 Table 5 row 6 2026-04-21 16:33:16 +03:00
gnezim 750a328528 Add centralized date-window constants per TZ 4.1.2-R12 (board/schedule/map) 2026-04-21 16:30:04 +03:00
gnezim 9efc76bab1 Auto-commit exact-match typed city/airport names in CityAutocomplete
Typing a full city name (or airport name) and clicking search without
picking a dropdown row previously did nothing: the parent-held city
code stayed empty and the submit handler silently short-circuited.
Exact case-insensitive name matches now resolve to the owning city
code immediately, so the Schedule and OnlineBoard start pages can act
on keyboard-only input. Partial text still requires a dropdown pick.
2026-04-21 12:19:55 +03:00
gnezim 3ae59dae1d Keep multi-leg operator logos compact (round) when schedule row is expanded
Expanding a connecting-flight row on /schedule/route used to swap the small
round airline badges in the header for the wide rectangular logo, which
overflowed the operator column and overlapped the departure time. The
header now always renders the round variant on schedule pages, regardless
of the expansion state.
2026-04-21 12:10:52 +03:00
gnezim 7577e703c2 Close SharePanel on Escape + mark as role=dialog with aria-label (a11y + PrimeNG parity) 2026-04-21 08:32:21 +03:00
gnezim 36db7d3f2e Add aria-label to OnlineBoard search forms (flight-number + route) for a11y 2026-04-21 08:30:25 +03:00
gnezim 3d815fa9e3 Add aria-label to Schedule search forms (a11y discoverable forms) 2026-04-20 23:08:55 +03:00