this repo has no description
at sound-effects 121 lines 2.8 kB view raw
1import { useReducer, useCallback } from 'react'; 2import type { Exercise } from '../types/lesson'; 3 4export interface LessonState { 5 exercises: Exercise[]; 6 currentIndex: number; 7 hearts: number; 8 correctCount: number; 9 selectedAnswer: unknown; 10 isCorrect: boolean | null; 11 isChecked: boolean; 12 isFinished: boolean; 13} 14 15type LessonAction = 16 | { type: 'SET_EXERCISES'; exercises: Exercise[] } 17 | { type: 'SELECT_ANSWER'; answer: unknown } 18 | { type: 'CHECK_ANSWER'; correct: boolean } 19 | { type: 'NEXT_EXERCISE' } 20 | { type: 'FINISH' }; 21 22const initialState: LessonState = { 23 exercises: [], 24 currentIndex: 0, 25 hearts: 5, 26 correctCount: 0, 27 selectedAnswer: null, 28 isCorrect: null, 29 isChecked: false, 30 isFinished: false, 31}; 32 33function lessonReducer(state: LessonState, action: LessonAction): LessonState { 34 switch (action.type) { 35 case 'SET_EXERCISES': 36 return { 37 ...initialState, 38 exercises: action.exercises, 39 }; 40 41 case 'SELECT_ANSWER': 42 if (state.isChecked) return state; 43 return { 44 ...state, 45 selectedAnswer: action.answer, 46 }; 47 48 case 'CHECK_ANSWER': { 49 const newHearts = action.correct ? state.hearts : state.hearts - 1; 50 const newCorrectCount = action.correct 51 ? state.correctCount + 1 52 : state.correctCount; 53 const isFinished = newHearts === 0; 54 return { 55 ...state, 56 isCorrect: action.correct, 57 isChecked: true, 58 hearts: newHearts, 59 correctCount: newCorrectCount, 60 isFinished, 61 }; 62 } 63 64 case 'NEXT_EXERCISE': { 65 const nextIndex = state.currentIndex + 1; 66 const isFinished = nextIndex >= state.exercises.length; 67 return { 68 ...state, 69 currentIndex: nextIndex, 70 selectedAnswer: null, 71 isCorrect: null, 72 isChecked: false, 73 isFinished, 74 }; 75 } 76 77 case 'FINISH': 78 return { 79 ...state, 80 isFinished: true, 81 }; 82 83 default: 84 return state; 85 } 86} 87 88export function useLesson() { 89 const [state, dispatch] = useReducer(lessonReducer, initialState); 90 91 const setExercises = useCallback( 92 (exercises: Exercise[]) => dispatch({ type: 'SET_EXERCISES', exercises }), 93 [], 94 ); 95 96 const selectAnswer = useCallback( 97 (answer: unknown) => dispatch({ type: 'SELECT_ANSWER', answer }), 98 [], 99 ); 100 101 const checkAnswer = useCallback( 102 (correct: boolean) => dispatch({ type: 'CHECK_ANSWER', correct }), 103 [], 104 ); 105 106 const nextExercise = useCallback( 107 () => dispatch({ type: 'NEXT_EXERCISE' }), 108 [], 109 ); 110 111 const finish = useCallback(() => dispatch({ type: 'FINISH' }), []); 112 113 return { 114 state, 115 setExercises, 116 selectAnswer, 117 checkAnswer, 118 nextExercise, 119 finish, 120 }; 121}