Files
encoach_ui_odoo19/src/exams/Reading.tsx
2023-04-18 12:12:26 +01:00

163 lines
5.7 KiB
TypeScript

import {ReadingExam, UserSolution} from "@/interfaces/exam";
import {Fragment, useEffect, useState} from "react";
import Icon from "@mdi/react";
import {mdiArrowRight, mdiNotebook} from "@mdi/js";
import clsx from "clsx";
import {infoButtonStyle} from "@/constants/buttonStyles";
import {Dialog, Transition} from "@headlessui/react";
import {renderExercise} from "@/components/Exercises";
import {renderSolution} from "@/components/Solutions";
import {Panel} from "primereact/panel";
import {Steps} from "primereact/steps";
interface Props {
exam: ReadingExam;
showSolutions?: boolean;
onFinish: (userSolutions: UserSolution[]) => void;
}
function TextModal({isOpen, title, content, onClose}: {isOpen: boolean; title: string; content: string; onClose: () => void}) {
return (
<Transition appear show={isOpen} as={Fragment}>
<Dialog as="div" className="relative z-10" onClose={onClose}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0">
<div className="fixed inset-0 bg-black bg-opacity-25" />
</Transition.Child>
<div className="fixed inset-0 overflow-y-auto">
<div className="flex min-h-full items-center justify-center p-4 text-center">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95">
<Dialog.Panel className="w-full max-w-4xl transform rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all">
<Dialog.Title as="h3" className="text-lg font-medium leading-6 text-gray-900">
{title}
</Dialog.Title>
<div className="mt-2 overflow-auto">
<p className="text-sm text-gray-500">
{content.split("\\n").map((line, index) => (
<Fragment key={index}>
{line}
<br />
</Fragment>
))}
</p>
</div>
<div className="mt-4">
<button
type="button"
className="inline-flex justify-center rounded-md border border-transparent bg-blue-100 px-4 py-2 text-sm font-medium text-blue-900 hover:bg-blue-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2"
onClick={onClose}>
Got it, thanks!
</button>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition>
);
}
export default function Reading({exam, showSolutions = false, onFinish}: Props) {
const [exerciseIndex, setExerciseIndex] = useState(-1);
const [showTextModal, setShowTextModal] = useState(false);
const [userSolutions, setUserSolutions] = useState<UserSolution[]>([]);
const nextExercise = (solution?: UserSolution) => {
if (solution) {
setUserSolutions((prev) => [...prev.filter((x) => x.id !== solution.id), solution]);
}
if (exerciseIndex + 1 < exam.exercises.length) {
setExerciseIndex((prev) => prev + 1);
return;
}
if (solution) {
onFinish([...userSolutions.filter((x) => x.id !== solution.id), solution].map((x) => ({...x, module: "reading", exam: exam.id})));
} else {
onFinish(userSolutions.map((x) => ({...x, module: "reading", exam: exam.id})));
}
};
const previousExercise = () => {
setExerciseIndex((prev) => prev - 1);
};
const renderText = () => (
<div className="flex flex-col gap-4 w-full">
<div className="flex flex-col w-full gap-2">
<span className="text-base md:text-lg font-semibold">
Please read the following excerpt attentively, you will then be asked questions about the text you&apos;ve read.
</span>
<span className="self-end text-sm">You will be allowed to read the text while doing the exercises</span>
</div>
<Panel header={exam.text.title}>
<p className="overflow-auto">
{exam.text.content.split("\\n").map((line, index) => (
<p key={index}>{line}</p>
))}
</p>
</Panel>
</div>
);
return (
<>
<TextModal {...exam.text} isOpen={showTextModal} onClose={() => setShowTextModal(false)} />
<div className="w-full h-full relative flex flex-col gap-8 items-center justify-center p-2 md:p-8 px-4 md:px-16 overflow-hidden">
{exerciseIndex === -1 && renderText()}
{exerciseIndex > -1 &&
exerciseIndex < exam.exercises.length &&
!showSolutions &&
renderExercise(exam.exercises[exerciseIndex], nextExercise, previousExercise)}
{exerciseIndex > -1 &&
exerciseIndex < exam.exercises.length &&
showSolutions &&
renderSolution(exam.exercises[exerciseIndex], nextExercise, previousExercise)}
<div
className={clsx("flex gap-8", exerciseIndex > -1 ? "w-full justify-center md:justify-between" : "self-end w-full md:w-fit flex")}>
{exerciseIndex > -1 && (
<button
className={clsx(
"btn btn-wide gap-4 relative text-white",
"border-2 border-ielts-reading hover:bg-ielts-reading hover:border-ielts-reading bg-ielts-reading-transparent",
)}
onClick={() => setShowTextModal(true)}>
Read Text
<div className="absolute right-4">
<Icon path={mdiNotebook} color="white" size={1} />
</div>
</button>
)}
{exerciseIndex === -1 && (
<button
className={clsx("btn w-full md:btn-wide gap-4 relative text-white self-end", infoButtonStyle)}
onClick={() => nextExercise()}>
Next
<div className="absolute right-4">
<Icon path={mdiArrowRight} color="white" size={1} />
</div>
</button>
)}
</div>
</div>
</>
);
}