Skip to content

Commit 584274e

Browse files
committed
Fixed bug
1 parent 6cb9e0b commit 584274e

File tree

8 files changed

+78
-51
lines changed

8 files changed

+78
-51
lines changed

src/pages/WordToTranslation/FinalReport/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ import EditRoundedIcon from '@mui/icons-material/EditRounded';
66
import { useDialogs } from '@toolpad/core';
77
import WordFormDialog from '@/components/WordFormDialog';
88
import { Fragment } from 'react/jsx-runtime';
9-
import { Question } from '@/services/words/types';
9+
import { QuizItem } from '@/services/words/types';
1010
import { renderWordTypes } from '@/services/words/utils';
1111

1212
interface Props {
13-
data: Question[];
13+
data: QuizItem[];
1414
}
1515

1616
export const FinalReport = ({ data }: Props) => {

src/pages/WordToTranslation/Quiz/Answers/index.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
import { Button, Stack } from '@mui/material';
2-
import { Word, Question } from '@/services/words/types';
2+
import { Word, QuizItem } from '@/services/words/types';
33

44
interface Props {
5-
data: Question;
5+
item: QuizItem;
66
onClickAnswer: (word: Word) => void;
77
}
88

9-
export const Answers = ({ data, onClickAnswer }: Props) => {
9+
export const Answers = ({ item, onClickAnswer }: Props) => {
1010
return (
1111
<Stack spacing={2}>
12-
{data.answers.map((it, index) => {
13-
const isAnswered: boolean = !!data.userAnswer;
14-
const isSelected: boolean = data.userAnswer?.id === it.id;
15-
const isSuccess: boolean = it.id === data.question.id;
12+
{item.answers.map((it, index) => {
13+
const isAnswered: boolean = !!item.userAnswer;
14+
const isSelected: boolean = item.userAnswer?.id === it.id;
15+
const isSuccess: boolean = it.id === item.question.id;
1616
return (
1717
<Button
1818
key={it.id}

src/pages/WordToTranslation/Quiz/index.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
import { Button, FormControlLabel, Grid2 as Grid, Switch, Typography } from '@mui/material';
22
import { Question } from './Question';
33
import { Answers } from './Answers';
4-
import { Word, Question as QuestionType } from '@/services/words/types';
4+
import { Word, QuizItem } from '@/services/words/types';
55

66
interface Props {
7-
question: QuestionType;
7+
item: QuizItem;
88
onClickAnswer: (answer: Word) => void;
99
onGoToNextQuestion: () => void;
1010
autoSpeak: boolean;
1111
onChangeAutoSpeak: (value: boolean) => void;
1212
}
1313

14-
export const Quiz = ({ question, onClickAnswer, onGoToNextQuestion, autoSpeak, onChangeAutoSpeak }: Props) => {
14+
export const Quiz = ({ item, onClickAnswer, onGoToNextQuestion, autoSpeak, onChangeAutoSpeak }: Props) => {
1515
return (
1616
<Grid container rowSpacing={4} columnSpacing={8}>
1717
<Grid size={12} textAlign="right">
@@ -23,13 +23,13 @@ export const Quiz = ({ question, onClickAnswer, onGoToNextQuestion, autoSpeak, o
2323
/>
2424
</Grid>
2525
<Grid size={6} sx={{ display: 'flex' }}>
26-
<Question data={question.question} autoSpeak={autoSpeak} />
26+
<Question data={item.question} autoSpeak={autoSpeak} />
2727
</Grid>
2828
<Grid size={6}>
29-
<Answers data={question} onClickAnswer={onClickAnswer} />
29+
<Answers item={item} onClickAnswer={onClickAnswer} />
3030
</Grid>
3131
<Grid offset={6} size={6}>
32-
{question.userAnswer && (
32+
{item.userAnswer && (
3333
<Button variant="outlined" onClick={onGoToNextQuestion} size="large">
3434
Дальше
3535
</Button>

src/pages/WordToTranslation/hooks.ts

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
import { useHotkeys, HotkeyCallback } from 'react-hotkeys-hook';
22
import { useGetWordList } from '@/services/words/hooks';
3-
import { Word, Question } from '@/services/words/types';
4-
import { filterWordsByTagIds, filterWordsByTypes, makeQuestions, renderWordTypes } from '@/services/words/utils';
5-
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
3+
import { Word, QuizItem } from '@/services/words/types';
4+
import {
5+
filterWordsByTagIds,
6+
filterWordsByTypes,
7+
makeQuizItems,
8+
renderWordTypes,
9+
updateQuizItems,
10+
} from '@/services/words/utils';
11+
import { useCallback, useMemo, useState } from 'react';
612
import { useLocation } from 'react-router-dom';
713
import { TrainerRouteState } from '../Trainers/types';
814
import {
@@ -13,23 +19,23 @@ import {
1319
import { useGetWordProgressList } from '@/services/wordProgress/hooks';
1420
import { useGetTagList } from '@/services/tags/hooks';
1521
import { renderTags } from '@/services/tags/utils';
22+
import { useEffectOnce } from '@/hooks/useOnceEffect';
1623

1724
export const useWordToTranslation = () => {
1825
const { data: tagList, isLoading: isLoadingTags } = useGetTagList();
1926
const { data: wordList, isLoading: isLoadingWordList } = useGetWordList();
2027
const { data: wordProgressList, isLoading: isLoadingWordProgressList } = useGetWordProgressList();
2128
const isLoading = isLoadingWordList || isLoadingWordProgressList || isLoadingTags;
2229

23-
const [questions, setQuestions] = useState<Question[]>([]);
30+
const [items, setItems] = useState<QuizItem[]>([]);
2431
const [curIndex, setCurIndex] = useState(0);
2532
const [isFinished, setIsFinished] = useState(false);
2633
const [autoSpeak, setAutoSpeak] = useState(false);
27-
const refOnlyOnce = useRef(false);
2834

2935
const stepNumber = curIndex + 1;
30-
const stepCount = questions.length;
31-
const question = questions.length > 0 ? questions[curIndex] : null;
32-
const isUserAnswered = !!question?.userAnswer;
36+
const stepCount = items.length;
37+
const curItem = items.length > 0 ? items[curIndex] : null;
38+
const isUserAnswered = !!curItem?.userAnswer;
3339

3440
const routeState = (useLocation().state ?? {}) as TrainerRouteState;
3541

@@ -58,53 +64,60 @@ export const useWordToTranslation = () => {
5864
const applyUserAnswer = useCallback(
5965
(word: Word) => {
6066
if (!isUserAnswered) {
61-
setQuestions((state) =>
67+
setItems((state) =>
6268
state.map((it) => {
63-
return it === question ? { ...it, userAnswer: word } : it;
69+
return it === curItem ? { ...it, userAnswer: word } : it;
6470
}),
6571
);
6672
}
6773
},
68-
[question, isUserAnswered],
74+
[curItem, isUserAnswered],
6975
);
7076

7177
const applyUserAnswerByKeyNumber: HotkeyCallback = useCallback(
7278
(event) => {
7379
const keyNumber = Number(event.key);
74-
const answer = question?.answers[keyNumber - 1];
80+
const answer = curItem?.answers[keyNumber - 1];
7581
if (answer) {
7682
applyUserAnswer(answer);
7783
}
7884
},
79-
[applyUserAnswer, question?.answers],
85+
[applyUserAnswer, curItem?.answers],
8086
);
8187

8288
const goToNextQuestion = useCallback(() => {
8389
if (isUserAnswered) {
84-
if (curIndex < questions.length - 1) {
90+
if (curIndex < items.length - 1) {
8591
setCurIndex((state) => state + 1);
8692
} else {
8793
setIsFinished(true);
88-
saveWordProgressList(questions);
94+
saveWordProgressList(items);
8995
}
9096
}
91-
}, [curIndex, isUserAnswered, questions]);
97+
}, [curIndex, isUserAnswered, items]);
9298

9399
const startQuiz = useCallback(() => {
94100
if (!filteredWordList) {
95101
return;
96102
}
97103
setIsFinished(false);
98104
setCurIndex(0);
99-
setQuestions(makeQuestions(filteredWordList));
105+
setItems(makeQuizItems(filteredWordList));
100106
}, [filteredWordList]);
101107

102-
useEffect(() => {
103-
if (filteredWordList && !refOnlyOnce.current) {
104-
refOnlyOnce.current = true;
105-
startQuiz();
106-
}
107-
}, [filteredWordList, startQuiz]);
108+
useEffectOnce({
109+
effect: startQuiz,
110+
condition: () => !!filteredWordList,
111+
deps: [filteredWordList, startQuiz],
112+
});
113+
114+
// Update items after changed word list
115+
useEffectOnce({
116+
effect: () => setItems((state) => updateQuizItems(state, wordList!)),
117+
condition: () => !!wordList,
118+
skipFirst: true,
119+
deps: [wordList],
120+
});
108121

109122
useHotkeys('space,enter', isFinished ? startQuiz : goToNextQuestion, { preventDefault: true });
110123
useHotkeys('1,2,3,4,5,6,7,8,9', applyUserAnswerByKeyNumber, { preventDefault: true });
@@ -113,11 +126,11 @@ export const useWordToTranslation = () => {
113126
isLoading,
114127
stepNumber,
115128
stepCount,
116-
question,
129+
curItem,
117130
applyUserAnswer,
118131
goToNextQuestion,
119132
isFinished,
120-
questions,
133+
items,
121134
startQuiz,
122135
autoSpeak,
123136
setAutoSpeak,

src/pages/WordToTranslation/index.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ const WordToTranslation = () => {
1111
isLoading,
1212
stepNumber,
1313
stepCount,
14-
question,
14+
curItem,
1515
applyUserAnswer,
1616
goToNextQuestion,
1717
isFinished,
18-
questions,
18+
items,
1919
startQuiz: restart,
2020
autoSpeak,
2121
setAutoSpeak,
@@ -45,10 +45,10 @@ const WordToTranslation = () => {
4545
</Stack>
4646
)}
4747
</Stack>
48-
{isFinished && <FinalReport data={questions} />}
49-
{!isFinished && question && (
48+
{isFinished && <FinalReport data={items} />}
49+
{!isFinished && curItem && (
5050
<Quiz
51-
question={question}
51+
item={curItem}
5252
onClickAnswer={applyUserAnswer}
5353
onGoToNextQuestion={goToNextQuestion}
5454
autoSpeak={autoSpeak}

src/services/wordProgress/utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { DateTime, Interval } from 'luxon';
2-
import { Question, Word } from '../words/types';
2+
import { QuizItem, Word } from '../words/types';
33
import { findWordProgressByWord, updateWordProgress } from './api';
44
import { WordProgress } from './types';
55
import { mergeValues } from '@/utils/form';
@@ -14,7 +14,7 @@ export const getWordProgressDefaultValues = (wordId: string): WordProgress => {
1414
};
1515
};
1616

17-
export const saveWordProgressList = async (questions: Question[]): Promise<void> => {
17+
export const saveWordProgressList = async (questions: QuizItem[]): Promise<void> => {
1818
for (const { question: word, userAnswer } of questions) {
1919
const isRightAnswer = word.id === userAnswer?.id;
2020
const wordProgress = (await findWordProgressByWord(word.id)) ?? getWordProgressDefaultValues(word.id);

src/services/words/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export enum WordType {
2626

2727
export type Word = z.infer<typeof WordSchema>;
2828

29-
export interface Question {
29+
export interface QuizItem {
3030
question: Word;
3131
answers: Word[];
3232
userAnswer: Word | null;

src/services/words/utils.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { DateTime } from 'luxon';
2-
import { Question, Word, WordType } from './types';
2+
import { QuizItem, Word, WordType } from './types';
33
import { getRandomItemOfArray, shuffle } from '@/utils/random';
44
import { WORD_TYPE_TO_NAME } from '@/constants/word';
55

@@ -65,8 +65,8 @@ export const renderWordTypes = (values: WordType[]) => {
6565
const QUESTIONS_MAX = 7;
6666
const ANSWERS_MAX = 5;
6767

68-
export const makeQuestions = (words: Word[]): Question[] => {
69-
const questions: Question[] = [];
68+
export const makeQuizItems = (words: Word[]): QuizItem[] => {
69+
const questions: QuizItem[] = [];
7070
for (const word of words.slice(0, QUESTIONS_MAX)) {
7171
const answers: Word[] = [word];
7272
const answerIds: string[] = [word.id];
@@ -88,3 +88,17 @@ export const makeQuestions = (words: Word[]): Question[] => {
8888
}
8989
return questions;
9090
};
91+
92+
export const updateQuizItems = (items: QuizItem[], words: Word[]): QuizItem[] => {
93+
const wordsById = new Map<string, Word>();
94+
for (const word of words) {
95+
wordsById.set(word.id, word);
96+
}
97+
return items.map((item) => {
98+
return {
99+
question: wordsById.get(item.question.id) ?? item.question,
100+
answers: item.answers.map((answer) => wordsById.get(answer.id) ?? answer),
101+
userAnswer: wordsById.get(item.userAnswer?.id ?? '') ?? item.userAnswer,
102+
};
103+
});
104+
};

0 commit comments

Comments
 (0)