high priority low complexity frontend pending frontend specialist Tier 0

Acceptance Criteria

MentorActivitySummaryPanel renders a card-style container with a title/header, total activity count, a time-range label, and a breakdown list
The breakdown list renders one row per activity type present in the provided data, showing the activity type label and its count
Activity types with a count of zero are NOT rendered in the breakdown list
When the total activity count is zero, the empty-state view is rendered instead of the breakdown list — empty state includes an icon and a descriptive message
The time-range label correctly renders the provided string (e.g., 'Last 30 days', 'All time') without truncation on any screen width ≥ 320dp
The panel is stateless and accepts all data as constructor parameters: int totalCount, List<ActivityTypeSummary> breakdown, String timeRangeLabel
The total activity count is displayed prominently (larger or bolder text than the breakdown rows) matching the design hierarchy
Widget renders without overflow for up to 10 distinct activity types in the breakdown list
The panel does not make any Supabase calls or BLoC/Riverpod state reads internally

Technical Requirements

frameworks
Flutter
flutter_test
data models
ActivityTypeSummary (activityType: String, count: int)
MentorActivitySummaryData (totalCount: int, breakdown: List<ActivityTypeSummary>, timeRangeLabel: String)
performance requirements
Panel must render synchronously — no FutureBuilder or StreamBuilder inside the widget
Breakdown list uses Column with mapped children (not ListView) since activity types are bounded; acceptable for ≤ 15 rows
ui components
Card or decorated Container for the panel shell
Text widget for total count (prominent style)
Text widget for time-range label
Column of activity type breakdown rows (label + count per row)
Empty-state widget (icon + message)
Divider between header and breakdown (optional, per design)

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Define ActivityTypeSummary as a simple immutable data class (or use a record in Dart 3+): final String activityType; final int count. Create MentorActivitySummaryPanel as a StatelessWidget. In the build method, first check if totalCount == 0 and return the empty-state widget early. For the breakdown, filter breakdown.where((e) => e.count > 0) before mapping to row widgets — this handles the 'zero counts hidden' requirement cleanly.

Use a Column for the breakdown rows rather than ListView since the count is bounded and shrinkWrap/NeverScrollableScrollPhysics complexity is unnecessary here. Style the total count using the design token for headline/display text size (e.g., tokenTypographyHeadline or similar) and the breakdown rows using body/label size. The panel should be self-contained in one file with a private _BreakdownRow widget. The time-range label is display-only — format logic (e.g., 'Last 30 days' vs ISO range) is the caller's responsibility.

Add a section-title string parameter (default: 'Activity Summary') so the caller can localise or org-customise the header label via OrgLabelsProvider if needed in the future.

Testing Requirements

Write widget tests using flutter_test. Test 1: pass totalCount=0 and empty breakdown — assert empty-state widget is present and breakdown rows are absent. Test 2: pass totalCount=5 with breakdown of 2 types — assert exactly 2 breakdown rows are rendered, each displaying the correct label and count. Test 3: pass a breakdown where one type has count=0 — assert that row is NOT rendered.

Test 4: pass 10 activity types — assert the widget builds without overflow (use tester.pump(), check for no RenderFlex overflow exceptions). Test 5: assert the total count Text widget displays the correct integer as a string. Test 6: assert the time-range label Text renders the provided string.

Epic Risks (2)
medium impact medium prob dependency

The org labels system may not yet have label keys defined for peer mentor detail screen terminology (role labels, section headings), requiring additions to the label key registry that must be coordinated with the admin configuration team.

Mitigation & Contingency

Mitigation: Audit existing label keys in the terminology system before starting OrgLabelsProvider integration. Submit required new label keys for admin configuration in parallel with component implementation.

Contingency: If label keys are not available at integration time, use hardcoded English fallbacks with a clear TODO for admin configuration, ensuring the widget renders correctly while keys are being provisioned.

high impact low prob technical

The design token semantic colors (warning, error surface) may not meet WCAG 2.2 AA 4.5:1 contrast ratio when rendered on the app's background surface tokens, requiring design system changes that affect the entire app.

Mitigation & Contingency

Mitigation: Run contrast ratio validation on the token palette during Epic 1 design token implementation. Flag any failing pairs to the design system owner before building UI components that depend on them.

Contingency: If tokens fail contrast requirements, define supplementary high-contrast override tokens specific to alert and badge contexts that meet AA without modifying the global palette.