← Component Specifications

Flight Finder Notifications — Grouping Design Gap & Proposals

Updated: 2026-08-12 19:37 ET Audited: 2026-08-02 05:32 ET AB#2286 For: design team review
What this asks for. The Flight Finder notifications area has a design gap that only became visible once the screen was wired to live data. This document states the gap, shows what shipped as a stopgap, and puts four layout options to the design team. Nothing here is blocking — the current behaviour is live and testable. We are asking which direction to take, not waiting to build.
Status update 2026-08-12 — the card is no longer a stopgap. The working Figma file (owEYzHf7FrHRvWC2u82UOl, parent page node notifications-ff 5060:14989, component set 5054:13776) delivered the flight-status card design, and the implementation now matches it: relative timestamp top-right, 44px icon slot (a generic placeholder circle in the design itself), the route as a “JFK » MIA”-style bold title (parsed from the message prose — see §1), the flight date beneath, and a caret-only expander pill. The open variant (5054:13777) also delivered an expanded state: a status row with the flight number and a rounded severity pill (“Delayed 34m”, yellow/500) — implemented as the first row of the expanded detail. The invented status chip no longer appears anywhere on this card; the drawn pill carries severity in the expanded state, and the collapsed face has no severity slot at all. Everything else in this document stands on the list question: the list is still Option A (flat, one card per alert — the delivered screen again shows a single card, so the grouping question in §5 remains open), cards are spaced 8px apart — the notifications-comms screen (5060:15039), the only frame that stacks two of these cards, wraps them in a list frame (5056:13945) with gap: var(--tiny, 8px) — and the §3 mock-ups below intentionally still show the pre-redesign card face — the options they illustrate concern list structure, which the face redesign does not change.

The card is now design-exact (series rule: match the design unless an annotation says otherwise), and that removed function. The stopgap's expanded extras — message text, sent time (relabelled from "Received" 2026-08-12: the value is the payload's server-side sentDateTime, device receipt is never captured), flight reference, and the VIEW FULL DETAILS link — are no longer on the production card. Consequences worth naming: the alert's message text has no surface in the list (an expanded card says "DL5328 · GATE CHANGE" but not which gate), and the Flight Updates history screen has lost its only in-list entry point — it is now reachable only by the readiness scenarios row and by route. That raises the stakes on §5 question 7: if the answer is "a tapped push opens the list", the history screen is unreachable for a real member. Both are faithful to the drawn design, flagged here rather than silently re-added. For the review itself: the retired detail is preserved behind ShowAlternateDetailView — entering Notifications from the readiness board (?showcase=true) renders it on expanded cards, so this comparison can be made on the device side-by-side with the drawn card rather than from memory.

1 · The gap, and how we know

The design covers one flight-status card, once. The live service sends a stream of alerts per flight. Nothing in the design says what a list of them should look like.

Verified against Figma, 2026-08-02

What live data actually sends

Measured against production on 2026-08-01/02, for one real subscription (fs-9fceb91f-…, a single JFK→SYR leg):

ObservationValueConsequence for the list
Alerts for one flight9, all within one afternoonOne subscription fills the whole screen
titleAlways "Flight Changed"Cannot distinguish rows — every row's headline is identical
RouteNot a field; embedded in message proseMust be parsed out; the design's "DEN » MIA" title does not exist in the data
Arrival orderNot guaranteed to match event orderA gate assignment can appear above the time revision that preceded it
destination"0" placeholderNo tap-through target the design could hang a CTA on
The design was drawn against assumed data. The Figma card shows “DEN » MIA” as the card title with a date beneath. In the real payload the title is the constant string "Flight Changed" and the route only exists inside a sentence. This is not a criticism of the design — it is what happens when a screen is specified before its feed exists. It does mean the card had to be re-derived rather than implemented literally.

2 · What shipped (the stopgap)

Built so the area is testable now, and deliberately reusing existing design language rather than inventing any: the Flight Card (D64) trip line and View Details pill, plus a status chip derived from the message text so the list is scannable at all. Tapping expands inline (accordion, one open at a time), matching Flight Search and FTDT. A Flight Updates screen shows every alert for the flight in one place, which is how an out-of-order arrival is made visible rather than misleading.

This is Option A below. It works, but it treats a stream as a flat list — the thing we would like design input on.

Why this default, and not one of the others

