Created a prototype for one exercise of the reading module
This commit is contained in:
112
src/components/Exercises/FillBlanks.tsx
Normal file
112
src/components/Exercises/FillBlanks.tsx
Normal file
@@ -0,0 +1,112 @@
|
||||
import {errorButtonStyle, infoButtonStyle} from "@/constants/buttonStyles";
|
||||
import {FillBlanksExercise} from "@/interfaces/exam";
|
||||
import {Dialog, Transition} from "@headlessui/react";
|
||||
import clsx from "clsx";
|
||||
import {Fragment, useState} from "react";
|
||||
import reactStringReplace from "react-string-replace";
|
||||
|
||||
interface WordsPopoutProps {
|
||||
words: string[];
|
||||
isOpen: boolean;
|
||||
onCancel: () => void;
|
||||
onAnswer: (answer: string) => void;
|
||||
}
|
||||
|
||||
function WordsPopout({words, isOpen, onCancel, onAnswer}: WordsPopoutProps) {
|
||||
return (
|
||||
<Transition appear show={isOpen} as={Fragment}>
|
||||
<Dialog as="div" className="relative z-10" onClose={onCancel}>
|
||||
<Transition.Child
|
||||
as={Fragment}
|
||||
enter="ease-out duration-300"
|
||||
enterFrom="opacity-0"
|
||||
enterTo="opacity-100"
|
||||
leave="ease-in duration-200"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0">
|
||||
<div className="fixed inset-0 bg-black bg-opacity-25" />
|
||||
</Transition.Child>
|
||||
|
||||
<div className="fixed inset-0 overflow-y-auto">
|
||||
<div className="flex min-h-full items-center justify-center p-4 text-center">
|
||||
<Transition.Child
|
||||
as={Fragment}
|
||||
enter="ease-out duration-300"
|
||||
enterFrom="opacity-0 scale-95"
|
||||
enterTo="opacity-100 scale-100"
|
||||
leave="ease-in duration-200"
|
||||
leaveFrom="opacity-100 scale-100"
|
||||
leaveTo="opacity-0 scale-95">
|
||||
<Dialog.Panel className="w-fit transform overflow-hidden rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all flex flex-col">
|
||||
<Dialog.Title as="h3" className="text-lg font-medium leading-6 text-gray-900">
|
||||
List of words
|
||||
</Dialog.Title>
|
||||
<div className="mt-4 grid grid-cols-3 gap-4">
|
||||
{words.map((word) => (
|
||||
<button
|
||||
key={word}
|
||||
onClick={() => onAnswer(word)}
|
||||
className={clsx("btn btn-wide gap-4 relative text-white", infoButtonStyle)}>
|
||||
{word}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="mt-4 self-end">
|
||||
<button onClick={onCancel} className={clsx("btn btn-wide gap-4 relative text-white", errorButtonStyle)}>
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
</Dialog.Panel>
|
||||
</Transition.Child>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
</Transition>
|
||||
);
|
||||
}
|
||||
|
||||
export default function FillBlanks({allowRepetition, prompt, solutions, text, words}: FillBlanksExercise) {
|
||||
const [userSolutions, setUserSolutions] = useState<{id: string; solution: string}[]>([]);
|
||||
const [currentBlankId, setCurrentBlankId] = useState<string>();
|
||||
|
||||
const renderLines = (line: string) => {
|
||||
return (
|
||||
<span>
|
||||
{reactStringReplace(line, /({{\d}})/g, (match) => {
|
||||
const id = match.replaceAll(/[\{\}]/g, "");
|
||||
const userSolution = userSolutions.find((x) => x.id === id);
|
||||
|
||||
return (
|
||||
<button className="border-2 rounded-xl px-4 text-blue-400 border-blue-400" onClick={() => setCurrentBlankId(id)}>
|
||||
{userSolution ? userSolution.solution : id}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col">
|
||||
<WordsPopout
|
||||
words={words}
|
||||
isOpen={!!currentBlankId}
|
||||
onCancel={() => setCurrentBlankId(undefined)}
|
||||
onAnswer={(solution: string) => {
|
||||
setUserSolutions((prev) => [...prev.filter((x) => x.id !== currentBlankId), {id: currentBlankId!, solution}]);
|
||||
setCurrentBlankId(undefined);
|
||||
}}
|
||||
/>
|
||||
<span className="text-lg font-medium text-center px-48">{prompt}</span>
|
||||
<span>
|
||||
{text.split("\n").map((line) => (
|
||||
<>
|
||||
{renderLines(line)}
|
||||
<br />
|
||||
</>
|
||||
))}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user