Files
encoach_frontend/src/components/ExamEditor/ImportExam/Templates.tsx
2024-12-09 18:37:51 +00:00

214 lines
11 KiB
TypeScript

import Button from "@/components/Low/Button";
import { Module } from "@/interfaces";
import { Dialog, DialogPanel, DialogTitle, Transition, TransitionChild } from "@headlessui/react";
import { capitalize } from "lodash";
import React, { Fragment, useCallback, useEffect, useState } from "react";
import { FaFileDownload } from "react-icons/fa";
import { HiOutlineDocumentText } from "react-icons/hi";
import { IoInformationCircleOutline } from "react-icons/io5";
interface Props {
module: Module;
state: { isOpen: boolean, type: "exam" | "solutions" };
setState: React.Dispatch<React.SetStateAction<{ isOpen: boolean, type: "exam" | "solutions" }>>;
}
const Templates: React.FC<Props> = ({ module, state, setState }) => {
const [isClosing, setIsClosing] = useState(false);
const [mounted, setMounted] = useState(false);
useEffect(() => {
if (state.isOpen) {
setMounted(true);
}
}, [state]);
useEffect(() => {
if (!state.isOpen && mounted) {
const timer = setTimeout(() => {
setMounted(false);
setIsClosing(false);
}, 300);
return () => clearTimeout(timer);
}
}, [state, mounted]);
const blockMultipleClicksClose = useCallback(() => {
if (isClosing) return;
setIsClosing(true);
setState({ isOpen: false, type: state.type });
const timer = setTimeout(() => {
setIsClosing(false);
}, 300);
return () => clearTimeout(timer);
}, [isClosing, setState, state]);
if (!mounted && !state.isOpen) return null;
const moduleExercises = {
"reading": [
"Multiple Choice",
"Write Blanks",
"True False",
"Paragraph Match",
"Idea Match"
],
"listening": [
"Multiple Choice",
"True False",
"Write Blanks: Questions",
"Write Blanks: Fill",
"Write Blanks: Form",
],
"level": [
"Fill Blanks: Multiple Choice",
"Multiple Choice: Blank Space",
"Multiple Choice: Underline",
"Multiple Choice: Reading Passage"
],
"writing": [],
"speaking": [],
}
const handleTemplateDownload = () => {
const fileName = `${capitalize(module)}${state.type === "exam" ? "Exam" : "Solutions"}Template`;
const url = `https://firebasestorage.googleapis.com/v0/b/encoach-staging.appspot.com/o/import_templates%2F${fileName}.docx?alt=media&token=b771a535-bf95-4060-889c-a086df65d480`;
const link = document.createElement('a');
link.href = url;
link.download = `${fileName}.docx`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
};
return (
<Transition
show={state.isOpen}
as={Fragment}
beforeEnter={() => setIsClosing(false)}
beforeLeave={() => setIsClosing(true)}
afterLeave={() => {
setIsClosing(false);
setMounted(false);
}}
>
<Dialog onClose={() => blockMultipleClicksClose()} className="relative z-50">
<TransitionChild
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/30" />
</TransitionChild>
<TransitionChild
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">
<div className="fixed inset-0 flex items-center justify-center p-4">
<DialogPanel className={`bg-ielts-${module}-light w-full max-w-6xl h-fit p-8 rounded-xl flex flex-col gap-4`}>
<DialogTitle className="flex font-bold text-xl justify-center text-gray-700"><span>{`${capitalize(module)} ${state.type === "exam" ? 'Exam' : 'Solutions'} Import`}</span></DialogTitle>
<div className="flex flex-col w-full mt-4 gap-6">
{state.type === "exam" ? (
<>
<div className="flex flex-col gap-3 bg-gray-50 rounded-lg p-4">
<div className="flex items-center gap-2">
<HiOutlineDocumentText className={`w-5 h-5 text-ielts-${module}`} />
<h2 className="text-lg font-semibold">
The {module} exam import accepts the following exercise types:
</h2>
</div>
<ul className="flex flex-col pl-10 gap-2">
{moduleExercises[module].map((item, index) => (
<li key={index} className="text-gray-700 list-disc">
{item}
</li>
))}
</ul>
</div>
<div className="flex flex-col gap-3 bg-gray-50 rounded-lg p-4">
<div className="flex items-center gap-2">
<IoInformationCircleOutline className={`w-5 h-5 text-ielts-${module}`} />
<h2 className="text-lg font-semibold">
The uploaded document must:
</h2>
</div>
<ul className="flex flex-col pl-10 gap-2">
<li className="text-gray-700 list-disc">
be a Word .docx document.
</li>
<li className="text-gray-700 list-disc">
have clear part and exercise delineation (e.g. Part 1, ... , Part X, Question 1 - 10, ... , Question y - x).
</li>
{["reading", "level"].includes(module) && (
<li className="text-gray-700 list-disc">
a part must only contain a single reading passage and it must be between the part delineator (e.g. Part 1) and the part exercises.
</li>
)}
<li className="text-gray-700 list-disc">
if solutions are going to be uploaded, the exercise numbers/id&apos;s must match the ones in the solutions.
</li>
</ul>
</div>
</>
) :
<>
<div className="flex flex-col gap-3 bg-gray-50 rounded-lg p-4">
<div className="flex items-center gap-2">
<IoInformationCircleOutline className={`w-5 h-5 text-ielts-${module}`} />
<h2 className="text-lg font-semibold">
The uploaded document must:
</h2>
</div>
<ul className="flex flex-col pl-10 gap-2">
<li className="text-gray-700 list-disc">
be a Word .docx document.
</li>
<li className="text-gray-700 list-disc">
match the exercise numbers/id&apos;s that are in the exam document.
</li>
</ul>
</div>
</>
}
<div className="bg-gray-50 rounded-lg p-4">
<p className="text-gray-600">
{`The downloadable template is an example of a file that can be imported. Your document doesn't need to be a carbon copy of the template - it can have different styling and formatting but it must adhere to the previous requirements${state.type === "exam" ? " and exercises of the same type should have the same formatting" : ""}.`}
</p>
</div>
<div className="w-full flex justify-between mt-4 gap-8">
<Button color="purple" onClick={() => blockMultipleClicksClose()} variant="outline" className="self-end w-full bg-white">
Close
</Button>
<Button color="purple" onClick={handleTemplateDownload} variant="solid" className="self-end w-full">
<div className="flex items-center gap-2">
<FaFileDownload size={24} />
Download Template
</div>
</Button>
</div>
</div>
</DialogPanel>
</div>
</TransitionChild>
</Dialog>
</Transition>
);
}
export default Templates;