Updated a bit more of the way the codes work
This commit is contained in:
@@ -3,7 +3,8 @@ import {BAND_SCORES} from "@/constants/ielts";
|
|||||||
import {Module} from "@/interfaces";
|
import {Module} from "@/interfaces";
|
||||||
import {User} from "@/interfaces/user";
|
import {User} from "@/interfaces/user";
|
||||||
import useExamStore from "@/stores/examStore";
|
import useExamStore from "@/stores/examStore";
|
||||||
import {getExamById} from "@/utils/exams";
|
import {getExam, getExamById} from "@/utils/exams";
|
||||||
|
import {MODULE_ARRAY} from "@/utils/moduleUtils";
|
||||||
import {writingMarking} from "@/utils/score";
|
import {writingMarking} from "@/utils/score";
|
||||||
import {Menu} from "@headlessui/react";
|
import {Menu} from "@headlessui/react";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
@@ -20,13 +21,6 @@ interface Props {
|
|||||||
onFinish: () => void;
|
onFinish: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DIAGNOSTIC_EXAMS = [
|
|
||||||
["reading", "CurQtQoxWmHaJHeN0JW2"],
|
|
||||||
["listening", "Y6cMao8kUcVnPQOo6teV"],
|
|
||||||
["writing", "B1J90R4Lmdn2dwjdHEwj"],
|
|
||||||
["speaking", "QVFm4pdcziJQZN2iUTDo"],
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function Diagnostic({onFinish}: Props) {
|
export default function Diagnostic({onFinish}: Props) {
|
||||||
const [focus, setFocus] = useState<"academic" | "general">();
|
const [focus, setFocus] = useState<"academic" | "general">();
|
||||||
const [levels, setLevels] = useState({reading: -1, listening: -1, writing: -1, speaking: -1});
|
const [levels, setLevels] = useState({reading: -1, listening: -1, writing: -1, speaking: -1});
|
||||||
@@ -43,7 +37,7 @@ export default function Diagnostic({onFinish}: Props) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const selectExam = () => {
|
const selectExam = () => {
|
||||||
const examPromises = DIAGNOSTIC_EXAMS.map((exam) => getExamById(exam[0] as Module, exam[1]));
|
const examPromises = MODULE_ARRAY.map((module) => getExam(module, true));
|
||||||
|
|
||||||
Promise.all(examPromises).then((exams) => {
|
Promise.all(examPromises).then((exams) => {
|
||||||
if (exams.every((x) => !!x)) {
|
if (exams.every((x) => !!x)) {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ export interface User {
|
|||||||
bio: string;
|
bio: string;
|
||||||
isVerified: boolean;
|
isVerified: boolean;
|
||||||
demographicInformation?: DemographicInformation;
|
demographicInformation?: DemographicInformation;
|
||||||
|
subscriptionExpirationDate?: null | Date;
|
||||||
isDisabled?: boolean;
|
isDisabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
|
|
||||||
const codePromises = codes.map(async (code, index) => {
|
const codePromises = codes.map(async (code, index) => {
|
||||||
const codeRef = doc(db, "codes", code);
|
const codeRef = doc(db, "codes", code);
|
||||||
await setDoc(codeRef, {type, code});
|
await setDoc(codeRef, {type, code, creator: req.session.user!.id});
|
||||||
|
|
||||||
if (emails && emails.length > index) {
|
if (emails && emails.length > index) {
|
||||||
const transport = prepareMailer();
|
const transport = prepareMailer();
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import {NextApiRequest, NextApiResponse} from "next";
|
import {NextApiRequest, NextApiResponse} from "next";
|
||||||
import {createUserWithEmailAndPassword, getAuth, sendPasswordResetEmail} from "firebase/auth";
|
import {createUserWithEmailAndPassword, getAuth} from "firebase/auth";
|
||||||
import {app} from "@/firebase";
|
import {app} from "@/firebase";
|
||||||
import {sessionOptions} from "@/lib/session";
|
import {sessionOptions} from "@/lib/session";
|
||||||
import {withIronSessionApiRoute} from "iron-session/next";
|
import {withIronSessionApiRoute} from "iron-session/next";
|
||||||
import {getFirestore, getDoc, doc, setDoc, deleteDoc} from "firebase/firestore";
|
import {getFirestore, doc, setDoc, query, collection, where, getDocs} from "firebase/firestore";
|
||||||
import {DemographicInformation, Type} from "@/interfaces/user";
|
import {DemographicInformation, Type} from "@/interfaces/user";
|
||||||
|
|
||||||
const auth = getAuth(app);
|
const auth = getAuth(app);
|
||||||
@@ -28,13 +28,15 @@ const DEFAULT_LEVELS = {
|
|||||||
async function login(req: NextApiRequest, res: NextApiResponse) {
|
async function login(req: NextApiRequest, res: NextApiResponse) {
|
||||||
const {email, password, code} = req.body as {email: string; password: string; code: string; demographicInformation: DemographicInformation};
|
const {email, password, code} = req.body as {email: string; password: string; code: string; demographicInformation: DemographicInformation};
|
||||||
|
|
||||||
const codeRef = await getDoc(doc(db, "codes", code));
|
const codeQuery = query(collection(db, "codes"), where("code", "==", code));
|
||||||
if (!codeRef.exists()) {
|
const codeDocs = (await getDocs(codeQuery)).docs.filter((x) => !Object.keys(x.data()).includes("userId"));
|
||||||
|
|
||||||
|
if (codeDocs.length === 0) {
|
||||||
res.status(400).json({error: "Invalid Code!"});
|
res.status(400).json({error: "Invalid Code!"});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const codeData = codeRef.data() as {code: string; type: Type};
|
const codeData = codeDocs[0].data() as {code: string; type: Type};
|
||||||
|
|
||||||
createUserWithEmailAndPassword(auth, email, password)
|
createUserWithEmailAndPassword(auth, email, password)
|
||||||
.then(async (userCredentials) => {
|
.then(async (userCredentials) => {
|
||||||
@@ -52,7 +54,7 @@ async function login(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
await setDoc(doc(db, "users", userId), user);
|
await setDoc(doc(db, "users", userId), user);
|
||||||
await deleteDoc(codeRef.ref);
|
await setDoc(codeDocs[0].ref, {userId: userId}, {merge: true});
|
||||||
|
|
||||||
req.session.user = {...user, id: userId};
|
req.session.user = {...user, id: userId};
|
||||||
await req.session.save();
|
await req.session.save();
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import {speakingReverseMarking, writingReverseMarking} from "@/utils/score";
|
|||||||
import AbandonPopup from "@/components/AbandonPopup";
|
import AbandonPopup from "@/components/AbandonPopup";
|
||||||
import {evaluateSpeakingAnswer, evaluateWritingAnswer} from "@/utils/evaluation";
|
import {evaluateSpeakingAnswer, evaluateWritingAnswer} from "@/utils/evaluation";
|
||||||
import {useRouter} from "next/router";
|
import {useRouter} from "next/router";
|
||||||
|
import {getExam} from "@/utils/exams";
|
||||||
|
|
||||||
export const getServerSideProps = withIronSessionSsr(({req, res}) => {
|
export const getServerSideProps = withIronSessionSsr(({req, res}) => {
|
||||||
const user = req.session.user;
|
const user = req.session.user;
|
||||||
@@ -85,10 +86,13 @@ export default function Page() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
if (selectedModules.length > 0 && exams.length === 0) {
|
if (selectedModules.length > 0 && exams.length === 0) {
|
||||||
const examPromises = selectedModules.map(getExam);
|
const examPromises = selectedModules.map((module) => getExam(module, avoidRepeated));
|
||||||
Promise.all(examPromises).then((values) => {
|
Promise.all(examPromises).then((values) => {
|
||||||
if (values.every((x) => !!x)) {
|
if (values.every((x) => !!x)) {
|
||||||
setExams(values.map((x) => x!));
|
setExams(values.map((x) => x!));
|
||||||
|
} else {
|
||||||
|
toast.error("Something went wrong, please try again");
|
||||||
|
setTimeout(router.reload, 500);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -115,27 +119,6 @@ export default function Page() {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [selectedModules, moduleIndex, hasBeenUploaded]);
|
}, [selectedModules, moduleIndex, hasBeenUploaded]);
|
||||||
|
|
||||||
const getExam = async (module: Module): Promise<Exam | undefined> => {
|
|
||||||
const examRequest = await axios<Exam[]>(`/api/exam/${module}?avoidRepeated=${avoidRepeated}`);
|
|
||||||
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 updateExamWithUserSolutions = (exam: Exam): Exam => {
|
const updateExamWithUserSolutions = (exam: Exam): Exam => {
|
||||||
if (exam.module === "reading" || exam.module === "listening") {
|
if (exam.module === "reading" || exam.module === "listening") {
|
||||||
const parts = exam.parts.map((p) =>
|
const parts = exam.parts.map((p) =>
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import {speakingReverseMarking, writingReverseMarking} from "@/utils/score";
|
|||||||
import AbandonPopup from "@/components/AbandonPopup";
|
import AbandonPopup from "@/components/AbandonPopup";
|
||||||
import {evaluateSpeakingAnswer, evaluateWritingAnswer} from "@/utils/evaluation";
|
import {evaluateSpeakingAnswer, evaluateWritingAnswer} from "@/utils/evaluation";
|
||||||
import {useRouter} from "next/router";
|
import {useRouter} from "next/router";
|
||||||
|
import {getExam} from "@/utils/exams";
|
||||||
|
|
||||||
export const getServerSideProps = withIronSessionSsr(({req, res}) => {
|
export const getServerSideProps = withIronSessionSsr(({req, res}) => {
|
||||||
const user = req.session.user;
|
const user = req.session.user;
|
||||||
@@ -89,10 +90,13 @@ export default function Page() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
if (selectedModules.length > 0 && exams.length === 0) {
|
if (selectedModules.length > 0 && exams.length === 0) {
|
||||||
const examPromises = selectedModules.map(getExam);
|
const examPromises = selectedModules.map((module) => getExam(module, avoidRepeated));
|
||||||
Promise.all(examPromises).then((values) => {
|
Promise.all(examPromises).then((values) => {
|
||||||
if (values.every((x) => !!x)) {
|
if (values.every((x) => !!x)) {
|
||||||
setExams(values.map((x) => x!));
|
setExams(values.map((x) => x!));
|
||||||
|
} else {
|
||||||
|
toast.error("Something went wrong, please try again");
|
||||||
|
setTimeout(router.reload, 500);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -119,27 +123,6 @@ export default function Page() {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [selectedModules, moduleIndex, hasBeenUploaded]);
|
}, [selectedModules, moduleIndex, hasBeenUploaded]);
|
||||||
|
|
||||||
const getExam = async (module: Module): Promise<Exam | undefined> => {
|
|
||||||
const examRequest = await axios<Exam[]>(`/api/exam/${module}?avoidRepeated=${avoidRepeated}`);
|
|
||||||
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 updateExamWithUserSolutions = (exam: Exam): Exam => {
|
const updateExamWithUserSolutions = (exam: Exam): Exam => {
|
||||||
if (exam.module === "reading" || exam.module === "listening") {
|
if (exam.module === "reading" || exam.module === "listening") {
|
||||||
const parts = exam.parts.map((p) =>
|
const parts = exam.parts.map((p) =>
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import Layout from "@/components/High/Layout";
|
|||||||
import {calculateAverageLevel} from "@/utils/score";
|
import {calculateAverageLevel} from "@/utils/score";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import DemographicInformationInput from "@/components/DemographicInformationInput";
|
import DemographicInformationInput from "@/components/DemographicInformationInput";
|
||||||
|
import moment from "moment";
|
||||||
|
|
||||||
export const getServerSideProps = withIronSessionSsr(({req, res}) => {
|
export const getServerSideProps = withIronSessionSsr(({req, res}) => {
|
||||||
const user = req.session.user;
|
const user = req.session.user;
|
||||||
@@ -51,6 +52,34 @@ export default function Home() {
|
|||||||
}
|
}
|
||||||
}, [user]);
|
}, [user]);
|
||||||
|
|
||||||
|
const checkIfUserExpired = () => {
|
||||||
|
const expirationDate = user!.subscriptionExpirationDate;
|
||||||
|
|
||||||
|
if (expirationDate === null || expirationDate === undefined) return false;
|
||||||
|
if (moment(expirationDate).isAfter(moment(new Date()))) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (user && (user.isDisabled || checkIfUserExpired())) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Head>
|
||||||
|
<title>EnCoach | Muscat Training Institute</title>
|
||||||
|
<meta
|
||||||
|
name="description"
|
||||||
|
content="A training platform for the IELTS exam provided by the Muscat Training Institute and developed by eCrop."
|
||||||
|
/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<link rel="icon" href="/favicon.ico" />
|
||||||
|
</Head>
|
||||||
|
<Layout user={user} navDisabled>
|
||||||
|
<div className="flex flex-col items-center justify-center text-center"></div>
|
||||||
|
</Layout>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (user && showDemographicInput) {
|
if (user && showDemographicInput) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export const getServerSideProps = (context: any) => {
|
|||||||
const {code} = context.query;
|
const {code} = context.query;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {code},
|
props: {code: code || null},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,26 @@ import {
|
|||||||
} from "@/interfaces/exam";
|
} from "@/interfaces/exam";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
|
export const getExam = async (module: Module, avoidRepeated: boolean): Promise<Exam | undefined> => {
|
||||||
|
const examRequest = await axios<Exam[]>(`/api/exam/${module}?avoidRepeated=${avoidRepeated}`);
|
||||||
|
if (examRequest.status !== 200) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const getExamById = async (module: Module, id: string): Promise<Exam | undefined> => {
|
export const getExamById = async (module: Module, id: string): Promise<Exam | undefined> => {
|
||||||
const examRequest = await axios<Exam>(`/api/exam/${module}/${id}`);
|
const examRequest = await axios<Exam>(`/api/exam/${module}/${id}`);
|
||||||
if (examRequest.status !== 200) {
|
if (examRequest.status !== 200) {
|
||||||
|
|||||||
Reference in New Issue
Block a user