high priority low complexity frontend pending frontend specialist Tier 0

Acceptance Criteria

ContactViewSwitcher renders a segmented control with exactly two segments by default
Default segment labels are 'Contacts' and 'Peer Mentors' when no label override map is provided
When an org-label override map is provided (e.g., {'contacts': 'Members', 'peerMentors': 'Mentors'}), the widget displays the overridden labels instead of the defaults
Tapping a segment updates the selected state visually and fires the onChanged callback with the newly selected view identifier
The widget is hidden (not rendered, not just transparent) when the parent passes visible: false
The selected segment is visually distinct from the unselected segment using design token colors
The widget's current selection can be read via the exposed selectedView ValueNotifier
Segment labels are accessible: each segment is a Semantics node with a label and selected state announced by screen readers
Override map keys that do not match known segment identifiers are silently ignored — no crash on unexpected keys
Widget is stateless with respect to the org-labels system — it does not call any provider directly; labels are passed in by the parent

Technical Requirements

frameworks
Flutter
flutter_test
Riverpod
data models
ContactViewType
OrgLabels
performance requirements
Widget re-renders only when selected view or label overrides change — avoid unnecessary rebuilds via const constructors and proper key usage
security requirements
Label override strings must be sanitized/truncated before rendering to prevent layout overflow from unexpectedly long org-supplied strings (enforce maxLines: 1, overflow: TextOverflow.ellipsis)
ui components
SegmentedButton<ContactViewType> (Material 3) or equivalent custom segmented control
Design token selected/unselected color tokens
Semantics widget per segment with label and selected properties
Visibility widget or conditional rendering based on parent boolean flag

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Use Flutter's built-in SegmentedButton (Material 3, available from Flutter 3.10+) for the segmented control to get accessibility and theming for free. Define a ContactViewType enum with values contacts and peerMentors. The label resolution logic should be a simple helper: String _resolveLabel(String key, String defaultLabel, Map? overrides) => overrides?[key] ??

defaultLabel. This keeps the build method clean. For visibility, prefer using a conditional expression (if visible widget else const SizedBox.shrink()) over Visibility widget to fully remove the widget from the tree when hidden — this is important for layout so it does not occupy space. The parent (ContactListScreen) is responsible for reading the org-labels provider and passing the override map down as a parameter.

Testing Requirements

Write flutter_test widget tests: (1) render with no label overrides and assert default 'Contacts' and 'Peer Mentors' text appears; (2) render with an override map {'contacts': 'Members', 'peerMentors': 'Mentors'} and assert overridden labels appear; (3) tap each segment and assert onChanged fires with the correct ContactViewType value; (4) render with visible: false and assert the widget is not present in the widget tree (findsNothing); (5) render with visible: true and assert the widget is present; (6) provide an unexpected key in the override map and assert no exception is thrown and default labels fall back correctly; (7) assert Semantics nodes for each segment carry correct label and isSelected state.

Component
Contact View Switcher
ui low
Epic Risks (2)
medium impact medium prob technical

Design token color values used in role badges, certification status indicators, and availability chips may not meet the WCAG 2.2 AA contrast ratio of 4.5:1 when rendered against card backgrounds, requiring rework after accessibility review and potentially blocking acceptance sign-off.

Mitigation & Contingency

Mitigation: Run the contrast-ratio-validator on every new token combination during widget development. Enforce the CI accessibility lint runner on all PRs touching visualization components, and validate against the contrast-safe-color-palette before finalizing card designs.

Contingency: If contrast failures are found late, adjust token values in the design token theme centrally — since all widgets consume design tokens rather than hardcoded colors, all affected widgets will be corrected by a single token update without per-widget changes.

low impact medium prob dependency

The ContactViewSwitcher is required for Barnekreftforeningen but must not appear for other organizations. If the organization labels provider does not yet expose a reliable feature flag for this widget, it may render universally or be conditionally hidden in an inconsistent way, breaking the role-specific layout contract.

Mitigation & Contingency

Mitigation: Implement view switcher visibility as a constructor parameter on ContactListScreen injected from a provider, defaulting to hidden. Document the integration point for the org labels provider so the flag can be wired without changing the widget's API.

Contingency: If org labels integration is delayed beyond this epic, use a feature flag constant keyed to the Barnekreftforeningen organization ID as a temporary gate, with a tracked issue to replace it with the runtime labels provider before general release.