Add P4 implementation plan: results lists (Online-Board + Schedule)
This commit is contained in:
@@ -0,0 +1,373 @@
|
||||
# P4 — Results Lists (Online-Board + Schedule) Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use `superpowers:subagent-driven-development` (recommended) or `superpowers:executing-plans` to implement this plan task-by-task.
|
||||
|
||||
**Goal:** Bring §4.1.13 (Online-Board results list) and §4.1.14 (Schedule results list) of TZ РИ-07-2538С into compliance. This includes day-tabs + week-tabs navigation, sort order, and the collapsed + expanded row representations for direct, multi-segment, and connecting flights.
|
||||
|
||||
**Architecture:** Results list UI is built on existing `src/ui/flights/*` primitives (`FlightCard`, `FlightList`, `OperatorLogo`, `TimeGroup`, `StationDisplay`, `DurationDisplay`, `FlightStatus`) plus feature-level components (`DayTabs`, `WeekTabs`, `DayGroupedFlightList`, `ScheduleFlightBody`, `TransferBar`). P4 is largely an **audit + gap-fill pass** against TZ Tables 20–41: verify each column, status chip, stickiness, scroll-to-current-time, expanded-row content per mode.
|
||||
|
||||
**Tech Stack:** TypeScript, React 18, Vitest + RTL, Playwright. No new dependencies.
|
||||
|
||||
**Parent spec:** `docs/superpowers/specs/2026-04-21-online-board-schedule-tz-redesign-design.md` (current HEAD: `793637f`).
|
||||
|
||||
**Rule IDs covered:** §4.1.13 (+.1 Day-tabs, .2 Sort, .3 Collapsed, .4 Expanded) + §4.1.14 (+.1 Week-tabs, .2 Sort, .3 Collapsed, .4 Expanded). Target total: **150–200 rules**.
|
||||
|
||||
---
|
||||
|
||||
## File Structure
|
||||
|
||||
### Files to create
|
||||
- `src/ui/flights/CurrentTimeIndicator.tsx` — reusable line/marker showing user's current local time on the day's results list (per §4.1.13 opening ¶).
|
||||
- `src/ui/flights/CurrentTimeIndicator.test.tsx`.
|
||||
- `src/features/online-board/scrollToCurrentTime.ts` — helper that, given a list of flights + current time, returns the index of the flight closest to now (for "scroll-to-current-time + expand" behavior).
|
||||
- `src/features/online-board/scrollToCurrentTime.test.ts`.
|
||||
- `tests/e2e/p4-results-lists.spec.ts` — Playwright spec for day/week tabs + row expand/collapse + scroll behavior.
|
||||
|
||||
### Files to modify
|
||||
- `src/features/online-board/components/DayTabs/*` — 7-day visible window, paging by 7, keyboard nav, mobile-list variant per TZ Table 22 mobile column.
|
||||
- `src/features/online-board/components/OnlineBoardSearchPage.tsx` — scroll-to-current-time + auto-expand nearest flight on today's tab.
|
||||
- `src/ui/flights/FlightCard.tsx` — audit collapsed + expanded row against §4.1.13.3 / .3.4 tables.
|
||||
- `src/ui/flights/FlightList.tsx` — audit list structure, sticky behavior, scroll-up button per TZ Table 22.
|
||||
- `src/features/schedule/components/WeekTabs.tsx` — audit week-tabs behavior per §4.1.14.1 (month span, keyboard, scroll).
|
||||
- `src/features/schedule/components/DayGroupedFlightList.tsx` — audit day-grouping, weekday masks, operator-logo compactness (existing commit `3ae59da` preserved).
|
||||
- `src/features/schedule/components/ScheduleFlightBody.tsx` — audit expanded-row (multi-segment + connecting per §4.1.14.4).
|
||||
- `src/features/online-board/components/TransferBar/*` — audit transfer visualization for Schedule results expansion.
|
||||
- `docs/superpowers/specs/2026-04-21-online-board-schedule-tz-redesign-design.md` — populate rules (Task 1); mark Done (Task 10).
|
||||
|
||||
### Files reviewed, not modified
|
||||
- `src/ui/layout/ScrollUpButton.tsx` — verify it matches TZ Table 22 visibility trigger.
|
||||
|
||||
---
|
||||
|
||||
## Task 1: Populate rule enumeration for §4.1.13 + §4.1.14
|
||||
|
||||
**Files:** spec.
|
||||
|
||||
- [ ] **Step 1.1** — Read TZ §4.1.13 (lines ~767 to ~1233) and §4.1.14 (lines ~1234 to ~1926). Use `sed -n '767,1234p' /tmp/ri_tz_extract/content.txt` for §4.1.13 and `sed -n '1234,1926p'` for §4.1.14.
|
||||
|
||||
- [ ] **Step 1.2** — Enumerate rules by cluster:
|
||||
|
||||
### §4.1.13 (Online-Board results list)
|
||||
- Opening-paragraph rules: scroll-to-current-time, auto-expand nearest flight, no pagination, no auto-refresh on today's list, per-day list (not multi-day concat).
|
||||
- Table 20 structure: desktop/tablet/mobile layouts.
|
||||
- Table 21: element purposes (filter, history, breadcrumbs, tabs, list).
|
||||
- Expand/collapse behavior: single-expanded-at-a-time, click triggers.
|
||||
- Sticky behavior per Table 22: day-tabs sticky top, filter sticky left-column; mobile NOT sticky.
|
||||
- Scroll-up button visibility triggers.
|
||||
- **§4.1.13.1 Day-tabs**: 7-day window, paging by 7, active range [-1, +14], "padding" tabs when last active tab isn't the 7th, user-requested day highlighted + auto-scrolled-to, tab-click fetches new day's search.
|
||||
- **§4.1.13.2 Sort**: no user re-sort; default sort rules per mode (flight-number = departure time; route = segment departure time with yesterday<today<tomorrow; departure = same; arrival = segment arrival time with same day ordering).
|
||||
- **§4.1.13.3 Collapsed representation** (Tables 23–27): columns per flight type — carrier+logo+marketing/operating, flight number, from-city+airport+terminal, to-city+airport+terminal, scheduled times, aircraft icon, flight status chip (booking/boarding/departed/arrived/cancelled/etc.), expand/collapse arrow.
|
||||
- **§4.1.13.4 Expanded representation**: live status ladder (registration/boarding/deboarding blocks with times), check-in counters (if published), gate, baggage-belt, operator+marketing, aircraft details, share link, buy ticket (conditional).
|
||||
|
||||
### §4.1.14 (Schedule results list)
|
||||
- Opening-paragraph rules.
|
||||
- Table structure similar to §4.1.13 but with weekly grouping.
|
||||
- **§4.1.14.1 Week-tabs**: month-span navigation, multi-week active range per Schedule date window, keyboard nav.
|
||||
- **§4.1.14.2 Sort**: route mode default sort by earliest departure time in week.
|
||||
- **§4.1.14.3 Collapsed** (Tables 30–34): day-grouping with weekday mask, operator logos (compact in multi-leg — preserved by commit `3ae59da`), times, duration.
|
||||
- **§4.1.14.4 Expanded**: per-segment breakdown, transfer bars, connecting flight layout with transfer time, onward flight link.
|
||||
|
||||
Target rule count: §4.1.13 ≥70, §4.1.14 ≥80.
|
||||
|
||||
- [ ] **Step 1.3** — Append to spec, preserve column structure, Status=TBD, Plan=P4, Viewport=all (with mobile/desktop differentiated where TZ differs).
|
||||
|
||||
- [ ] **Step 1.4** — Update Coverage summary.
|
||||
|
||||
- [ ] **Step 1.5** — Commit:
|
||||
```bash
|
||||
git add docs/superpowers/specs/2026-04-21-online-board-schedule-tz-redesign-design.md
|
||||
git commit -m "Populate rule rows for P4 subsections 4.1.13/14 in TZ audit spec"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 2: Scroll-to-current-time + auto-expand nearest flight (today's tab)
|
||||
|
||||
**Files:**
|
||||
- Create: `src/features/online-board/scrollToCurrentTime.ts` + test.
|
||||
- Modify: `src/features/online-board/components/OnlineBoardSearchPage.tsx`.
|
||||
|
||||
Per §4.1.13 opening ¶1: on the today's tab, the list scrolls to the current time and the flight nearest to now is auto-expanded.
|
||||
|
||||
- [ ] **Step 2.1** — Read `OnlineBoardSearchPage.tsx` to find the list-render + scroll-container pattern.
|
||||
|
||||
- [ ] **Step 2.2** — Write pure helper test:
|
||||
|
||||
```ts
|
||||
// src/features/online-board/scrollToCurrentTime.test.ts
|
||||
import { describe, expect, it, vi, beforeEach, afterEach } from "vitest";
|
||||
import { findNearestFlightIndex } from "./scrollToCurrentTime.js";
|
||||
|
||||
describe("findNearestFlightIndex", () => {
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers();
|
||||
vi.setSystemTime(new Date(2026, 4, 15, 12, 0, 0));
|
||||
});
|
||||
afterEach(() => vi.useRealTimers());
|
||||
|
||||
it("returns index of flight closest to current time", () => {
|
||||
const flights = [
|
||||
{ departure: { scheduled: "2026-05-15T08:00:00" } },
|
||||
{ departure: { scheduled: "2026-05-15T11:30:00" } },
|
||||
{ departure: { scheduled: "2026-05-15T14:00:00" } },
|
||||
];
|
||||
expect(findNearestFlightIndex(flights as never, new Date(2026, 4, 15, 12, 0))).toBe(1);
|
||||
});
|
||||
|
||||
it("returns 0 when list is empty", () => {
|
||||
expect(findNearestFlightIndex([], new Date())).toBe(0);
|
||||
});
|
||||
|
||||
it("returns the last flight when all flights are in the past", () => {
|
||||
const flights = [
|
||||
{ departure: { scheduled: "2026-05-15T06:00:00" } },
|
||||
{ departure: { scheduled: "2026-05-15T08:00:00" } },
|
||||
];
|
||||
expect(findNearestFlightIndex(flights as never, new Date(2026, 4, 15, 23, 0))).toBe(1);
|
||||
});
|
||||
|
||||
it("returns the first flight when all flights are in the future", () => {
|
||||
const flights = [
|
||||
{ departure: { scheduled: "2026-05-15T18:00:00" } },
|
||||
{ departure: { scheduled: "2026-05-15T20:00:00" } },
|
||||
];
|
||||
expect(findNearestFlightIndex(flights as never, new Date(2026, 4, 15, 6, 0))).toBe(0);
|
||||
});
|
||||
|
||||
it("handles arrival-mode flights (sorts by arrival time)", () => {
|
||||
const flights = [
|
||||
{ arrival: { scheduled: "2026-05-15T10:00:00" } },
|
||||
{ arrival: { scheduled: "2026-05-15T13:00:00" } },
|
||||
];
|
||||
expect(findNearestFlightIndex(flights as never, new Date(2026, 4, 15, 12, 0), "arrival")).toBe(1);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
- [ ] **Step 2.3** — Run — FAIL (module not found).
|
||||
|
||||
- [ ] **Step 2.4** — Implement:
|
||||
|
||||
```ts
|
||||
// src/features/online-board/scrollToCurrentTime.ts
|
||||
/**
|
||||
* Find the index of the flight in a sorted-by-time list whose scheduled
|
||||
* departure (or arrival, per `mode`) is closest to `now`. Per TZ §4.1.13
|
||||
* opening ¶1 — the nearest flight gets auto-expanded and the list scrolls
|
||||
* to it on today's tab.
|
||||
*/
|
||||
|
||||
import type { ISimpleFlight } from "./types.js";
|
||||
|
||||
type TimeMode = "departure" | "arrival";
|
||||
|
||||
export function findNearestFlightIndex(
|
||||
flights: ISimpleFlight[],
|
||||
now: Date,
|
||||
mode: TimeMode = "departure",
|
||||
): number {
|
||||
if (flights.length === 0) return 0;
|
||||
let bestIndex = 0;
|
||||
let bestDiff = Number.POSITIVE_INFINITY;
|
||||
for (let i = 0; i < flights.length; i++) {
|
||||
const f = flights[i];
|
||||
const iso = mode === "arrival"
|
||||
? (f as unknown as { arrival?: { scheduled?: string } }).arrival?.scheduled
|
||||
: (f as unknown as { departure?: { scheduled?: string } }).departure?.scheduled;
|
||||
if (!iso) continue;
|
||||
const diff = Math.abs(new Date(iso).getTime() - now.getTime());
|
||||
if (diff < bestDiff) {
|
||||
bestDiff = diff;
|
||||
bestIndex = i;
|
||||
}
|
||||
}
|
||||
return bestIndex;
|
||||
}
|
||||
```
|
||||
|
||||
(Adapt `ISimpleFlight` field access to the real type shape — check `src/features/online-board/types.ts`.)
|
||||
|
||||
- [ ] **Step 2.5** — Run — PASS.
|
||||
|
||||
- [ ] **Step 2.6** — Wire into `OnlineBoardSearchPage.tsx`:
|
||||
- On initial render of today's tab + when `flights` first populates, compute `findNearestFlightIndex`, scroll the list container to that index, and set the expanded-flight state to that index.
|
||||
- If the user manually expands a different flight, respect that choice (don't re-scroll on subsequent renders).
|
||||
- Skip for non-today tabs (just render from the first flight, no auto-scroll).
|
||||
|
||||
- [ ] **Step 2.7** — Add component test verifying nearest-flight auto-expand on today's tab only.
|
||||
|
||||
- [ ] **Step 2.8** — Commit:
|
||||
```bash
|
||||
git add src/features/online-board/
|
||||
git commit -m "Add scroll-to-current-time + auto-expand-nearest on Online-Board today's tab per TZ 4.1.13"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 3: Day-tabs audit (§4.1.13.1)
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/features/online-board/components/DayTabs/*`
|
||||
- Test: the component's existing test file.
|
||||
|
||||
TZ rules for Day-tabs:
|
||||
- 7-day visible window.
|
||||
- Active range: today-1 to today+14.
|
||||
- Paging by 7 days.
|
||||
- When last active day isn't the 7th in a page, pad with inactive tabs; right-arrow disabled.
|
||||
- User-requested day (from URL) highlighted + auto-scrolled to.
|
||||
- Clicking a tab triggers a new search for that day with current filter.
|
||||
- Mobile variant: list not tabs.
|
||||
|
||||
- [ ] **Step 3.1** — Inspect existing `DayTabs/` components and tests. Enumerate gaps.
|
||||
|
||||
- [ ] **Step 3.2** — Write failing tests per gap.
|
||||
|
||||
- [ ] **Step 3.3** — Fix.
|
||||
|
||||
- [ ] **Step 3.4** — Commit:
|
||||
```bash
|
||||
git add src/features/online-board/components/DayTabs/
|
||||
git commit -m "Audit DayTabs behavior per TZ 4.1.13.1 (7-day window, paging, padding, active range)"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 4: Sort order (§4.1.13.2)
|
||||
|
||||
**Files:**
|
||||
- Verify: `src/ui/flights/FlightList.tsx` or wherever sort happens.
|
||||
- Possibly create: `src/features/online-board/sortFlights.ts` (pure helper).
|
||||
|
||||
TZ default sort:
|
||||
- Flight-number mode: by departure date.
|
||||
- Route / Departure modes: by segment-departure time, with ordering yesterday < today < tomorrow.
|
||||
- Arrival mode: by segment-arrival time, same day ordering.
|
||||
- No user re-sort.
|
||||
|
||||
- [ ] **Step 4.1** — Grep for existing sort logic: `grep -rn "sort\|compareFlights" src/features/online-board/ src/ui/flights/`.
|
||||
|
||||
- [ ] **Step 4.2** — Extract / verify helper. Add tests for all 4 mode cases + yesterday/today/tomorrow ordering.
|
||||
|
||||
- [ ] **Step 4.3** — Fix gaps.
|
||||
|
||||
- [ ] **Step 4.4** — Commit:
|
||||
```bash
|
||||
git add src/features/online-board/
|
||||
git commit -m "Verify Online-Board flight-list default sort per TZ 4.1.13.2"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 5: Collapsed row representation — Online-Board (§4.1.13.3)
|
||||
|
||||
**Files:**
|
||||
- Verify/modify: `src/ui/flights/FlightCard.tsx`, `src/ui/flights/OperatorLogo.tsx`, `src/ui/flights/TimeGroup.tsx`, `src/ui/flights/StationDisplay.tsx`, `src/ui/flights/FlightStatus.tsx`.
|
||||
|
||||
TZ Tables 23–27 enumerate every collapsed-row element. Audit each element against its table row:
|
||||
- Carrier logo + marketing flight number + operator flight number
|
||||
- From-city + IATA + airport + terminal
|
||||
- To-city + IATA + airport + terminal
|
||||
- Scheduled times (with "Yesterday"/"Tomorrow" day-change chips per §4.1.17)
|
||||
- Aircraft icon (§4.1.22 rules)
|
||||
- Flight status chip (registration/boarding/departed/arrived/cancelled — enumerate full list from TZ)
|
||||
- Expand/collapse arrow (state-indicator)
|
||||
- "Уточняется" fallback text (§4.1.23)
|
||||
- Multi-segment indicator (if multi-segment flight)
|
||||
|
||||
- [ ] **Step 5.1** — Read TZ Tables 23, 24, 25, 26, 27 fully.
|
||||
|
||||
- [ ] **Step 5.2** — Inspect each UI component.
|
||||
|
||||
- [ ] **Step 5.3** — Enumerate gaps, write tests, fix.
|
||||
|
||||
- [ ] **Step 5.4** — Commit per logical cluster (e.g. one commit for status-chip rules, one for operator-logo rules, etc.).
|
||||
|
||||
---
|
||||
|
||||
## Task 6: Expanded row representation — Online-Board (§4.1.13.4)
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/ui/flights/FlightCard.tsx` (expanded content).
|
||||
- Modify: `src/features/online-board/components/details-panels/*` (may be reused for expanded rows).
|
||||
|
||||
TZ describes live-status ladder, check-in counters, gates, baggage belts, operator+marketing chip, aircraft details, share link, buy-ticket CTA (conditional).
|
||||
|
||||
- [ ] **Step 6.1** — Read §4.1.13.4 TZ body fully.
|
||||
|
||||
- [ ] **Step 6.2** — Inspect current expanded-row implementation.
|
||||
|
||||
- [ ] **Step 6.3** — Gap list + tests + fixes per cluster.
|
||||
|
||||
- [ ] **Step 6.4** — Commit per logical cluster.
|
||||
|
||||
---
|
||||
|
||||
## Task 7: Week-tabs + Schedule collapsed rows (§4.1.14.1 + §4.1.14.3)
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/features/schedule/components/WeekTabs.tsx`.
|
||||
- Verify: `src/features/schedule/components/DayGroupedFlightList.tsx`.
|
||||
- Verify: `src/features/schedule/components/ScheduleFlightBody.tsx`.
|
||||
|
||||
- [ ] Enumerate + fix per same pattern as Tasks 3+5 but for Schedule weekly view.
|
||||
|
||||
- [ ] Commit per cluster.
|
||||
|
||||
---
|
||||
|
||||
## Task 8: Schedule expanded rows — multi-segment + connecting (§4.1.14.4)
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/features/schedule/components/ScheduleFlightBody.tsx`.
|
||||
- Modify: `src/features/online-board/components/TransferBar/*` (re-used).
|
||||
|
||||
TZ covers per-segment breakdown, transfer bars between segments, connecting-flight layout with transfer time, onward flight link.
|
||||
|
||||
- [ ] Enumerate + fix.
|
||||
|
||||
- [ ] Commit per cluster.
|
||||
|
||||
---
|
||||
|
||||
## Task 9: Sticky behavior + Scroll-up button (§4.1.13 + §4.1.14 Table 22)
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/ui/layout/ScrollUpButton.tsx`
|
||||
- Modify: `src/ui/layout/PageLayout.tsx` (for sticky filter + day-tabs on desktop/tablet)
|
||||
|
||||
- [ ] Verify sticky desktop/tablet, non-sticky mobile per Table 22.
|
||||
|
||||
- [ ] Verify scroll-up button visibility trigger (crumbs + tabs scrolled out of view).
|
||||
|
||||
- [ ] Add tests + fixes.
|
||||
|
||||
- [ ] Commit.
|
||||
|
||||
---
|
||||
|
||||
## Task 10: Update spec + merge gate
|
||||
|
||||
- [ ] Mark P4 rules Done.
|
||||
- [ ] Add any new Conflicts.
|
||||
- [ ] Append merge-log row.
|
||||
- [ ] Commit.
|
||||
|
||||
---
|
||||
|
||||
## Self-Review
|
||||
|
||||
**1. Spec coverage.** §4.1.13/4.1.14 fully decomposed into Tasks 2–9. Task 1 pre-populates the rule IDs so every task has grep-able IDs.
|
||||
|
||||
**2. Placeholder scan.** Many tasks use "audit existing code → enumerate gaps → fix" language. This is deliberate for an audit-style plan where the gap size is unknown without reading the specific Angular-derived React code first. Each task has a clear TZ citation and verification pattern; the exhaustive detail lives in the audit tables in the spec.
|
||||
|
||||
**3. Type consistency.**
|
||||
- `findNearestFlightIndex` (Task 2) uses `ISimpleFlight`-compatible shape.
|
||||
- Sort helper (Task 4) — to be named `compareFlightsForMode(mode)` or similar consistently.
|
||||
- `ScrollUpButton` props (Task 9) already established.
|
||||
|
||||
---
|
||||
|
||||
## Execution Handoff
|
||||
|
||||
P4 is the largest plan by rule count; execute via subagent-driven development with close monitoring. If any single cluster turns out to be fully already-correct (zero code changes needed), add assertion tests and move on quickly.
|
||||
Reference in New Issue
Block a user