diff --git a/src/components/Generation/fill.blanks.edit.tsx b/src/components/Generation/fill.blanks.edit.tsx new file mode 100644 index 00000000..c2210093 --- /dev/null +++ b/src/components/Generation/fill.blanks.edit.tsx @@ -0,0 +1,84 @@ +import { FillBlanksExercise } from "@/interfaces/exam"; +import React from "react"; +import Input from "@/components/Low/Input"; + +interface Props { + exercise: FillBlanksExercise; + updateExercise: (data: any) => void; +} + +const FillBlanksEdit = (props: Props) => { + const { exercise, updateExercise } = props; + return ( + <> + + updateExercise({ + prompt: value, + }) + } + /> + + updateExercise({ + text: value, + }) + } + /> +

Solutions

+
+ {exercise.solutions.map((solution, index) => ( +
+ + updateExercise({ + solutions: exercise.solutions.map((sol) => + sol.id === solution.id ? { ...sol, solution: value } : sol + ), + }) + } + /> +
+ ))} +
+

Words

+
+ {exercise.words.map((word, index) => ( +
+ + updateExercise({ + words: exercise.words.map((sol, idx) => + index === idx ? value : sol + ), + }) + } + /> +
+ ))} +
+ + ); +}; + +export default FillBlanksEdit; diff --git a/src/components/Generation/interactive.speaking.edit.tsx b/src/components/Generation/interactive.speaking.edit.tsx new file mode 100644 index 00000000..351f8b4b --- /dev/null +++ b/src/components/Generation/interactive.speaking.edit.tsx @@ -0,0 +1,7 @@ +import React from "react"; + +const InteractiveSpeakingEdit = () => { + return null; +}; + +export default InteractiveSpeakingEdit; diff --git a/src/components/Generation/match.sentences.edit.tsx b/src/components/Generation/match.sentences.edit.tsx new file mode 100644 index 00000000..a4027a2e --- /dev/null +++ b/src/components/Generation/match.sentences.edit.tsx @@ -0,0 +1,7 @@ +import React from 'react'; + +const MatchSentencesEdit = () => { + return null; +} + +export default MatchSentencesEdit; \ No newline at end of file diff --git a/src/components/Generation/multiple.choice.edit.tsx b/src/components/Generation/multiple.choice.edit.tsx new file mode 100644 index 00000000..d943aed5 --- /dev/null +++ b/src/components/Generation/multiple.choice.edit.tsx @@ -0,0 +1,7 @@ +import React from 'react'; + +const MultipleChoiceEdit = () => { + return null; +} + +export default MultipleChoiceEdit; \ No newline at end of file diff --git a/src/components/Generation/speaking.edit.tsx b/src/components/Generation/speaking.edit.tsx new file mode 100644 index 00000000..a5649371 --- /dev/null +++ b/src/components/Generation/speaking.edit.tsx @@ -0,0 +1,7 @@ +import React from 'react'; + +const SpeakingEdit = () => { + return null; +} + +export default SpeakingEdit; \ No newline at end of file diff --git a/src/components/Generation/true.false.edit.tsx b/src/components/Generation/true.false.edit.tsx new file mode 100644 index 00000000..2a9281d2 --- /dev/null +++ b/src/components/Generation/true.false.edit.tsx @@ -0,0 +1,71 @@ +import React from "react"; +import { TrueFalseExercise } from "@/interfaces/exam"; +import Input from "@/components/Low/Input"; +import Select from "@/components/Low/Select"; +interface Props { + exercise: TrueFalseExercise; + updateExercise: (data: any) => void; +} + +const options = [ + { value: "true", label: "True" }, + { value: "false", label: "False" }, + { value: "not_given", label: "Not Given" }, +]; + +const TrueFalseEdit = (props: Props) => { + const { exercise, updateExercise } = props; + return ( + <> + + updateExercise({ + prompt: value, + }) + } + /> +

Questions

+
+ {exercise.questions.map((question, index) => ( +
+ + updateExercise({ + questions: exercise.questions.map((sol) => + sol.id === question.id ? { ...sol, prompt: value } : sol + ), + }) + } + /> +
+ - -
- {isLoading && ( -
- - Generating... -
- )} - {part && ( -
-
- {part.exercises.map((x) => ( - - {x.type && convertCamelCaseToReadable(x.type)} - - ))} -
-

{part.text.title}

- {part.text.content} -
- )} - - ); + const renderExercises = () => { + return part?.exercises.map((exercise) => { + switch (exercise.type) { + case "fillBlanks": + return ( + <> +

Exercise: Fill Blanks

+ + updatePart((part?: ReadingPart) => { + if (part) { + const exercises = part.exercises.map((x) => + x.id === exercise.id ? { ...x, ...data } : x + ) as Exercise[]; + const updatedPart = { ...part, exercises } as ReadingPart; + return updatedPart; + } + }) + } + /> + + ); + case "trueFalse": + return ( + <> +

Exercise: True or False

+ { + updatePart((part?: ReadingPart) => { + if (part) { + return { + ...part, + exercises: part.exercises.map((x) => + x.id === exercise.id ? { ...x, ...data } : x + ), + } as ReadingPart; + } + }); + }} + /> + + ); + default: + return null; + } + }); + }; + + return ( + +
+ + +
+ {isLoading && ( +
+ + + Generating... + +
+ )} + {part && ( + <> +
+
+ {part.exercises.map((x) => ( + + {x.type && convertCamelCaseToReadable(x.type)} + + ))} +
+

{part.text.title}

+ {part.text.content} +
+ {renderExercises()} + + )} +
+ ); }; const ReadingGeneration = () => { - const [part1, setPart1] = useState(); - const [part2, setPart2] = useState(); - const [part3, setPart3] = useState(); - const [minTimer, setMinTimer] = useState(60); - const [types, setTypes] = useState([]); - const [isLoading, setIsLoading] = useState(false); - const [resultingExam, setResultingExam] = useState(); - const [difficulty, setDifficulty] = useState(sample(DIFFICULTIES)!); + const [part1, setPart1] = useState(); + const [part2, setPart2] = useState(); + const [part3, setPart3] = useState(); + const [minTimer, setMinTimer] = useState(60); + const [types, setTypes] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const [resultingExam, setResultingExam] = useState(); + const [difficulty, setDifficulty] = useState( + sample(DIFFICULTIES)! + ); - useEffect(() => { - const parts = [part1, part2, part3].filter((x) => !!x); - setMinTimer(parts.length === 0 ? 60 : parts.length * 20); - }, [part1, part2, part3]); + useEffect(() => { + const parts = [part1, part2, part3].filter((x) => !!x); + setMinTimer(parts.length === 0 ? 60 : parts.length * 20); + }, [part1, part2, part3]); - const router = useRouter(); + const router = useRouter(); - const setExams = useExamStore((state) => state.setExams); - const setSelectedModules = useExamStore((state) => state.setSelectedModules); + const setExams = useExamStore((state) => state.setExams); + const setSelectedModules = useExamStore((state) => state.setSelectedModules); - const availableTypes = [ - {type: "fillBlanks", label: "Fill the Blanks"}, - {type: "trueFalse", label: "True or False"}, - {type: "writeBlanks", label: "Write the Blanks"}, - {type: "matchSentences", label: "Match Sentences"}, - ]; + const availableTypes = [ + { type: "fillBlanks", label: "Fill the Blanks" }, + { type: "trueFalse", label: "True or False" }, + { type: "writeBlanks", label: "Write the Blanks" }, + { type: "matchSentences", label: "Match Sentences" }, + ]; - const toggleType = (type: string) => setTypes((prev) => (prev.includes(type) ? [...prev.filter((x) => x !== type)] : [...prev, type])); + const toggleType = (type: string) => + setTypes((prev) => + prev.includes(type) + ? [...prev.filter((x) => x !== type)] + : [...prev, type] + ); - const loadExam = async (examId: string) => { - const exam = await getExamById("reading", examId.trim()); - if (!exam) { - toast.error("Unknown Exam ID! Please make sure you selected the right module and entered the right exam ID", { - toastId: "invalid-exam-id", - }); + const loadExam = async (examId: string) => { + const exam = await getExamById("reading", examId.trim()); + if (!exam) { + toast.error( + "Unknown Exam ID! Please make sure you selected the right module and entered the right exam ID", + { + toastId: "invalid-exam-id", + } + ); - return; - } + return; + } - setExams([exam]); - setSelectedModules(["reading"]); + setExams([exam]); + setSelectedModules(["reading"]); - router.push("/exercises"); - }; + router.push("/exercises"); + }; - const submitExam = () => { - const parts = [part1, part2, part3].filter((x) => !!x) as ReadingPart[]; - if (parts.length === 0) { - toast.error("Please generate at least one passage before submitting"); - return; - } + const submitExam = () => { + const parts = [part1, part2, part3].filter((x) => !!x) as ReadingPart[]; + if (parts.length === 0) { + toast.error("Please generate at least one passage before submitting"); + return; + } - setIsLoading(true); - const exam: ReadingExam = { - parts, - isDiagnostic: false, - minTimer, - module: "reading", - id: v4(), - type: "academic", - variant: parts.length === 3 ? "full" : "partial", - difficulty, - }; + setIsLoading(true); + const exam: ReadingExam = { + parts, + isDiagnostic: false, + minTimer, + module: "reading", + id: v4(), + type: "academic", + variant: parts.length === 3 ? "full" : "partial", + difficulty, + }; - axios - .post(`/api/exam/reading`, exam) - .then((result) => { - playSound("sent"); - console.log(`Generated Exam ID: ${result.data.id}`); - toast.success("This new exam has been generated successfully! Check the ID in our browser's console."); - setResultingExam(result.data); + axios + .post(`/api/exam/reading`, exam) + .then((result) => { + playSound("sent"); + console.log(`Generated Exam ID: ${result.data.id}`); + toast.success( + "This new exam has been generated successfully! Check the ID in our browser's console." + ); + setResultingExam(result.data); - setPart1(undefined); - setPart2(undefined); - setPart3(undefined); - setDifficulty(sample(DIFFICULTIES)!); - setMinTimer(60); - setTypes([]); - }) - .catch((error) => { - console.log(error); - toast.error("Something went wrong while generating, please try again later."); - }) - .finally(() => setIsLoading(false)); - }; + setPart1(undefined); + setPart2(undefined); + setPart3(undefined); + setDifficulty(sample(DIFFICULTIES)!); + setMinTimer(60); + setTypes([]); + }) + .catch((error) => { + console.log(error); + toast.error( + "Something went wrong while generating, please try again later." + ); + }) + .finally(() => setIsLoading(false)); + }; - return ( - <> -
-
- - setMinTimer(parseInt(e) < 15 ? 15 : parseInt(e))} - value={minTimer} - className="max-w-[300px]" - /> -
-
- - setMinTimer(parseInt(e) < 15 ? 15 : parseInt(e))} + value={minTimer} + className="max-w-[300px]" + /> +
+
+ +