diff --git a/apps/web/.claude/REMEDIATION_CTA_PLAN.md b/apps/web/.claude/REMEDIATION_CTA_PLAN.md new file mode 100644 index 00000000..0c35cdb8 --- /dev/null +++ b/apps/web/.claude/REMEDIATION_CTA_PLAN.md @@ -0,0 +1,151 @@ +# Remediation CTA Plan + +## Overview + +Add special "fancy" treatment to the StartPracticeModal when the student is in remediation mode (has weak skills that need strengthening). This mirrors the existing tutorial CTA treatment. + +## Current Tutorial CTA Treatment (lines 1311-1428) + +When `sessionMode.type === 'progression' && tutorialRequired`: + +1. **Visual Design:** + - Green gradient background with border + - 🌟 icon + - "You've unlocked: [skill name]" heading + - "Start with a quick tutorial" subtitle + - Green gradient button: "🎓 Begin Tutorial →" + +2. **Behavior:** + - Replaces the regular "Let's Go!" button + - Clicking opens the SkillTutorialLauncher + +## Proposed Remediation CTA + +When `sessionMode.type === 'remediation'`: + +1. **Visual Design:** + - Amber/orange gradient background with border (warm "focus" colors) + - 💪 icon (strength/building) + - "Time to build strength!" heading + - "Focusing on [N] skills that need practice" subtitle + - Show weak skill badges with pKnown percentages + - Amber gradient button: "💪 Start Focus Practice →" + +2. **Behavior:** + - Replaces the regular "Let's Go!" button + - Clicking goes straight to practice (no separate launcher needed) + - The session will automatically target weak skills via sessionMode + +## Implementation Steps + +### Step 1: Add remediation detection + +```typescript +// Derive whether to show remediation CTA +const showRemediationCta = sessionMode.type === 'remediation' && sessionMode.weakSkills.length > 0 +``` + +### Step 2: Create RemediationCta component section + +Add after the Tutorial CTA section (line ~1428), or restructure to have a single "special CTA" section that handles both cases. + +```tsx +{/* Remediation CTA - Weak skills need strengthening */} +{showRemediationCta && !showTutorialGate && ( +
+ {/* Info section */} +
+ 💪 +
+

Time to build strength!

+

Focusing on {weakSkills.length} skill{weakSkills.length > 1 ? 's' : ''} that need practice

