Fixed a bug in fill blanks where the input would be reset by the re-rendering of lines

This commit is contained in:
Carlos Mesquita
2024-08-27 09:20:00 +01:00
parent eb7c539a0e
commit 72b498eb85

View File

@@ -1,7 +1,7 @@
import { FillBlanksExercise, FillBlanksMCOption } from "@/interfaces/exam"; import { FillBlanksExercise, FillBlanksMCOption } from "@/interfaces/exam";
import useExamStore from "@/stores/examStore"; import useExamStore from "@/stores/examStore";
import clsx from "clsx"; import clsx from "clsx";
import { Fragment, useEffect, useState } from "react"; import { Fragment, useCallback, useEffect, useMemo, useState } from "react";
import reactStringReplace from "react-string-replace"; import reactStringReplace from "react-string-replace";
import { CommonProps } from ".."; import { CommonProps } from "..";
import Button from "../../Low/Button"; import Button from "../../Low/Button";
@@ -45,7 +45,7 @@ const FillBlanks: React.FC<FillBlanksExercise & CommonProps> = ({
let correctWords: any; let correctWords: any;
if (exam && exam.module === "level" && exam.parts[partIndex].exercises[exerciseIndex].type === "fillBlanks") { if (exam && (exam.module === "level" || exam.module === "reading") && exam.parts[partIndex].exercises[exerciseIndex].type === "fillBlanks") {
correctWords = (exam.parts[partIndex].exercises[exerciseIndex] as FillBlanksExercise).words; correctWords = (exam.parts[partIndex].exercises[exerciseIndex] as FillBlanksExercise).words;
} }
@@ -77,7 +77,7 @@ const FillBlanks: React.FC<FillBlanksExercise & CommonProps> = ({
const missing = total - answers!.filter((x) => solutions.find((y) => x.id.toString() === y.id.toString())).length; const missing = total - answers!.filter((x) => solutions.find((y) => x.id.toString() === y.id.toString())).length;
return { total, correct, missing }; return { total, correct, missing };
}; };
const renderLines = (line: string) => { const renderLines = useCallback((line: string) => {
return ( return (
<div className="text-base leading-5" key={v4()}> <div className="text-base leading-5" key={v4()}>
{reactStringReplace(line, /({{\d+}})/g, (match) => { {reactStringReplace(line, /({{\d+}})/g, (match) => {
@@ -121,21 +121,33 @@ const FillBlanks: React.FC<FillBlanksExercise & CommonProps> = ({
})} })}
</div> </div>
); );
}; }, [variant, words, setCurrentMCSelection, answers]);
const memoizedLines = useMemo(() => {
return text.split("\\n").map((line, index) => (
<p key={index} className={clsx(variant === "mc" && "whitespace-pre-wrap")}>
{renderLines(line)}
<br />
</p>
));
}, [text, variant, renderLines]);
const onSelection = (questionID: string, value: string) => { const onSelection = (questionID: string, value: string) => {
setAnswers((prev) => [...prev.filter((x) => x.id !== questionID), { id: questionID, solution: value }]); setAnswers((prev) => [...prev.filter((x) => x.id !== questionID), { id: questionID, solution: value }]);
} }
useEffect(() => { useEffect(() => {
setCurrentSolution({ exercise: id, solutions: answers, score: calculateScore(), type, shuffleMaps: shuffleMaps }); if (variant === "mc") {
setCurrentSolution({ exercise: id, solutions: answers, score: calculateScore(), type, shuffleMaps: shuffleMaps });
}
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [answers]) }, [answers])
return ( return (
<> <>
<div className="flex flex-col gap-4 mt-4 h-full w-full mb-20"> <div className="flex flex-col gap-4 mt-4 h-full w-full mb-20">
{false && <span className="text-sm w-full leading-6"> {variant !== "mc" && <span className="text-sm w-full leading-6">
{prompt.split("\\n").map((line, index) => ( {prompt.split("\\n").map((line, index) => (
<Fragment key={index}> <Fragment key={index}>
{line} {line}
@@ -144,12 +156,7 @@ const FillBlanks: React.FC<FillBlanksExercise & CommonProps> = ({
))} ))}
</span>} </span>}
<span className="bg-mti-gray-smoke rounded-xl px-5 py-6"> <span className="bg-mti-gray-smoke rounded-xl px-5 py-6">
{text.split("\\n").map((line, index) => ( {memoizedLines}
<p key={index} className={clsx(variant === "mc" && "whitespace-pre-wrap")}>
{renderLines(line)}
<br />
</p>
))}
</span> </span>
{variant === "mc" && typeCheckWordsMC(words) ? ( {variant === "mc" && typeCheckWordsMC(words) ? (
<> <>