Found the bug
This commit is contained in:
@@ -44,39 +44,39 @@ const FillBlanks: React.FC<FillBlanksExercise & CommonProps> = ({
|
||||
}, [hasExamEnded]);
|
||||
|
||||
|
||||
let correctWords: any;
|
||||
let correctWords: any;
|
||||
if (exam && exam.module === "level" && exam.parts[partIndex].exercises[exerciseIndex].type === "fillBlanks") {
|
||||
correctWords = (exam.parts[partIndex].exercises[exerciseIndex] as FillBlanksExercise).words;
|
||||
}
|
||||
}
|
||||
|
||||
const calculateScore = () => {
|
||||
const total = text.match(/({{\d+}})/g)?.length || 0;
|
||||
const correct = answers!.filter((x) => {
|
||||
const solution = solutions.find((y) => x.id.toString() === y.id.toString())?.solution;
|
||||
if (!solution) return false;
|
||||
const option = correctWords!.find((w: any) => {
|
||||
if (typeof w === "string") {
|
||||
return w.toLowerCase() === x.solution.toLowerCase();
|
||||
} else if ('letter' in w) {
|
||||
return w.word.toLowerCase() === x.solution.toLowerCase();
|
||||
} else {
|
||||
return w.id.toString() === x.id.toString();
|
||||
}
|
||||
});
|
||||
if (!option) return false;
|
||||
const calculateScore = () => {
|
||||
const total = text.match(/({{\d+}})/g)?.length || 0;
|
||||
const correct = answers!.filter((x) => {
|
||||
const solution = solutions.find((y) => x.id.toString() === y.id.toString())?.solution;
|
||||
if (!solution) return false;
|
||||
const option = correctWords!.find((w: any) => {
|
||||
if (typeof w === "string") {
|
||||
return w.toLowerCase() === x.solution.toLowerCase();
|
||||
} else if ('letter' in w) {
|
||||
return w.word.toLowerCase() === x.solution.toLowerCase();
|
||||
} else {
|
||||
return w.id.toString() === x.id.toString();
|
||||
}
|
||||
});
|
||||
if (!option) return false;
|
||||
|
||||
if (typeof option === "string") {
|
||||
return solution.toLowerCase() === option.toLowerCase();
|
||||
} else if ('letter' in option) {
|
||||
return solution.toLowerCase() === option.word.toLowerCase();
|
||||
} else if ('options' in option) {
|
||||
return option.options[solution as keyof typeof option.options] == x.solution;
|
||||
}
|
||||
return false;
|
||||
}).length;
|
||||
const missing = total - answers!.filter((x) => solutions.find((y) => x.id.toString() === y.id.toString())).length;
|
||||
if (typeof option === "string") {
|
||||
return solution.toLowerCase() === option.toLowerCase();
|
||||
} else if ('letter' in option) {
|
||||
return solution.toLowerCase() === option.word.toLowerCase();
|
||||
} else if ('options' in option) {
|
||||
return option.options[solution as keyof typeof option.options] == x.solution;
|
||||
}
|
||||
return false;
|
||||
}).length;
|
||||
const missing = total - answers!.filter((x) => solutions.find((y) => x.id.toString() === y.id.toString())).length;
|
||||
return { total, correct, missing };
|
||||
};
|
||||
};
|
||||
const renderLines = (line: string) => {
|
||||
return (
|
||||
<div className="text-base leading-5" key={v4()}>
|
||||
@@ -125,9 +125,13 @@ const FillBlanks: React.FC<FillBlanksExercise & CommonProps> = ({
|
||||
|
||||
const onSelection = (questionID: string, value: string) => {
|
||||
setAnswers((prev) => [...prev.filter((x) => x.id !== questionID), { id: questionID, solution: value }]);
|
||||
setCurrentSolution({ exercise: id, solutions: answers, score: calculateScore(), type, shuffleMaps: shuffleMaps });
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
setCurrentSolution({ exercise: id, solutions: answers, score: calculateScore(), type, shuffleMaps: shuffleMaps });
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [answers])
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-col gap-4 mt-4 h-full w-full mb-20">
|
||||
@@ -214,15 +218,18 @@ const FillBlanks: React.FC<FillBlanksExercise & CommonProps> = ({
|
||||
onClick={() => onBack({ exercise: id, solutions: answers, score: calculateScore(), type, shuffleMaps: shuffleMaps })}
|
||||
className="max-w-[200px] w-full"
|
||||
disabled={
|
||||
exam && typeof partIndex !== "undefined" && exam.module === "level" &&
|
||||
typeof exam.parts[0].intro === "string" && questionIndex === 0}
|
||||
exam && exam.module === "level" &&
|
||||
typeof exam.parts[0].intro === "string" &&
|
||||
partIndex === 0 &&
|
||||
questionIndex === 0
|
||||
}
|
||||
>
|
||||
Back
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
color="purple"
|
||||
onClick={() => {onNext({ exercise: id, solutions: answers, score: calculateScore(), type, shuffleMaps: shuffleMaps })}}
|
||||
onClick={() => { onNext({ exercise: id, solutions: answers, score: calculateScore(), type, shuffleMaps: shuffleMaps }) }}
|
||||
className="max-w-[200px] self-end w-full">
|
||||
Next
|
||||
</Button>
|
||||
|
||||
@@ -24,7 +24,7 @@ function Question({
|
||||
const renderPrompt = (prompt: string) => {
|
||||
return reactStringReplace(prompt, /(<u>.*?<\/u>)/g, (match) => {
|
||||
const word = match.replaceAll("<u>", "").replaceAll("</u>", "");
|
||||
return word.length > 0 ? <u>{word}</u> : null;
|
||||
return word.length > 0 ? <u key={v4()}>{word}</u> : null;
|
||||
});
|
||||
};
|
||||
|
||||
@@ -49,7 +49,7 @@ function Question({
|
||||
"flex flex-col items-center border border-mti-gray-platinum p-4 px-8 rounded-xl gap-4 cursor-pointer bg-white relative select-none",
|
||||
userSolution === option.id.toString() && "border-mti-purple-light",
|
||||
)}>
|
||||
<span className={clsx("text-sm", userSolution !== option.id.toString() && "opacity-50")}>{option.id.toString()}</span>
|
||||
<span key={v4()} className={clsx("text-sm", userSolution !== option.id.toString() && "opacity-50")}>{option.id.toString()}</span>
|
||||
<img src={option.src!} alt={`Option ${option.id.toString()}`} />
|
||||
</div>
|
||||
))}
|
||||
@@ -79,6 +79,7 @@ export default function MultipleChoice({ id, prompt, type, questions, userSoluti
|
||||
exam,
|
||||
shuffles,
|
||||
hasExamEnded,
|
||||
partIndex,
|
||||
userSolutions: storeUserSolutions,
|
||||
setQuestionIndex,
|
||||
setUserSolutions,
|
||||
@@ -107,7 +108,7 @@ export default function MultipleChoice({ id, prompt, type, questions, userSoluti
|
||||
setAnswers((prev) => [...prev.filter((x) => x.question !== question.id), { option, question: question.id }]);
|
||||
};
|
||||
|
||||
useEffect(()=> {
|
||||
useEffect(() => {
|
||||
setCurrentSolution({ exercise: id, solutions: answers, score: calculateScore(), type, shuffleMaps: shuffleMaps });
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [answers])
|
||||
@@ -136,7 +137,7 @@ export default function MultipleChoice({ id, prompt, type, questions, userSoluti
|
||||
const shuffleMap = shuffleMaps.find((map) => map.questionID == x.question);
|
||||
if (shuffleMap) {
|
||||
isSolutionCorrect = getShuffledSolution(x.option, shuffleMap) == matchingQuestion?.solution;
|
||||
}else {
|
||||
} else {
|
||||
isSolutionCorrect = matchingQuestion?.solution === x.option;
|
||||
}
|
||||
}
|
||||
@@ -159,6 +160,7 @@ export default function MultipleChoice({ id, prompt, type, questions, userSoluti
|
||||
if (questionIndex === 0) {
|
||||
onBack({ exercise: id, solutions: answers, score: calculateScore(), type, shuffleMaps: shuffleMaps });
|
||||
} else {
|
||||
if (exam?.module === "level" && typeof exam.parts[0].intro !== "undefined" && questionIndex === 0) return;
|
||||
setQuestionIndex(questionIndex - 1);
|
||||
}
|
||||
|
||||
@@ -181,7 +183,11 @@ export default function MultipleChoice({ id, prompt, type, questions, userSoluti
|
||||
<div className="self-end flex justify-between w-full gap-8 absolute bottom-8 left-0 px-8">
|
||||
<Button color="purple" variant="outline" onClick={back} className="max-w-[200px] w-full"
|
||||
disabled={
|
||||
exam && exam.module === "level" && typeof exam.parts[0].intro === "string" && questionIndex === 0}
|
||||
exam && exam.module === "level" &&
|
||||
typeof exam.parts[0].intro === "string" &&
|
||||
partIndex === 0 &&
|
||||
questionIndex === 0
|
||||
}
|
||||
>
|
||||
Back
|
||||
</Button>
|
||||
|
||||
@@ -63,7 +63,7 @@ export default function Button({
|
||||
type={type}
|
||||
onClick={onClick}
|
||||
className={clsx(
|
||||
"rounded-full transition ease-in-out duration-300 disabled:cursor-not-allowed cursor-pointer",
|
||||
"rounded-full transition ease-in-out duration-300 disabled:cursor-not-allowed cursor-pointer select-none",
|
||||
padding,
|
||||
colorClassNames[color][variant],
|
||||
className,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Dialog, Transition } from "@headlessui/react";
|
||||
import { Fragment } from "react";
|
||||
import { Fragment, useEffect, useState } from "react";
|
||||
import Button from "./Low/Button";
|
||||
|
||||
interface Props {
|
||||
@@ -10,6 +10,19 @@ interface Props {
|
||||
}
|
||||
|
||||
export default function QuestionsModal({ isOpen, onClose, type = "module", unanswered = false }: Props) {
|
||||
const [isClosing, setIsClosing] = useState(false);
|
||||
|
||||
const blockMultipleClicksClose = (x: boolean) => {
|
||||
if (!isClosing) {
|
||||
setIsClosing(true);
|
||||
onClose(x);
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
setIsClosing(false);
|
||||
}, 400);
|
||||
}
|
||||
|
||||
return (
|
||||
<Transition show={isOpen} as={Fragment}>
|
||||
<Dialog onClose={() => onClose(false)} className="relative z-50">
|
||||
@@ -44,10 +57,10 @@ export default function QuestionsModal({ isOpen, onClose, type = "module", unans
|
||||
Are you sure you want to continue without completing those questions?
|
||||
</span>
|
||||
<div className="w-full flex justify-between mt-8">
|
||||
<Button color="purple" onClick={() => onClose(false)} variant="outline" className="max-w-[200px] self-end w-full">
|
||||
<Button color="purple" onClick={() => blockMultipleClicksClose(false)} variant="outline" className="max-w-[200px] self-end w-full">
|
||||
Go Back
|
||||
</Button>
|
||||
<Button color="purple" onClick={() => onClose(true)} className="max-w-[200px] self-end w-full">
|
||||
<Button color="purple" onClick={() => blockMultipleClicksClose(true)} className="max-w-[200px] self-end w-full">
|
||||
Continue
|
||||
</Button>
|
||||
</div>
|
||||
@@ -56,18 +69,16 @@ export default function QuestionsModal({ isOpen, onClose, type = "module", unans
|
||||
{type === "blankQuestions" && (
|
||||
<>
|
||||
<Dialog.Title className="font-bold text-xl">Questions Unanswered</Dialog.Title>
|
||||
<span>
|
||||
You have left some questions unanswered in the current part. <br />
|
||||
<br />
|
||||
If you wish to continue, you can still access this part later using the navigation bar at the top. <br />
|
||||
<br />
|
||||
Do you want to proceed to the next part, or would you like to go back and complete the unanswered questions in the current part?
|
||||
</span>
|
||||
<div className="w-full flex justify-between mt-8">
|
||||
<Button color="purple" onClick={() => onClose(false)} variant="outline" className="max-w-[200px] self-end w-full">
|
||||
<div className="flex flex-col text-lg gap-2">
|
||||
<p>You have left some questions unanswered in the current part.</p>
|
||||
<p>If you wish to continue, you can still access this part later using the navigation bar at the top or the "Back" button.</p>
|
||||
<p>Do you want to proceed to the next part, or would you like to go back and complete the unanswered questions in the current part?</p>
|
||||
</div>
|
||||
<div className="w-full flex justify-between mt-6">
|
||||
<Button color="purple" onClick={() => blockMultipleClicksClose(false)} variant="outline" className="max-w-[200px] self-end w-full">
|
||||
Go Back
|
||||
</Button>
|
||||
<Button color="purple" onClick={() => onClose(true)} className="max-w-[200px] self-end w-full">
|
||||
<Button color="purple" onClick={() => blockMultipleClicksClose(true)} className="max-w-[200px] self-end w-full">
|
||||
Continue
|
||||
</Button>
|
||||
</div>
|
||||
@@ -92,10 +103,10 @@ export default function QuestionsModal({ isOpen, onClose, type = "module", unans
|
||||
)}
|
||||
</span>
|
||||
<div className="w-full flex justify-between mt-8">
|
||||
<Button color="purple" onClick={() => onClose(false)} variant="outline" className="max-w-[200px] self-end w-full">
|
||||
<Button color="purple" onClick={() => blockMultipleClicksClose(false)} variant="outline" className="max-w-[200px] self-end w-full">
|
||||
Go Back
|
||||
</Button>
|
||||
<Button color="purple" onClick={() => onClose(true)} className="max-w-[200px] self-end w-full">
|
||||
<Button color="purple" onClick={() => blockMultipleClicksClose(true)} className="max-w-[200px] self-end w-full">
|
||||
Submit
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user