diff --git a/src/components/Exercises/WriteBlanks.tsx b/src/components/Exercises/WriteBlanks.tsx index abdc55cd..5f014c40 100644 --- a/src/components/Exercises/WriteBlanks.tsx +++ b/src/components/Exercises/WriteBlanks.tsx @@ -3,9 +3,55 @@ import {WriteBlanksExercise} from "@/interfaces/exam"; import {mdiArrowLeft, mdiArrowRight} from "@mdi/js"; import Icon from "@mdi/react"; import clsx from "clsx"; -import {useState} from "react"; +import {useEffect, useState} from "react"; import reactStringReplace from "react-string-replace"; import {CommonProps} from "."; +import {toast} from "react-toastify"; + +function Blank({ + id, + maxWords, + solutions, + userSolution, + disabled = false, + setUserSolution, +}: { + id: string; + solutions?: string[]; + userSolution?: string; + maxWords: number; + disabled?: boolean; + setUserSolution?: (solution: string) => void; +}) { + const [userInput, setUserInput] = useState(userSolution || ""); + + useEffect(() => { + const words = userInput.split(" ").filter((x) => x !== ""); + if (words.length >= maxWords) { + toast.warning(`You have reached your word limit of ${maxWords} words!`, {toastId: "word-limit"}); + setUserInput(words.join(" ").trim()); + if (setUserSolution) setUserSolution(words.join(" ").trim()); + } + }, [maxWords, userInput, setUserSolution]); + + const getSolutionStyling = () => { + if (solutions && userSolution) { + if (solutions.map((x) => x.trim().toLowerCase()).includes(userSolution.trim().toLowerCase())) return "text-green-500 border-green-500"; + } + + return "text-red-500 border-red-500"; + }; + + return ( + setUserInput(e.target.value)} + value={!solutions ? userInput : solutions.join(" / ")} + contentEditable={disabled} + /> + ); +} export default function WriteBlanks({prompt, maxWords, solutions, text, onNext, onBack}: WriteBlanksExercise & CommonProps) { const [userSolutions, setUserSolutions] = useState<{id: string; solution: string}[]>([]); @@ -16,8 +62,58 @@ export default function WriteBlanks({prompt, maxWords, solutions, text, onNext, {reactStringReplace(line, /({{\d+}})/g, (match) => { const id = match.replaceAll(/[\{\}]/g, ""); const userSolution = userSolutions.find((x) => x.id === id); + const setUserSolution = (solution: string) => { + setUserSolutions((prev) => [...prev.filter((x) => x.id !== id), {id, solution}]); + }; - return ; + return ; + })} + + ); + }; + + return ( + <> +
+ {prompt} + + {text.split("\n").map((line) => ( + <> + {renderLines(line)} +
+ + ))} +
+
+ +
+ + +
+ + ); +} + +export function WriteBlanksSolutions({prompt, maxWords, solutions, userSolutions, text, onNext, onBack}: WriteBlanksExercise & CommonProps) { + const renderLines = (line: string) => { + return ( + + {reactStringReplace(line, /({{\d+}})/g, (match) => { + const id = match.replaceAll(/[\{\}]/g, ""); + const userSolution = userSolutions.find((x) => x.id === id); + const solution = solutions.find((x) => x.id === id)!; + + return ; })} ); diff --git a/src/interfaces/exam.ts b/src/interfaces/exam.ts index ac436690..5083cab2 100644 --- a/src/interfaces/exam.ts +++ b/src/interfaces/exam.ts @@ -60,6 +60,10 @@ export interface WriteBlanksExercise { id: string; // *EXAMPLE: "14" solution: string[]; // *EXAMPLE: ["Prescott"] - All possible solutions (case sensitive) }[]; + userSolutions: { + id: string; + solution: string; + }[]; } export interface MatchSentencesExercise {