Files
flights_web/docs/superpowers/plans/2026-04-15-phase-2a-ui-adapter.md
T
gnezim fc03c08278 Add Phase 2A UI adapter implementation plan
Covers data model types, datetime utilities, dictionary hook,
and flight display components for the online board feature.
2026-04-15 07:52:23 +03:00

3.8 KiB

Phase 2A -- UI Adapter Layer

Sub-plan of Phase 2 (Online Board). Implements the flight-display component library at src/ui/flights/ and supporting utilities.

Depends on: Phase 1 (foundation complete). Consumed by: 2C (API hooks use types), 2E (pages compose components).


Tasks

Task 1: Data model types (src/features/online-board/types.ts)

Port the key Angular interfaces to minimal React-friendly TypeScript types. Source analysis:

  • Angular ISimpleFlight = IDirectFlight | IMultiLegFlight (ClientApp/src/typings/flight/flight.ts)
  • IFlightLeg with stations, times, status (ClientApp/src/typings/flight/flight-leg.ts)
  • IFlightLegStation with IAirportInfo (ClientApp/src/typings/flight/flight-station.ts)
  • ITimesSet with dayChange, local, utc, tzOffset (ClientApp/src/typings/times.ts)
  • FlightRequestType enum mapping from Angular RequestMode (ClientApp/src/typings/enums.ts)
  • IParsedFlightId (ClientApp/src/typings/flight/flight-id.ts)
  • IBoardResponse, IDaysResponse (ClientApp/src/typings/responses.ts)

Flatten into idiomatic TS -- no class hierarchies, no Angular deps.

Test: Type-level tests (compile-time satisfaction checks) in src/features/online-board/types.test.ts.

Task 2: Datetime utility functions (src/shared/utils/datetime/)

Pure functions ported from Angular pipes:

  • formatDuration(minutes: number): string -- from DurationPipe logic
  • formatTime(date: string | Date): string -- "HH:mm" format
  • formatDate(date: string | Date, locale?: string): string -- localized date string
  • isDayChange(scheduledDate: string | Date, actualDate: string | Date): number -- day offset

Test: src/shared/utils/datetime/datetime.test.ts -- TDD, write tests first.

Task 3: Airport/city dictionary hook (src/shared/hooks/useDictionaries.ts)

  • useCityName(code: string): string -- returns city name for IATA code
  • Phase 2 stub: returns the code itself (passthrough) with TODO for real API
  • Angular source: DictionariesService fetches from networkService.getDictionary('cities') -- API endpoint TBD from customer

Test: src/shared/hooks/useDictionaries.test.ts -- verify passthrough behavior.

Task 4: StationDisplay.tsx component

Renders airport IATA code + city name. Uses useCityName hook.

Props: { airportCode: string; airportName?: string; cityName?: string }.

No test (UI component -- visual testing in 2G).

Task 5: TimeGroup.tsx component

Displays scheduled + actual times with day-change indicator.

Props: { scheduled: string; actual?: string; dayChange?: number; label?: string }.

Uses formatTime utility.

Task 6: FlightStatus.tsx component

Status badge with semantic styling.

Props: { status: FlightStatus }.

Maps status to display label + CSS class.

Task 7: DurationDisplay.tsx component

Flight duration display.

Props: { minutes: number }.

Uses formatDuration utility.

Task 8: FlightCard.tsx component

Composes Station + TimeGroup + Status + Duration into a flight row.

Props: { flight: ISimpleFlight }.

Task 9: FlightListSkeleton.tsx component

Loading placeholder for flight list. Renders N placeholder rows with CSS animation.

Props: { count?: number }.

Task 10: FlightList.tsx component

List of FlightCards with loading state.

Props: { flights: ISimpleFlight[]; loading?: boolean }.

Uses FlightListSkeleton when loading.

Task 11: Update barrel exports

  • src/ui/flights/index.ts -- export all components and types
  • src/ui/index.ts -- re-export from ./flights

Exit criteria

  • pnpm typecheck green
  • pnpm lint green
  • pnpm test green with datetime utility tests + type satisfaction tests + dictionary hook test passing
  • No Angular dependencies in any new file
  • All components are pure functional React components with typed props