diff --git a/apps/web/src/app/tutorial-editor/page.tsx b/apps/web/src/app/tutorial-editor/page.tsx index 2801aea3..ae382dc9 100644 --- a/apps/web/src/app/tutorial-editor/page.tsx +++ b/apps/web/src/app/tutorial-editor/page.tsx @@ -26,7 +26,19 @@ export default function TutorialEditorPage() { editingTitle: false }) const [saveStatus, setSaveStatus] = useState<'idle' | 'saving' | 'saved' | 'error'>('idle') - const [validationResult, setValidationResult] = useState(() => validateTutorialConversion()) + const [validationResult, setValidationResult] = useState(() => { + const result = validateTutorialConversion() + return { + isValid: result.isValid, + errors: result.errors.map(error => ({ + stepId: '', + field: 'general', + message: error, + severity: 'error' as const + })), + warnings: [] + } + }) const [debugEvents, setDebugEvents] = useState([]) // Save tutorial (placeholder - would connect to actual backend) @@ -179,15 +191,8 @@ export default function TutorialEditorPage() { }) } - // Error messages validation - if (!step.errorMessages.wrongBead.trim() || !step.errorMessages.wrongAction.trim() || !step.errorMessages.hint.trim()) { - warnings.push({ - stepId: step.id, - field: 'errorMessages', - message: `Step ${index + 1}: All error messages should be provided`, - severity: 'warning' - }) - } + // Error messages validation removed - errorMessages property no longer exists + // Bead diff tooltip provides better guidance instead }) const validation: TutorialValidation = { diff --git a/apps/web/src/components/EnhancedChampionArena.tsx b/apps/web/src/components/EnhancedChampionArena.tsx index d81035fa..8f785f69 100644 --- a/apps/web/src/components/EnhancedChampionArena.tsx +++ b/apps/web/src/components/EnhancedChampionArena.tsx @@ -101,12 +101,11 @@ function ChampionCard({ }) return ( - { + onClick={(e: React.MouseEvent) => { // Only handle click if not dragging and we have the toggle handler if (!isDragging && onToggleArena) { e.stopPropagation() @@ -135,8 +134,9 @@ function ChampionCard({ boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)' } })} + style={cardStyle} > - )} - {player.emoji} - +
{zone === 'arena' ? 'READY! 🔥' : `Level ${player.level}`}
-
+ ) } @@ -294,7 +294,7 @@ function DroppableZone({ {title} - {isEmpty && ( - {isOver ? `Drop to ${id === 'arena' ? 'enter the arena' : 'return to roster'}!` : subtitle}

-
+ )} {children} -
+ ) } @@ -569,8 +569,8 @@ export function EnhancedChampionArena({ onGameModeChange, onConfigurePlayer, cla Drag champions to experience the most tactile arena ever built!

- {/* Mode Indicator with Spring Animation */} - {arenaPlayers.length === 0 ? 'Select Champions' : gameMode === 'single' ? 'Solo Mode' : gameMode === 'battle' ? 'Battle Mode' : 'Tournament Mode'} - +
+ readonly?: boolean + showPlaceValues?: boolean + onBeadClick?: (placeValue: number, beadType: 'earth' | 'heaven', position: number) => void + } + + export const Abacus: React.ComponentType + + export interface BeadPosition { + placeValue: number + beadType: 'earth' | 'heaven' + position?: number + } + + export interface AbacusState { + beads: BeadPosition[] + value: number + } + + export function createAbacusState(value: number): AbacusState + export function calculateValue(state: AbacusState): number + export function addToAbacus(state: AbacusState, amount: number): AbacusState + export function resetAbacus(): AbacusState +} \ No newline at end of file diff --git a/apps/web/src/types/vitest.d.ts b/apps/web/src/types/vitest.d.ts new file mode 100644 index 00000000..6c57cb45 --- /dev/null +++ b/apps/web/src/types/vitest.d.ts @@ -0,0 +1,9 @@ +/// + +// Extend vitest global types if needed +declare global { + // Vitest globals are already included via the reference above + // This file ensures TypeScript recognizes describe, it, expect, etc. +} + +export {} \ No newline at end of file diff --git a/apps/web/src/utils/skillConfiguration.ts b/apps/web/src/utils/skillConfiguration.ts index 48357043..e38fc339 100644 --- a/apps/web/src/utils/skillConfiguration.ts +++ b/apps/web/src/utils/skillConfiguration.ts @@ -113,8 +113,8 @@ export function skillConfigurationToSkillSets(config: SkillConfiguration): { } } - const target: Partial = { basic: {}, fiveComplements: {}, tenComplements: {} } - const forbidden: Partial = { basic: {}, fiveComplements: {}, tenComplements: {} } + const target: Partial = {} + const forbidden: Partial = {} // Basic skills Object.entries(config.basic).forEach(([skill, mode]) => { @@ -122,10 +122,12 @@ export function skillConfigurationToSkillSets(config: SkillConfiguration): { required.basic[skill as keyof typeof required.basic] = true } if (mode === 'target') { - target.basic![skill as keyof typeof target.basic] = true + if (!target.basic) target.basic = {} as any + target.basic[skill as keyof typeof required.basic] = true } if (mode === 'forbidden') { - forbidden.basic![skill as keyof typeof forbidden.basic] = true + if (!forbidden.basic) forbidden.basic = {} as any + forbidden.basic[skill as keyof typeof required.basic] = true } }) @@ -135,10 +137,12 @@ export function skillConfigurationToSkillSets(config: SkillConfiguration): { required.fiveComplements[skill as keyof typeof required.fiveComplements] = true } if (mode === 'target') { - target.fiveComplements![skill as keyof typeof target.fiveComplements] = true + if (!target.fiveComplements) target.fiveComplements = {} as any + target.fiveComplements[skill as keyof typeof required.fiveComplements] = true } if (mode === 'forbidden') { - forbidden.fiveComplements![skill as keyof typeof forbidden.fiveComplements] = true + if (!forbidden.fiveComplements) forbidden.fiveComplements = {} as any + forbidden.fiveComplements[skill as keyof typeof required.fiveComplements] = true } }) @@ -148,10 +152,12 @@ export function skillConfigurationToSkillSets(config: SkillConfiguration): { required.tenComplements[skill as keyof typeof required.tenComplements] = true } if (mode === 'target') { - target.tenComplements![skill as keyof typeof target.tenComplements] = true + if (!target.tenComplements) target.tenComplements = {} as any + target.tenComplements[skill as keyof typeof required.tenComplements] = true } if (mode === 'forbidden') { - forbidden.tenComplements![skill as keyof typeof forbidden.tenComplements] = true + if (!forbidden.tenComplements) forbidden.tenComplements = {} as any + forbidden.tenComplements[skill as keyof typeof required.tenComplements] = true } }) diff --git a/apps/web/src/utils/test/instructionGenerator.test.ts b/apps/web/src/utils/test/instructionGenerator.test.ts index 25bbd821..106c11c3 100644 --- a/apps/web/src/utils/test/instructionGenerator.test.ts +++ b/apps/web/src/utils/test/instructionGenerator.test.ts @@ -1024,7 +1024,7 @@ describe('Automatic Abacus Instruction Generator', () => { expect(instruction.totalSteps).toBeGreaterThan(0) // Verify pedagogical ordering if multi-step - if (instruction.totalSteps > 1) { + if (instruction.totalSteps && instruction.totalSteps > 1) { const stepBeads = instruction.stepBeadHighlights! const placeValues = [...new Set(stepBeads.map(b => b.placeValue))].sort((a, b) => b - a) diff --git a/apps/web/src/utils/tutorialConverter.ts b/apps/web/src/utils/tutorialConverter.ts index ce18f44d..83fe681e 100644 --- a/apps/web/src/utils/tutorialConverter.ts +++ b/apps/web/src/utils/tutorialConverter.ts @@ -41,11 +41,6 @@ export const guidedAdditionSteps: ExistingTutorialStep[] = [ tooltip: { content: 'Adding earth beads', explanation: 'Earth beads (bottom) are worth 1 each. Push them UP to activate them.' - }, - errorMessages: { - wrongBead: 'Click the highlighted earth bead at the bottom', - wrongAction: 'Move the bead UP to add it', - hint: 'Earth beads move up when adding numbers 1-4' } }, { @@ -61,11 +56,6 @@ export const guidedAdditionSteps: ExistingTutorialStep[] = [ tooltip: { content: 'Building up earth beads', explanation: 'Continue adding earth beads one by one for numbers 2, 3, and 4' - }, - errorMessages: { - wrongBead: 'Click the highlighted earth bead', - wrongAction: 'Move the bead UP to add it', - hint: 'You need 2 earth beads for the number 2' } }, { @@ -81,11 +71,6 @@ export const guidedAdditionSteps: ExistingTutorialStep[] = [ tooltip: { content: 'Adding earth beads in sequence', explanation: 'Continue adding earth beads one by one until you reach 4' - }, - errorMessages: { - wrongBead: 'Click the highlighted earth bead', - wrongAction: 'Move the bead UP to add it', - hint: 'You need 3 earth beads for the number 3' } }, { @@ -101,11 +86,6 @@ export const guidedAdditionSteps: ExistingTutorialStep[] = [ tooltip: { content: 'Maximum earth beads', explanation: 'Four earth beads is the maximum - next we need a different approach' - }, - errorMessages: { - wrongBead: 'Click the highlighted earth bead', - wrongAction: 'Move the bead UP to add it', - hint: 'Four earth beads represent the number 4' } }, @@ -123,11 +103,6 @@ export const guidedAdditionSteps: ExistingTutorialStep[] = [ tooltip: { content: 'Heaven bead = 5', explanation: 'The single bead above the bar represents 5' - }, - errorMessages: { - wrongBead: 'Click the heaven bead at the top', - wrongAction: 'Move the heaven bead DOWN to activate it', - hint: 'The heaven bead is worth 5 points' } }, { @@ -143,11 +118,6 @@ export const guidedAdditionSteps: ExistingTutorialStep[] = [ tooltip: { content: 'Heaven + Earth = 6', explanation: 'When you have room in the earth section, simply add directly' - }, - errorMessages: { - wrongBead: 'Click the first earth bead', - wrongAction: 'Move the earth bead UP to add it', - hint: 'With the heaven bead active, add earth beads for 6, 7, 8, 9' } }, @@ -172,11 +142,6 @@ export const guidedAdditionSteps: ExistingTutorialStep[] = [ tooltip: { content: 'Five Complement: 4 = 5 - 1', explanation: 'When you need to add 4 but only have 1 space, use: add 5, remove 1' - }, - errorMessages: { - wrongBead: 'Follow the two-step process: heaven bead first, then remove earth bead', - wrongAction: 'Add heaven bead, then remove earth bead', - hint: 'Complement thinking: 4 = 5 - 1, so add 5 and take away 1' } }, { @@ -201,11 +166,6 @@ export const guidedAdditionSteps: ExistingTutorialStep[] = [ tooltip: { content: 'Five Complement: 3 = 5 - 2', explanation: 'To add 3, think: 3 = 5 - 2, so add 5 and take away 2' - }, - errorMessages: { - wrongBead: 'Follow the multi-step process: add heaven, then remove earth beads', - wrongAction: 'Add heaven bead first, then remove the necessary earth beads', - hint: 'Complement: 3 = 5 - 2, so add heaven and remove 2 earth' } }, @@ -226,11 +186,6 @@ export const guidedAdditionSteps: ExistingTutorialStep[] = [ tooltip: { content: 'Direct addition when possible', explanation: 'When you have space in the earth section, just add directly' - }, - errorMessages: { - wrongBead: 'Click the next earth beads in sequence', - wrongAction: 'Move the earth beads UP to add them', - hint: 'You have room for 2 more earth beads' } }, { @@ -257,11 +212,6 @@ export const guidedAdditionSteps: ExistingTutorialStep[] = [ tooltip: { content: 'Carrying to tens place', explanation: '7 + 4 = 11, which needs the tens column heaven bead' - }, - errorMessages: { - wrongBead: 'First activate tens heaven, then clear all beads from ones place', - wrongAction: 'Add tens heaven first, then remove heaven and earth beads from ones', - hint: '7 + 4 = 11: add 10 (tens heaven), then subtract 6 by clearing ones place (7-1=6 remaining)' } } ] diff --git a/apps/web/tsconfig.json b/apps/web/tsconfig.json index ddbb8237..d2809693 100644 --- a/apps/web/tsconfig.json +++ b/apps/web/tsconfig.json @@ -1,6 +1,7 @@ { "compilerOptions": { "lib": ["dom", "dom.iterable", "es6"], + "types": ["vitest/globals", "@testing-library/jest-dom"], "allowJs": true, "skipLibCheck": true, "strict": true,