high priority medium complexity frontend pending frontend specialist Tier 7

Acceptance Criteria

PeerMentorProfileHeader receives and renders the mentor's name, organization, role, and profile image URL from PeerMentorDetailModel.profile
CertificationStatusBadge receives PeerMentorDetailModel.certification and displays the correct status (active, expired, pending) using design token colors
CertificationAlertBanner is rendered only when certification.isExpired == true or certification.isExpiringSoon == true; it is absent from the widget tree otherwise
AssignedContactsList receives PeerMentorDetailModel.assignedContacts and renders each contact item; renders fallback text 'No assigned contacts' when the list is empty
MentorActivitySummaryPanel receives PeerMentorDetailModel.activitySummary and renders the summary metrics; shows 'Activity data unavailable' when activitySummary is null
All org-filtered optional fields (fields present only for HLF, NHF, or Blindeforbundet) propagate null to child widgets correctly — no null pointer exceptions at runtime
Child widgets receive immutable data slices; no widget mutates shared state directly
All placeholders (e.g., Container(), SizedBox(), Text('TODO')) are fully removed from the assembled layout
The assembled screen scrolls as a single CustomScrollView or SingleChildScrollView with consistent spacing defined by design tokens
Visual regression: the assembled layout matches the design mockup for both loaded and partial-error states

Technical Requirements

frameworks
Flutter
BLoC (flutter_bloc)
data models
PeerMentorDetailModel
PeerMentorProfile
CertificationModel
AssignedContact
ActivitySummaryModel
performance requirements
Each sub-component widget must be a const constructor where possible to minimize rebuilds
AssignedContactsList must use ListView.builder for lists exceeding 5 items to avoid jank
security requirements
Sensitive mentor fields (e.g., personal identification numbers, health-related notes) must not be rendered in plain text — use masked display or omit based on role permissions
Org-filtered fields must only render when the current organization context matches — validate org context from BLoC state, not from widget props alone
ui components
PeerMentorProfileHeader
CertificationStatusBadge
CertificationAlertBanner
AssignedContactsList
MentorActivitySummaryPanel
SectionFallbackWidget

Execution Context

Execution Tier
Tier 7

Tier 7 - 84 tasks

Can start after Tier 6 completes

Implementation Notes

Extract each section into its own method (e.g., _buildProfileSection, _buildCertificationSection) within PeerMentorDetailScreenWidget to keep build() readable. Use null-safe access operators consistently (model.activitySummary?.totalHours ?? 0) rather than nested null checks. The CertificationAlertBanner should be conditionally included using if (model.certification?.isExpired == true || model.certification?.isExpiringSoon == true) in the Column children list — do not use Visibility or Opacity, as these keep the widget in the tree unnecessarily.

For org-filtered rendering, use the organization context from the BLoC state (not from a Provider or global) so that the screen is self-contained and testable in isolation. Apply consistent vertical spacing using design token values (e.g., AppSpacing.lg between sections).

Testing Requirements

Write widget tests for PeerMentorDetailScreenWidget in the assembled state using flutter_test. Pump the screen with a BLoC stub emitting a fully-loaded PeerMentorDetailLoaded state and verify all five sub-component widget types are present via find.byType. Pump with a partial-error state where activitySummary is null and assert MentorActivitySummaryPanel shows fallback text. Pump with certification.isExpired = false and assert CertificationAlertBanner is absent.

Pump with an empty assignedContacts list and assert fallback text is shown. Test org-filtered fields: pump with HLF org context and verify HLF-only fields render; pump with NHF context and verify they are absent.

Component
Peer Mentor Detail Screen
ui medium
Epic Risks (3)
medium impact medium prob technical

The parallel Future.wait aggregation pattern may produce race conditions or incorrect merged state when some repositories resolve significantly faster than others, particularly if the BLoC receives a RefreshDetail event while a prior fetch is still in flight.

Mitigation & Contingency

Mitigation: Implement cancellation token pattern in the aggregation service to abort in-flight fetches on new events. Add BLoC test scenarios for rapid successive refresh events to validate state consistency.

Contingency: If race conditions persist, switch to a sequential-with-timeout fetch strategy for the first release and profile the performance impact before deciding whether parallel fetch optimization is worth the complexity.

medium impact medium prob integration

Integrating PeerMentorDetailScreenWidget into the existing StatefulShellRoute navigation structure may conflict with the Contacts tab's existing route hierarchy, requiring changes to navigation-route-config that could affect other teams' features.

Mitigation & Contingency

Mitigation: Coordinate with the Contact List and Contact Detail feature teams before adding the new route. Review the existing StatefulShellRoute configuration and confirm the peer mentor detail route can be nested under the Contacts branch without path conflicts.

Contingency: If route conflicts arise, temporarily implement the peer mentor detail as a modal overlay (push route) rather than a shell route child, preserving functionality while the navigation architecture conflict is resolved.

low impact high prob dependency

The course enrollment screen that the certification alert banner links to may not yet exist or may be implemented in a separate feature epic, leaving a broken navigation tap for HLF users in the initial release.

Mitigation & Contingency

Mitigation: Check the certification management feature implementation status before finalizing Epic 4 scope. If the enrollment screen is not available, design the tap action to open the HLF course enrollment URL in an external browser as an interim solution.

Contingency: Implement the CTA as a configurable action: if the enrollment route exists in the router, push it; otherwise, launch the configured org-specific enrollment URL via url_launcher, ensuring HLF users can always take action on expired certifications.