Previous Level exams were being broken by the part divider changes, fixed it.

This commit is contained in:
Carlos Mesquita
2024-09-02 22:18:33 +01:00
parent 39752cbb1d
commit caddf87231
16 changed files with 142 additions and 96 deletions

View File

@@ -4,7 +4,7 @@ import Button from "@/components/Low/Button";
import ModuleTitle from "@/components/Medium/ModuleTitle";
import { renderSolution } from "@/components/Solutions";
import { Module } from "@/interfaces";
import { Exercise, FillBlanksMCOption, LevelExam, MultipleChoiceExercise, MultipleChoiceQuestion, ShuffleMap, UserSolution } from "@/interfaces/exam";
import { Exercise, FillBlanksMCOption, LevelExam, MultipleChoiceExercise, UserSolution } from "@/interfaces/exam";
import useExamStore from "@/stores/examStore";
import { countExercises } from "@/utils/moduleUtils";
import clsx from "clsx";
@@ -68,8 +68,15 @@ export default function Level({ exam, showSolutions = false, onFinish, editing =
onClose: function (x: boolean | undefined) { if (x) { setShowQuestionsModal(false); nextExercise(); } else { setShowQuestionsModal(false) } }
});
const [currentExercise, setCurrentExercise] = useState<Exercise>(exam.parts[0].exercises[0]);
const [currentExercise, setCurrentExercise] = useState<Exercise | undefined>(undefined);
const [showPartDivider, setShowPartDivider] = useState<boolean>(typeof exam.parts[0].intro === "string" && !showSolutions);
const [startNow, setStartNow] = useState<boolean>(true && !showSolutions);
useEffect(() => {
if (currentExercise === undefined && partIndex === 0 && exerciseIndex === 0) {
setCurrentExercise(exam.parts[0].exercises[0]);
}
}, [currentExercise, partIndex, exerciseIndex]);
const scrollToTop = () => Array.from(document.getElementsByTagName("body")).forEach((body) => body.scrollTo(0, 0));
@@ -108,10 +115,9 @@ export default function Level({ exam, showSolutions = false, onFinish, editing =
let exercise = exam.parts[partIndex]?.exercises[exerciseIndex];
exercise = {
...exercise,
userSolutions: userSolutions.find((x) => x.exercise === exercise.id)?.solutions || [],
userSolutions: userSolutions.find((x) => x.exercise == exercise.id)?.solutions || [],
};
exercise = shuffleExamExercise(exam.shuffle, exercise, showSolutions, userSolutions, shuffles, setShuffles);
return exercise;
};
@@ -162,7 +168,7 @@ export default function Level({ exam, showSolutions = false, onFinish, editing =
return;
}
if(partIndex + 1 === exam.parts.length && exerciseIndex === exam.parts[partIndex].exercises.length - 1 && !continueAnyways) {
if (partIndex + 1 === exam.parts.length && exerciseIndex === exam.parts[partIndex].exercises.length - 1 && !continueAnyways) {
modalKwargs();
setShowQuestionsModal(true);
}
@@ -219,11 +225,22 @@ export default function Level({ exam, showSolutions = false, onFinish, editing =
if (i == (partIndex - 1)) break;
for (let j = 0; j < exam.parts[i].exercises.length; j++) {
const exercise = exam.parts[i].exercises[j];
if (exercise.type === "multipleChoice") {
multipleChoiceQuestionsDone.push({ id: exercise.id, amount: exercise.questions.length - 1 })
}
if (exercise.type === "fillBlanks") {
multipleChoiceQuestionsDone.push({ id: exercise.id, amount: exercise.words.length - 1 })
switch(exercise.type) {
case 'multipleChoice':
multipleChoiceQuestionsDone.push({ id: exercise.id, amount: exercise.questions.length - 1 })
break;
case 'fillBlanks':
multipleChoiceQuestionsDone.push({ id: exercise.id, amount: exercise.words.length - 1 })
break;
case 'writeBlanks':
multipleChoiceQuestionsDone.push({ id: exercise.id, amount: exercise.solutions.length - 1 })
break;
case 'matchSentences':
multipleChoiceQuestionsDone.push({ id: exercise.id, amount: exercise.sentences.length - 1})
break;
case 'trueFalse':
multipleChoiceQuestionsDone.push({ id: exercise.id, amount: exercise.questions.length - 1})
break;
}
}
}
@@ -233,28 +250,12 @@ export default function Level({ exam, showSolutions = false, onFinish, editing =
};
const calculateExerciseIndex = () => {
if (exam.parts[0].intro) {
return exam.parts.reduce((acc, curr, index) => {
if (index < partIndex) {
return acc + countExercises(curr.exercises)
}
return acc;
}, 0) + (questionIndex + 1);
} else {
if (partIndex === 0) {
return (
(exerciseIndex === -1 ? 0 : exerciseIndex + 1) + questionIndex //+ multipleChoicesDone.reduce((acc, curr) => acc + curr.amount, 0)
);
return exam.parts.reduce((acc, curr, index) => {
if (index < partIndex) {
return acc + countExercises(curr.exercises)
}
const exercisesPerPart = exam.parts.map((x) => x.exercises.length);
const exercisesDone = exercisesPerPart.filter((_, index) => index < partIndex).reduce((acc, curr) => curr + acc, 0);
return (
exercisesDone +
(exerciseIndex === -1 ? 0 : exerciseIndex + 1) +
questionIndex
+ multipleChoicesDone.reduce((acc, curr) => { return acc + curr.amount }, 0)
);
}
return acc;
}, 0) + (questionIndex + 1);
};
const renderText = () => (
@@ -320,11 +321,17 @@ export default function Level({ exam, showSolutions = false, onFinish, editing =
const answeredEveryQuestion = (partIndex: number) => {
return exam.parts[partIndex].exercises.every((exercise) => {
const userSolution = userSolutions.find(x => x.exercise === exercise.id);
if (exercise.type === "multipleChoice") {
return userSolution?.solutions.length === exercise.questions.length;
}
if (exercise.type === "fillBlanks") {
return userSolution?.solutions.length === exercise.words.length;
switch(exercise.type) {
case 'multipleChoice':
return userSolution?.solutions.length === exercise.questions.length;
case 'fillBlanks':
return userSolution?.solutions.length === exercise.words.length;
case 'writeBlanks':
return userSolution?.solutions.length === exercise.solutions.length;
case 'matchSentences':
return userSolution?.solutions.length === exercise.sentences.length;
case 'trueFalse':
return userSolution?.solutions.length === exercise.questions.length;
}
return false;
});
@@ -405,8 +412,8 @@ export default function Level({ exam, showSolutions = false, onFinish, editing =
<>
{exam.parts[partIndex].context && renderText()}
{(showSolutions || editing) ?
renderSolution(currentExercise, nextExercise, previousExercise) :
renderExercise(currentExercise, exam.id, next, previousExercise)
currentExercise && renderSolution(currentExercise, nextExercise, previousExercise) :
currentExercise && renderExercise(currentExercise, exam.id, next, previousExercise)
}
</>
}
@@ -419,10 +426,10 @@ export default function Level({ exam, showSolutions = false, onFinish, editing =
<div className={clsx("flex flex-col h-full w-full gap-8 items-center", showPartDivider && "justify-center")}>
<QuestionsModal isOpen={showQuestionsModal} {...questionModalKwargs} />
{
!(partIndex === 0 && questionIndex === 0 && showPartDivider) &&
!(partIndex === 0 && questionIndex === 0 && (showPartDivider || startNow)) &&
<Timer minTimer={exam.minTimer} disableTimer={showSolutions} standalone={true} />
}
{exam.parts[0].intro && showPartDivider ? <PartDivider part={exam.parts[partIndex]} partIndex={partIndex} onNext={() => { setShowPartDivider(false); setBgColor("bg-white") }} /> : (
{(showPartDivider || startNow) ? <PartDivider part={exam.parts[partIndex]} partIndex={partIndex} onNext={() => { setShowPartDivider(false); setStartNow(false); setBgColor("bg-white"); }} /> : (
<>
{exam.parts[0].intro && (
<div className="w-full">
@@ -470,33 +477,6 @@ export default function Level({ exam, showSolutions = false, onFinish, editing =
)}>
{memoizedRender}
</div>
{/*exerciseIndex === -1 && partIndex > 0 && (
<div className="self-end flex justify-between w-full gap-8 absolute bottom-8 left-0 px-8">
<Button
color="purple"
variant="outline"
onClick={() => {
setExerciseIndex(exam.parts[partIndex - 1].exercises.length - 1);
setPartIndex(partIndex - 1);
}}
className="max-w-[200px] w-full"
disabled={
exam && typeof partIndex !== "undefined" && exam.module === "level" &&
typeof exam.parts[0].intro === "string" && questionIndex === 0}
>
Back
</Button>
<Button color="purple" onClick={() => nextExercise()} className="max-w-[200px] self-end w-full">
Next
</Button>
</div>
)*/}
{exerciseIndex === -1 && partIndex === 0 && (
<Button color="purple" onClick={() => nextExercise()} className="max-w-[200px] self-end w-full">
Start now
</Button>
)}
</>
)}
</div>