diff --git a/src/pages/(generation)/SpeakingGeneration.tsx b/src/pages/(generation)/SpeakingGeneration.tsx new file mode 100644 index 00000000..3a10cb48 --- /dev/null +++ b/src/pages/(generation)/SpeakingGeneration.tsx @@ -0,0 +1,234 @@ +import Input from "@/components/Low/Input"; +import {Exercise, SpeakingExam} from "@/interfaces/exam"; +import useExamStore from "@/stores/examStore"; +import {getExamById} from "@/utils/exams"; +import {playSound} from "@/utils/sound"; +import {convertCamelCaseToReadable} from "@/utils/string"; +import {Tab} from "@headlessui/react"; +import axios from "axios"; +import clsx from "clsx"; +import {useRouter} from "next/router"; +import {useState} from "react"; +import {BsArrowRepeat} from "react-icons/bs"; +import {toast} from "react-toastify"; + +const PartTab = ({part, index, setPart}: {part?: SpeakingPart; index: number; setPart: (part?: SpeakingPart) => void}) => { + const [isLoading, setIsLoading] = useState(false); + + const generate = () => { + setPart(undefined); + setIsLoading(true); + axios + .get(`/api/exam/speaking/generate/speaking_task_${index}`) + .then((result) => { + playSound("check"); + setPart(result.data); + }) + .catch((error) => { + console.log(error); + toast.error("Something went wrong!"); + }) + .finally(() => setIsLoading(false)); + }; + + return ( + +
+ +
+ {isLoading && ( +
+ + Generating... +
+ )} + {part && ( +
+

{part.topic}

+ {part.question && {part.question}} + {part.questions && ( +
+ {part.questions.map((question, index) => ( + + - {question} + + ))} +
+ )} + {part.prompts && ( +
+ You should talk about the following things: + {part.prompts.map((prompt, index) => ( + + - {prompt} + + ))} +
+ )} +
+ )} +
+ ); +}; + +interface SpeakingPart { + prompts?: string[]; + question?: string; + questions?: string[]; + topic: string; +} + +const SpeakingGeneration = () => { + const [part1, setPart1] = useState(); + const [part2, setPart2] = useState(); + const [part3, setPart3] = useState(); + const [isLoading, setIsLoading] = useState(false); + const [resultingExam, setResultingExam] = useState(); + + const router = useRouter(); + + const setExams = useExamStore((state) => state.setExams); + const setSelectedModules = useExamStore((state) => state.setSelectedModules); + + const submitExam = () => { + if (!part1 || !part2 || !part3) return toast.error("Please generate all for tasks!"); + + setIsLoading(true); + + axios + .post(`/api/exam/speaking/generate/speaking`, {exercises: [part1, part2, part3]}) + .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); + }) + .catch((error) => { + console.log(error); + toast.error("Something went wrong!"); + }) + .finally(() => setIsLoading(false)); + }; + + const loadExam = async (examId: string) => { + const exam = await getExamById("speaking", 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; + } + + setExams([exam]); + setSelectedModules(["speaking"]); + + router.push("/exercises"); + }; + + return ( + <> + + + + clsx( + "w-full rounded-lg py-2.5 text-sm font-medium leading-5 text-ielts-speaking/70", + "ring-white ring-opacity-60 ring-offset-2 ring-offset-ielts-speaking focus:outline-none focus:ring-2", + "transition duration-300 ease-in-out", + selected ? "bg-white shadow" : "text-blue-100 hover:bg-white/[0.12] hover:text-ielts-speaking", + ) + }> + Task 1 + + + clsx( + "w-full rounded-lg py-2.5 text-sm font-medium leading-5 text-ielts-speaking/70", + "ring-white ring-opacity-60 ring-offset-2 ring-offset-ielts-speaking focus:outline-none focus:ring-2", + "transition duration-300 ease-in-out", + selected ? "bg-white shadow" : "text-blue-100 hover:bg-white/[0.12] hover:text-ielts-speaking", + ) + }> + Task 2 + + + clsx( + "w-full rounded-lg py-2.5 text-sm font-medium leading-5 text-ielts-speaking/70", + "ring-white ring-opacity-60 ring-offset-2 ring-offset-ielts-speaking focus:outline-none focus:ring-2", + "transition duration-300 ease-in-out", + selected ? "bg-white shadow" : "text-blue-100 hover:bg-white/[0.12] hover:text-ielts-speaking", + ) + }> + Task 3 + + + + {[ + {part: part1, setPart: setPart1}, + {part: part2, setPart: setPart2}, + {part: part3, setPart: setPart3}, + ].map(({part, setPart}, index) => ( + + ))} + + +
+ {resultingExam && ( + + )} + +
+ + ); +}; + +export default SpeakingGeneration; diff --git a/src/pages/generation.tsx b/src/pages/generation.tsx index 62828726..cd905767 100644 --- a/src/pages/generation.tsx +++ b/src/pages/generation.tsx @@ -20,6 +20,7 @@ import ReadingGeneration from "./(generation)/ReadingGeneration"; import ListeningGeneration from "./(generation)/ListeningGeneration"; import WritingGeneration from "./(generation)/WritingGeneration"; import LevelGeneration from "./(generation)/LevelGeneration"; +import SpeakingGeneration from "./(generation)/SpeakingGeneration"; export const getServerSideProps = withIronSessionSsr(({req, res}) => { const user = req.session.user; @@ -115,6 +116,7 @@ export default function Generation() { {module === "reading" && } {module === "listening" && } {module === "writing" && } + {module === "speaking" && } {module === "level" && } )}