Updated the use of the Desired Levels to be configurable
This commit is contained in:
@@ -14,6 +14,7 @@ import {useEffect, useState} from "react";
|
|||||||
import {BsBook, BsChevronDown, BsHeadphones, BsMegaphone, BsPen, BsQuestionSquare} from "react-icons/bs";
|
import {BsBook, BsChevronDown, BsHeadphones, BsMegaphone, BsPen, BsQuestionSquare} from "react-icons/bs";
|
||||||
import {toast} from "react-toastify";
|
import {toast} from "react-toastify";
|
||||||
import Button from "./Low/Button";
|
import Button from "./Low/Button";
|
||||||
|
import ModuleLevelSelector from "./Medium/ModuleLevelSelector";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
user: User;
|
user: User;
|
||||||
@@ -90,111 +91,17 @@ export default function Diagnostic({onFinish}: Props) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-col items-center justify-center gap-8 w-full">
|
<div className="flex flex-col items-center justify-center gap-8 w-full">
|
||||||
<h2 className="font-semibold text-xl">What is your current IELTS level?</h2>
|
<h2 className="font-semibold text-xl">What is your current IELTS level?</h2>
|
||||||
<div className="flex flex-col gap-32 w-full mb-20">
|
<ModuleLevelSelector levels={levels} setLevels={setLevels} />
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-y-4 gap-x-16 mb-24">
|
|
||||||
<div className="w-full flex flex-col gap-3.5 relative">
|
|
||||||
<span className="text-sm text-mti-gray-dim">
|
|
||||||
<span className="font-bold">Reading</span> level
|
|
||||||
</span>
|
|
||||||
<Menu>
|
|
||||||
<Menu.Button className="w-full border border-mti-gray-platinum rounded-full px-6 py-4 flex justify-between items-center gap-12 bg-white">
|
|
||||||
<BsBook className="text-ielts-reading" size={34} />
|
|
||||||
<span className="text-mti-gray-cool text-sm">
|
|
||||||
{levels.reading === -1 ? "Select your reading level" : `Level ${levels.reading}`}
|
|
||||||
</span>
|
|
||||||
<BsChevronDown className="text-mti-gray-cool" size={12} />
|
|
||||||
</Menu.Button>
|
|
||||||
<Menu.Items className="absolute overflow-y-scroll scrollbar-hide max-h-[230px] origin-top top-full bg-white flex flex-col items-center w-full z-20 drop-shadow-lg rounded-2xl">
|
|
||||||
{Object.values(writingMarking).map((x) => (
|
|
||||||
<Menu.Item key={x}>
|
|
||||||
<span
|
|
||||||
onClick={() => setLevels((prev) => ({...prev, reading: x}))}
|
|
||||||
className="w-full py-4 text-center cursor-pointer bg-white hover:bg-mti-gray-platinum transition ease-in-out duration-300">
|
|
||||||
Level {x}
|
|
||||||
</span>
|
|
||||||
</Menu.Item>
|
|
||||||
))}
|
|
||||||
</Menu.Items>
|
|
||||||
</Menu>
|
|
||||||
</div>
|
|
||||||
<div className="w-full flex flex-col gap-3.5 relative">
|
|
||||||
<span className="text-sm text-mti-gray-dim">
|
|
||||||
<span className="font-bold">Listening</span> level
|
|
||||||
</span>
|
|
||||||
<Menu>
|
|
||||||
<Menu.Button className="w-full border border-mti-gray-platinum rounded-full px-6 py-4 flex justify-between items-center gap-12 bg-white">
|
|
||||||
<BsHeadphones className="text-ielts-listening" size={34} />
|
|
||||||
<span className="text-mti-gray-cool text-sm">
|
|
||||||
{levels.listening === -1 ? "Select your listening level" : `Level ${levels.listening}`}
|
|
||||||
</span>
|
|
||||||
<BsChevronDown className="text-mti-gray-cool" size={12} />
|
|
||||||
</Menu.Button>
|
|
||||||
<Menu.Items className="absolute overflow-y-scroll scrollbar-hide max-h-[230px] origin-top top-full bg-white flex flex-col items-center w-full z-20 drop-shadow-lg rounded-2xl">
|
|
||||||
{Object.values(writingMarking).map((x) => (
|
|
||||||
<Menu.Item key={x}>
|
|
||||||
<span
|
|
||||||
onClick={() => setLevels((prev) => ({...prev, listening: x}))}
|
|
||||||
className="w-full py-5 text-center cursor-pointer bg-white hover:bg-mti-gray-platinum transition ease-in-out duration-300">
|
|
||||||
Level {x}
|
|
||||||
</span>
|
|
||||||
</Menu.Item>
|
|
||||||
))}
|
|
||||||
</Menu.Items>
|
|
||||||
</Menu>
|
|
||||||
</div>
|
|
||||||
<div className="w-full flex flex-col gap-3.5 relative">
|
|
||||||
<span className="text-sm text-mti-gray-dim">
|
|
||||||
<span className="font-bold">Writing</span> level
|
|
||||||
</span>
|
|
||||||
<Menu>
|
|
||||||
<Menu.Button className="w-full border border-mti-gray-platinum rounded-full px-6 py-4 flex justify-between items-center gap-12 bg-white">
|
|
||||||
<BsPen className="text-ielts-writing" size={34} />
|
|
||||||
<span className="text-mti-gray-cool text-sm">
|
|
||||||
{levels.writing === -1 ? "Select your writing level" : `Level ${levels.writing}`}
|
|
||||||
</span>
|
|
||||||
<BsChevronDown className="text-mti-gray-cool" size={12} />
|
|
||||||
</Menu.Button>
|
|
||||||
<Menu.Items className="absolute overflow-y-scroll scrollbar-hide max-h-[230px] origin-top top-full bg-white flex flex-col items-center w-full z-20 drop-shadow-lg rounded-2xl">
|
|
||||||
{Object.values(writingMarking).map((x) => (
|
|
||||||
<Menu.Item key={x}>
|
|
||||||
<span
|
|
||||||
onClick={() => setLevels((prev) => ({...prev, writing: x}))}
|
|
||||||
className="w-full py-5 text-center cursor-pointer bg-white hover:bg-mti-gray-platinum transition ease-in-out duration-300">
|
|
||||||
Level {x}
|
|
||||||
</span>
|
|
||||||
</Menu.Item>
|
|
||||||
))}
|
|
||||||
</Menu.Items>
|
|
||||||
</Menu>
|
|
||||||
</div>
|
|
||||||
<div className="w-full flex flex-col gap-3.5 relative">
|
|
||||||
<span className="text-sm text-mti-gray-dim">
|
|
||||||
<span className="font-bold">Speaking</span> level
|
|
||||||
</span>
|
|
||||||
<Menu>
|
|
||||||
<Menu.Button className="w-full border border-mti-gray-platinum rounded-full px-6 py-4 flex justify-between items-center gap-12 bg-white">
|
|
||||||
<BsMegaphone className="text-ielts-speaking" size={34} />
|
|
||||||
<span className="text-mti-gray-cool text-sm">
|
|
||||||
{levels.speaking === -1 ? "Select your speaking level" : `Level ${levels.speaking}`}
|
|
||||||
</span>
|
|
||||||
<BsChevronDown className="text-mti-gray-cool" size={12} />
|
|
||||||
</Menu.Button>
|
|
||||||
<Menu.Items className="absolute overflow-y-scroll scrollbar-hide max-h-[230px] origin-top top-full bg-white flex flex-col items-center w-full z-20 drop-shadow-lg rounded-2xl">
|
|
||||||
{Object.values(writingMarking).map((x) => (
|
|
||||||
<Menu.Item key={x}>
|
|
||||||
<span
|
|
||||||
onClick={() => setLevels((prev) => ({...prev, speaking: x}))}
|
|
||||||
className="w-full py-5 text-center cursor-pointer bg-white hover:bg-mti-gray-platinum transition ease-in-out duration-300">
|
|
||||||
Level {x}
|
|
||||||
</span>
|
|
||||||
</Menu.Item>
|
|
||||||
))}
|
|
||||||
</Menu.Items>
|
|
||||||
</Menu>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-col items-center justify-center gap-8 w-full mb-44">
|
||||||
|
<h2 className="font-semibold text-xl">What is your desired IELTS level?</h2>
|
||||||
|
<ModuleLevelSelector levels={desiredLevels} setLevels={setDesiredLevels} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="md:self-end flex -md:flex-col justify-between w-full gap-8 absolute bottom-8 left-0 px-4 md:px-8">
|
<div className="md:self-end flex -md:flex-col justify-between w-full gap-8 absolute bottom-8 left-0 px-4 md:px-8">
|
||||||
<div className="w-full tooltip" data-tip="Your screen size is too small to perform a diagnostic test">
|
<div className="w-full tooltip" data-tip="Your screen size is too small to perform a diagnostic test">
|
||||||
<Button
|
<Button
|
||||||
@@ -224,7 +131,5 @@ export default function Diagnostic({onFinish}: Props) {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,12 +5,14 @@ interface Props {
|
|||||||
label: string;
|
label: string;
|
||||||
percentage: number;
|
percentage: number;
|
||||||
color: "red" | "rose" | "purple" | Module;
|
color: "red" | "rose" | "purple" | Module;
|
||||||
|
mark?: number;
|
||||||
|
markLabel?: string;
|
||||||
useColor?: boolean;
|
useColor?: boolean;
|
||||||
className?: string;
|
className?: string;
|
||||||
textClassName?: string;
|
textClassName?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ProgressBar({label, percentage, color, useColor = false, className, textClassName}: Props) {
|
export default function ProgressBar({label, percentage, color, mark, markLabel, useColor = false, className, textClassName}: Props) {
|
||||||
const progressColorClass: {[key in typeof color]: string} = {
|
const progressColorClass: {[key in typeof color]: string} = {
|
||||||
red: "bg-mti-red-light",
|
red: "bg-mti-red-light",
|
||||||
rose: "bg-mti-rose-light",
|
rose: "bg-mti-rose-light",
|
||||||
@@ -30,6 +32,9 @@ export default function ProgressBar({label, percentage, color, useColor = false,
|
|||||||
!useColor ? "bg-mti-gray-anti-flash" : progressColorClass[color],
|
!useColor ? "bg-mti-gray-anti-flash" : progressColorClass[color],
|
||||||
useColor && "bg-opacity-20",
|
useColor && "bg-opacity-20",
|
||||||
)}>
|
)}>
|
||||||
|
{mark && (
|
||||||
|
<div style={{left: `${mark}%`}} className={clsx("w-3 h-2 bg-mti-gray-davy/60 absolute -translate-x-1/2 top-0 z-20 cursor-pointer")} />
|
||||||
|
)}
|
||||||
<div
|
<div
|
||||||
style={{width: `${percentage}%`}}
|
style={{width: `${percentage}%`}}
|
||||||
className={clsx("absolute transition-all duration-300 ease-in-out top-0 left-0 h-full overflow-hidden", progressColorClass[color])}
|
className={clsx("absolute transition-all duration-300 ease-in-out top-0 left-0 h-full overflow-hidden", progressColorClass[color])}
|
||||||
|
|||||||
121
src/components/Medium/ModuleLevelSelector.tsx
Normal file
121
src/components/Medium/ModuleLevelSelector.tsx
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
import {Module} from "@/interfaces";
|
||||||
|
import {writingMarking} from "@/utils/score";
|
||||||
|
import {Menu} from "@headlessui/react";
|
||||||
|
import {Dispatch, SetStateAction} from "react";
|
||||||
|
import {BsBook, BsChevronDown, BsHeadphones, BsMegaphone, BsPen} from "react-icons/bs";
|
||||||
|
|
||||||
|
type Levels = {[key in Module]: number};
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
levels: Levels;
|
||||||
|
setLevels: Dispatch<SetStateAction<Levels>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ModuleLevelSelector({levels, setLevels}: Props) {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col gap-32 w-full">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-y-4 gap-x-16">
|
||||||
|
<div className="w-full flex flex-col gap-3.5 relative">
|
||||||
|
<span className="text-sm text-mti-gray-dim">
|
||||||
|
<span className="font-bold">Reading</span> level
|
||||||
|
</span>
|
||||||
|
<Menu>
|
||||||
|
<Menu.Button className="w-full border border-mti-gray-platinum rounded-full px-6 py-4 flex justify-between items-center gap-12 bg-white">
|
||||||
|
<BsBook className="text-ielts-reading" size={34} />
|
||||||
|
<span className="text-mti-gray-cool text-sm">
|
||||||
|
{levels.reading === -1 ? "Select your reading level" : `Level ${levels.reading}`}
|
||||||
|
</span>
|
||||||
|
<BsChevronDown className="text-mti-gray-cool" size={12} />
|
||||||
|
</Menu.Button>
|
||||||
|
<Menu.Items className="absolute overflow-y-scroll scrollbar-hide max-h-[230px] origin-top top-full bg-white flex flex-col items-center w-full z-20 drop-shadow-lg rounded-2xl">
|
||||||
|
{Object.values(writingMarking).map((x) => (
|
||||||
|
<Menu.Item key={x}>
|
||||||
|
<span
|
||||||
|
onClick={() => setLevels((prev) => ({...prev, reading: x}))}
|
||||||
|
className="w-full py-4 text-center cursor-pointer bg-white hover:bg-mti-gray-platinum transition ease-in-out duration-300">
|
||||||
|
Level {x}
|
||||||
|
</span>
|
||||||
|
</Menu.Item>
|
||||||
|
))}
|
||||||
|
</Menu.Items>
|
||||||
|
</Menu>
|
||||||
|
</div>
|
||||||
|
<div className="w-full flex flex-col gap-3.5 relative">
|
||||||
|
<span className="text-sm text-mti-gray-dim">
|
||||||
|
<span className="font-bold">Listening</span> level
|
||||||
|
</span>
|
||||||
|
<Menu>
|
||||||
|
<Menu.Button className="w-full border border-mti-gray-platinum rounded-full px-6 py-4 flex justify-between items-center gap-12 bg-white">
|
||||||
|
<BsHeadphones className="text-ielts-listening" size={34} />
|
||||||
|
<span className="text-mti-gray-cool text-sm">
|
||||||
|
{levels.listening === -1 ? "Select your listening level" : `Level ${levels.listening}`}
|
||||||
|
</span>
|
||||||
|
<BsChevronDown className="text-mti-gray-cool" size={12} />
|
||||||
|
</Menu.Button>
|
||||||
|
<Menu.Items className="absolute overflow-y-scroll scrollbar-hide max-h-[230px] origin-top top-full bg-white flex flex-col items-center w-full z-50 drop-shadow-lg rounded-2xl">
|
||||||
|
{Object.values(writingMarking).map((x) => (
|
||||||
|
<Menu.Item key={x}>
|
||||||
|
<span
|
||||||
|
onClick={() => setLevels((prev) => ({...prev, listening: x}))}
|
||||||
|
className="w-full py-5 text-center cursor-pointer bg-white hover:bg-mti-gray-platinum transition ease-in-out duration-300">
|
||||||
|
Level {x}
|
||||||
|
</span>
|
||||||
|
</Menu.Item>
|
||||||
|
))}
|
||||||
|
</Menu.Items>
|
||||||
|
</Menu>
|
||||||
|
</div>
|
||||||
|
<div className="w-full flex flex-col gap-3.5 relative">
|
||||||
|
<span className="text-sm text-mti-gray-dim">
|
||||||
|
<span className="font-bold">Writing</span> level
|
||||||
|
</span>
|
||||||
|
<Menu>
|
||||||
|
<Menu.Button className="w-full border border-mti-gray-platinum rounded-full px-6 py-4 flex justify-between items-center gap-12 bg-white">
|
||||||
|
<BsPen className="text-ielts-writing" size={34} />
|
||||||
|
<span className="text-mti-gray-cool text-sm">
|
||||||
|
{levels.writing === -1 ? "Select your writing level" : `Level ${levels.writing}`}
|
||||||
|
</span>
|
||||||
|
<BsChevronDown className="text-mti-gray-cool" size={12} />
|
||||||
|
</Menu.Button>
|
||||||
|
<Menu.Items className="absolute overflow-y-scroll scrollbar-hide max-h-[230px] origin-top top-full bg-white flex flex-col items-center w-full z-20 drop-shadow-lg rounded-2xl">
|
||||||
|
{Object.values(writingMarking).map((x) => (
|
||||||
|
<Menu.Item key={x}>
|
||||||
|
<span
|
||||||
|
onClick={() => setLevels((prev) => ({...prev, writing: x}))}
|
||||||
|
className="w-full py-5 text-center cursor-pointer bg-white hover:bg-mti-gray-platinum transition ease-in-out duration-300">
|
||||||
|
Level {x}
|
||||||
|
</span>
|
||||||
|
</Menu.Item>
|
||||||
|
))}
|
||||||
|
</Menu.Items>
|
||||||
|
</Menu>
|
||||||
|
</div>
|
||||||
|
<div className="w-full flex flex-col gap-3.5 relative">
|
||||||
|
<span className="text-sm text-mti-gray-dim">
|
||||||
|
<span className="font-bold">Speaking</span> level
|
||||||
|
</span>
|
||||||
|
<Menu>
|
||||||
|
<Menu.Button className="w-full border border-mti-gray-platinum rounded-full px-6 py-4 flex justify-between items-center gap-12 bg-white">
|
||||||
|
<BsMegaphone className="text-ielts-speaking" size={34} />
|
||||||
|
<span className="text-mti-gray-cool text-sm">
|
||||||
|
{levels.speaking === -1 ? "Select your speaking level" : `Level ${levels.speaking}`}
|
||||||
|
</span>
|
||||||
|
<BsChevronDown className="text-mti-gray-cool" size={12} />
|
||||||
|
</Menu.Button>
|
||||||
|
<Menu.Items className="absolute overflow-y-scroll scrollbar-hide max-h-[230px] origin-top top-full bg-white flex flex-col items-center w-full z-20 drop-shadow-lg rounded-2xl">
|
||||||
|
{Object.values(writingMarking).map((x) => (
|
||||||
|
<Menu.Item key={x}>
|
||||||
|
<span
|
||||||
|
onClick={() => setLevels((prev) => ({...prev, speaking: x}))}
|
||||||
|
className="w-full py-5 text-center cursor-pointer bg-white hover:bg-mti-gray-platinum transition ease-in-out duration-300">
|
||||||
|
Level {x}
|
||||||
|
</span>
|
||||||
|
</Menu.Item>
|
||||||
|
))}
|
||||||
|
</Menu.Items>
|
||||||
|
</Menu>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -13,19 +13,9 @@ import { CorporateUser, User } from "@/interfaces/user";
|
|||||||
import useExamStore from "@/stores/examStore";
|
import useExamStore from "@/stores/examStore";
|
||||||
import {getExamById} from "@/utils/exams";
|
import {getExamById} from "@/utils/exams";
|
||||||
import {getUserCorporate} from "@/utils/groups";
|
import {getUserCorporate} from "@/utils/groups";
|
||||||
import {
|
import {MODULE_ARRAY, sortByModule, sortByModuleName} from "@/utils/moduleUtils";
|
||||||
MODULE_ARRAY,
|
|
||||||
sortByModule,
|
|
||||||
sortByModuleName,
|
|
||||||
} from "@/utils/moduleUtils";
|
|
||||||
import {averageScore, groupBySession} from "@/utils/stats";
|
import {averageScore, groupBySession} from "@/utils/stats";
|
||||||
import {
|
import {CreateOrderActions, CreateOrderData, OnApproveActions, OnApproveData, OrderResponseBody} from "@paypal/paypal-js";
|
||||||
CreateOrderActions,
|
|
||||||
CreateOrderData,
|
|
||||||
OnApproveActions,
|
|
||||||
OnApproveData,
|
|
||||||
OrderResponseBody,
|
|
||||||
} from "@paypal/paypal-js";
|
|
||||||
import {PayPalButtons} from "@paypal/react-paypal-js";
|
import {PayPalButtons} from "@paypal/react-paypal-js";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
@@ -34,17 +24,7 @@ import moment from "moment";
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import {useRouter} from "next/router";
|
import {useRouter} from "next/router";
|
||||||
import {useEffect, useState} from "react";
|
import {useEffect, useState} from "react";
|
||||||
import {
|
import {BsArrowRepeat, BsBook, BsClipboard, BsFileEarmarkText, BsHeadphones, BsMegaphone, BsPen, BsPencil, BsStar} from "react-icons/bs";
|
||||||
BsArrowRepeat,
|
|
||||||
BsBook,
|
|
||||||
BsClipboard,
|
|
||||||
BsFileEarmarkText,
|
|
||||||
BsHeadphones,
|
|
||||||
BsMegaphone,
|
|
||||||
BsPen,
|
|
||||||
BsPencil,
|
|
||||||
BsStar,
|
|
||||||
} from "react-icons/bs";
|
|
||||||
import {toast} from "react-toastify";
|
import {toast} from "react-toastify";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -52,21 +32,12 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function StudentDashboard({user}: Props) {
|
export default function StudentDashboard({user}: Props) {
|
||||||
const [corporateUserToShow, setCorporateUserToShow] =
|
const [corporateUserToShow, setCorporateUserToShow] = useState<CorporateUser>();
|
||||||
useState<CorporateUser>();
|
|
||||||
|
|
||||||
const {stats} = useStats(user.id);
|
const {stats} = useStats(user.id);
|
||||||
const {users} = useUsers();
|
const {users} = useUsers();
|
||||||
const {
|
const {assignments, isLoading: isAssignmentsLoading, reload: reloadAssignments} = useAssignments({assignees: user?.id});
|
||||||
assignments,
|
const {invites, isLoading: isInvitesLoading, reload: reloadInvites} = useInvites({to: user.id});
|
||||||
isLoading: isAssignmentsLoading,
|
|
||||||
reload: reloadAssignments,
|
|
||||||
} = useAssignments({ assignees: user?.id });
|
|
||||||
const {
|
|
||||||
invites,
|
|
||||||
isLoading: isInvitesLoading,
|
|
||||||
reload: reloadInvites,
|
|
||||||
} = useInvites({ to: user.id });
|
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
@@ -81,9 +52,7 @@ export default function StudentDashboard({ user }: Props) {
|
|||||||
}, [user]);
|
}, [user]);
|
||||||
|
|
||||||
const startAssignment = (assignment: Assignment) => {
|
const startAssignment = (assignment: Assignment) => {
|
||||||
const examPromises = assignment.exams
|
const examPromises = assignment.exams.filter((e) => e.assignee === user.id).map((e) => getExamById(e.module, e.id));
|
||||||
.filter((e) => e.assignee === user.id)
|
|
||||||
.map((e) => getExamById(e.module, e.id));
|
|
||||||
|
|
||||||
Promise.all(examPromises).then((exams) => {
|
Promise.all(examPromises).then((exams) => {
|
||||||
if (exams.every((x) => !!x)) {
|
if (exams.every((x) => !!x)) {
|
||||||
@@ -107,68 +76,50 @@ export default function StudentDashboard({ user }: Props) {
|
|||||||
<>
|
<>
|
||||||
{corporateUserToShow && (
|
{corporateUserToShow && (
|
||||||
<div className="absolute right-4 top-4 rounded-lg bg-neutral-200 px-2 py-1">
|
<div className="absolute right-4 top-4 rounded-lg bg-neutral-200 px-2 py-1">
|
||||||
Linked to:{" "}
|
Linked to: <b>{corporateUserToShow?.corporateInformation?.companyInformation.name || corporateUserToShow.name}</b>
|
||||||
<b>
|
|
||||||
{corporateUserToShow?.corporateInformation?.companyInformation
|
|
||||||
.name || corporateUserToShow.name}
|
|
||||||
</b>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<ProfileSummary
|
<ProfileSummary
|
||||||
user={user}
|
user={user}
|
||||||
items={[
|
items={[
|
||||||
{
|
{
|
||||||
icon: (
|
icon: <BsFileEarmarkText className="text-mti-red-light h-6 w-6 md:h-8 md:w-8" />,
|
||||||
<BsFileEarmarkText className="text-mti-red-light h-6 w-6 md:h-8 md:w-8" />
|
|
||||||
),
|
|
||||||
value: Object.keys(groupBySession(stats)).length,
|
value: Object.keys(groupBySession(stats)).length,
|
||||||
label: "Exams",
|
label: "Exams",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: (
|
icon: <BsPencil className="text-mti-red-light h-6 w-6 md:h-8 md:w-8" />,
|
||||||
<BsPencil className="text-mti-red-light h-6 w-6 md:h-8 md:w-8" />
|
|
||||||
),
|
|
||||||
value: stats.length,
|
value: stats.length,
|
||||||
label: "Exercises",
|
label: "Exercises",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: (
|
icon: <BsStar className="text-mti-red-light h-6 w-6 md:h-8 md:w-8" />,
|
||||||
<BsStar className="text-mti-red-light h-6 w-6 md:h-8 md:w-8" />
|
|
||||||
),
|
|
||||||
value: `${stats.length > 0 ? averageScore(stats) : 0}%`,
|
value: `${stats.length > 0 ? averageScore(stats) : 0}%`,
|
||||||
label: "Average Score",
|
label: "Average Score",
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* Bio */}
|
||||||
<section className="flex flex-col gap-1 md:gap-3">
|
<section className="flex flex-col gap-1 md:gap-3">
|
||||||
<span className="text-lg font-bold">Bio</span>
|
<span className="text-lg font-bold">Bio</span>
|
||||||
<span className="text-mti-gray-taupe">
|
<span className="text-mti-gray-taupe">
|
||||||
{user.bio ||
|
{user.bio || "Your bio will appear here, you can change it by clicking on your name in the top right corner."}
|
||||||
"Your bio will appear here, you can change it by clicking on your name in the top right corner."}
|
|
||||||
</span>
|
</span>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
{/* Assignments */}
|
||||||
<section className="flex flex-col gap-1 md:gap-3">
|
<section className="flex flex-col gap-1 md:gap-3">
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
<div
|
<div
|
||||||
onClick={reloadAssignments}
|
onClick={reloadAssignments}
|
||||||
className="text-mti-purple-light hover:text-mti-purple-dark flex cursor-pointer items-center gap-2 transition duration-300 ease-in-out"
|
className="text-mti-purple-light hover:text-mti-purple-dark flex cursor-pointer items-center gap-2 transition duration-300 ease-in-out">
|
||||||
>
|
<span className="text-mti-black text-lg font-bold">Assignments</span>
|
||||||
<span className="text-mti-black text-lg font-bold">
|
<BsArrowRepeat className={clsx("text-xl", isAssignmentsLoading && "animate-spin")} />
|
||||||
Assignments
|
|
||||||
</span>
|
|
||||||
<BsArrowRepeat
|
|
||||||
className={clsx(
|
|
||||||
"text-xl",
|
|
||||||
isAssignmentsLoading && "animate-spin",
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<span className="text-mti-gray-taupe scrollbar-hide flex gap-8 overflow-x-scroll">
|
<span className="text-mti-gray-taupe scrollbar-hide flex gap-8 overflow-x-scroll">
|
||||||
{assignments.filter((a) => moment(a.endDate).isSameOrAfter(moment()))
|
{assignments.filter((a) => moment(a.endDate).isSameOrAfter(moment())).length === 0 &&
|
||||||
.length === 0 &&
|
|
||||||
"Assignments will appear here. It seems that for now there are no assignments for you."}
|
"Assignments will appear here. It seems that for now there are no assignments for you."}
|
||||||
{assignments
|
{assignments
|
||||||
.filter((a) => moment(a.endDate).isSameOrAfter(moment()))
|
.filter((a) => moment(a.endDate).isSameOrAfter(moment()))
|
||||||
@@ -177,23 +128,15 @@ export default function StudentDashboard({ user }: Props) {
|
|||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"border-mti-gray-anti-flash flex min-w-[300px] flex-col gap-6 rounded-xl border p-4",
|
"border-mti-gray-anti-flash flex min-w-[300px] flex-col gap-6 rounded-xl border p-4",
|
||||||
assignment.results.map((r) => r.user).includes(user.id) &&
|
assignment.results.map((r) => r.user).includes(user.id) && "border-mti-green-light",
|
||||||
"border-mti-green-light",
|
|
||||||
)}
|
)}
|
||||||
key={assignment.id}
|
key={assignment.id}>
|
||||||
>
|
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
<h3 className="text-mti-black/90 text-xl font-semibold">
|
<h3 className="text-mti-black/90 text-xl font-semibold">{assignment.name}</h3>
|
||||||
{assignment.name}
|
|
||||||
</h3>
|
|
||||||
<span className="flex justify-between gap-1">
|
<span className="flex justify-between gap-1">
|
||||||
<span>
|
<span>{moment(assignment.startDate).format("DD/MM/YY, HH:mm")}</span>
|
||||||
{moment(assignment.startDate).format("DD/MM/YY, HH:mm")}
|
|
||||||
</span>
|
|
||||||
<span>-</span>
|
<span>-</span>
|
||||||
<span>
|
<span>{moment(assignment.endDate).format("DD/MM/YY, HH:mm")}</span>
|
||||||
{moment(assignment.endDate).format("DD/MM/YY, HH:mm")}
|
|
||||||
</span>
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex w-full items-center justify-between">
|
<div className="flex w-full items-center justify-between">
|
||||||
@@ -213,23 +156,12 @@ export default function StudentDashboard({ user }: Props) {
|
|||||||
module === "writing" && "bg-ielts-writing",
|
module === "writing" && "bg-ielts-writing",
|
||||||
module === "speaking" && "bg-ielts-speaking",
|
module === "speaking" && "bg-ielts-speaking",
|
||||||
module === "level" && "bg-ielts-level",
|
module === "level" && "bg-ielts-level",
|
||||||
)}
|
)}>
|
||||||
>
|
{module === "reading" && <BsBook className="h-4 w-4" />}
|
||||||
{module === "reading" && (
|
{module === "listening" && <BsHeadphones className="h-4 w-4" />}
|
||||||
<BsBook className="h-4 w-4" />
|
{module === "writing" && <BsPen className="h-4 w-4" />}
|
||||||
)}
|
{module === "speaking" && <BsMegaphone className="h-4 w-4" />}
|
||||||
{module === "listening" && (
|
{module === "level" && <BsClipboard className="h-4 w-4" />}
|
||||||
<BsHeadphones className="h-4 w-4" />
|
|
||||||
)}
|
|
||||||
{module === "writing" && (
|
|
||||||
<BsPen className="h-4 w-4" />
|
|
||||||
)}
|
|
||||||
{module === "speaking" && (
|
|
||||||
<BsMegaphone className="h-4 w-4" />
|
|
||||||
)}
|
|
||||||
{module === "level" && (
|
|
||||||
<BsClipboard className="h-4 w-4" />
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@@ -237,26 +169,19 @@ export default function StudentDashboard({ user }: Props) {
|
|||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
className="tooltip flex h-full w-full items-center justify-end pl-8 md:hidden"
|
className="tooltip flex h-full w-full items-center justify-end pl-8 md:hidden"
|
||||||
data-tip="Your screen size is too small to perform an assignment"
|
data-tip="Your screen size is too small to perform an assignment">
|
||||||
>
|
|
||||||
<Button
|
<Button
|
||||||
disabled={moment(assignment.startDate).isAfter(
|
disabled={moment(assignment.startDate).isAfter(moment())}
|
||||||
moment(),
|
|
||||||
)}
|
|
||||||
className="h-full w-full !rounded-xl"
|
className="h-full w-full !rounded-xl"
|
||||||
variant="outline"
|
variant="outline">
|
||||||
>
|
|
||||||
Start
|
Start
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
disabled={moment(assignment.startDate).isAfter(
|
disabled={moment(assignment.startDate).isAfter(moment())}
|
||||||
moment(),
|
|
||||||
)}
|
|
||||||
className="-md:hidden h-full w-full max-w-[50%] !rounded-xl"
|
className="-md:hidden h-full w-full max-w-[50%] !rounded-xl"
|
||||||
onClick={() => startAssignment(assignment)}
|
onClick={() => startAssignment(assignment)}
|
||||||
variant="outline"
|
variant="outline">
|
||||||
>
|
|
||||||
Start
|
Start
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
@@ -266,8 +191,7 @@ export default function StudentDashboard({ user }: Props) {
|
|||||||
onClick={() => router.push("/record")}
|
onClick={() => router.push("/record")}
|
||||||
color="green"
|
color="green"
|
||||||
className="-md:hidden h-full w-full max-w-[50%] !rounded-xl"
|
className="-md:hidden h-full w-full max-w-[50%] !rounded-xl"
|
||||||
variant="outline"
|
variant="outline">
|
||||||
>
|
|
||||||
Submitted
|
Submitted
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
@@ -277,65 +201,43 @@ export default function StudentDashboard({ user }: Props) {
|
|||||||
</span>
|
</span>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
{/* Invites */}
|
||||||
{invites.length > 0 && (
|
{invites.length > 0 && (
|
||||||
<section className="flex flex-col gap-1 md:gap-3">
|
<section className="flex flex-col gap-1 md:gap-3">
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
<div
|
<div
|
||||||
onClick={reloadInvites}
|
onClick={reloadInvites}
|
||||||
className="text-mti-purple-light hover:text-mti-purple-dark flex cursor-pointer items-center gap-2 transition duration-300 ease-in-out"
|
className="text-mti-purple-light hover:text-mti-purple-dark flex cursor-pointer items-center gap-2 transition duration-300 ease-in-out">
|
||||||
>
|
|
||||||
<span className="text-mti-black text-lg font-bold">Invites</span>
|
<span className="text-mti-black text-lg font-bold">Invites</span>
|
||||||
<BsArrowRepeat
|
<BsArrowRepeat className={clsx("text-xl", isInvitesLoading && "animate-spin")} />
|
||||||
className={clsx("text-xl", isInvitesLoading && "animate-spin")}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<span className="text-mti-gray-taupe scrollbar-hide flex gap-8 overflow-x-scroll">
|
<span className="text-mti-gray-taupe scrollbar-hide flex gap-8 overflow-x-scroll">
|
||||||
{invites.map((invite) => (
|
{invites.map((invite) => (
|
||||||
<InviteCard
|
<InviteCard key={invite.id} invite={invite} users={users} reload={reloadInvites} />
|
||||||
key={invite.id}
|
|
||||||
invite={invite}
|
|
||||||
users={users}
|
|
||||||
reload={reloadInvites}
|
|
||||||
/>
|
|
||||||
))}
|
))}
|
||||||
</span>
|
</span>
|
||||||
</section>
|
</section>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Score History */}
|
||||||
<section className="flex flex-col gap-3">
|
<section className="flex flex-col gap-3">
|
||||||
<span className="text-lg font-bold">Score History</span>
|
<span className="text-lg font-bold">Score History</span>
|
||||||
<div className="-md:grid-rows-4 grid gap-6 md:grid-cols-2">
|
<div className="-md:grid-rows-4 grid gap-6 md:grid-cols-2">
|
||||||
{MODULE_ARRAY.map((module) => (
|
{MODULE_ARRAY.map((module) => (
|
||||||
<div
|
<div className="border-mti-gray-anti-flash flex flex-col gap-2 rounded-xl border p-4" key={module}>
|
||||||
className="border-mti-gray-anti-flash flex flex-col gap-2 rounded-xl border p-4"
|
|
||||||
key={module}
|
|
||||||
>
|
|
||||||
<div className="flex items-center gap-2 md:gap-3">
|
<div className="flex items-center gap-2 md:gap-3">
|
||||||
<div className="bg-mti-gray-smoke flex h-8 w-8 items-center justify-center rounded-lg md:h-12 md:w-12 md:rounded-xl">
|
<div className="bg-mti-gray-smoke flex h-8 w-8 items-center justify-center rounded-lg md:h-12 md:w-12 md:rounded-xl">
|
||||||
{module === "reading" && (
|
{module === "reading" && <BsBook className="text-ielts-reading h-4 w-4 md:h-5 md:w-5" />}
|
||||||
<BsBook className="text-ielts-reading h-4 w-4 md:h-5 md:w-5" />
|
{module === "listening" && <BsHeadphones className="text-ielts-listening h-4 w-4 md:h-5 md:w-5" />}
|
||||||
)}
|
{module === "writing" && <BsPen className="text-ielts-writing h-4 w-4 md:h-5 md:w-5" />}
|
||||||
{module === "listening" && (
|
{module === "speaking" && <BsMegaphone className="text-ielts-speaking h-4 w-4 md:h-5 md:w-5" />}
|
||||||
<BsHeadphones className="text-ielts-listening h-4 w-4 md:h-5 md:w-5" />
|
{module === "level" && <BsClipboard className="text-ielts-level h-4 w-4 md:h-5 md:w-5" />}
|
||||||
)}
|
|
||||||
{module === "writing" && (
|
|
||||||
<BsPen className="text-ielts-writing h-4 w-4 md:h-5 md:w-5" />
|
|
||||||
)}
|
|
||||||
{module === "speaking" && (
|
|
||||||
<BsMegaphone className="text-ielts-speaking h-4 w-4 md:h-5 md:w-5" />
|
|
||||||
)}
|
|
||||||
{module === "level" && (
|
|
||||||
<BsClipboard className="text-ielts-level h-4 w-4 md:h-5 md:w-5" />
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
<div className="flex w-full justify-between">
|
<div className="flex w-full justify-between">
|
||||||
<span className="text-sm font-bold md:font-extrabold">
|
<span className="text-sm font-bold md:font-extrabold">{capitalize(module)}</span>
|
||||||
{capitalize(module)}
|
|
||||||
</span>
|
|
||||||
<span className="text-mti-gray-dim text-sm font-normal">
|
<span className="text-mti-gray-dim text-sm font-normal">
|
||||||
Level {user.levels[module] || 0} / Level{" "}
|
Level {user.levels[module] || 0} / Level 9 (Desired Level: {user.desiredLevels[module] || 9})
|
||||||
{user.desiredLevels[module] || 9}
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -343,9 +245,9 @@ export default function StudentDashboard({ user }: Props) {
|
|||||||
<ProgressBar
|
<ProgressBar
|
||||||
color={module}
|
color={module}
|
||||||
label=""
|
label=""
|
||||||
percentage={Math.round(
|
mark={Math.round((user.desiredLevels[module] * 100) / 9)}
|
||||||
(user.levels[module] * 100) / user.desiredLevels[module],
|
markLabel={`Desired Level: ${user.desiredLevels[module]}`}
|
||||||
)}
|
percentage={Math.round((user.levels[module] * 100) / 9)}
|
||||||
className="h-2 w-full"
|
className="h-2 w-full"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,16 +4,7 @@ import { Module } from "@/interfaces";
|
|||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import {User} from "@/interfaces/user";
|
import {User} from "@/interfaces/user";
|
||||||
import ProgressBar from "@/components/Low/ProgressBar";
|
import ProgressBar from "@/components/Low/ProgressBar";
|
||||||
import {
|
import {BsBook, BsCheck, BsCheckCircle, BsClipboard, BsHeadphones, BsMegaphone, BsPen, BsXCircle} from "react-icons/bs";
|
||||||
BsBook,
|
|
||||||
BsCheck,
|
|
||||||
BsCheckCircle,
|
|
||||||
BsClipboard,
|
|
||||||
BsHeadphones,
|
|
||||||
BsMegaphone,
|
|
||||||
BsPen,
|
|
||||||
BsXCircle,
|
|
||||||
} from "react-icons/bs";
|
|
||||||
import {totalExamsByModule} from "@/utils/stats";
|
import {totalExamsByModule} from "@/utils/stats";
|
||||||
import useStats from "@/hooks/useStats";
|
import useStats from "@/hooks/useStats";
|
||||||
import Button from "@/components/Low/Button";
|
import Button from "@/components/Low/Button";
|
||||||
@@ -26,20 +17,11 @@ import { Variant } from "@/interfaces/exam";
|
|||||||
interface Props {
|
interface Props {
|
||||||
user: User;
|
user: User;
|
||||||
page: "exercises" | "exams";
|
page: "exercises" | "exams";
|
||||||
onStart: (
|
onStart: (modules: Module[], avoidRepeated: boolean, variant: Variant) => void;
|
||||||
modules: Module[],
|
|
||||||
avoidRepeated: boolean,
|
|
||||||
variant: Variant,
|
|
||||||
) => void;
|
|
||||||
disableSelection?: boolean;
|
disableSelection?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Selection({
|
export default function Selection({user, page, onStart, disableSelection = false}: Props) {
|
||||||
user,
|
|
||||||
page,
|
|
||||||
onStart,
|
|
||||||
disableSelection = false,
|
|
||||||
}: Props) {
|
|
||||||
const [selectedModules, setSelectedModules] = useState<Module[]>([]);
|
const [selectedModules, setSelectedModules] = useState<Module[]>([]);
|
||||||
const [avoidRepeatedExams, setAvoidRepeatedExams] = useState(true);
|
const [avoidRepeatedExams, setAvoidRepeatedExams] = useState(true);
|
||||||
const [variant, setVariant] = useState<Variant>("full");
|
const [variant, setVariant] = useState<Variant>("full");
|
||||||
@@ -47,9 +29,7 @@ export default function Selection({
|
|||||||
|
|
||||||
const toggleModule = (module: Module) => {
|
const toggleModule = (module: Module) => {
|
||||||
const modules = selectedModules.filter((x) => x !== module);
|
const modules = selectedModules.filter((x) => x !== module);
|
||||||
setSelectedModules((prev) =>
|
setSelectedModules((prev) => (prev.includes(module) ? modules : [...modules, module]));
|
||||||
prev.includes(module) ? modules : [...modules, module],
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -60,38 +40,28 @@ export default function Selection({
|
|||||||
user={user}
|
user={user}
|
||||||
items={[
|
items={[
|
||||||
{
|
{
|
||||||
icon: (
|
icon: <BsBook className="text-ielts-reading h-6 w-6 md:h-8 md:w-8" />,
|
||||||
<BsBook className="text-ielts-reading h-6 w-6 md:h-8 md:w-8" />
|
|
||||||
),
|
|
||||||
label: "Reading",
|
label: "Reading",
|
||||||
value: totalExamsByModule(stats, "reading"),
|
value: totalExamsByModule(stats, "reading"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: (
|
icon: <BsHeadphones className="text-ielts-listening h-6 w-6 md:h-8 md:w-8" />,
|
||||||
<BsHeadphones className="text-ielts-listening h-6 w-6 md:h-8 md:w-8" />
|
|
||||||
),
|
|
||||||
label: "Listening",
|
label: "Listening",
|
||||||
value: totalExamsByModule(stats, "listening"),
|
value: totalExamsByModule(stats, "listening"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: (
|
icon: <BsPen className="text-ielts-writing h-6 w-6 md:h-8 md:w-8" />,
|
||||||
<BsPen className="text-ielts-writing h-6 w-6 md:h-8 md:w-8" />
|
|
||||||
),
|
|
||||||
label: "Writing",
|
label: "Writing",
|
||||||
value: totalExamsByModule(stats, "writing"),
|
value: totalExamsByModule(stats, "writing"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: (
|
icon: <BsMegaphone className="text-ielts-speaking h-6 w-6 md:h-8 md:w-8" />,
|
||||||
<BsMegaphone className="text-ielts-speaking h-6 w-6 md:h-8 md:w-8" />
|
|
||||||
),
|
|
||||||
label: "Speaking",
|
label: "Speaking",
|
||||||
value: totalExamsByModule(stats, "speaking"),
|
value: totalExamsByModule(stats, "speaking"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: (
|
icon: <BsClipboard className="text-ielts-level h-6 w-6 md:h-8 md:w-8" />,
|
||||||
<BsClipboard className="text-ielts-level h-6 w-6 md:h-8 md:w-8" />
|
label: "Vocab/Grammar",
|
||||||
),
|
|
||||||
label: "Level",
|
|
||||||
value: totalExamsByModule(stats, "level"),
|
value: totalExamsByModule(stats, "level"),
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
@@ -103,205 +73,131 @@ export default function Selection({
|
|||||||
<span className="text-mti-gray-taupe">
|
<span className="text-mti-gray-taupe">
|
||||||
{page === "exercises" && (
|
{page === "exercises" && (
|
||||||
<>
|
<>
|
||||||
In the realm of language acquisition, practice makes perfect,
|
In the realm of language acquisition, practice makes perfect, and our exercises are the key to unlocking your full
|
||||||
and our exercises are the key to unlocking your full potential.
|
potential. Dive into a world of interactive and engaging exercises that cater to diverse learning styles. From grammar
|
||||||
Dive into a world of interactive and engaging exercises that
|
drills that build a strong foundation to vocabulary challenges that broaden your lexicon, our exercises are carefully
|
||||||
cater to diverse learning styles. From grammar drills that build
|
designed to make learning English both enjoyable and effective. Whether you're looking to reinforce specific
|
||||||
a strong foundation to vocabulary challenges that broaden your
|
skills or embark on a holistic language journey, our exercises are your companions in the pursuit of excellence.
|
||||||
lexicon, our exercises are carefully designed to make learning
|
Embrace the joy of learning as you navigate through a variety of activities that cater to every facet of language
|
||||||
English both enjoyable and effective. Whether you're
|
acquisition. Your linguistic adventure starts here!
|
||||||
looking to reinforce specific skills or embark on a holistic
|
|
||||||
language journey, our exercises are your companions in the
|
|
||||||
pursuit of excellence. Embrace the joy of learning as you
|
|
||||||
navigate through a variety of activities that cater to every
|
|
||||||
facet of language acquisition. Your linguistic adventure starts
|
|
||||||
here!
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{page === "exams" && (
|
{page === "exams" && (
|
||||||
<>
|
<>
|
||||||
Welcome to the heart of success on your English language
|
Welcome to the heart of success on your English language journey! Our exams are crafted with precision to assess and
|
||||||
journey! Our exams are crafted with precision to assess and
|
enhance your language skills. Each test is a passport to your linguistic prowess, designed to challenge and elevate
|
||||||
enhance your language skills. Each test is a passport to your
|
your abilities. Whether you're a beginner or a seasoned learner, our exams cater to all levels, providing a
|
||||||
linguistic prowess, designed to challenge and elevate your
|
comprehensive evaluation of your reading, writing, speaking, and listening skills. Prepare to embark on a journey of
|
||||||
abilities. Whether you're a beginner or a seasoned learner,
|
self-discovery and language mastery as you navigate through our thoughtfully curated exams. Your success is not just a
|
||||||
our exams cater to all levels, providing a comprehensive
|
destination; it's a testament to your dedication and our commitment to empowering you with the English language.
|
||||||
evaluation of your reading, writing, speaking, and listening
|
|
||||||
skills. Prepare to embark on a journey of self-discovery and
|
|
||||||
language mastery as you navigate through our thoughtfully
|
|
||||||
curated exams. Your success is not just a destination; it's
|
|
||||||
a testament to your dedication and our commitment to empowering
|
|
||||||
you with the English language.
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</section>
|
</section>
|
||||||
<section className="-lg:flex-col -lg:items-center -lg:gap-12 mt-8 flex w-full justify-between gap-8">
|
<section className="-lg:flex-col -lg:items-center -lg:gap-12 mt-8 flex w-full justify-between gap-8">
|
||||||
<div
|
<div
|
||||||
onClick={
|
onClick={!disableSelection && !selectedModules.includes("level") ? () => toggleModule("reading") : undefined}
|
||||||
!disableSelection && !selectedModules.includes("level")
|
|
||||||
? () => toggleModule("reading")
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"bg-mti-white-alt relative flex w-64 max-w-xs cursor-pointer flex-col items-center gap-2 rounded-xl border p-5 pt-12 transition duration-300 ease-in-out",
|
"bg-mti-white-alt relative flex w-64 max-w-xs cursor-pointer flex-col items-center gap-2 rounded-xl border p-5 pt-12 transition duration-300 ease-in-out",
|
||||||
selectedModules.includes("reading") || disableSelection
|
selectedModules.includes("reading") || disableSelection ? "border-mti-purple-light" : "border-mti-gray-platinum",
|
||||||
? "border-mti-purple-light"
|
)}>
|
||||||
: "border-mti-gray-platinum",
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div className="bg-ielts-reading absolute top-0 flex h-16 w-16 -translate-y-1/2 items-center justify-center rounded-full">
|
<div className="bg-ielts-reading absolute top-0 flex h-16 w-16 -translate-y-1/2 items-center justify-center rounded-full">
|
||||||
<BsBook className="h-7 w-7 text-white" />
|
<BsBook className="h-7 w-7 text-white" />
|
||||||
</div>
|
</div>
|
||||||
<span className="font-semibold">Reading:</span>
|
<span className="font-semibold">Reading:</span>
|
||||||
<p className="text-left text-xs">
|
<p className="text-left text-xs">
|
||||||
Expand your vocabulary, improve your reading comprehension and
|
Expand your vocabulary, improve your reading comprehension and improve your ability to interpret texts in English.
|
||||||
improve your ability to interpret texts in English.
|
|
||||||
</p>
|
</p>
|
||||||
{!selectedModules.includes("reading") &&
|
{!selectedModules.includes("reading") && !selectedModules.includes("level") && !disableSelection && (
|
||||||
!selectedModules.includes("level") &&
|
|
||||||
!disableSelection && (
|
|
||||||
<div className="border-mti-gray-platinum mt-4 h-8 w-8 rounded-full border" />
|
<div className="border-mti-gray-platinum mt-4 h-8 w-8 rounded-full border" />
|
||||||
)}
|
)}
|
||||||
{(selectedModules.includes("reading") || disableSelection) && (
|
{(selectedModules.includes("reading") || disableSelection) && (
|
||||||
<BsCheckCircle className="text-mti-purple-light mt-4 h-8 w-8" />
|
<BsCheckCircle className="text-mti-purple-light mt-4 h-8 w-8" />
|
||||||
)}
|
)}
|
||||||
{selectedModules.includes("level") && (
|
{selectedModules.includes("level") && <BsXCircle className="text-mti-red-light mt-4 h-8 w-8" />}
|
||||||
<BsXCircle className="text-mti-red-light mt-4 h-8 w-8" />
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
onClick={
|
onClick={!disableSelection && !selectedModules.includes("level") ? () => toggleModule("listening") : undefined}
|
||||||
!disableSelection && !selectedModules.includes("level")
|
|
||||||
? () => toggleModule("listening")
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"bg-mti-white-alt relative flex w-64 max-w-xs cursor-pointer flex-col items-center gap-2 rounded-xl border p-5 pt-12 transition duration-300 ease-in-out",
|
"bg-mti-white-alt relative flex w-64 max-w-xs cursor-pointer flex-col items-center gap-2 rounded-xl border p-5 pt-12 transition duration-300 ease-in-out",
|
||||||
selectedModules.includes("listening") || disableSelection
|
selectedModules.includes("listening") || disableSelection ? "border-mti-purple-light" : "border-mti-gray-platinum",
|
||||||
? "border-mti-purple-light"
|
)}>
|
||||||
: "border-mti-gray-platinum",
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div className="bg-ielts-listening absolute top-0 flex h-16 w-16 -translate-y-1/2 items-center justify-center rounded-full">
|
<div className="bg-ielts-listening absolute top-0 flex h-16 w-16 -translate-y-1/2 items-center justify-center rounded-full">
|
||||||
<BsHeadphones className="h-7 w-7 text-white" />
|
<BsHeadphones className="h-7 w-7 text-white" />
|
||||||
</div>
|
</div>
|
||||||
<span className="font-semibold">Listening:</span>
|
<span className="font-semibold">Listening:</span>
|
||||||
<p className="text-left text-xs">
|
<p className="text-left text-xs">
|
||||||
Improve your ability to follow conversations in English and your
|
Improve your ability to follow conversations in English and your ability to understand different accents and intonations.
|
||||||
ability to understand different accents and intonations.
|
|
||||||
</p>
|
</p>
|
||||||
{!selectedModules.includes("listening") &&
|
{!selectedModules.includes("listening") && !selectedModules.includes("level") && !disableSelection && (
|
||||||
!selectedModules.includes("level") &&
|
|
||||||
!disableSelection && (
|
|
||||||
<div className="border-mti-gray-platinum mt-4 h-8 w-8 rounded-full border" />
|
<div className="border-mti-gray-platinum mt-4 h-8 w-8 rounded-full border" />
|
||||||
)}
|
)}
|
||||||
{(selectedModules.includes("listening") || disableSelection) && (
|
{(selectedModules.includes("listening") || disableSelection) && (
|
||||||
<BsCheckCircle className="text-mti-purple-light mt-4 h-8 w-8" />
|
<BsCheckCircle className="text-mti-purple-light mt-4 h-8 w-8" />
|
||||||
)}
|
)}
|
||||||
{selectedModules.includes("level") && (
|
{selectedModules.includes("level") && <BsXCircle className="text-mti-red-light mt-4 h-8 w-8" />}
|
||||||
<BsXCircle className="text-mti-red-light mt-4 h-8 w-8" />
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
onClick={
|
onClick={!disableSelection && !selectedModules.includes("level") ? () => toggleModule("writing") : undefined}
|
||||||
!disableSelection && !selectedModules.includes("level")
|
|
||||||
? () => toggleModule("writing")
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"bg-mti-white-alt relative flex w-64 max-w-xs cursor-pointer flex-col items-center gap-2 rounded-xl border p-5 pt-12 transition duration-300 ease-in-out",
|
"bg-mti-white-alt relative flex w-64 max-w-xs cursor-pointer flex-col items-center gap-2 rounded-xl border p-5 pt-12 transition duration-300 ease-in-out",
|
||||||
selectedModules.includes("writing") || disableSelection
|
selectedModules.includes("writing") || disableSelection ? "border-mti-purple-light" : "border-mti-gray-platinum",
|
||||||
? "border-mti-purple-light"
|
)}>
|
||||||
: "border-mti-gray-platinum",
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div className="bg-ielts-writing absolute top-0 flex h-16 w-16 -translate-y-1/2 items-center justify-center rounded-full">
|
<div className="bg-ielts-writing absolute top-0 flex h-16 w-16 -translate-y-1/2 items-center justify-center rounded-full">
|
||||||
<BsPen className="h-7 w-7 text-white" />
|
<BsPen className="h-7 w-7 text-white" />
|
||||||
</div>
|
</div>
|
||||||
<span className="font-semibold">Writing:</span>
|
<span className="font-semibold">Writing:</span>
|
||||||
<p className="text-left text-xs">
|
<p className="text-left text-xs">
|
||||||
Allow you to practice writing in a variety of formats, from simple
|
Allow you to practice writing in a variety of formats, from simple paragraphs to complex essays.
|
||||||
paragraphs to complex essays.
|
|
||||||
</p>
|
</p>
|
||||||
{!selectedModules.includes("writing") &&
|
{!selectedModules.includes("writing") && !selectedModules.includes("level") && !disableSelection && (
|
||||||
!selectedModules.includes("level") &&
|
|
||||||
!disableSelection && (
|
|
||||||
<div className="border-mti-gray-platinum mt-4 h-8 w-8 rounded-full border" />
|
<div className="border-mti-gray-platinum mt-4 h-8 w-8 rounded-full border" />
|
||||||
)}
|
)}
|
||||||
{(selectedModules.includes("writing") || disableSelection) && (
|
{(selectedModules.includes("writing") || disableSelection) && (
|
||||||
<BsCheckCircle className="text-mti-purple-light mt-4 h-8 w-8" />
|
<BsCheckCircle className="text-mti-purple-light mt-4 h-8 w-8" />
|
||||||
)}
|
)}
|
||||||
{selectedModules.includes("level") && (
|
{selectedModules.includes("level") && <BsXCircle className="text-mti-red-light mt-4 h-8 w-8" />}
|
||||||
<BsXCircle className="text-mti-red-light mt-4 h-8 w-8" />
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
onClick={
|
onClick={!disableSelection && !selectedModules.includes("level") ? () => toggleModule("speaking") : undefined}
|
||||||
!disableSelection && !selectedModules.includes("level")
|
|
||||||
? () => toggleModule("speaking")
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"bg-mti-white-alt relative flex w-64 max-w-xs cursor-pointer flex-col items-center gap-2 rounded-xl border p-5 pt-12 transition duration-300 ease-in-out",
|
"bg-mti-white-alt relative flex w-64 max-w-xs cursor-pointer flex-col items-center gap-2 rounded-xl border p-5 pt-12 transition duration-300 ease-in-out",
|
||||||
selectedModules.includes("speaking") || disableSelection
|
selectedModules.includes("speaking") || disableSelection ? "border-mti-purple-light" : "border-mti-gray-platinum",
|
||||||
? "border-mti-purple-light"
|
)}>
|
||||||
: "border-mti-gray-platinum",
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div className="bg-ielts-speaking absolute top-0 flex h-16 w-16 -translate-y-1/2 items-center justify-center rounded-full">
|
<div className="bg-ielts-speaking absolute top-0 flex h-16 w-16 -translate-y-1/2 items-center justify-center rounded-full">
|
||||||
<BsMegaphone className="h-7 w-7 text-white" />
|
<BsMegaphone className="h-7 w-7 text-white" />
|
||||||
</div>
|
</div>
|
||||||
<span className="font-semibold">Speaking:</span>
|
<span className="font-semibold">Speaking:</span>
|
||||||
<p className="text-left text-xs">
|
<p className="text-left text-xs">
|
||||||
You'll have access to interactive dialogs, pronunciation
|
You'll have access to interactive dialogs, pronunciation exercises and speech recordings.
|
||||||
exercises and speech recordings.
|
|
||||||
</p>
|
</p>
|
||||||
{!selectedModules.includes("speaking") &&
|
{!selectedModules.includes("speaking") && !selectedModules.includes("level") && !disableSelection && (
|
||||||
!selectedModules.includes("level") &&
|
|
||||||
!disableSelection && (
|
|
||||||
<div className="border-mti-gray-platinum mt-4 h-8 w-8 rounded-full border" />
|
<div className="border-mti-gray-platinum mt-4 h-8 w-8 rounded-full border" />
|
||||||
)}
|
)}
|
||||||
{(selectedModules.includes("speaking") || disableSelection) && (
|
{(selectedModules.includes("speaking") || disableSelection) && (
|
||||||
<BsCheckCircle className="text-mti-purple-light mt-4 h-8 w-8" />
|
<BsCheckCircle className="text-mti-purple-light mt-4 h-8 w-8" />
|
||||||
)}
|
)}
|
||||||
{selectedModules.includes("level") && (
|
{selectedModules.includes("level") && <BsXCircle className="text-mti-red-light mt-4 h-8 w-8" />}
|
||||||
<BsXCircle className="text-mti-red-light mt-4 h-8 w-8" />
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
{!disableSelection && (
|
{!disableSelection && (
|
||||||
<div
|
<div
|
||||||
onClick={
|
onClick={selectedModules.length === 0 || selectedModules.includes("level") ? () => toggleModule("level") : undefined}
|
||||||
selectedModules.length === 0 ||
|
|
||||||
selectedModules.includes("level")
|
|
||||||
? () => toggleModule("level")
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"bg-mti-white-alt relative flex w-64 max-w-xs cursor-pointer flex-col items-center gap-2 rounded-xl border p-5 pt-12 transition duration-300 ease-in-out",
|
"bg-mti-white-alt relative flex w-64 max-w-xs cursor-pointer flex-col items-center gap-2 rounded-xl border p-5 pt-12 transition duration-300 ease-in-out",
|
||||||
selectedModules.includes("level") || disableSelection
|
selectedModules.includes("level") || disableSelection ? "border-mti-purple-light" : "border-mti-gray-platinum",
|
||||||
? "border-mti-purple-light"
|
)}>
|
||||||
: "border-mti-gray-platinum",
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div className="bg-ielts-level absolute top-0 flex h-16 w-16 -translate-y-1/2 items-center justify-center rounded-full">
|
<div className="bg-ielts-level absolute top-0 flex h-16 w-16 -translate-y-1/2 items-center justify-center rounded-full">
|
||||||
<BsClipboard className="h-7 w-7 text-white" />
|
<BsClipboard className="h-7 w-7 text-white" />
|
||||||
</div>
|
</div>
|
||||||
<span className="font-semibold">Level:</span>
|
<span className="font-semibold">Level:</span>
|
||||||
<p className="text-left text-xs">
|
<p className="text-left text-xs">You'll be able to test your english level with multiple choice questions.</p>
|
||||||
You'll be able to test your english level with multiple
|
{!selectedModules.includes("level") && selectedModules.length === 0 && !disableSelection && (
|
||||||
choice questions.
|
|
||||||
</p>
|
|
||||||
{!selectedModules.includes("level") &&
|
|
||||||
selectedModules.length === 0 &&
|
|
||||||
!disableSelection && (
|
|
||||||
<div className="border-mti-gray-platinum mt-4 h-8 w-8 rounded-full border" />
|
<div className="border-mti-gray-platinum mt-4 h-8 w-8 rounded-full border" />
|
||||||
)}
|
)}
|
||||||
{(selectedModules.includes("level") || disableSelection) && (
|
{(selectedModules.includes("level") || disableSelection) && (
|
||||||
<BsCheckCircle className="text-mti-purple-light mt-4 h-8 w-8" />
|
<BsCheckCircle className="text-mti-purple-light mt-4 h-8 w-8" />
|
||||||
)}
|
)}
|
||||||
{!selectedModules.includes("level") &&
|
{!selectedModules.includes("level") && selectedModules.length > 0 && (
|
||||||
selectedModules.length > 0 && (
|
|
||||||
<BsXCircle className="text-mti-red-light mt-4 h-8 w-8" />
|
<BsXCircle className="text-mti-red-light mt-4 h-8 w-8" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -311,70 +207,51 @@ export default function Selection({
|
|||||||
<div className="flex w-full flex-col items-center gap-3">
|
<div className="flex w-full flex-col items-center gap-3">
|
||||||
<div
|
<div
|
||||||
className="text-mti-gray-dim -md:justify-center flex w-full cursor-pointer items-center gap-3 text-sm"
|
className="text-mti-gray-dim -md:justify-center flex w-full cursor-pointer items-center gap-3 text-sm"
|
||||||
onClick={() => setAvoidRepeatedExams((prev) => !prev)}
|
onClick={() => setAvoidRepeatedExams((prev) => !prev)}>
|
||||||
>
|
|
||||||
<input type="checkbox" className="hidden" />
|
<input type="checkbox" className="hidden" />
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"border-mti-purple-light flex h-6 w-6 items-center justify-center rounded-md border bg-white",
|
"border-mti-purple-light flex h-6 w-6 items-center justify-center rounded-md border bg-white",
|
||||||
"transition duration-300 ease-in-out",
|
"transition duration-300 ease-in-out",
|
||||||
avoidRepeatedExams && "!bg-mti-purple-light ",
|
avoidRepeatedExams && "!bg-mti-purple-light ",
|
||||||
)}
|
)}>
|
||||||
>
|
|
||||||
<BsCheck color="white" className="h-full w-full" />
|
<BsCheck color="white" className="h-full w-full" />
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span className="tooltip" data-tip="If possible, the platform will choose exams not yet done.">
|
||||||
className="tooltip"
|
|
||||||
data-tip="If possible, the platform will choose exams not yet done."
|
|
||||||
>
|
|
||||||
Avoid Repeated Questions
|
Avoid Repeated Questions
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="text-mti-gray-dim -md:justify-center flex w-full cursor-pointer items-center gap-3 text-sm"
|
className="text-mti-gray-dim -md:justify-center flex w-full cursor-pointer items-center gap-3 text-sm"
|
||||||
onClick={() =>
|
onClick={() => setVariant((prev) => (prev === "full" ? "partial" : "full"))}>
|
||||||
setVariant((prev) => (prev === "full" ? "partial" : "full"))
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<input type="checkbox" className="hidden" />
|
<input type="checkbox" className="hidden" />
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"border-mti-purple-light flex h-6 w-6 items-center justify-center rounded-md border bg-white",
|
"border-mti-purple-light flex h-6 w-6 items-center justify-center rounded-md border bg-white",
|
||||||
"transition duration-300 ease-in-out",
|
"transition duration-300 ease-in-out",
|
||||||
variant === "full" && "!bg-mti-purple-light ",
|
variant === "full" && "!bg-mti-purple-light ",
|
||||||
)}
|
)}>
|
||||||
>
|
|
||||||
<BsCheck color="white" className="h-full w-full" />
|
<BsCheck color="white" className="h-full w-full" />
|
||||||
</div>
|
</div>
|
||||||
<span>Full length exams</span>
|
<span>Full length exams</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div className="tooltip w-full" data-tip={`Your screen size is too small to do ${page}`}>
|
||||||
className="tooltip w-full"
|
<Button color="purple" className="w-full max-w-xs px-12 md:hidden" disabled>
|
||||||
data-tip={`Your screen size is too small to do ${page}`}
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
color="purple"
|
|
||||||
className="w-full max-w-xs px-12 md:hidden"
|
|
||||||
disabled
|
|
||||||
>
|
|
||||||
Start Exam
|
Start Exam
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
onStart(
|
onStart(
|
||||||
!disableSelection
|
!disableSelection ? selectedModules.sort(sortByModuleName) : ["reading", "listening", "writing", "speaking"],
|
||||||
? selectedModules.sort(sortByModuleName)
|
|
||||||
: ["reading", "listening", "writing", "speaking"],
|
|
||||||
avoidRepeatedExams,
|
avoidRepeatedExams,
|
||||||
variant,
|
variant,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
color="purple"
|
color="purple"
|
||||||
className="-md:hidden w-full max-w-xs px-12 md:self-end"
|
className="-md:hidden w-full max-w-xs px-12 md:self-end"
|
||||||
disabled={selectedModules.length === 0 && !disableSelection}
|
disabled={selectedModules.length === 0 && !disableSelection}>
|
||||||
>
|
|
||||||
Start Exam
|
Start Exam
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import {withIronSessionSsr} from "iron-session/next";
|
import {withIronSessionSsr} from "iron-session/next";
|
||||||
import {sessionOptions} from "@/lib/session";
|
import {sessionOptions} from "@/lib/session";
|
||||||
import {ChangeEvent, ReactNode, useEffect, useRef, useState} from "react";
|
import {ChangeEvent, Dispatch, ReactNode, SetStateAction, useEffect, useRef, useState} from "react";
|
||||||
import useUser from "@/hooks/useUser";
|
import useUser from "@/hooks/useUser";
|
||||||
import {toast, ToastContainer} from "react-toastify";
|
import {toast, ToastContainer} from "react-toastify";
|
||||||
import Layout from "@/components/High/Layout";
|
import Layout from "@/components/High/Layout";
|
||||||
@@ -25,6 +25,9 @@ import {Divider} from "primereact/divider";
|
|||||||
import GenderInput from "@/components/High/GenderInput";
|
import GenderInput from "@/components/High/GenderInput";
|
||||||
import EmploymentStatusInput from "@/components/High/EmploymentStatusInput";
|
import EmploymentStatusInput from "@/components/High/EmploymentStatusInput";
|
||||||
import TimezoneSelect from "@/components/Low/TImezoneSelect";
|
import TimezoneSelect from "@/components/Low/TImezoneSelect";
|
||||||
|
import Modal from "@/components/Modal";
|
||||||
|
import {Module} from "@/interfaces";
|
||||||
|
import ModuleLevelSelector from "@/components/Medium/ModuleLevelSelector";
|
||||||
export const getServerSideProps = withIronSessionSsr(({req, res}) => {
|
export const getServerSideProps = withIronSessionSsr(({req, res}) => {
|
||||||
const user = req.session.user;
|
const user = req.session.user;
|
||||||
|
|
||||||
@@ -69,6 +72,10 @@ function UserProfile({user, mutateUser}: Props) {
|
|||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [profilePicture, setProfilePicture] = useState(user.profilePicture);
|
const [profilePicture, setProfilePicture] = useState(user.profilePicture);
|
||||||
|
|
||||||
|
const [desiredLevels, setDesiredLevels] = useState<{[key in Module]: number} | undefined>(
|
||||||
|
["developer", "student"].includes(user.type) ? user.desiredLevels : undefined,
|
||||||
|
);
|
||||||
|
|
||||||
const [country, setCountry] = useState<string>(user.demographicInformation?.country || "");
|
const [country, setCountry] = useState<string>(user.demographicInformation?.country || "");
|
||||||
const [phone, setPhone] = useState<string>(user.demographicInformation?.phone || "");
|
const [phone, setPhone] = useState<string>(user.demographicInformation?.phone || "");
|
||||||
const [gender, setGender] = useState<Gender | undefined>(user.demographicInformation?.gender || undefined);
|
const [gender, setGender] = useState<Gender | undefined>(user.demographicInformation?.gender || undefined);
|
||||||
@@ -138,6 +145,7 @@ function UserProfile({user, mutateUser}: Props) {
|
|||||||
password,
|
password,
|
||||||
newPassword,
|
newPassword,
|
||||||
profilePicture,
|
profilePicture,
|
||||||
|
desiredLevels,
|
||||||
demographicInformation: {
|
demographicInformation: {
|
||||||
phone,
|
phone,
|
||||||
country,
|
country,
|
||||||
@@ -319,6 +327,18 @@ function UserProfile({user, mutateUser}: Props) {
|
|||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
|
{desiredLevels && ["developer", "student"].includes(user.type) && (
|
||||||
|
<div className="flex flex-col gap-3 w-full">
|
||||||
|
<label className="font-normal text-base text-mti-gray-dim">Desired Levels</label>
|
||||||
|
<ModuleLevelSelector
|
||||||
|
levels={desiredLevels}
|
||||||
|
setLevels={setDesiredLevels as Dispatch<SetStateAction<{[key in Module]: number}>>}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Divider />
|
||||||
|
|
||||||
{user.type === "corporate" && (
|
{user.type === "corporate" && (
|
||||||
<>
|
<>
|
||||||
<DoubleColumnRow>
|
<DoubleColumnRow>
|
||||||
|
|||||||
Reference in New Issue
Block a user