Build NotificationListItem widget
epic-in-app-notification-centre-foundation-task-007 — Implement the NotificationListItem as a stateless Flutter widget accepting a Notification object. Render: type-specific icon (color-coded per notification type using design tokens), title derived from payload type, subtitle with relative timestamp (e.g., '2 hours ago'), and a read/unread visual indicator (bold text + accent dot). Add an onTap callback for deep link handling and a swipe-to-dismiss gesture for deletion. Ensure full semantics labels for accessibility compliance with WCAG 2.2 AA.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 2 - 518 tasks
Can start after Tier 1 completes
Implementation Notes
Keep the widget purely presentational — no BLoC or Riverpod access inside. All data comes via constructor parameters. For relative time formatting, implement a `_formatRelativeTime(DateTime createdAt)` private function using `DateTime.now().difference(createdAt)` — handle durations: < 1min → 'just now', < 60min → 'X minutes ago', < 24h → 'X hours ago', < 48h → 'yesterday', else → `DateFormat.yMMMd().format(createdAt)` from the `intl` package. For the icon/color mapping, define a `_NotificationTypeVisuals` value object or extension on `NotificationType` that returns `({IconData icon, Color color})` — this keeps the switch statement out of the build method and makes it testable.
Use `Dismissible(key: ValueKey(notification.id), ...)` to ensure stable keys in lists. For the `Semantics` label, build it as: `'${isRead ? "Read" : "Unread"} ${typeLabel} notification, ${relativeTime}'`. Design tokens should be accessed via the app's theme extension or a `DesignTokens.of(context)` pattern — never via hardcoded hex values.
Testing Requirements
Widget tests in `notification_list_item_test.dart` using `flutter_test` and `WidgetTester`. Required test cases: (1) renders unread indicator (accent dot + bold) for an unread notification, (2) renders without indicator for a read notification, (3) each of the five NotificationType values renders a non-null, type-distinct icon (use `find.byIcon` or `find.byWidgetPredicate`), (4) tapping the widget invokes `onTap` callback exactly once, (5) swiping left triggers `onDismiss`, (6) `Semantics` label contains the word 'notification' and a time reference, (7) widget renders without overflow at `textScaleFactor: 2.0`. Use `TestWidgetsFlutterBinding` and `pumpWidget` with a minimal `MaterialApp` wrapper. Golden test (screenshot comparison) is optional but recommended for read vs.
unread visual states. Target 100% widget-level statement coverage for this file.
Supabase Realtime channels on mobile networks can drop silently. If reconnection logic is flawed, users miss notifications without knowing it, undermining the audit-trail guarantee.
Mitigation & Contingency
Mitigation: Implement exponential-backoff reconnection with a maximum of 5 retries; expose a channel-status stream to the BLoC so it can trigger a full-fetch fallback when the channel reconnects after a gap.
Contingency: If Realtime reliability proves insufficient in production, fall back to polling the repository every 60 seconds as a background supplement to the Realtime channel.
Coordinator and org-admin RLS expansions require joining user_roles and org_memberships tables. An incorrect policy could expose notifications to wrong users or block legitimate access entirely.
Mitigation & Contingency
Mitigation: Write dedicated RLS integration tests for each role (peer mentor, coordinator, org admin) using separate Supabase test projects. Review policies with the security checklist before merging.
Contingency: If an RLS defect is discovered post-deployment, disable the expanded-scope policy and revert to user-scoped-only access while a corrected migration is prepared and tested.
JSONB payload structure may vary across notification types created by different Edge Functions (reminder, expiry, scenario, pause). Missing or renamed fields will cause runtime parse failures.
Mitigation & Contingency
Mitigation: Define a canonical NotificationPayload union type in a shared schema document. Each Edge Function must validate its payload against this schema before inserting. Add fallback parsing with default values in the domain model.
Contingency: Wrap all payload parsing in try/catch and log malformed payloads to a monitoring channel; render a generic notification item rather than crashing when the payload cannot be parsed.