← Back to Index

Saved Search Card Figma: flight card-saved & recent searches domain control

Updated: 2026-07-14 12:20 ET

Audited: 2026-07-14 12:20 ET

A saved jumpseat query — origin → destination IATA, trip-type and date — with a composed trailing Action Column (save / re-search).
ViewModel: SavedSearchCardViewModel (implemented, standalone) · ALPAMobile.Presentation/Components/Library/SavedSearchCard.razor · decision D55 (2026-07-14)
Standalone domain control (D40). A saved search is a query, not a flight — so per D40 it is its own control, not a force-fit of Flight Segment Card and not a shared "Saved Item Card" base. It composes the shared Status Badge atom (optional — no current consumer sets it) and the shared Action Column atom for its trailing actions, and inherits the shared colour / spacing / typography tokens for consistency. This same control backs both Saved Searches and Recent Searches (Figma names it flight card-saved & recent searches).
Design tokens sourced from the scaffold (.alpa-saved-card* in ALPAMobile/wwwroot/css/alpa-components.css) and the Figma frames in file key R6hPjBdjSIn6946qTJasUC: Recent Searches 4713:25203, Saved Searches 4713:25253 (row instance flight card-saved & recent searches, e.g. 0:284), Saved Flights 4713:25365. Captured 2026-06-29.
Figma divergence closed (WI-C / AB#2314, 2026-07-20). Swipe-to-reveal is now built: both list pages wrap the row in the shared SwipeRevealRow (Presentation library) — flick left reveals the Figma action tray (100 px zones, 22 px white icons; Recent → save heart, Saved → trash per 4713:25203/4713:25253), flick right or a body tap closes it, and tapping the row body re-runs the search. The persistent Action Column was removed from these pages; the component keeps its optional in-row ActionColumn only as a legacy shape for other consumers. The gesture is the repo's touchstart/touchend flick idiom (no native SwipeView exists in a WebView), and UI tests drive the tray via synthesized TouchEvents because Appium's native swipe is unreliable inside WKWebView.

Live CSS Preview

DEN MIA
Nonstop · Mon Apr 20
ORD LAX Round-trip
One Stop · Any date

Row 1 (Recent Searches): unsaved item — outline heart toggles to filled/red on save, search-history re-runs the query. Row 2 (Saved Searches): a saved item — always filled/red, tap removes it from the list (no unsave/toggle state). Both compose the shared Action Column atom (D53/D54) — icons are real exported vectors, not text glyphs. The optional Status Badge ("Round-trip" here) composes the shared atom, but no current consumer page actually sets it — illustrative only.

Design Tokens

Card Layout

Display
flex · align center · gap 12px
Padding
14px 16px
Background
white
Border-bottom
1px rgba(0,0,0,0.08)

Route (IATA)

Font
Eyebrow · 18px · weight 700 · ls 1px
IATA colour
navy #05273e
Arrow / meta colour
gray #9ba1a8
Route gap
6 px

Meta (trip-type · date)

Font
Body · 12px
Margin-top
4 px

Action Column (composed atom)

Buttons gap
8 px
Icon size
18px mask, 20px box (see Action Column)
Save (active)
red #c0392b
Re-search
blue #007bc2

Layer Tree

└── saved-search-card · flex · align center · gap:12px · padding:14px 16px · border-bottom
    ├── body · flex:1
    │   ├── route · flex · gap:6px
    │   │  ├── [Origin] · TEXT · 18px/700 · navy
    │   │  ├── [arrow ›] · gray
    │   │  ├── [Destination] · TEXT · 18px/700 · navy
    │   │  └── [StatusBadge] [optional] · composes atom
    │   └── meta · TEXT · 12px · gray (trip-type · date)
    └── ActionColumn (composed atom, D53) · flex · gap:8px
        ├── btn [save Heart/HeartSelected] · per-item toggle · Accent when saved
        └── btn [re-search SearchHistory] · Highlight

ViewModel

Tier: domain control (standalone — does not derive from a card base). Implemented (D55) in both ALPAMobile/Components/ViewModels/ComponentViewModels.cs (live) and ALPAMobile.Presentation/ViewModels/SavedSearchCardViewModel.cs (staged copy).

└── SavedSearchCardViewModel : ComponentViewModel (standalone)
    ├── Origin : string — origin IATA (e.g. "DEN")
    ├── Destination : string — destination IATA
    ├── TripType : string — e.g. "Nonstop", "One Stop"
    ├── Date : string — date label or "Any date"
    ├── Badge : StatusBadgeViewModel? — optional composed atom, unused by any current consumer
    └── Actions : ActionColumnViewModel — composed atom; the page builds its own Items and handles ActionKey

No IsSaved/OnToggleSave/OnReSearch parameters — those were the original spec-only draft's guess at a fixed 2-action shape. The real atom (D53) is a generic ActionColumnViewModel composed as Actions; the card renders whatever items the caller puts there and raises a single OnActionClicked, keyed by ActionKey.

Blazor Component API

Home: ALPAMobile.Presentation/Components/Library/SavedSearchCard.razor (migrated 2026-07-15, WI-2254/D61).

ParameterTypeRequiredDescription
VmSavedSearchCardViewModelYesRoute, meta, optional badge, composed Actions.
OnActionClickedEventCallback<ActionColumnItemViewModel>NoFires with the clicked action item — switch on item.ActionKey.

Razor Usage (actual — JumpseatRecentSearchesPage.razor)

@foreach (var (search, i) in _searches.Select((s, i) => (s, i)))
{
    <SavedSearchCard Vm="@BuildVm(search, i)"
                     OnActionClicked="@(item => OnActionClicked(item, search, i))" />
}

@code {
    private SavedSearchCardViewModel BuildVm(SavedSearch search, int index)
    {
        var saved = _savedIndices.Contains(index);
        return new SavedSearchCardViewModel
        {
            Origin = search.Origin, Destination = search.Destination,
            TripType = search.TripType, Date = search.Date,
            Actions = new ActionColumnViewModel
            {
                Items = [
                    new ActionColumnItemViewModel { ActionKey = "toggle-save",
                        Icon = saved ? ActionColumnIconAsset.HeartSelected : ActionColumnIconAsset.Heart,
                        Title = saved ? "Saved" : "Save search",
                        Variant = saved ? ActionColumnItemVariant.Accent : ActionColumnItemVariant.Neutral },
                    new ActionColumnItemViewModel { ActionKey = "search-again",
                        Icon = ActionColumnIconAsset.SearchHistory, Title = "Search again",
                        Variant = ActionColumnItemVariant.Highlight },
                ],
            },
        };
    }

    private void OnActionClicked(ActionColumnItemViewModel item, SavedSearch search, int index)
    {
        switch (item.ActionKey)
        {
            case "toggle-save": ToggleSave(index); break;
            case "search-again": SearchAgain(search); break;
        }
    }
}

CSS Class Reference (actual)

Classes live in ALPAMobile/wwwroot/css/alpa-components.css under the alpa-saved-card BEM block. The action buttons are the shared Action Column vocabulary (.alpa-action-column*), not bespoke to this control.

ClassScopeKey rules
.alpa-saved-cardCarddisplay:flex; align-items:center; background:white; border-bottom:1px solid rgba(0,0,0,0.08); padding:14px 16px; gap:12px
.alpa-saved-card-bodyBodyflex:1; min-width:0
.alpa-saved-card-routeRoute rowdisplay:flex; align-items:center; gap:6px; margin-bottom:4px
.alpa-saved-card-iataIATAfont-size:18px; font-weight:700; color:var(--navy); letter-spacing:1px
.alpa-saved-card-arrowArrowfont-size:18px; color:var(--gray)
.alpa-saved-card-metaMetafont-size:12px; color:var(--gray)

Related — Saved Flight Card

ListControlTrailing actions
Saved / Recent SearchesSaved Search Card (this spec)save Heart/HeartSelected · re-search SearchHistory (swipe-to-delete in Figma, not built)
Saved FlightsSaved Flight Card (standalone, this section)alert Notifications (colour-only on/off) · delete Trash (Compact)

ViewModel

└── SavedFlightCardViewModel : ComponentViewModel (standalone)
    ├── Origin / Destination : string — route IATA
    ├── Carrier / FlightNumber : string
    ├── Date / DepartTime / ArriveTime / Duration : string
    ├── DetailsRoute : string — nav route the card body links to (e.g. "/jumpseat/details")
    └── Actions : ActionColumnViewModel — composed atom

Blazor Component API

Home: ALPAMobile.Presentation/Components/Library/SavedFlightCard.razor (migrated 2026-07-15, WI-2254/D61).

ParameterTypeRequiredDescription
VmSavedFlightCardViewModelYesRoute, carrier/flight details, times, details link, composed Actions.
OnActionClickedEventCallback<ActionColumnItemViewModel>NoFires with the clicked action item — toggle-alert or delete.
DEN MIA
United · UA 1482 · Mon Apr 20
6:00 AM → 2:15 PM · 4h 15m

.alpa-saved-flight-card-body is a link (<a>) to DetailsRoute; the trailing Action Column sits outside it. The former duplicate .alpa-saved-flight-card-actions CSS rule (byte-identical to .alpa-action-column) was removed — the page composes <ActionColumn> directly, no wrapper class needed.

Developer Notes