Activity type list item with status and metadata badges
epic-activity-type-configuration-admin-interface-task-010 — Implement the ActivityTypeListItem widget used inside ActivityTypeAdminScreen. Display: display name as card title, org_label_override as subtle subtext if set, status badge (active in green, archived in grey), and three compact icon badges for the metadata flags (travel eligible, report required, reimbursement trigger). Show the mapped Bufdir category as a small violet tech badge. Tapping the item navigates to the edit form. Apply design token card-clickable class conventions.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 8 - 48 tasks
Can start after Tier 7 completes
Implementation Notes
Make `ActivityTypeListItem` a `StatelessWidget` accepting `({required ActivityType activityType, required VoidCallback onTap})`. Resolve the Bufdir label by calling `BufdirCategories.labelForKey(activityType.bufdirCategory)` — this must be a pure synchronous lookup. For icon badges, create a small private `_MetadataIconBadge` widget accepting `(IconData icon, bool active, String semanticLabel)` that renders a filled icon in `colorPrimary` when active and an outlined icon in `colorOutline` when inactive. Wrap each icon badge with `Tooltip(message: semanticLabel)` for pointer devices and `Semantics(label: semanticLabel)` for screen readers.
Use `Card` with `InkWell` child and `borderRadius` matching design tokens. Keep all badge colors sourced from the design token system — no hardcoded hex values in this widget.
Testing Requirements
Write widget tests covering: (1) org_label_override visible when set, hidden when null/empty; (2) active status badge rendered green, archived rendered grey; (3) each metadata flag badge renders correctly in true and false state; (4) Bufdir badge shows human-readable label, not enum key; (5) onTap callback fires when card is tapped; (6) Semantics tree contains meaningful labels for all icon badges. Add golden tests for the card in four states: active with all flags true, active with all flags false, archived, and a card with org_label_override set. These goldens should be checked into version control.
The Bufdir reporting category list is defined externally by Bufdir and may change between reporting years. If the dropdown in ActivityTypeFormScreen is hardcoded, existing activity type mappings could become invalid after a Bufdir schema update, breaking export validation for all organisations.
Mitigation & Contingency
Mitigation: Store the valid Bufdir category list in a Supabase configuration table (bufdir_categories) rather than as a Dart constant, so it can be updated by an admin without a mobile app release. Load the list in the form screen via a lightweight repository call cached locally.
Contingency: If the Bufdir category list cannot be externalised before the admin screen ships, expose a manual override field that allows coordinators to enter a raw Bufdir category code as a fallback, and schedule the configuration table migration as a follow-up task.
Reusing ActivityTypeFormScreen for both creation and editing requires careful Riverpod provider scoping. If the form provider is not properly reset between navigation events, stale values from a previously edited type may pre-populate a new creation form, leading to incorrect data being saved.
Mitigation & Contingency
Mitigation: Scope the form state provider to the route using Riverpod's autoDispose modifier, ensuring the state is torn down when the screen is popped. Write a widget test that navigates to edit type A, pops, navigates to create new, and asserts all fields are empty.
Contingency: If provider scoping proves complex with the current router setup, fall back to separate widget implementations for create and edit that share a common form widget but maintain independent provider instances.
Archiving an activity type must not break historical Bufdir export queries that filter activities by type. If the export pipeline performs an INNER JOIN against only active activity types, archived types will cause historical activities to be silently excluded from exports, producing incorrect reporting data.
Mitigation & Contingency
Mitigation: Audit all downstream query builders (Bufdir export, stats aggregation) before shipping the archive feature to confirm they join against all activity types regardless of is_active status. Add an integration test that archives a type, then asserts historical activity records for that type still appear in export queries.
Contingency: If a downstream query is discovered to filter on is_active post-launch, apply a targeted Supabase view fix that unions active and archived types for export contexts without requiring a mobile app update.