We did not pick A because we think it is the best answer. We picked it because it is the only one that does not require a design decision we are not entitled to make:

The consolidated Flight Updates history screen is the one place we did go further, and for a specific reason: alerts do not necessarily arrive in the order the changes happened, so a flat list can genuinely mislead — a gate assignment can sit above the arrival revision that preceded it. The history view is where that ordering becomes legible. If B or C is chosen it stays; the entry point changes, not the screen.

2b · Where an OS push notification has to land

This is behaviour the design team will want to specify, so it is stated explicitly rather than left implicit in the code.

A flight-status push arrives with contentType: "FlightNotification" and the notification's id. Tapping it previously opened the native Saved Flights list — neither the alert that was tapped nor anything about it. A member tapped “DL5328 now departs from gate A17” and landed on a list of saved searches.

It now lands on the alert itself. The full path:

#StepWhere
1OS delivers the push; the member taps itiOS / Android
2contentType switch routes flightnotificationPushNotificationHandler
3Destination rides the Shell navigation itself as a query attribute (?entry=/notifications?tab=flight&focus={id}, escaped)PushNotificationHandlerGoToAsync
4Host page applies it as the web view's StartPath before the web view boots (IQueryAttributable — the XAML pages' query-property pattern)BlazorDevPage
5Router's first frame is already the destination — no boot-at-/ frame, no default-tab flash (replaced the BlazorEntryRoute hand-off, which navigated after first render; flash reported and fixed 2026-08-12)Main.razor Router
6Flight Finder tab selected, that alert expanded and marked readNotificationsPage
7The card is scrolled to the middle of the viewalpaScroll.centerOn
Why a query parameter and not its own route. The same screen serves the deep link and ordinary browsing, so the back button behaves normally and the tab selection survives navigation. It also means the deep link degrades gracefully: an id that is no longer in the feed — a stale notification tapped days later — focuses nothing and leaves a usable list rather than erroring.

Why centred and not merely expanded. Expanding a card the member cannot see is indistinguishable from doing nothing. Verified live 2026-08-02: the target card landed with its midpoint within 1 px of the viewport midpoint, including for alerts that start below the fold. Re-measured 2026-08-12 after the card-face redesign: the midpoint now lands 58 px below the viewport midpoint (card midpoint 536 vs viewport midpoint 478 on the 393-pt simulator) — the redesigned collapsed card is shorter, so the post-scroll expansion shifts the midpoint further than before. The functional requirement still holds — the alert is expanded, visible, and has neighbours above and below — but the centring is no longer exact; re-anchoring the scroll after expansion is a queued polish item.
Open question for design (see §5). Should the tapped alert open expanded in the list (built) or go straight to the Flight Updates history for that flight? The list keeps context — you can see the alerts around it — whereas the history answers “what is happening with my flight” in one screen. We chose the list because it preserves the back path and matches what the notification itself referred to.

How to test it without sending a push

The routes a tapped push produces are exposed on the readiness board: Page Readiness → Notifications → Push / Deep-link Test Scenarios. Rows are built from the live feed, so the ids are real; each opens exactly the route the push handler produces. Covers the newest alert, one deliberately below the fold (which is where “centred” actually gets tested), the history view, and both stale-id cases.

Since 2026-08-12 the same page can also produce the push itself: Real push tap → post a local notification schedules a local OS notification carrying the newest alert's real FlightNotification payload (via the ILocalPushTester port — APNS aps-dictionary shape on iOS, flat intent extras on Android, matching what each platform's tap handler parses). Tapping its banner exercises the entire chain in §2b's table — OS → delegate → PushNotificationHandler → deep link — with no backend send, no subscription and no flight that actually changes.

3 · Four options

All four are drawn with the same real data: nine alerts, one flight. Options B–D assume a member watching two or three flights, which is where the difference matters most.

A · Flat list, newest first (shipped today)
Every alert is its own card. Status chip carries the meaning.
Notifications
COMMS
FLIGHT FINDER
ARRIVAL UPDATEDJul 29 · 4:51 PM
JFKSYR
DL5328Wed July 29
VIEW DETAILS ⌄
TIMES UPDATEDJul 29 · 2:31 PM
JFKSYR
DL5328Wed July 29
VIEW DETAILS ⌄
GATE CHANGEJul 29 · 11:21 AM
JFKSYR
DL5328Wed July 29
VIEW DETAILS ⌄
…6 more, same flight
WORKS
  • No new components
  • Chip makes it scannable
