# 03 — Shared UI & Cross-Cutting Context

## 1. High-Level Overview

**Purpose**: Reusable presentational components and the **flight selection context** that every authenticated page reads from. This is the "page chrome + flight scope" layer — the navbar, the help modal, the confirmation dialog, the detection-class picker, and the `FlightContext` provider that holds "which flight the user is currently working in".

**Architectural Pattern**: Mix of presentational components + one cross-cutting Context provider. `FlightContext` lives in `components/` (not `features/flights/`) because it is read by every feature page (Annotations, Dataset, Admin, Settings, Header).

**Upstream dependencies**: `00_foundation` (types), `01_api-transport`, `02_auth` (Header reads `useAuth`), `11_class-colors` (DetectionClasses fallback colors / names).

**Downstream consumers**: `10_app-shell` (mounts Header + FlightProvider), every feature page (consumes `useFlight()` and uses ConfirmDialog), `06_annotations` and `07_dataset` (use DetectionClasses + ConfirmDialog).

## 2. Internal Interfaces

### `src/components/Header.tsx`

| Export | Notes |
|--------|-------|
| `Header()` | Top bar: app logo, page nav links (`/flights`, `/annotations`, `/dataset`, `/admin`, `/settings`), flight-picker dropdown, language switch, user menu (logout, help). Mobile bottom-nav variant rendered conditionally (lines 113–129 per state.json correction). |

### `src/components/HelpModal.tsx`

| Export | Notes |
|--------|-------|
| `HelpModal({ open, onClose })` | Renders an in-page modal with `GUIDELINES` (currently a hardcoded string — finding: should be in i18n bundle). Esc does NOT close (inconsistent with `ConfirmDialog`). |

### `src/components/ConfirmDialog.tsx`

| Export | Notes |
|--------|-------|
| `ConfirmDialog({ open, title, message, confirmLabel, onConfirm, onCancel })` | Reusable confirm modal. Esc closes. **Missing `aria-modal` and `role="dialog"`** — finding flagged for Step 4 vs `ui_design/README.md` confirmation-dialogs spec. |

### `src/components/DetectionClasses.tsx`

| Export | Notes |
|--------|-------|
| `DetectionClasses({ value, onChange, ... })` | Detection-class picker grid. Loads classes from `GET /api/annotations/classes`. Number-key shortcuts 1–9 select `classes[idx + photoMode]` — ordering against the annotations service contract is unverified (Step 4). Imports from `11_class-colors` for fallback color and name (current physical path: `src/features/annotations/classColors.ts` — file location is misplaced; see `11_class-colors` §7 for refactor target). |

### `src/components/FlightContext.tsx`

| Export | Notes |
|--------|-------|
| `FlightProvider({ children })` | Loads flight list (paged, **`pageSize=1000` ceiling hardcoded** — finding B3) on mount. |
| `useFlight(): FlightContextValue` | hook returning `{ flights, selectedFlight, selectFlight, refresh }`. `selectFlight` is **fire-and-forget** PUT to `/api/flights/select` — no error UI. |

## 5. Implementation Details

**State Management**:
- Local component state for modals (open/closed).
- One Context provider (`FlightProvider`) holding the cached flight list and current selection.
- No global event bus.

**Routing awareness**: `Header` reads `useLocation()` to highlight the active link. `FlightProvider` does **not** persist selection across reloads.

**Accessibility** (cross-cutting findings, Step 4):
- `ConfirmDialog` — no `aria-modal` / `role="dialog"` / focus trap.
- `Header` flight dropdown — no `role="combobox"`, no `aria-expanded`, no Esc-to-close, no focus trap; outside-click handler always attached.
- `HelpModal` — Esc does NOT close.

**Key Dependencies**: `react-router-dom` 7 (Header), `react-i18next`.

## 6. Extensions and Helpers

Class color / fallback name / PhotoMode suffix logic lives in `11_class-colors`. This component depends on it; it is no longer treated as a cross-layer leak — the *physical* file is misplaced (still in `src/features/annotations/`) but the *logical* dependency is a normal shared-layer dependency.

## 7. Caveats & Edge Cases

- **`classColors.ts` physical location** is `src/features/annotations/` even though it is logically a `11_class-colors` shared module. Step 4 testability candidate (file move) — does not break this component's dependency graph.
- **`FlightContext.pageSize=1000`** — silent ceiling; >1000 flights are invisible.
- **`selectFlight` fire-and-forget PUT** — server failures are invisible to the UI.
- **`Header` flight dropdown a11y gaps** — Step 4 + Step 8.
- **`HelpModal` GUIDELINES hardcoded** — Step 4 i18n.

## 8. Dependency Graph

**Must be implemented after**: `00_foundation`, `01_api-transport`, `02_auth`, `11_class-colors`.

**Can be implemented in parallel with**: nothing critical inside the workspace.

**Blocks**: `10_app-shell`, every feature page (they import `ConfirmDialog`, `useFlight`, and read `Header` from the shell).

## Module Inventory

| Path | Module Doc |
|------|------------|
| `src/components/Header.tsx` | `_docs/02_document/modules/src__components__Header.md` |
| `src/components/HelpModal.tsx` | `_docs/02_document/modules/src__components__HelpModal.md` |
| `src/components/ConfirmDialog.tsx` | `_docs/02_document/modules/src__components__ConfirmDialog.md` |
| `src/components/DetectionClasses.tsx` | `_docs/02_document/modules/src__components__DetectionClasses.md` |
| `src/components/FlightContext.tsx` | `_docs/02_document/modules/src__components__FlightContext.md` |
