this repo has no description
at fix-ts-uint8array 138 lines 3.3 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: 'RESTORE_STATE'; exercises: Exercise[]; currentIndex: number; hearts: number; correctCount: number } 18 | { type: 'SELECT_ANSWER'; answer: unknown } 19 | { type: 'CHECK_ANSWER'; correct: boolean } 20 | { type: 'NEXT_EXERCISE' } 21 | { type: 'FINISH' }; 22 23const initialState: LessonState = { 24 exercises: [], 25 currentIndex: 0, 26 hearts: 5, 27 correctCount: 0, 28 selectedAnswer: null, 29 isCorrect: null, 30 isChecked: false, 31 isFinished: false, 32}; 33 34function lessonReducer(state: LessonState, action: LessonAction): LessonState { 35 switch (action.type) { 36 case 'SET_EXERCISES': 37 return { 38 ...initialState, 39 exercises: action.exercises, 40 }; 41 42 case 'RESTORE_STATE': 43 return { 44 ...initialState, 45 exercises: action.exercises, 46 currentIndex: action.currentIndex, 47 hearts: action.hearts, 48 correctCount: action.correctCount, 49 }; 50 51 case 'SELECT_ANSWER': 52 if (state.isChecked) return state; 53 return { 54 ...state, 55 selectedAnswer: action.answer, 56 }; 57 58 case 'CHECK_ANSWER': { 59 const newHearts = action.correct ? state.hearts : state.hearts - 1; 60 const newCorrectCount = action.correct 61 ? state.correctCount + 1 62 : state.correctCount; 63 const isFinished = newHearts === 0; 64 return { 65 ...state, 66 isCorrect: action.correct, 67 isChecked: true, 68 hearts: newHearts, 69 correctCount: newCorrectCount, 70 isFinished, 71 }; 72 } 73 74 case 'NEXT_EXERCISE': { 75 const nextIndex = state.currentIndex + 1; 76 const isFinished = nextIndex >= state.exercises.length; 77 return { 78 ...state, 79 currentIndex: nextIndex, 80 selectedAnswer: null, 81 isCorrect: null, 82 isChecked: false, 83 isFinished, 84 }; 85 } 86 87 case 'FINISH': 88 return { 89 ...state, 90 isFinished: true, 91 }; 92 93 default: 94 return state; 95 } 96} 97 98export function useLesson() { 99 const [state, dispatch] = useReducer(lessonReducer, initialState); 100 101 const setExercises = useCallback( 102 (exercises: Exercise[]) => dispatch({ type: 'SET_EXERCISES', exercises }), 103 [], 104 ); 105 106 const restoreState = useCallback( 107 (exercises: Exercise[], currentIndex: number, hearts: number, correctCount: number) => 108 dispatch({ type: 'RESTORE_STATE', exercises, currentIndex, hearts, correctCount }), 109 [], 110 ); 111 112 const selectAnswer = useCallback( 113 (answer: unknown) => dispatch({ type: 'SELECT_ANSWER', answer }), 114 [], 115 ); 116 117 const checkAnswer = useCallback( 118 (correct: boolean) => dispatch({ type: 'CHECK_ANSWER', correct }), 119 [], 120 ); 121 122 const nextExercise = useCallback( 123 () => dispatch({ type: 'NEXT_EXERCISE' }), 124 [], 125 ); 126 127 const finish = useCallback(() => dispatch({ type: 'FINISH' }), []); 128 129 return { 130 state, 131 setExercises, 132 restoreState, 133 selectAnswer, 134 checkAnswer, 135 nextExercise, 136 finish, 137 }; 138}