Took care of some warnings
This commit is contained in:
@@ -1,22 +1,32 @@
|
||||
import BlankQuestionsModal from "@/components/BlankQuestionsModal";
|
||||
import { renderExercise } from "@/components/Exercises";
|
||||
import {renderExercise} from "@/components/Exercises";
|
||||
import HighlightContent from "@/components/HighlightContent";
|
||||
import Button from "@/components/Low/Button";
|
||||
import ModuleTitle from "@/components/Medium/ModuleTitle";
|
||||
import { renderSolution } from "@/components/Solutions";
|
||||
import { infoButtonStyle } from "@/constants/buttonStyles";
|
||||
import { Module } from "@/interfaces";
|
||||
import { Exercise, FillBlanksExercise, FillBlanksMCOption, LevelExam, LevelPart, MultipleChoiceExercise, ShuffleMap, UserSolution, WritingExam } from "@/interfaces/exam";
|
||||
import {renderSolution} from "@/components/Solutions";
|
||||
import {infoButtonStyle} from "@/constants/buttonStyles";
|
||||
import {Module} from "@/interfaces";
|
||||
import {
|
||||
Exercise,
|
||||
FillBlanksExercise,
|
||||
FillBlanksMCOption,
|
||||
LevelExam,
|
||||
LevelPart,
|
||||
MultipleChoiceExercise,
|
||||
ShuffleMap,
|
||||
UserSolution,
|
||||
WritingExam,
|
||||
} from "@/interfaces/exam";
|
||||
import useExamStore from "@/stores/examStore";
|
||||
import { defaultUserSolutions } from "@/utils/exams";
|
||||
import { countExercises } from "@/utils/moduleUtils";
|
||||
import { mdiArrowRight } from "@mdi/js";
|
||||
import {defaultUserSolutions} from "@/utils/exams";
|
||||
import {countExercises} from "@/utils/moduleUtils";
|
||||
import {mdiArrowRight} from "@mdi/js";
|
||||
import Icon from "@mdi/react";
|
||||
import clsx from "clsx";
|
||||
import { Dispatch, Fragment, SetStateAction, use, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { BsChevronDown, BsChevronUp } from "react-icons/bs";
|
||||
import { toast } from "react-toastify";
|
||||
import { v4 } from "uuid";
|
||||
import {Dispatch, Fragment, SetStateAction, use, useEffect, useMemo, useRef, useState} from "react";
|
||||
import {BsChevronDown, BsChevronUp} from "react-icons/bs";
|
||||
import {toast} from "react-toastify";
|
||||
import {v4} from "uuid";
|
||||
|
||||
interface Props {
|
||||
exam: LevelExam;
|
||||
@@ -26,9 +36,13 @@ interface Props {
|
||||
}
|
||||
|
||||
function TextComponent({
|
||||
part, contextWord, setContextWordLine
|
||||
part,
|
||||
contextWord,
|
||||
setContextWordLine,
|
||||
}: {
|
||||
part: LevelPart, contextWord: string | undefined, setContextWordLine: React.Dispatch<React.SetStateAction<number | undefined>>
|
||||
part: LevelPart;
|
||||
contextWord: string | undefined;
|
||||
setContextWordLine: React.Dispatch<React.SetStateAction<number | undefined>>;
|
||||
}) {
|
||||
const textRef = useRef<HTMLDivElement>(null);
|
||||
const [lineNumbers, setLineNumbers] = useState<number[]>([]);
|
||||
@@ -42,21 +56,21 @@ function TextComponent({
|
||||
const containerWidth = textRef.current.clientWidth;
|
||||
setLineHeight(lineHeightValue);
|
||||
|
||||
const offscreenElement = document.createElement('div');
|
||||
offscreenElement.style.position = 'absolute';
|
||||
offscreenElement.style.top = '-9999px';
|
||||
offscreenElement.style.left = '-9999px';
|
||||
offscreenElement.style.whiteSpace = 'pre-wrap';
|
||||
const offscreenElement = document.createElement("div");
|
||||
offscreenElement.style.position = "absolute";
|
||||
offscreenElement.style.top = "-9999px";
|
||||
offscreenElement.style.left = "-9999px";
|
||||
offscreenElement.style.whiteSpace = "pre-wrap";
|
||||
offscreenElement.style.width = `${containerWidth}px`;
|
||||
offscreenElement.style.font = computedStyle.font;
|
||||
offscreenElement.style.lineHeight = computedStyle.lineHeight;
|
||||
offscreenElement.style.textAlign = computedStyle.textAlign as CanvasTextAlign;
|
||||
|
||||
const textContent = textRef.current.textContent || '';
|
||||
const textContent = textRef.current.textContent || "";
|
||||
textContent.split(/(\s+)/).forEach((word: string) => {
|
||||
const span = document.createElement('span');
|
||||
const span = document.createElement("span");
|
||||
span.textContent = word;
|
||||
span.style.display = 'inline-block';
|
||||
span.style.display = "inline-block";
|
||||
span.style.height = `calc(1em + 16px)`;
|
||||
offscreenElement.appendChild(span);
|
||||
});
|
||||
@@ -73,9 +87,9 @@ function TextComponent({
|
||||
currentLineTop = firstChild.getBoundingClientRect().top;
|
||||
}
|
||||
|
||||
const spans = offscreenElement.querySelectorAll<HTMLSpanElement>('span');
|
||||
const spans = offscreenElement.querySelectorAll<HTMLSpanElement>("span");
|
||||
|
||||
spans.forEach(span => {
|
||||
spans.forEach((span) => {
|
||||
const rect = span.getBoundingClientRect();
|
||||
const top = rect.top;
|
||||
|
||||
@@ -85,8 +99,7 @@ function TextComponent({
|
||||
lines.push([]);
|
||||
}
|
||||
|
||||
lines[lines.length - 1].push(span.textContent?.trim() || '');
|
||||
|
||||
lines[lines.length - 1].push(span.textContent?.trim() || "");
|
||||
|
||||
if (contextWord && contextWordLine === null && span.textContent?.includes(contextWord)) {
|
||||
contextWordLine = currentLine;
|
||||
@@ -115,9 +128,11 @@ function TextComponent({
|
||||
|
||||
return () => {
|
||||
if (textRef.current) {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
resizeObserver.unobserve(textRef.current);
|
||||
}
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [part.context, part.showContextLines, contextWord]);
|
||||
|
||||
if (typeof part.showContextLines === "undefined") {
|
||||
@@ -142,8 +157,13 @@ function TextComponent({
|
||||
<div className="border border-mti-gray-dim w-full rounded-full opacity-10" />
|
||||
<div className="flex mt-2">
|
||||
<div ref={textRef} className="h-fit ml-2 flex flex-col gap-4">
|
||||
{part.context!.split('\n\n').map((line, index) => {
|
||||
return <p key={`line-${index}`}><span className="mr-6">{index + 1}</span>{line}</p>
|
||||
{part.context!.split("\n\n").map((line, index) => {
|
||||
return (
|
||||
<p key={`line-${index}`}>
|
||||
<span className="mr-6">{index + 1}</span>
|
||||
{line}
|
||||
</p>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
@@ -151,22 +171,18 @@ function TextComponent({
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
const typeCheckWordsMC = (words: any[]): words is FillBlanksMCOption[] => {
|
||||
return Array.isArray(words) && words.every(
|
||||
word => word && typeof word === 'object' && 'id' in word && 'options' in word
|
||||
);
|
||||
}
|
||||
return Array.isArray(words) && words.every((word) => word && typeof word === "object" && "id" in word && "options" in word);
|
||||
};
|
||||
|
||||
|
||||
export default function Level({ exam, showSolutions = false, onFinish, editing = false }: Props) {
|
||||
const [multipleChoicesDone, setMultipleChoicesDone] = useState<{ id: string; amount: number }[]>([]);
|
||||
export default function Level({exam, showSolutions = false, onFinish, editing = false}: Props) {
|
||||
const [multipleChoicesDone, setMultipleChoicesDone] = useState<{id: string; amount: number}[]>([]);
|
||||
const [showBlankModal, setShowBlankModal] = useState(false);
|
||||
|
||||
const { userSolutions, setUserSolutions } = useExamStore((state) => state);
|
||||
const { hasExamEnded, setHasExamEnded } = useExamStore((state) => state);
|
||||
const { partIndex, setPartIndex } = useExamStore((state) => state);
|
||||
const { exerciseIndex, setExerciseIndex } = useExamStore((state) => state);
|
||||
const {userSolutions, setUserSolutions} = useExamStore((state) => state);
|
||||
const {hasExamEnded, setHasExamEnded} = useExamStore((state) => state);
|
||||
const {partIndex, setPartIndex} = useExamStore((state) => state);
|
||||
const {exerciseIndex, setExerciseIndex} = useExamStore((state) => state);
|
||||
const [storeQuestionIndex, setStoreQuestionIndex] = useExamStore((state) => [state.questionIndex, state.setQuestionIndex]);
|
||||
//const [shuffleMaps, setShuffleMaps] = useExamStore((state) => [state.shuffleMaps, state.setShuffleMaps])
|
||||
const [currentExercise, setCurrentExercise] = useState<Exercise>();
|
||||
@@ -197,7 +213,6 @@ export default function Level({ exam, showSolutions = false, onFinish, editing =
|
||||
onFinish(userSolutions);
|
||||
};
|
||||
|
||||
|
||||
const getExercise = () => {
|
||||
if (exerciseIndex === -1) {
|
||||
return undefined;
|
||||
@@ -287,12 +302,10 @@ export default function Level({ exam, showSolutions = false, onFinish, editing =
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
//console.log("Getting another exercise");
|
||||
//setShuffleMaps([]);
|
||||
setCurrentExercise(getExercise());
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [partIndex, exerciseIndex]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
const regex = /.*?['"](.*?)['"] in line (\d+)\?$/;
|
||||
if (currentExercise && currentExercise.type === "multipleChoice") {
|
||||
@@ -307,7 +320,7 @@ export default function Level({ exam, showSolutions = false, onFinish, editing =
|
||||
|
||||
const updatedPrompt = currentExercise.questions[storeQuestionIndex].prompt.replace(
|
||||
`in line ${originalLineNumber}`,
|
||||
`in line ${contextWordLine || originalLineNumber}`
|
||||
`in line ${contextWordLine || originalLineNumber}`,
|
||||
);
|
||||
|
||||
currentExercise.questions[storeQuestionIndex].prompt = updatedPrompt;
|
||||
@@ -315,16 +328,20 @@ export default function Level({ exam, showSolutions = false, onFinish, editing =
|
||||
setContextWord(undefined);
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [storeQuestionIndex, contextWordLine, exerciseIndex, partIndex]); //, shuffleMaps]);
|
||||
|
||||
const nextExercise = (solution?: UserSolution) => {
|
||||
scrollToTop();
|
||||
if (solution) {
|
||||
setUserSolutions([...userSolutions.filter((x) => x.exercise !== solution.exercise), { ...solution, module: "level", exam: exam.id }]);
|
||||
setUserSolutions([...userSolutions.filter((x) => x.exercise !== solution.exercise), {...solution, module: "level", exam: exam.id}]);
|
||||
}
|
||||
|
||||
if (storeQuestionIndex > 0 || currentExercise?.type == "fillBlanks") {
|
||||
setMultipleChoicesDone((prev) => [...prev.filter((x) => x.id !== currentExercise!.id), { id: currentExercise!.id, amount: currentExercise?.type == "fillBlanks" ? currentExercise.words.length - 1 : storeQuestionIndex }]);
|
||||
setMultipleChoicesDone((prev) => [
|
||||
...prev.filter((x) => x.id !== currentExercise!.id),
|
||||
{id: currentExercise!.id, amount: currentExercise?.type == "fillBlanks" ? currentExercise.words.length - 1 : storeQuestionIndex},
|
||||
]);
|
||||
}
|
||||
setStoreQuestionIndex(0);
|
||||
|
||||
@@ -355,11 +372,11 @@ export default function Level({ exam, showSolutions = false, onFinish, editing =
|
||||
setHasExamEnded(false);
|
||||
|
||||
if (solution) {
|
||||
let stat = { ...solution, module: "level" as Module, exam: exam.id }
|
||||
let stat = {...solution, module: "level" as Module, exam: exam.id};
|
||||
/*if (exam.shuffle) {
|
||||
stat.shuffleMaps = shuffleMaps
|
||||
}*/
|
||||
onFinish([...userSolutions.filter((x) => x.exercise !== solution.exercise), { ...stat }]);
|
||||
onFinish([...userSolutions.filter((x) => x.exercise !== solution.exercise), {...stat}]);
|
||||
} else {
|
||||
onFinish(userSolutions);
|
||||
}
|
||||
@@ -368,11 +385,14 @@ export default function Level({ exam, showSolutions = false, onFinish, editing =
|
||||
const previousExercise = (solution?: UserSolution) => {
|
||||
scrollToTop();
|
||||
if (solution) {
|
||||
setUserSolutions([...userSolutions.filter((x) => x.exercise !== solution.exercise), { ...solution, module: "level", exam: exam.id }]);
|
||||
setUserSolutions([...userSolutions.filter((x) => x.exercise !== solution.exercise), {...solution, module: "level", exam: exam.id}]);
|
||||
}
|
||||
|
||||
if (storeQuestionIndex > 0 || currentExercise?.type == "fillBlanks") {
|
||||
setMultipleChoicesDone((prev) => [...prev.filter((x) => x.id !== currentExercise!.id), { id: currentExercise!.id, amount: currentExercise?.type == "fillBlanks" ? currentExercise.words.length - 1 : storeQuestionIndex }]);
|
||||
setMultipleChoicesDone((prev) => [
|
||||
...prev.filter((x) => x.id !== currentExercise!.id),
|
||||
{id: currentExercise!.id, amount: currentExercise?.type == "fillBlanks" ? currentExercise.words.length - 1 : storeQuestionIndex},
|
||||
]);
|
||||
}
|
||||
setStoreQuestionIndex(0);
|
||||
|
||||
@@ -391,7 +411,9 @@ export default function Level({ exam, showSolutions = false, onFinish, editing =
|
||||
exercisesDone +
|
||||
(exerciseIndex === -1 ? 0 : exerciseIndex + 1) +
|
||||
storeQuestionIndex +
|
||||
multipleChoicesDone.reduce((acc, curr) => { return acc + curr.amount}, 0)
|
||||
multipleChoicesDone.reduce((acc, curr) => {
|
||||
return acc + curr.amount;
|
||||
}, 0)
|
||||
);
|
||||
};
|
||||
|
||||
@@ -404,21 +426,21 @@ export default function Level({ exam, showSolutions = false, onFinish, editing =
|
||||
</h4>
|
||||
<span className="text-base">You will be allowed to read the text while doing the exercises</span>
|
||||
</div>
|
||||
<TextComponent
|
||||
part={exam.parts[partIndex]}
|
||||
contextWord={contextWord}
|
||||
setContextWordLine={setContextWordLine}
|
||||
/>
|
||||
<TextComponent part={exam.parts[partIndex]} contextWord={contextWord} setContextWordLine={setContextWordLine} />
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
|
||||
const partLabel = () => {
|
||||
if (currentExercise?.type === "fillBlanks" && typeCheckWordsMC(currentExercise.words))
|
||||
return `Part ${partIndex + 1} (Questions ${currentExercise.words[0].id} - ${currentExercise.words[currentExercise.words.length - 1].id})\n\n${currentExercise.prompt}`
|
||||
return `Part ${partIndex + 1} (Questions ${currentExercise.words[0].id} - ${
|
||||
currentExercise.words[currentExercise.words.length - 1].id
|
||||
})\n\n${currentExercise.prompt}`;
|
||||
if (currentExercise?.type === "multipleChoice")
|
||||
return `Part ${partIndex + 1} (Questions ${currentExercise.questions[0].id} - ${currentExercise.questions[currentExercise.questions.length - 1].id})\n\n${currentExercise.prompt}`
|
||||
}
|
||||
return `Part ${partIndex + 1} (Questions ${currentExercise.questions[0].id} - ${
|
||||
currentExercise.questions[currentExercise.questions.length - 1].id
|
||||
})\n\n${currentExercise.prompt}`;
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
Reference in New Issue
Block a user