COSTS
  • One flight buries the list
  • Route repeats 9×
B · Grouped by flight
A section per flight; its alerts nest beneath. Collapsible.
Notifications
COMMS
FLIGHT FINDER
JFK ✈ SYR · DL5328 9 updates ⌃
ARRIVAL UPDATED4:51 PM
Now arrives 15:38.
TIMES UPDATED2:31 PM
Departs 14:27, arrives 16:05.
GATE CHANGE11:21 AM
Departs from gate A17.
show 6 more
ORD ✈ SEA · AA1892 2 updates ⌄
WORKS
  • Flight is the unit, as a pilot thinks
  • Scales to many flights
COSTS
  • New group-header component
  • Two nested collapse levels
C · One row per flight, latest only
The list answers “what is happening now”. Tap opens the full history.
Notifications
COMMS
FLIGHT FINDER
ARRIVAL UPDATED94:51 PM
JFKSYR
DL5328Wed July 29
Latest: now arrives at 15:38.
ALL 9 UPDATES ›
DELAYED2Jul 27
ORDSEA
AA1892Mon July 27
Latest: delayed 35 minutes.
ALL 2 UPDATES ›
WORKS
  • Shortest, calmest list
  • Out-of-order noise hidden
  • Reuses the history screen
COSTS
  • “Latest” ≠ most important
  • A gate change can be hidden behind a time nudge
D · Day dividers over a flat list
Smallest change to A — adds time structure, no grouping.
Notifications
COMMS
FLIGHT FINDER
TODAY
CANCELLED9:02 AM
ORDSEA
AA1892Today
WED JULY 29
ARRIVAL UPDATED4:51 PM
JFKSYR
DL5328Wed July 29
GATE CHANGE11:21 AM
JFKSYR
DL5328Wed July 29
WORKS
  • Cheapest to build
  • Familiar pattern
COSTS
  • Does not solve the real problem
  • One flight still dominates a day

4 · Our suggestion

C, with B as the fallback. The member's question is “what is happening with my flight”, not “what messages arrived”. Option C answers that in the list and keeps the full sequence one tap away on the Flight Updates screen that already exists — so it is the cheapest of the three real options to reach, and the calmest to read. Its weakness is real though: latest is not always most important, and a cancellation must never be hidden behind a later cosmetic update. If that cannot be resolved with chip precedence, B is the safer answer because it hides nothing.

5 · Questions for the design team

  1. Which option — A, B, C, D, or something we have not drawn?
  2. Status chip: we invented it, because the feed gives every alert the same title and the list is unusable without it. Does it belong in the design system, and what should its vocabulary and colours be? Current set: Cancelled · Delayed · Gate change · Times updated · Arrival updated · Departure updated, plus the raw status word. Partially answered 2026-08-12: the delivered collapsed face has no severity slot, and the open variant carries severity as a rounded pill in the expanded status row — with exactly one severity drawn: “Delayed 34m” on yellow/500 (the existing Status/Delayed token). The implementation uses the drawn pill shape for all severities, keeping the invented tint palette for the ones the design has not drawn (cancelled · gate · info). Still needed from design: pill colours for the rest of the vocabulary, and whether the magnitude (“34m”) is expected — the payload does not carry it as a field. Note the collapsed list is now unscannable by change type by design, which raises the stakes on question 1.
  3. Precedence: if a flight's latest alert is cosmetic but an earlier one was a cancellation, which does the collapsed row show?
  4. Card title: answered in practice 2026-08-12 — the working file kept “DEN » MIA” as the card title, so the implementation now renders the route as the title, parsed from the message prose (FlightNotificationText.ParseRoute); when the prose does not parse, the card falls back to the message headline. The underlying backend ask stands: route and flight number should be payload fields, not sentence content.
  5. Read state: should opening a flight's history mark every alert in it read (as built), or only the one opened?
  6. Empty and single-alert states for whichever option is chosen — B and C both look odd with exactly one alert.
  7. Push landing (see §2b): should a tapped notification open the alert expanded in the list (built today), or go straight to that flight's Flight Updates history? And if the alert is older than the history the app keeps, what should the member see instead of the current "no longer in your list"?

6 · Related