Add Phase 2A UI adapter implementation plan

Covers data model types, datetime utilities, dictionary hook,
and flight display components for the online board feature.
This commit is contained in:
2026-04-15 07:52:23 +03:00
parent bd9cc92766
commit fc03c08278
@@ -0,0 +1,112 @@
# 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