Angular's FlightsMapFiltersStateService.setDeparture(undefined) also
resets domestic/international/connections to false — none of them make
sense without a departure anchor. React now mirrors that reset on clear
so a re-opened filter doesn't show phantom 'on' toggles.
Also added a `title` attribute on each disabled toggle that points
users to the missing city input. The toggles are still disabled (per
Angular behavior) but the hint explains *why* they can't be toggled,
which was the source of confusion in the 'feature not fully
implemented' report.
Previously hasValue was computed from `selectedCity` — which required
the dictionaries to be loaded AND the raw code to map to a known city.
If the dictionaries were slow or the user typed free text, the clear
button stayed hidden and the filter became stuck with no way to wipe it.
Angular's CityAutocomplete uses `[ngClass]="{'has-value': city}"` on
the raw two-way-bound model, so any truthy value reveals the clear
button. Mirror that: `hasValue` is now true whenever the resolved
city, the outbound code, or the AutoComplete inputValue (free text or
suggestion object) is truthy.
Previously handleRouteSubmit required both fields and returned silently
when only one was filled. Angular's
OnlineBoardUrlBuilderService.getRoutePageUrl switches on which side is
populated, routing to /onlineboard/departure/{dep}-{date} or
/onlineboard/arrival/{arr}-{date} for one-sided searches. React now
mirrors the same branch and only no-ops when neither side is filled
(matching Angular's `if (!departure && !arrival) return;` in
OnlineBoardFilterService.toRoutePage).
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.
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).
- ErrorPage.tsx: FALLBACK_CONFIG literal instead of ERROR_CONFIG["500"]!
- ErrorBoundary.tsx: hoist FALLBACK_RU / FALLBACK_EN to consts so
pickStrings returns them without the bang.
- routesToPolylines.ts: narrow spider-mode block on filterState.departure
truthy; guard each route-code lookup.
- FlightsMapStartPage.tsx: narrow firstRoute/depCode/arrCode together
instead of asserting each individually.
- OnlineBoardDetailsPage.tsx: IIFE over legs[i+1] for TransferBar;
`_canonicalOrigin` prefix for currently-unused prop.
Warning count: 30 → 19.
- 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.
Replace `zoomLayers[c]![t]!` patterns with explicit null-guard
`continue` branches. The dimensions (2×5) are still initialized the
same way; the narrowing just makes the linter happy without changing
runtime behavior. Warning count: 65 → 55.
- eslint.config.js: disable no-non-null-assertion for *.test.ts/tsx and
tests/** (fixture-driven tests routinely use arr[0]! after a length
check — signal there is low).
- closestFlight.ts: replace flights.legs[0]! / flights[flights.length-1]!
with explicit null checks.
- FlightDetailsAccordion.tsx: refactor transition + meal/service
branches to use local consts narrowed by a preceding truthy check,
dropping the `leg.transition!.registration!` patterns.
Warning count: 190 → 65. Remaining warnings are pre-existing production-code
non-null assertions spread across the codebase.
- 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.