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: '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}