diff --git a/apps/web/src/components/tutorial/ProblemGenerator.stories.tsx b/apps/web/src/components/tutorial/ProblemGenerator.stories.tsx new file mode 100644 index 00000000..7e11baff --- /dev/null +++ b/apps/web/src/components/tutorial/ProblemGenerator.stories.tsx @@ -0,0 +1,301 @@ +import type { Meta, StoryObj } from '@storybook/react' +import { useState } from 'react' +import { css } from '../../../styled-system/css' +import { vstack, hstack } from '../../../styled-system/patterns' +import { PracticeProblemPlayer } from './PracticeProblemPlayer' +import { PracticeStepEditor } from './PracticeStepEditor' +import { createBasicSkillSet, createEmptySkillSet, PracticeStep } from '../../types/tutorial' +import { generateProblems, validatePracticeStepConfiguration } from '../../utils/problemGenerator' + +const meta: Meta = { + title: 'Tutorial/Problem Generator', + parameters: { + layout: 'fullscreen', + }, +} + +export default meta + +// Demo practice step for testing +const defaultPracticeStep: PracticeStep = { + id: 'practice-basic-addition', + type: 'practice', + title: 'Basic Addition Practice', + description: 'Practice basic addition problems using direct addition and heaven bead', + problemCount: 5, + maxTerms: 3, + requiredSkills: { + ...createBasicSkillSet(), + basic: { + directAddition: true, + heavenBead: true, + simpleCombinations: false + } + }, + targetSkills: { + basic: { + directAddition: true, + heavenBead: true, + simpleCombinations: false + } + }, + numberRange: { min: 1, max: 9 }, + sumConstraints: { maxSum: 9 } +} + +const advancedPracticeStep: PracticeStep = { + id: 'practice-five-complements', + type: 'practice', + title: 'Five Complements Practice', + description: 'Practice problems requiring five complement techniques', + problemCount: 8, + maxTerms: 4, + requiredSkills: { + ...createBasicSkillSet(), + basic: { + directAddition: true, + heavenBead: true, + simpleCombinations: true + }, + fiveComplements: { + "4=5-1": true, + "3=5-2": true, + "2=5-3": false, + "1=5-4": false + } + }, + targetSkills: { + fiveComplements: { + "4=5-1": true, + "3=5-2": true, + "2=5-3": false, + "1=5-4": false + } + }, + numberRange: { min: 1, max: 9 }, + sumConstraints: { maxSum: 15 } +} + +// Interactive Problem Generator Demo +function ProblemGeneratorDemo() { + const [practiceStep, setPracticeStep] = useState(defaultPracticeStep) + const [mode, setMode] = useState<'editor' | 'player'>('editor') + const [generatedProblems, setGeneratedProblems] = useState([]) + const [validationResult, setValidationResult] = useState(null) + + const handleGenerate = () => { + const problems = generateProblems(practiceStep) + setGeneratedProblems(problems) + + const validation = validatePracticeStepConfiguration(practiceStep) + setValidationResult(validation) + } + + const handlePracticeComplete = (results: any) => { + console.log('Practice completed:', results) + alert(`Practice completed! Score: ${results.correctAnswers}/${results.totalProblems}`) + } + + return ( +
+ {/* Header */} +
+
+

+ Problem Generator Demo +

+ +
+ + + +
+
+
+ + {/* Content */} +
+ {mode === 'editor' ? ( +
+ {/* Editor */} +
+ +
+ + {/* Generated Problems Display */} +
+

+ Generated Problems ({generatedProblems.length}) +

+ + {validationResult && ( +
+

+ {validationResult.isValid ? '✅ Valid Configuration' : '⚠️ Configuration Issues'} +

+ {validationResult.warnings.map((warning: string, i: number) => ( +
+ • {warning} +
+ ))} +
+ )} + +
+ {generatedProblems.map((problem, index) => ( +
+
+
+
+ {problem.terms.map((term, index) => ( +
{term}
+ ))} +
+ {problem.answer} +
+
+ = {problem.answer} +
+ + {problem.difficulty} + +
+
+
Sequential skills: {problem.requiredSkills.join(', ')}
+
{problem.explanation}
+
+
+ ))} +
+ + {generatedProblems.length === 0 && ( +
+ Click "Generate Problems" to see sample problems +
+ )} +
+
+ ) : ( + /* Player */ +
+ +
+ )} +
+
+ ) +} + +export const InteractiveDemo: StoryObj = { + render: () => +} + +export const BasicAdditionPractice: StoryObj = { + render: () => ( +
+ { + console.log('Practice completed:', results) + alert(`Practice completed! Score: ${results.correctAnswers}/${results.totalProblems}`) + }} + /> +
+ ) +} + +export const FiveComplementsPractice: StoryObj = { + render: () => ( +
+ { + console.log('Practice completed:', results) + alert(`Practice completed! Score: ${results.correctAnswers}/${results.totalProblems}`) + }} + /> +
+ ) +} + +export const PracticeStepEditorStory: StoryObj = { + render: () => { + const [step, setStep] = useState(defaultPracticeStep) + + return ( +
+

+ Practice Step Editor +

+ +
+ ) + } +} \ No newline at end of file