ENCOA-154: Increase the number of questions per page in all modules (Priority in Level Test)

This commit is contained in:
Tiago Ribeiro
2024-09-04 11:41:48 +01:00
parent becc91d8ea
commit 4654c21d92
2 changed files with 82 additions and 72 deletions

View File

@@ -18,9 +18,8 @@ function Question({
}: MultipleChoiceQuestion & {
userSolution: string | undefined;
onSelectOption?: (option: string) => void;
showSolution?: boolean,
showSolution?: boolean;
}) {
const renderPrompt = (prompt: string) => {
return reactStringReplace(prompt, /(<u>.*?<\/u>)/g, (match) => {
const word = match.replaceAll("<u>", "").replaceAll("</u>", "");
@@ -49,7 +48,9 @@ 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 key={v4()} 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>
))}
@@ -74,16 +75,9 @@ function Question({
export default function MultipleChoice({id, prompt, type, questions, userSolutions, onNext, onBack}: MultipleChoiceExercise & CommonProps) {
const [answers, setAnswers] = useState<{question: string; option: string}[]>(userSolutions);
const {
questionIndex,
exerciseIndex,
exam,
shuffles,
hasExamEnded,
partIndex,
setQuestionIndex,
setCurrentSolution
} = useExamStore((state) => state);
const {questionIndex, exerciseIndex, exam, shuffles, hasExamEnded, partIndex, setQuestionIndex, setCurrentSolution} = useExamStore(
(state) => state,
);
const shuffleMaps = shuffles.find((x) => x.exerciseID == id)?.shuffles;
@@ -94,15 +88,14 @@ export default function MultipleChoice({ id, prompt, type, questions, userSoluti
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [hasExamEnded]);
const onSelectOption = (option: string) => {
const question = questions[questionIndex];
const onSelectOption = (option: string, question: MultipleChoiceQuestion) => {
setAnswers((prev) => [...prev.filter((x) => x.question !== question.id), {option, question: question.id}]);
};
useEffect(() => {
setCurrentSolution({exercise: id, solutions: answers, score: calculateScore(), type, shuffleMaps: shuffleMaps});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [answers, setAnswers])
}, [answers, setAnswers]);
const getShuffledSolution = (originalSolution: string, questionShuffleMap: ShuffleMap) => {
for (const [newPosition, originalPosition] of Object.entries(questionShuffleMap.map)) {
@@ -111,8 +104,7 @@ export default function MultipleChoice({ id, prompt, type, questions, userSoluti
}
}
return originalSolution;
}
};
const calculateScore = () => {
const total = questions.length;
@@ -139,10 +131,10 @@ export default function MultipleChoice({ id, prompt, type, questions, userSoluti
};
const next = () => {
if (questionIndex === questions.length - 1) {
if (questionIndex + 1 >= questions.length - 1) {
onNext({exercise: id, solutions: answers, score: calculateScore(), type, shuffleMaps: shuffleMaps});
} else {
setQuestionIndex(questionIndex + 1);
setQuestionIndex(questionIndex + 2);
}
scrollToTop();
};
@@ -152,7 +144,7 @@ export default function MultipleChoice({ id, prompt, type, questions, userSoluti
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);
setQuestionIndex(questionIndex - 2);
}
scrollToTop();
@@ -160,35 +152,47 @@ export default function MultipleChoice({ id, prompt, type, questions, userSoluti
return (
<>
<div className="flex flex-col gap-2 mt-4 h-fit w-full mb-20 bg-mti-gray-smoke rounded-xl px-16 py-8">
<div className="flex flex-col gap-4 mt-2 mb-20">
<div className="flex flex-col gap-8 h-fit w-full bg-mti-gray-smoke rounded-xl px-16 py-8">
{/*<span className="text-xl font-semibold mb-2">{"Select the appropriate option."}</span>*/}
{questionIndex < questions.length && (
<Question
{...questions[questionIndex]}
userSolution={answers.find((x) => questions[questionIndex].id === x.question)?.option}
onSelectOption={onSelectOption}
onSelectOption={(option) => onSelectOption(option, questions[questionIndex])}
/>
)}
</div>
{questionIndex + 1 < questions.length && (
<div className="flex flex-col gap-8 h-fit w-full bg-mti-gray-smoke rounded-xl px-16 py-8">
<Question
{...questions[questionIndex + 1]}
userSolution={answers.find((x) => questions[questionIndex + 1].id === x.question)?.option}
onSelectOption={(option) => onSelectOption(option, questions[questionIndex + 1])}
/>
</div>
)}
</div>
<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" &&
partIndex === 0 &&
questionIndex === 0
}
>
<Button
color="purple"
variant="outline"
onClick={back}
className="max-w-[200px] w-full"
disabled={exam && exam.module === "level" && partIndex === 0 && questionIndex === 0}>
Back
</Button>
<Button color="purple" onClick={next} className="max-w-[200px] self-end w-full">
{
exam && exam.module === "level" &&
{exam &&
exam.module === "level" &&
partIndex === exam.parts.length - 1 &&
exerciseIndex === exam.parts[partIndex].exercises.length - 1 &&
questionIndex === questions.length - 1
? "Submit" : "Next"}
questionIndex + 1 >= questions.length - 1
? "Submit"
: "Next"}
</Button>
</div>
</>

View File

@@ -111,10 +111,10 @@ export default function MultipleChoice({id, type, prompt, questions, userSolutio
};
const next = () => {
if (questionIndex === questions.length - 1) {
if (questionIndex + 1 >= questions.length - 1) {
onNext({exercise: id, solutions: userSolutions, score: calculateScore(), type});
} else {
setQuestionIndex(questionIndex + 1);
setQuestionIndex(questionIndex + 2);
}
};
@@ -122,14 +122,15 @@ export default function MultipleChoice({id, type, prompt, questions, userSolutio
if (questionIndex === 0) {
onBack({exercise: id, solutions: userSolutions, score: calculateScore(), type});
} else {
setQuestionIndex(questionIndex - 1);
setQuestionIndex(questionIndex - 2);
}
};
return (
<>
<div className="flex flex-col gap-4 w-full h-full mb-20">
<div className="flex flex-col gap-2 mt-4 h-full bg-mti-gray-smoke rounded-xl px-16 py-8">
<div className="flex flex-col gap-4 mt-2">
<div className="flex flex-col gap-8 h-fit w-full bg-mti-gray-smoke rounded-xl px-16 py-8">
{/*<span className="text-xl font-semibold">{prompt}</span>*/}
{userSolutions && questionIndex < questions.length && (
<Question
@@ -138,6 +139,17 @@ export default function MultipleChoice({id, type, prompt, questions, userSolutio
/>
)}
</div>
{userSolutions && questionIndex + 1 < questions.length && (
<div className="flex flex-col gap-8 h-fit w-full bg-mti-gray-smoke rounded-xl px-16 py-8">
<Question
{...questions[questionIndex + 1]}
userSolution={userSolutions.find((x) => questions[questionIndex + 1].id === x.question)?.option}
/>
</div>
)}
</div>
<div className="flex gap-4 items-center">
<div className="flex gap-2 items-center">
<div className="w-4 h-4 rounded-full bg-mti-purple" />
@@ -160,13 +172,7 @@ export default function MultipleChoice({id, type, prompt, questions, userSolutio
variant="outline"
onClick={back}
className="max-w-[200px] w-full"
disabled={
exam &&
typeof partIndex !== "undefined" &&
exam.module === "level" &&
questionIndex === 0 &&
partIndex === 0
}>
disabled={exam && typeof partIndex !== "undefined" && exam.module === "level" && questionIndex === 0 && partIndex === 0}>
Back
</Button>