Documents the Angular feature analysis and sub-plan breakdown for porting popular-requests to React with useSearchHistory hook.
6.5 KiB
Phase 5 — Popular Requests MASTER Plan
This document is a plan INDEX, not an executable plan. It lists the Phase 5 sub-plans, their dependency order, the contracts each sub-plan exports for downstream sub-plans to consume, and the shared files that cross sub-plan boundaries.
Goal of Phase 5: Port the Popular Requests feature from Angular to React, wire it into existing route pages, implement the useSearchHistory hook backed by @/shared/storage, and verify SEO + parity. Popular Requests is an embedded component (not a standalone routed page) — used inside the OnlineBoard and Schedule start pages. It also includes the language switcher (ported from Angular layout) and a per-language-namespaced search history hook.
Phase 5 exit gate (must pass before next phase starts):
PopularRequestsPanelrenders correctly with all 5 request modes:FlightNumber,Route,Arrival,Departure,RouteWithBack.usePopularRequestshook callsGET /Requests/1/getpopularand handles loading/error states.useSearchHistoryhook persists search history via@/shared/storagewith per-language namespacing (afl_history_{lang}).- No direct
localStorageaccess outsidesrc/shared/storage.ts(enforced by ESLintno-restricted-globals). - MF expose
PopularRequests.tsxupgraded from stub to real component. - Feature barrel
src/features/popular-requests/index.tsexports all public surface. pnpm typecheck && pnpm lint && pnpm test && pnpm build:standaloneall green.
Angular source analyzed:
- API:
GET /api/Requests/1/getpopularreturnsIPopularRequest[](union of 4 discriminated types keyed byRequestMode). - Types:
RequestModeenum:FlightNumber | Route | RouteWithBack | Departure | Arrival.IPopularRequestType:'Schedule' | 'Onlineboard'.IPopularRequest= union ofIPopularRouteRequest | IPopularArrivalRequest | IPopularDepartureRequest | IPopularFlightNumberRequest. - Components:
PopularRequestsComponent(container, fetches data, handles clicks + navigation),PopularRequestComponent(switch by mode),ArrivalRequestComponent,DepartureRequestComponent,FlightNumberRequestComponent,RouteRequestComponent,RequestInfoComponent(styled clickable span). - Behavior: On click, populates filter state in
OnlineBoardFiltersStateService/ScheduleFiltersStateServiceand navigates toonlineboardorscheduleroute. UsescityNamepipe (maps IATA code to city name via dictionaries). - Search History:
SearchHistoryService— in-memory array ofISearchHistoryItemwith dedup-by-URL and prepend logic. Displayed on start pages. React version should persist to localStorage via@/shared/storage. - No dedicated route — embedded inside
OnlineBoardStartPageandScheduleStartPage.
Sub-plan inventory
| ID | Sub-plan | Estimated size | Description |
|---|---|---|---|
| 5A | Types + API + hooks | Small (8-12 tasks) | PopularRequest types, getPopularRequests API fn, usePopularRequests hook |
| 5B | Route page + components | Medium (12-18 tasks) | PopularRequestsPanel, mode-specific sub-components, MF expose update |
| 5C | SEO + parity + integration tests | Small (6-10 tasks) | Verify no SEO regression, integration tests for the panel |
| 5D | Search history hook | Small (8-12 tasks) | useSearchHistory with per-language localStorage namespacing via @/shared/storage |
Dependency graph
┌──────────────────────────────┐
│ 5A Types + API + hooks │
│ src/features/popular- │
│ requests/{types,api,hooks} │
└──────────────┬───────────────┘
│
┌──────────────▼───────────────┐
│ 5B Components + MF expose │◄── depends on 5A types/hooks
│ src/features/popular- │
│ requests/components/ │
│ src/mf/expose/ │
└──────────────┬───────────────┘
│
┌──────────────▼───────────────┐
│ 5C SEO + parity + tests │◄── depends on 5B components
└──────────────────────────────┘
┌──────────────────────────────┐
│ 5D useSearchHistory hook │ (independent of 5A-5C)
│ src/shared/hooks/ │
└──────────────────────────────┘
5D is independent and can be executed in parallel with 5A-5C.
Contracts exported per sub-plan
5A — Types + API + hooks
Files created:
src/features/popular-requests/types.ts—RequestMode,PopularRequestType,PopularRequestunion, sub-typessrc/features/popular-requests/api.ts—getPopularRequests(client: ApiClient): Promise<PopularRequest[]>src/features/popular-requests/api.test.ts— API function testssrc/features/popular-requests/hooks/usePopularRequests.ts— React hook wrapping the API callsrc/features/popular-requests/index.ts— barrel update
Consumed by: 5B (types + hook), 5C (tests)
5B — Components + MF expose
Files created:
src/features/popular-requests/components/PopularRequestsPanel.tsx— container componentsrc/features/popular-requests/components/PopularRequestItem.tsx— mode-switching renderersrc/features/popular-requests/components/RequestInfo.tsx— styled clickable span
Files modified:
src/mf/expose/PopularRequests.tsx— stub replaced with real componentsrc/features/popular-requests/index.ts— barrel update
Consumed by: 5C (integration tests), route pages (OnlineBoardStartPage, ScheduleStartPage)
5C — SEO + parity + integration tests
Files created:
src/features/popular-requests/components/PopularRequestsPanel.test.tsx— component tests
Consumed by: Exit gate verification
5D — Search history hook
Files created:
src/shared/hooks/useSearchHistory.ts— hook with per-language localStorage namespacingsrc/shared/hooks/useSearchHistory.test.ts— hook tests
Files modified:
src/features/popular-requests/index.ts— re-export if appropriate
Consumed by: Start pages (OnlineBoardStartPage, ScheduleStartPage) in future integration