Implement participant name and color personalization with dynamic background colors that change based on the active speaker (Partner A or Partner B).
- Existing codebase at v1.0.0
- All 338 tests passing
- React 18 + TypeScript 5 + Vite setup
- Tailwind CSS configured
Goal: Define the domain model for participant configuration
Steps:
- Create file
src/domain/ParticipantConfig.ts - Define
ParticipantConfiginterface with fields:nameA,nameB,colorA,colorB - Export
DEFAULT_PARTICIPANT_CONFIGconstant with default values - Export
PARTICIPANT_COLOR_PALETTEarray with 8 calm, accessible colors - Add helper function
getParticipantName(speaker: Speaker, config: ParticipantConfig): string - Add helper function
getParticipantColor(speaker: Speaker, config: ParticipantConfig): string
Verification:
npm run buildShould build without errors.
Files to create:
src/domain/ParticipantConfig.ts
Goal: Add participant configuration to session state
Steps:
- Open
src/domain/SessionState.ts - Import
ParticipantConfigfrom./ParticipantConfig - Add field
participantConfig: ParticipantConfig | nulltoSessionStateinterface - Update
createInitialState()to setparticipantConfig: null
Verification:
npm run buildShould build without errors.
Files to modify:
src/domain/SessionState.ts
Goal: Allow engine to receive and store participant configuration on session start
Steps:
- Open
src/domain/SessionEngine.ts - Import
ParticipantConfigfrom./ParticipantConfig - Find the
start(mode: SessionMode)method signature - Update signature to
start(mode: SessionMode, participantConfig?: ParticipantConfig) - In the method body, update the state initialization to include
participantConfig: participantConfig ?? null - Ensure the config is passed through to the state
Verification:
npm run build
npm run test:runAll tests should still pass.
Files to modify:
src/domain/SessionEngine.ts
Goal: Update context to pass participant config to engine
Steps:
- Open
src/contexts/SessionContext.tsx - Import
ParticipantConfigfrom../domain/ParticipantConfig - Update
startaction signature inSessionContextValueinterface tostart: (mode: SessionMode, participantConfig?: ParticipantConfig) => Promise<boolean> - Update the
startcallback implementation to acceptparticipantConfigparameter - Pass
participantConfigtoengine.start(mode, participantConfig)
Verification:
npm run buildShould build without errors.
Files to modify:
src/contexts/SessionContext.tsx
Goal: Make participant names available in view model for UI consumption
Steps:
- Open
src/viewmodels/SessionViewModel.ts - Import
ParticipantConfig, DEFAULT_PARTICIPANT_CONFIGfrom../domain/ParticipantConfig - Add fields to
SessionViewModelinterface:participantNameA: stringparticipantNameB: stringparticipantColorA: stringparticipantColorB: string
- In
createSessionViewModelfunction, derive these values fromstate.participantConfig ?? DEFAULT_PARTICIPANT_CONFIG - Update
speakerDisplayNameto use participant names instead of hardcoded "Partner A/B"
Verification:
npm run build
npm run test:runAll tests should still pass.
Files to modify:
src/viewmodels/SessionViewModel.ts
Goal: Ensure WCAG AA compliance for text on colored backgrounds
Steps:
- Create file
src/utils/colorContrast.ts - Implement
hexToRgb(hex: string): {r: number, g: number, b: number}function - Implement
calculateLuminance(rgb: {r: number, g: number, b: number}): numberusing WCAG formula - Implement
calculateContrastRatio(color1: string, color2: string): number - Implement
getContrastingTextColor(bgColor: string): stringthat returns dark or light color - Implement
meetsContrastRequirement(bg: string, fg: string, ratio?: number): booleanwith default ratio 4.5
Verification:
npm run buildShould build without errors.
Files to create:
src/utils/colorContrast.ts
Goal: Provide dynamic background color based on active speaker
Steps:
- Create file
src/hooks/useParticipantBackground.ts - Import necessary dependencies:
useSession,getCurrentPhase,getSpeakerForPhase,Speaker,useMemo - Create hook
useParticipantBackground()that:- Gets current session state
- Determines current speaker from phase
- Returns appropriate background color (colorA for Speaker.A, colorB for Speaker.B, null for Speaker.None)
- Also returns text color using
getContrastingTextColor
- Export the hook
Verification:
npm run buildShould build without errors.
Files to create:
src/hooks/useParticipantBackground.ts
Goal: UI for entering participant names and selecting colors before session start
Steps:
- Create file
src/components/SessionSetup.tsx - Import dependencies:
useState,ParticipantConfig,DEFAULT_PARTICIPANT_CONFIG,PARTICIPANT_COLOR_PALETTE,useTranslation,motionfrom framer-motion - Create component
SessionSetupwith props:isOpen: booleanonClose: () => voidonConfirm: (config: ParticipantConfig) => void
- Implement state management for name and color selection
- Create UI layout:
- Modal backdrop with Framer Motion AnimatePresence
- Two sections: Partner A and Partner B
- Each section has: name input + color palette selector
- Color swatches from PARTICIPANT_COLOR_PALETTE (show visual selection indicator)
- Cancel and "Start Session" buttons at bottom
- Add validation: prevent starting with empty names by falling back to defaults
- Style with Tailwind CSS for clean, accessible design
Verification:
npm run buildShould build without errors. Component should render when isOpen=true.
Files to create:
src/components/SessionSetup.tsx
Goal: Show setup modal before starting a session
Steps:
- Open
src/components/SessionView.tsx - Import
SessionSetupcomponent - Import
ParticipantConfigtype - In
ModeSelectionViewcomponent, add state:const [setupOpen, setSetupOpen] = useState(false) - Add state:
const [pendingMode, setPendingMode] = useState<SessionMode | null>(null) - Modify the
StartButtonto:- Not start session directly
- Instead: set
pendingModeand open setup modal
- Add
SessionSetupcomponent to JSX:isOpen={setupOpen}onClose={() => { setSetupOpen(false); setPendingMode(null) }}onConfirm={(config) => { session.start(pendingMode!, config); setSetupOpen(false) }}
- Position modal appropriately in the component tree
Verification:
npm run devNavigate to app, select a mode, click Start. Setup modal should appear.
Files to modify:
src/components/SessionView.tsx
Goal: Change background color based on active speaker
Steps:
- Open
src/components/SessionView.tsx - In
ActiveSessionViewcomponent, useuseParticipantBackground()hook - Destructure
{ backgroundColor, textColor }from hook - Wrap the session view in a
motion.div - Use
animateprop to transitionbackgroundColor - Set transition with
duration: 1.2andease: 'easeInOut' - Apply computed
textColorto text elements for contrast - Ensure smooth transitions between phases
Verification:
npm run devStart a session with custom colors. During SlotA/ClosingA, background should be Partner A's color. During SlotB/ClosingB, background should be Partner B's color.
Files to modify:
src/components/SessionView.tsx
Goal: Replace hardcoded "Partner A/B" with actual participant names
Steps:
- Open
src/components/PhaseIndicator.tsx - In the component, get participant names from
viewModel.participantNameAandviewModel.participantNameB - Update the speaker name display (line ~122) to use these dynamic names
- Ensure the speaker icon and badge still display correctly
- Consider adding a subtle color indicator (small dot/badge) matching participant's color
Verification:
npm run devStart session with custom names. PhaseIndicator should show the custom names instead of "Partner A/B".
Files to modify:
src/components/PhaseIndicator.tsx
Goal: Add localized strings for the setup modal
Steps:
- Open
src/i18n/locales/en/translation.json - Add new section
"participants":"participants": { "setup": "Setup Participants", "partnerA": "Partner A", "partnerB": "Partner B", "namePlaceholder": "Enter name", "nameLabel": "Name", "chooseColor": "Choose Color", "cancel": "Cancel", "startSession": "Start Session" }
- Open
src/i18n/locales/de/translation.json - Add German translations for the same keys
- Update SessionSetup component to use these i18n keys via
useTranslation()
Verification:
npm run build
npm run devTest language switcher - modal should show correct language.
Files to modify:
src/i18n/locales/en/translation.jsonsrc/i18n/locales/de/translation.jsonsrc/components/SessionSetup.tsx(update to use i18n)
Goal: Test domain logic for participant configuration
Steps:
- Create file
src/domain/__tests__/ParticipantConfig.test.ts - Write test for default config values
- Write test for
getParticipantNamehelper - Write test for
getParticipantColorhelper - Write test for color palette (ensure 8 colors, all valid hex)
- Run tests with
npm run test:run
Verification:
npm run test:run src/domain/__tests__/ParticipantConfig.test.tsAll tests should pass.
Files to create:
src/domain/__tests__/ParticipantConfig.test.ts
Goal: Verify WCAG compliance calculations
Steps:
- Create file
src/utils/__tests__/colorContrast.test.ts - Test
hexToRgbwith valid hex colors - Test
calculateContrastRatiowith known color pairs - Test
getContrastingTextColorreturns dark text for light backgrounds and vice versa - Test
meetsContrastRequirementwith passing and failing contrast ratios - Run tests
Verification:
npm run test:run src/utils/__tests__/colorContrast.test.tsAll tests should pass.
Files to create:
src/utils/__tests__/colorContrast.test.ts
Goal: Test setup modal behavior
Steps:
- Create file
src/components/__tests__/SessionSetup.test.tsx - Test modal renders when
isOpen=true - Test modal does not render when
isOpen=false - Test name input changes update local state
- Test color selection updates local state
- Test "Start Session" button calls
onConfirmwith correct config - Test "Cancel" button calls
onClose - Run tests
Verification:
npm run test:run src/components/__tests__/SessionSetup.test.tsxAll tests should pass.
Files to create:
src/components/__tests__/SessionSetup.test.tsx
Goal: Verify end-to-end participant personalization flow
Steps:
- Create file
src/__tests__/participantPersonalization.integration.test.tsx - Test flow:
- Render SessionView
- Select a mode
- Click Start
- Setup modal appears
- Enter names and colors
- Click "Start Session"
- Verify session starts with correct config
- Verify background changes during phase transitions
- Run tests
Verification:
npm run test:run src/__tests__/participantPersonalization.integration.test.tsxAll tests should pass.
Files to create:
src/__tests__/participantPersonalization.integration.test.tsx
Goal: Ensure all code compiles, tests pass, and app works correctly
Steps:
- Run TypeScript compiler:
npm run build - Run all tests:
npm run test:run - Start dev server:
npm run dev - Manually test the complete flow:
- Select "Commitment" mode
- Click Start
- Enter custom names (e.g., "Alex" and "Jordan")
- Select different colors for each
- Start session
- Verify background changes to Alex's color during SlotA
- Verify background changes to Jordan's color during SlotB
- Verify names appear in PhaseIndicator
- Test with all 3 preset modes
- Test language switcher (DE/EN)
- Test dark mode compatibility
Verification:
- Build: ✓ No TypeScript errors
- Tests: ✓ All tests passing
- Manual: ✓ Features work as expected
This plan implements Phase 11 (Participant Personalization) with:
- Custom names for Partner A and Partner B
- Color selection from a calm, accessible palette
- Dynamic background colors that transition smoothly based on active speaker
- Full i18n support (DE/EN)
- WCAG AA compliant contrast ratios
- Comprehensive test coverage
- Clean integration with existing architecture
Total tasks: 17 Estimated complexity: Medium Architecture impact: Extends domain, adds new UI component, updates session flow