Added title to the exam generate

This commit is contained in:
Joao Ramos
2024-08-06 19:24:43 +01:00
parent cf64a91651
commit 95c3f89911
7 changed files with 94 additions and 19 deletions

View File

@@ -230,7 +230,11 @@ const TaskTab = ({section, setSection}: {section: LevelSection; setSection: (sec
); );
}; };
const LevelGeneration = () => { interface Props {
id: string;
}
const LevelGeneration = ({ id } : Props) => {
const [generatedExam, setGeneratedExam] = useState<LevelExam>(); const [generatedExam, setGeneratedExam] = useState<LevelExam>();
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [resultingExam, setResultingExam] = useState<LevelExam>(); const [resultingExam, setResultingExam] = useState<LevelExam>();
@@ -420,10 +424,16 @@ const LevelGeneration = () => {
return; return;
} }
if(!id) {
toast.error("Please insert a title before submitting");
return;
}
setIsLoading(true); setIsLoading(true);
const exam = { const exam = {
...generatedExam, ...generatedExam,
id,
parts: generatedExam.parts.map((p, i) => ({...p, exercises: parts[i].part!.exercises})), parts: generatedExam.parts.map((p, i) => ({...p, exercises: parts[i].part!.exercises})),
}; };

View File

@@ -228,7 +228,11 @@ interface ListeningPart {
| string; | string;
} }
const ListeningGeneration = () => { interface Props {
id: string;
}
const ListeningGeneration = ({ id } : Props) => {
const [part1, setPart1] = useState<ListeningPart>(); const [part1, setPart1] = useState<ListeningPart>();
const [part2, setPart2] = useState<ListeningPart>(); const [part2, setPart2] = useState<ListeningPart>();
const [part3, setPart3] = useState<ListeningPart>(); const [part3, setPart3] = useState<ListeningPart>();
@@ -258,11 +262,16 @@ const ListeningGeneration = () => {
console.log({parts}); console.log({parts});
if (parts.length === 0) return toast.error("Please generate at least one section!"); if (parts.length === 0) return toast.error("Please generate at least one section!");
if(!id) {
toast.error("Please insert a title before submitting");
return;
}
setIsLoading(true); setIsLoading(true);
axios axios
.post(`/api/exam/listening/generate/listening`, { .post(`/api/exam/listening/generate/listening`, {
id: generate({minLength: 4, maxLength: 8, min: 3, max: 5, join: " ", formatter: capitalize}), id,
parts, parts,
minTimer, minTimer,
difficulty, difficulty,

View File

@@ -258,7 +258,11 @@ const PartTab = ({
); );
}; };
const ReadingGeneration = () => { interface Props {
id: string;
}
const ReadingGeneration = ({ id } : Props) => {
const [part1, setPart1] = useState<ReadingPart>(); const [part1, setPart1] = useState<ReadingPart>();
const [part2, setPart2] = useState<ReadingPart>(); const [part2, setPart2] = useState<ReadingPart>();
const [part3, setPart3] = useState<ReadingPart>(); const [part3, setPart3] = useState<ReadingPart>();
@@ -300,13 +304,18 @@ const ReadingGeneration = () => {
return; return;
} }
if(!id) {
toast.error("Please insert a title before submitting");
return;
}
setIsLoading(true); setIsLoading(true);
const exam: ReadingExam = { const exam: ReadingExam = {
parts, parts,
isDiagnostic: false, isDiagnostic: false,
minTimer, minTimer,
module: "reading", module: "reading",
id: generate({minLength: 4, maxLength: 8, min: 3, max: 5, join: " ", formatter: capitalize}), id,
type: "academic", type: "academic",
variant: parts.length === 3 ? "full" : "partial", variant: parts.length === 3 ? "full" : "partial",
difficulty, difficulty,
@@ -328,7 +337,7 @@ const ReadingGeneration = () => {
}) })
.catch((error) => { .catch((error) => {
console.log(error); console.log(error);
toast.error("Something went wrong while generating, please try again later."); toast.error(error.response.data.error || "Something went wrong while generating, please try again later.");
}) })
.finally(() => setIsLoading(false)); .finally(() => setIsLoading(false));
}; };

View File

@@ -221,7 +221,11 @@ interface SpeakingPart {
avatar?: (typeof AVATARS)[number]; avatar?: (typeof AVATARS)[number];
} }
const SpeakingGeneration = () => { interface Props {
id: string;
}
const SpeakingGeneration = ({ id } : Props) => {
const [part1, setPart1] = useState<SpeakingPart>(); const [part1, setPart1] = useState<SpeakingPart>();
const [part2, setPart2] = useState<SpeakingPart>(); const [part2, setPart2] = useState<SpeakingPart>();
const [part3, setPart3] = useState<SpeakingPart>(); const [part3, setPart3] = useState<SpeakingPart>();
@@ -243,6 +247,11 @@ const SpeakingGeneration = () => {
const submitExam = () => { const submitExam = () => {
if (!part1?.result && !part2?.result && !part3?.result) return toast.error("Please generate at least one task!"); if (!part1?.result && !part2?.result && !part3?.result) return toast.error("Please generate at least one task!");
if(!id) {
toast.error("Please insert a title before submitting");
return;
}
setIsLoading(true); setIsLoading(true);
const genders = [part1?.gender, part2?.gender, part3?.gender].filter((x) => !!x); const genders = [part1?.gender, part2?.gender, part3?.gender].filter((x) => !!x);
@@ -256,7 +265,7 @@ const SpeakingGeneration = () => {
})); }));
const exam: SpeakingExam = { const exam: SpeakingExam = {
id: generate({minLength: 4, maxLength: 8, min: 3, max: 5, join: " ", formatter: capitalize}), id,
isDiagnostic: false, isDiagnostic: false,
exercises: exercises as (SpeakingExercise | InteractiveSpeakingExercise)[], exercises: exercises as (SpeakingExercise | InteractiveSpeakingExercise)[],
minTimer, minTimer,

View File

@@ -75,7 +75,11 @@ const TaskTab = ({task, index, difficulty, setTask}: {task?: string; difficulty:
); );
}; };
const WritingGeneration = () => { interface Props {
id: string;
}
const WritingGeneration = ({ id } : Props) => {
const [task1, setTask1] = useState<string>(); const [task1, setTask1] = useState<string>();
const [task2, setTask2] = useState<string>(); const [task2, setTask2] = useState<string>();
const [minTimer, setMinTimer] = useState(60); const [minTimer, setMinTimer] = useState(60);
@@ -116,6 +120,11 @@ const WritingGeneration = () => {
return; return;
} }
if(!id) {
toast.error("Please insert a title before submitting");
return;
}
const exercise1 = task1 const exercise1 = task1
? ({ ? ({
id: v4(), id: v4(),
@@ -152,7 +161,7 @@ const WritingGeneration = () => {
minTimer, minTimer,
module: "writing", module: "writing",
exercises: [...(exercise1 ? [exercise1] : []), ...(exercise2 ? [exercise2] : [])], exercises: [...(exercise1 ? [exercise1] : []), ...(exercise2 ? [exercise2] : [])],
id: generate({minLength: 4, maxLength: 8, min: 3, max: 5, join: " ", formatter: capitalize}), id,
variant: exercise1 && exercise2 ? "full" : "partial", variant: exercise1 && exercise2 ? "full" : "partial",
difficulty, difficulty,
}; };

View File

@@ -1,7 +1,7 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction // Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type {NextApiRequest, NextApiResponse} from "next"; import type {NextApiRequest, NextApiResponse} from "next";
import {app} from "@/firebase"; import {app} from "@/firebase";
import {getFirestore, setDoc, doc} from "firebase/firestore"; import {getFirestore, setDoc, doc, runTransaction, collection, query, where, getDocs} from "firebase/firestore";
import {withIronSessionApiRoute} from "iron-session/next"; import {withIronSessionApiRoute} from "iron-session/next";
import {sessionOptions} from "@/lib/session"; import {sessionOptions} from "@/lib/session";
import {Exam, InstructorGender, Variant} from "@/interfaces/exam"; import {Exam, InstructorGender, Variant} from "@/interfaces/exam";
@@ -47,8 +47,25 @@ async function POST(req: NextApiRequest, res: NextApiResponse) {
} }
const {module} = req.query as {module: string}; const {module} = req.query as {module: string};
const exam = {...req.body, module: module};
await setDoc(doc(db, module, req.body.id), exam);
res.status(200).json(exam); try {
const exam = {...req.body, module: module};
await runTransaction(db, async (transaction) => {
const docRef = doc(db, module, req.body.id);
const docSnap = await transaction.get(docRef);
if (docSnap.exists()) {
throw new Error('Name already exists');
}
const newDocRef = doc(db, module, req.body.id);
transaction.set(newDocRef, exam);
});
res.status(200).json(exam);
} catch (error) {
console.error("Transaction failed: ", error);
res.status(500).json({ok: false, error: (error as any).message});
}
} }

View File

@@ -57,6 +57,7 @@ export default function Generation() {
const { user } = useUser({ redirectTo: "/login" }); const { user } = useUser({ redirectTo: "/login" });
const [title, setTitle] = useState<string>("");
return ( return (
<> <>
<Head> <Head>
@@ -73,6 +74,17 @@ export default function Generation() {
<Layout user={user} className="gap-6"> <Layout user={user} className="gap-6">
<h1 className="text-2xl font-semibold">Exam Generation</h1> <h1 className="text-2xl font-semibold">Exam Generation</h1>
<div className="flex flex-col gap-3"> <div className="flex flex-col gap-3">
<Input
type="text"
placeholder="Insert a title here"
name="title"
label="Title"
onChange={setTitle}
roundness="xl"
defaultValue={title}
required
/>
<label className="font-normal text-base text-mti-gray-dim"> <label className="font-normal text-base text-mti-gray-dim">
Module Module
</label> </label>
@@ -117,11 +129,11 @@ export default function Generation() {
))} ))}
</RadioGroup> </RadioGroup>
</div> </div>
{module === "reading" && <ReadingGeneration />} {module === "reading" && <ReadingGeneration id={title} />}
{module === "listening" && <ListeningGeneration />} {module === "listening" && <ListeningGeneration id={title} />}
{module === "writing" && <WritingGeneration />} {module === "writing" && <WritingGeneration id={title} />}
{module === "speaking" && <SpeakingGeneration />} {module === "speaking" && <SpeakingGeneration id={title} />}
{module === "level" && <LevelGeneration />} {module === "level" && <LevelGeneration id={title} />}
</Layout> </Layout>
)} )}
</> </>