# 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
