import {FillBlanksExercise} from "@/interfaces/exam"; import useExamStore from "@/stores/examStore"; import clsx from "clsx"; import {Fragment, useEffect, useState} from "react"; import reactStringReplace from "react-string-replace"; import {CommonProps} from "."; import Button from "../Low/Button"; interface WordsDrawerProps { words: {word: string; isDisabled: boolean}[]; isOpen: boolean; blankId?: string; previouslySelectedWord?: string; onCancel: () => void; onAnswer: (answer: string) => void; } function WordsDrawer({words, isOpen, blankId, previouslySelectedWord, onCancel, onAnswer}: WordsDrawerProps) { const [selectedWord, setSelectedWord] = useState(previouslySelectedWord); return ( <>
{blankId}
Choose the correct word:
{words.map(({word, isDisabled}) => ( ))}
); } export default function FillBlanks({ id, allowRepetition, type, prompt, solutions, text, words, userSolutions, onNext, onBack, }: FillBlanksExercise & CommonProps) { const [answers, setAnswers] = useState<{id: string; solution: string}[]>(userSolutions); const [currentBlankId, setCurrentBlankId] = useState(); const [isDrawerShowing, setIsDrawerShowing] = useState(false); const hasExamEnded = useExamStore((state) => state.hasExamEnded); const allBlanks = Array.from(text.match(/({{\d+}})/g) || []).map((x) => x.replaceAll("{", "").replaceAll("}", "")); useEffect(() => { setTimeout(() => setIsDrawerShowing(!!currentBlankId), 100); }, [currentBlankId]); useEffect(() => { if (hasExamEnded) onNext({exercise: id, solutions: answers, score: calculateScore(), type}); // eslint-disable-next-line react-hooks/exhaustive-deps }, [hasExamEnded]); const calculateScore = () => { const total = text.match(/({{\d+}})/g)?.length || 0; const correct = answers.filter( (x) => solutions.find((y) => x.id.toString() === y.id.toString())?.solution === x.solution.toLowerCase() || false, ).length; const missing = total - answers.filter((x) => solutions.find((y) => x.id.toString() === y.id.toString())).length; return {total, correct, missing}; }; const renderLines = (line: string) => { return ( {reactStringReplace(line, /({{\d+}})/g, (match) => { const id = match.replaceAll(/[\{\}]/g, ""); const userSolution = answers.find((x) => x.id === id); return ( ); })} ); }; return ( <>
{(!!currentBlankId || isDrawerShowing) && ( ({word, isDisabled: allowRepetition ? false : answers.map((x) => x.solution).includes(word)}))} previouslySelectedWord={currentBlankId ? answers.find((x) => x.id === currentBlankId)?.solution : undefined} isOpen={isDrawerShowing} onCancel={() => setCurrentBlankId(undefined)} onAnswer={(solution: string) => { setAnswers((prev) => [...prev.filter((x) => x.id !== currentBlankId), {id: currentBlankId!, solution}]); if (allBlanks.findIndex((x) => x === currentBlankId) + 1 < allBlanks.length) { setCurrentBlankId(allBlanks[allBlanks.findIndex((x) => x === currentBlankId) + 1]); return; } setCurrentBlankId(undefined); }} /> )} {prompt.split("\\n").map((line, index) => ( {line}
))}
{text.split("\\n").map((line, index) => (

{renderLines(line)}

))}
); }