Skip to main content

Maintenance Hub

Route /maintenance?tab=open|history — the launch screen (lib/features/maintenance/presentation/...). Aggregates booking, inventory, inspections, tasks, charges, notifications from LocalStore.hubSnapshotStream.

Anatomy

KxHeroAppBar("Maintenance Hub")
BookingSelector (KxSelectorField) — propertyCode / roomName / dates
Tabs (KxTabs) — Open | History (query param ?tab= derived from BookingCubit)
Outstanding banner (KxBanner.info, blue) — deadline + "View charge" when any `outstanding`
Recommendations banner (inspection-driven)
Inventory card(s) — status tag, location, "Working report" → /reports/:id (External link)
Inspection card(s) — status, location, date, → /inspections/:id
Task lane — Raise Task + TaskCard{category, notes, location, date, status}
Charge section — ChargeCard{amount, status pill, location} per charge
Bottom: KxNavShell destinations [Home, Book, Maintenance*, Notifications(badge)]

Per-spec: Home/Book are inert; Maintenance is selected.

Banners & actions

Banner policy mirrors domain/charge_state.py:

Hub stateBannerAction
any outstandingOutstanding blueView (routes to first outstanding charge)
any contested in historyContested warningReview pending
accepted acceptedAccepted green outlinePay (routes to statement or charge pay)
no openEmpty message state

Cards never duplicate business logic — charge_card_header.dart maps ChargeStatus→KxTone + pill text; maintenance_banner.dart composes KxBanner.

Tabs contract

  • OpenisOpen(status) = outstanding|accepted|contested. Ordered by deadlineAt ascending then raisedAt.
  • HistoryisHistory(status) = accepted|contested|resolved|paid, ordered by latest event timestamp (acceptedAt??contestedAt??resolvedAt??paidAt??raisedAt) descending, includes contest reason snapshot when present.
  • accepted appears on both.

BookingCubit.rememberHubTab(tab) persists last tab per booking; redirect in app_router.dart repairs unknown ?tab= to fallback.

Data wiring

LocalStore.hubSnapshotStream → MaintenanceHubCubit → BlocBuilder → MaintenanceHubPage
local_annotations (L10n strings) injected via BuildContext.l10n

tool/check_evidence.dart guards HubTab routing contract via test/router/*.

Responsive

  • 360–599: single-column cards, selector stacked, horizontal no-overflow (photo strip is the only horizontal scroll).
  • 600–839: cards 2-per-row.
  • ≥840: two-column KxContentContainer split (list + detail hint). Breakpoints from KxBreakpoints.

Tests

  • test/features/maintenance/hub_page_test.dart — header, selector switch, banner variants, inventory/inspection/task/charge lanes, nav shell destinations.
  • test/golden/... banner and card variants in light/dark.