this repo has no description
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}