diff --git a/src/components/Diagnostic.tsx b/src/components/Diagnostic.tsx
new file mode 100644
index 00000000..dde882ec
--- /dev/null
+++ b/src/components/Diagnostic.tsx
@@ -0,0 +1,86 @@
+import {infoButtonStyle} from "@/constants/buttonStyles";
+import {Module} from "@/interfaces";
+import {User} from "@/interfaces/user";
+import useExamStore from "@/stores/examStore";
+import {getExamById} from "@/utils/exams";
+import axios from "axios";
+import clsx from "clsx";
+import {useRouter} from "next/router";
+import {useEffect, useState} from "react";
+import {ToastContainer, toast} from "react-toastify";
+
+interface Props {
+ user: User;
+}
+
+const DIAGNOSTIC_EXAMS = [
+ ["reading", ""],
+ ["listening", ""],
+ ["writing", ""],
+ ["speaking", ""],
+];
+
+export default function Diagnostic({user}: Props) {
+ const [focus, setFocus] = useState<"academic" | "general">();
+ const [isInsert, setIsInsert] = useState(false);
+
+ const router = useRouter();
+
+ const setExams = useExamStore((state) => state.setExams);
+ const setSelectedModules = useExamStore((state) => state.setSelectedModules);
+
+ const selectExam = () => {
+ const examPromises = DIAGNOSTIC_EXAMS.map((exam) => getExamById(exam[0] as Module, exam[1]));
+
+ Promise.all(examPromises).then((exams) => {
+ if (exams.every((x) => !!x)) {
+ setExams(exams.map((x) => x!));
+ setSelectedModules(exams.map((x) => x!.module));
+ router.push("/exam");
+ }
+ });
+ };
+
+ const onPerformDiagnosis = async () => {
+ axios
+ .post("/api/users/update", {focus, isFirstLogin: false})
+ .then(selectExam)
+ .catch(() => {
+ toast.error("Something went wrong, please try again later!", {toastId: "user-update-error"});
+ });
+ };
+
+ useEffect(() => {
+ toast.error("Something went wrong, please try again later!", {toastId: "user-update-error"});
+ }, []);
+
+ if (!focus) {
+ return (
+
+
What is your focus?
+
+
+
+
+
+ );
+ }
+
+ return (
+
+
What is your current IELTS level?
+
+
+
+
+
+ );
+}
diff --git a/src/interfaces/exam.ts b/src/interfaces/exam.ts
index ea4102f4..572228ea 100644
--- a/src/interfaces/exam.ts
+++ b/src/interfaces/exam.ts
@@ -11,6 +11,7 @@ export interface ReadingExam {
exercises: Exercise[];
module: "reading";
minTimer: number;
+ type: "academic" | "general";
}
export interface ListeningExam {
diff --git a/src/interfaces/user.ts b/src/interfaces/user.ts
index 5bec2c57..fc39e641 100644
--- a/src/interfaces/user.ts
+++ b/src/interfaces/user.ts
@@ -6,6 +6,8 @@ export interface User {
profilePicture: string;
id: string;
experience: number;
+ isFirstLogin: boolean;
+ focus: "academic" | "general";
type: Type;
}
diff --git a/src/pages/api/users/update.ts b/src/pages/api/users/update.ts
new file mode 100644
index 00000000..4c353f70
--- /dev/null
+++ b/src/pages/api/users/update.ts
@@ -0,0 +1,26 @@
+// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
+import type {NextApiRequest, NextApiResponse} from "next";
+import {app} from "@/firebase";
+import {getFirestore, collection, getDocs, getDoc, doc, setDoc} from "firebase/firestore";
+import {withIronSessionApiRoute} from "iron-session/next";
+import {sessionOptions} from "@/lib/session";
+import {User} from "@/interfaces/user";
+
+const db = getFirestore(app);
+
+export default withIronSessionApiRoute(handler, sessionOptions);
+
+async function handler(req: NextApiRequest, res: NextApiResponse) {
+ if (!req.session.user) {
+ res.status(401).json({ok: false});
+ return;
+ }
+
+ const docUser = await getDoc(doc(db, "users", req.session.user.id));
+ const user = docUser.data() as User;
+
+ const userRef = doc(db, "users", user.id);
+ setDoc(userRef, req.body, {merge: true});
+
+ res.status(200).json({ok: true});
+}
diff --git a/src/pages/history.tsx b/src/pages/history.tsx
index d8ae5a92..2083e7a7 100644
--- a/src/pages/history.tsx
+++ b/src/pages/history.tsx
@@ -24,6 +24,8 @@ import {toast} from "react-toastify";
import {useRouter} from "next/router";
import Icon from "@mdi/react";
import {mdiArrowRight, mdiChevronRight} from "@mdi/js";
+import {uniqBy} from "lodash";
+import {getExamById} from "@/utils/exams";
export const getServerSideProps = withIronSessionSsr(({req, res}) => {
const user = req.session.user;
@@ -64,27 +66,6 @@ export default function History({user}: {user: User}) {
}
}, [stats, isStatsLoading]);
- const getExam = async (module: Module): Promise => {
- const examRequest = await axios(`/api/exam/${module}`);
- if (examRequest.status !== 200) {
- toast.error("Something went wrong!");
- return undefined;
- }
-
- const newExam = examRequest.data;
-
- switch (module) {
- case "reading":
- return newExam.shift() as ReadingExam;
- case "listening":
- return newExam.shift() as ListeningExam;
- case "writing":
- return newExam.shift() as WritingExam;
- case "speaking":
- return newExam.shift() as SpeakingExam;
- }
- };
-
const formatTimestamp = (timestamp: string) => {
const date = moment(parseInt(timestamp));
const formatter = "YYYY/MM/DD - HH:mm";
@@ -100,9 +81,7 @@ export default function History({user}: {user: User}) {
const total = dateStats.reduce((accumulator, current) => accumulator + current.score.total, 0);
const selectExam = () => {
- const examPromises = formatModuleTotalStats(dateStats)
- .filter((x) => x.value > 0)
- .map((module) => getExam(module.label.toLowerCase() as Module));
+ const examPromises = uniqBy(dateStats, "exam").map((stat) => getExamById(stat.module, stat.exam));
Promise.all(examPromises).then((exams) => {
if (exams.every((x) => !!x)) {
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index 639cb0a3..a388fff6 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -11,6 +11,8 @@ import useStats from "@/hooks/useStats";
import {averageScore, formatModuleTotalStats, totalExams} from "@/utils/stats";
import {Divider} from "primereact/divider";
import useUser from "@/hooks/useUser";
+import Diagnostic from "@/components/Diagnostic";
+import {ToastContainer} from "react-toastify";
export const getServerSideProps = withIronSessionSsr(({req, res}) => {
const user = req.session.user;
@@ -41,6 +43,25 @@ export default function Home() {
useEffect(() => setShowEndExam(window.innerWidth <= 960), []);
useEffect(() => setWindowWidth(window.innerWidth), []);
+ if (user && user.isFirstLogin) {
+ return (
+ <>
+
+ IELTS GPT | Muscat Training Institute
+
+
+
+
+
+
+
+ >
+ );
+ }
+
return (
<>
@@ -52,6 +73,7 @@ export default function Home() {
+
{user && (
diff --git a/src/utils/exams.ts b/src/utils/exams.ts
new file mode 100644
index 00000000..83a2498e
--- /dev/null
+++ b/src/utils/exams.ts
@@ -0,0 +1,23 @@
+import {Module} from "@/interfaces";
+import {Exam, ReadingExam, ListeningExam, WritingExam, SpeakingExam} from "@/interfaces/exam";
+import axios from "axios";
+
+export const getExamById = async (module: Module, id: string): Promise => {
+ const examRequest = await axios(`/api/exam/${module}/${id}`);
+ if (examRequest.status !== 200) {
+ return undefined;
+ }
+
+ const newExam = examRequest.data;
+
+ switch (module) {
+ case "reading":
+ return newExam as ReadingExam;
+ case "listening":
+ return newExam as ListeningExam;
+ case "writing":
+ return newExam as WritingExam;
+ case "speaking":
+ return newExam as SpeakingExam;
+ }
+};