# 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` |