ENCOA-137: Top right side Next Button on the exams

This commit is contained in:
Tiago Ribeiro
2024-09-04 15:10:17 +01:00
parent 49aac93618
commit 2d95cbd3dc
16 changed files with 1115 additions and 768 deletions

View File

@@ -1,28 +1,17 @@
import { FillBlanksExercise, FillBlanksMCOption, ShuffleMap } from "@/interfaces/exam";
import {FillBlanksExercise, FillBlanksMCOption, ShuffleMap} from "@/interfaces/exam";
import clsx from "clsx";
import reactStringReplace from "react-string-replace";
import { CommonProps } from ".";
import { Fragment } from "react";
import {CommonProps} from ".";
import {Fragment} from "react";
import Button from "../Low/Button";
import useExamStore from "@/stores/examStore";
export default function FillBlanksSolutions({
id,
type,
prompt,
solutions,
words,
text,
onNext,
onBack,
}: FillBlanksExercise & CommonProps) {
export default function FillBlanksSolutions({id, type, prompt, solutions, words, text, onNext, onBack}: FillBlanksExercise & CommonProps) {
const storeUserSolutions = useExamStore((state) => state.userSolutions);
const {questionIndex, setQuestionIndex, partIndex, exam} = useExamStore((state) => state);
const correctUserSolutions = storeUserSolutions.find(
(solution) => solution.exercise === id
)?.solutions;
const correctUserSolutions = storeUserSolutions.find((solution) => solution.exercise === id)?.solutions;
const shuffles = useExamStore((state) => state.shuffles);
const calculateScore = () => {
@@ -34,7 +23,7 @@ export default function FillBlanksSolutions({
const option = words.find((w) => {
if (typeof w === "string") {
return w.toLowerCase() === x.solution.toLowerCase();
} else if ('letter' in w) {
} else if ("letter" in w) {
return w.letter.toLowerCase() === x.solution.toLowerCase();
} else {
return w.id.toString() === x.id.toString();
@@ -44,23 +33,20 @@ export default function FillBlanksSolutions({
if (typeof option === "string") {
return solution.toLowerCase() === option.toLowerCase();
} else if ('letter' in option) {
} else if ("letter" in option) {
return solution.toLowerCase() === option.word.toLowerCase();
} else if ('options' in option) {
} else if ("options" in option) {
return option.options[solution as keyof typeof option.options] == x.solution;
}
return false;
}).length;
const missing = total - correctUserSolutions!.filter((x) => solutions.find((y) => x.id.toString() === y.id.toString())).length;
return { total, correct, missing };
return {total, correct, missing};
};
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);
};
const renderLines = (line: string) => {
return (
@@ -68,17 +54,17 @@ export default function FillBlanksSolutions({
{reactStringReplace(line, /({{\d+}})/g, (match) => {
const questionId = match.replaceAll(/[\{\}]/g, "");
const userSolution = correctUserSolutions!.find((x) => x.id.toString() === questionId.toString());
const answerSolution = solutions.find(sol => sol.id.toString() === questionId.toString())!.solution;
const answerSolution = solutions.find((sol) => sol.id.toString() === questionId.toString())!.solution;
const questionShuffleMap = shuffles.find((x) => x.exerciseID == id)?.shuffles.find((y) => y.questionID == questionId);
const newAnswerSolution = questionShuffleMap ? questionShuffleMap.map[answerSolution].toLowerCase() : answerSolution.toLowerCase();
const newAnswerSolution = questionShuffleMap
? questionShuffleMap.map[answerSolution].toLowerCase()
: answerSolution.toLowerCase();
if (!userSolution) {
let answerText;
if (typeCheckWordsMC(words)) {
const options = words.find((x) => x.id.toString() === questionId.toString());
const correctKey = Object.keys(options!.options).find(key =>
key.toLowerCase() === newAnswerSolution
);
const correctKey = Object.keys(options!.options).find((key) => key.toLowerCase() === newAnswerSolution);
answerText = options!.options[correctKey as keyof typeof options];
} else {
answerText = answerSolution;
@@ -97,37 +83,34 @@ export default function FillBlanksSolutions({
const userSolutionWord = words.find((w) =>
typeof w === "string"
? w.toLowerCase() === userSolution.solution.toLowerCase()
: 'letter' in w
? w.letter.toLowerCase() === userSolution.solution.toLowerCase()
: 'options' in w
? w.id === userSolution.questionId
: false
: "letter" in w
? w.letter.toLowerCase() === userSolution.solution.toLowerCase()
: "options" in w
? w.id === userSolution.questionId
: false,
);
const userSolutionText =
typeof userSolutionWord === "string"
? userSolutionWord
: userSolutionWord && 'letter' in userSolutionWord
? userSolutionWord.word
: userSolutionWord && 'options' in userSolutionWord
? userSolution.solution
: userSolution.solution;
: userSolutionWord && "letter" in userSolutionWord
? userSolutionWord.word
: userSolutionWord && "options" in userSolutionWord
? userSolution.solution
: userSolution.solution;
let correct;
let solutionText;
if (typeCheckWordsMC(words)) {
const options = words.find((x) => x.id.toString() === questionId.toString());
if (options) {
const correctKey = Object.keys(options.options).find(key =>
key.toLowerCase() === newAnswerSolution
);
const correctKey = Object.keys(options.options).find((key) => key.toLowerCase() === newAnswerSolution);
correct = userSolution.solution == options.options[correctKey as keyof typeof options.options];
solutionText = options.options[correctKey as keyof typeof options.options] || answerSolution;
} else {
correct = false;
solutionText = answerSolution;
}
} else {
correct = userSolutionText === answerSolution;
solutionText = answerSolution;
@@ -170,7 +153,25 @@ export default function FillBlanksSolutions({
};
return (
<>
<div className="flex flex-col gap-4">
<div className="flex justify-between w-full gap-8">
<Button
color="purple"
variant="outline"
onClick={() => onBack({exercise: id, solutions: correctUserSolutions!, score: calculateScore(), type})}
className="max-w-[200px] w-full"
disabled={exam && typeof partIndex !== "undefined" && exam.module === "level" && questionIndex === 0 && partIndex === 0}>
Back
</Button>
<Button
color="purple"
onClick={() => onNext({exercise: id, solutions: correctUserSolutions!, score: calculateScore(), type})}
className="max-w-[200px] self-end w-full">
Next
</Button>
</div>
<div className="flex flex-col gap-4 mt-4 h-full w-full mb-20">
<span className="bg-mti-gray-smoke rounded-xl px-5 py-6">
{correctUserSolutions &&
@@ -201,25 +202,19 @@ export default function FillBlanksSolutions({
<Button
color="purple"
variant="outline"
onClick={() => onBack({ exercise: id, solutions: correctUserSolutions!, score: calculateScore(), type })}
onClick={() => onBack({exercise: id, solutions: correctUserSolutions!, score: calculateScore(), type})}
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>
<Button
color="purple"
onClick={() => onNext({ exercise: id, solutions: correctUserSolutions!, score: calculateScore(), type })}
onClick={() => onNext({exercise: id, solutions: correctUserSolutions!, score: calculateScore(), type})}
className="max-w-[200px] self-end w-full">
Next
</Button>
</div>
</>
</div>
);
}