diff --git a/package.json b/package.json index 6ae3f361..512991e0 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "react-lineto": "^3.3.0", "react-player": "^2.12.0", "react-string-replace": "^1.1.0", + "react-toastify": "^9.1.2", "typescript": "4.9.5", "zustand": "^4.3.6" }, diff --git a/src/demo/writing.json b/src/demo/writing.json new file mode 100644 index 00000000..ad980986 --- /dev/null +++ b/src/demo/writing.json @@ -0,0 +1,11 @@ +{ + "module": "writing", + "text": { + "info": "You should spend about 20 minutes on this task.", + "prompt": "The charts below show the results of a survey of adult education. The first chart shows the reasons why adults decide to study. The pie chart shows how people think the costs of adult education should be shared.\nWrite a report for a university lecturer, describing the information shown below.", + "wordCounter": { + "type": "min", + "limit": 5 + } + } +} \ No newline at end of file diff --git a/src/exams/Writing.tsx b/src/exams/Writing.tsx new file mode 100644 index 00000000..e4631268 --- /dev/null +++ b/src/exams/Writing.tsx @@ -0,0 +1,67 @@ +import {infoButtonStyle} from "@/constants/buttonStyles"; +import {WritingExam} from "@/interfaces/exam"; +import clsx from "clsx"; +import {Fragment, useEffect, useState} from "react"; +import {toast} from "react-toastify"; + +interface Props { + exam: WritingExam; +} + +export default function Writing({exam}: Props) { + const [inputText, setInputText] = useState(""); + const [isSubmitEnabled, setIsSubmitEnabled] = useState(false); + + useEffect(() => { + const words = inputText.split(" ").filter((x) => x !== ""); + const {wordCounter} = exam.text; + if (wordCounter.type === "min") { + setIsSubmitEnabled(wordCounter.limit <= words.length); + } else { + setIsSubmitEnabled(true); + if (wordCounter.limit < words.length) { + toast.warning(`You have reached your word limit of ${wordCounter.limit} words!`); + setInputText(words.slice(0, words.length - 1).join(" ")); + } + } + }, [inputText, exam]); + + return ( +
+
+ {exam.text.info} + + {exam.text.prompt.split("\n").map((line, index) => ( + + {line} +
+
+ ))} +
+ + You should write {exam.text.wordCounter.type === "min" ? "at least" : "at most"} {exam.text.wordCounter.limit} words. + +
+