+
+
+ + {/* Weak skills badges */} +
+ {sessionMode.weakSkills.slice(0, 4).map((skill) => ( + + {skill.displayName} ({Math.round(skill.pKnown * 100)}%) + + ))} + {sessionMode.weakSkills.length > 4 && ( + +{sessionMode.weakSkills.length - 4} more + )} +
+ + {/* Integrated start button */} + +
+)} +``` + +### Step 3: Update start button visibility logic + +Change from: +```tsx +{!showTutorialGate && ( + +)} +``` + +To: +```tsx +{!showTutorialGate && !showRemediationCta && ( + +)} +``` + +## Visual Comparison + +| Mode | Icon | Color Theme | Heading | Button Text | +|------|------|-------------|---------|-------------| +| Tutorial | 🌟 | Green | "You've unlocked: [skill]" | "🎓 Begin Tutorial →" | +| Remediation | 💪 | Amber | "Time to build strength!" | "💪 Start Focus Practice →" | +| Normal | - | Blue | "Ready to practice?" | "Let's Go! →" | + +## Files to Modify + +1. `apps/web/src/components/practice/StartPracticeModal.tsx` + - Add `showRemediationCta` derived state + - Add Remediation CTA section (similar structure to Tutorial CTA) + - Update regular start button visibility condition + +## Testing Considerations + +1. Storybook stories should cover: + - Remediation mode with 1 weak skill + - Remediation mode with 3+ weak skills + - Remediation mode with 5+ weak skills (overflow) + +2. The existing `StartPracticeModal.stories.tsx` already has sessionMode mocks - add remediation variants. + +## Accessibility + +- Ensure proper ARIA labels on the remediation CTA +- Color contrast should meet WCAG guidelines (amber text on amber background needs checking) +- Screen reader should announce the focus practice intent diff --git a/apps/web/src/components/practice/StartPracticeModal.stories.tsx b/apps/web/src/components/practice/StartPracticeModal.stories.tsx index ea4989bc..9ebd3ef6 100644 --- a/apps/web/src/components/practice/StartPracticeModal.stories.tsx +++ b/apps/web/src/components/practice/StartPracticeModal.stories.tsx @@ -108,6 +108,25 @@ const mockRemediationMode: RemediationMode = { focusDescription: 'Strengthening: +3 and +4', } +const mockRemediationModeSingleSkill: RemediationMode = { + type: 'remediation', + weakSkills: [{ skillId: 'add-2', displayName: '+2', pKnown: 0.28 }], + focusDescription: 'Strengthening: +2', +} + +const mockRemediationModeManySkills: RemediationMode = { + type: 'remediation', + weakSkills: [ + { skillId: 'add-1', displayName: '+1', pKnown: 0.31 }, + { skillId: 'add-2', displayName: '+2', pKnown: 0.38 }, + { skillId: 'add-3', displayName: '+3', pKnown: 0.25 }, + { skillId: 'add-4', displayName: '+4', pKnown: 0.42 }, + { skillId: 'sub-1', displayName: '-1', pKnown: 0.33 }, + { skillId: 'sub-2', displayName: '-2', pKnown: 0.29 }, + ], + focusDescription: 'Strengthening: +1, +2, +3, +4, -1, -2', +} + // Default props const defaultProps = { studentId: 'test-student-1', @@ -183,7 +202,7 @@ export const DarkTheme: Story = { } /** - * Remediation mode - student has weak skills to strengthen + * Remediation mode - student has weak skills to strengthen (2 skills) */ export const RemediationMode: Story = { render: () => ( @@ -198,6 +217,56 @@ export const RemediationMode: Story = { ), } +/** + * Remediation mode with a single weak skill + */ +export const RemediationModeSingleSkill: Story = { + render: () => ( + + + + ), +} + +/** + * Remediation mode with many weak skills (shows overflow) + */ +export const RemediationModeManySkills: Story = { + render: () => ( + + + + ), +} + +/** + * Remediation mode - dark theme + */ +export const RemediationModeDark: Story = { + render: () => ( + +
+ +
+
+ ), +} + /** * Progression mode - student is ready to learn a new skill */ diff --git a/apps/web/src/components/practice/StartPracticeModal.tsx b/apps/web/src/components/practice/StartPracticeModal.tsx index df998ee7..2948ec22 100644 --- a/apps/web/src/components/practice/StartPracticeModal.tsx +++ b/apps/web/src/components/practice/StartPracticeModal.tsx @@ -83,6 +83,10 @@ export function StartPracticeModal({ // Whether to show the tutorial gate prompt const showTutorialGate = !!tutorialConfig && !showTutorial + // Whether to show the remediation CTA (weak skills need strengthening) + const showRemediationCta = + sessionMode.type === 'remediation' && sessionMode.weakSkills.length > 0 + // Get skill info for tutorial from sessionMode const nextSkill = sessionMode.type === 'progression' ? sessionMode.nextSkill : null @@ -1427,6 +1431,181 @@ export function StartPracticeModal({ )} + {/* Remediation CTA - Weak skills need strengthening */} + {showRemediationCta && !showTutorialGate && sessionMode.type === 'remediation' && ( +
+ {/* Info section */} +
+ + 💪 + +
+

+ Time to build strength! +

+

+ Focusing on {sessionMode.weakSkills.length} skill + {sessionMode.weakSkills.length > 1 ? 's' : ''} that need practice +

+ {/* Weak skills badges */} +
+ {sessionMode.weakSkills.slice(0, 4).map((skill) => ( + + {skill.displayName}{' '} + + ({Math.round(skill.pKnown * 100)}%) + + + ))} + {sessionMode.weakSkills.length > 4 && ( + + +{sessionMode.weakSkills.length - 4} more + + )} +
+
+
+ {/* Integrated start button */} + +
+ )} + {/* Error display */} {displayError && (
)} - {/* Start button - only shown when no tutorial is pending */} - {!showTutorialGate && ( + {/* Start button - only shown when no special CTA is active */} + {!showTutorialGate && !showRemediationCta && (