diff --git a/src/components/Low/ProgressBar.tsx b/src/components/Low/ProgressBar.tsx index b26b475e..341a9869 100644 --- a/src/components/Low/ProgressBar.tsx +++ b/src/components/Low/ProgressBar.tsx @@ -19,6 +19,7 @@ export default function ProgressBar({label, percentage, color, useColor = false, listening: "bg-ielts-listening", writing: "bg-ielts-writing", speaking: "bg-ielts-speaking", + level: "bg-ielts-level", }; return ( diff --git a/src/components/Medium/ModuleTitle.tsx b/src/components/Medium/ModuleTitle.tsx index 55c8d72c..d9eb6df5 100644 --- a/src/components/Medium/ModuleTitle.tsx +++ b/src/components/Medium/ModuleTitle.tsx @@ -4,7 +4,7 @@ import {moduleLabels} from "@/utils/moduleUtils"; import clsx from "clsx"; import {motion} from "framer-motion"; import {ReactNode, useEffect, useState} from "react"; -import {BsBook, BsHeadphones, BsMegaphone, BsPen, BsStopwatch} from "react-icons/bs"; +import {BsBook, BsClipboard, BsHeadphones, BsMegaphone, BsPen, BsStopwatch} from "react-icons/bs"; import ProgressBar from "../Low/ProgressBar"; import TimerEndedModal from "../TimerEndedModal"; @@ -46,6 +46,7 @@ export default function ModuleTitle({minTimer, module, label, exerciseIndex, tot listening: , writing: , speaking: , + level: , }; return ( diff --git a/src/components/UserResultChart.tsx b/src/components/UserResultChart.tsx deleted file mode 100644 index f9b3d826..00000000 --- a/src/components/UserResultChart.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import {SEMI_TRANSPARENT} from "@/resources/colors"; -import {Chart as ChartJS, RadialLinearScale, ArcElement, Tooltip, Legend} from "chart.js"; -import clsx from "clsx"; -import {PolarArea} from "react-chartjs-2"; -import {Chart} from "primereact/chart"; - -interface Props { - data: {label: string; value: number}[]; - label?: string; - title: string; - type: string; - colors?: string[]; -} - -ChartJS.register(RadialLinearScale, ArcElement, Tooltip, Legend); - -export default function SingleDatasetChart({data, type, label, title, colors = Object.values(SEMI_TRANSPARENT)}: Props) { - const labels = data.map((x) => x.label); - const chartData = { - labels, - datasets: [ - { - label, - data: data.map((x) => x.value), - backgroundColor: colors, - }, - ], - }; - - return ; -} diff --git a/src/constants/ielts.tsx b/src/constants/ielts.tsx index 296131ae..e3f6347a 100644 --- a/src/constants/ielts.tsx +++ b/src/constants/ielts.tsx @@ -7,17 +7,78 @@ export const BAND_SCORES: {[key in Module]: number[]} = { listening: [0, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 6, 6.5, 7, 7.5, 8, 8.5, 9], writing: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], speaking: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + level: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], }; -export const LEVEL_TEXT = { - excellent: - "Congratulations on your exam performance! You achieved an impressive {{level}}, demonstrating excellent mastery of the assessed knowledge.\n\nIf you disagree with the result, you can request a review by a qualified teacher. We are committed to the accuracy and transparency of the results.\n\nPlease contact us for further information. Congratulations again on your outstanding achievement! We are here to support you on your academic journey.", - high: "Congratulations on your exam performance! You achieved a commendable {{level}}, demonstrating a good understanding of the assessed knowledge.\n\nIf you have any concerns about the result, you can request a review by a qualified teacher. We are committed to the accuracy and transparency of the results.\n\nPlease contact us for further information. Congratulations again on your achievement! We are here to support you on your academic journey.", - medium: "Congratulations on your exam performance! You achieved a {{level}}, demonstrating a satisfactory understanding of the assessed knowledge.\n\nIf you have any concerns about the result, you can request a review by a qualified teacher. We are committed to the accuracy and transparency of the results.\n\nPlease contact us for further information. Congratulations again on your achievement! We are here to support you on your academic journey.", - low: "Thank you for taking the exam. You achieved a {{level}}, but unfortunately, it did not meet the required standards.\n\nIf you have any concerns about the result, you can request a review by a qualified teacher. We are committed to the accuracy and transparency of the results.\n\nPlease contact us for further information. We encourage you to continue your studies and wish you the best of luck in your future endeavors.", -}; - -export const levelText = (level: number) => { +export const moduleResultText = (level: number) => { + if (level === 9) { + return ( + <> + Congratulations on your exam performance! You achieved an impressive level {level}, demonstrating + excellent mastery of the assessed knowledge. +
+
+ If you disagree with the result, you can request a review by a qualified teacher. We are committed to the accuracy and transparency of + the results. +
+
+ Please contact us for further information. Congratulations again on your outstanding achievement! We are here to support you on your + academic journey. + + ); + } + + if (level >= 6) { + return ( + <> + Congratulations on your exam performance! You achieved a commendable level {level}, demonstrating a + good understanding of the assessed knowledge. +
+
+ If you have any concerns about the result, you can request a review by a qualified teacher. We are committed to the accuracy and + transparency of the results. +
+
+ Please contact us for further information. Congratulations again on your achievement! We are here to support you on your academic + journey. + + ); + } + + if (level >= 3) { + return ( + <> + Congratulations on your exam performance! You achieved a level of {level}, demonstrating a + satisfactory understanding of the assessed knowledge. +
+
+ If you have any concerns about the result, you can request a review by a qualified teacher. We are committed to the accuracy and + transparency of the results. +
+
+ Please contact us for further information. Congratulations again on your achievement! We are here to support you on your academic + journey. + + ); + } + + return ( + <> + Thank you for taking the exam. You achieved a level {level}, but unfortunately, it did not meet the + required standards. +
+
+ If you have any concerns about the result, you can request a review by a qualified teacher. We are committed to the accuracy and + transparency of the results. +
+
+ Please contact us for further information. We encourage you to continue your studies and wish you the best of luck in your future + endeavors. + + ); +}; + +export const levelResultText = (level: number) => { if (level === 9) { return ( <> diff --git a/src/dashboards/AssignmentView.tsx b/src/dashboards/AssignmentView.tsx index 27b2a5a1..f88b598c 100644 --- a/src/dashboards/AssignmentView.tsx +++ b/src/dashboards/AssignmentView.tsx @@ -13,7 +13,7 @@ import clsx from "clsx"; import {uniqBy} from "lodash"; import moment from "moment"; import {useRouter} from "next/router"; -import {BsBook, BsHeadphones, BsMegaphone, BsPen} from "react-icons/bs"; +import {BsBook, BsClipboard, BsHeadphones, BsMegaphone, BsPen} from "react-icons/bs"; interface Props { isOpen: boolean; @@ -73,6 +73,11 @@ export default function AssignmentView({isOpen, assignment, onClose}: Props) { correct: 0, missing: 0, }, + level: { + total: 0, + correct: 0, + missing: 0, + }, }; stats.forEach((x) => { @@ -153,11 +158,13 @@ export default function AssignmentView({isOpen, assignment, onClose}: Props) { module === "listening" && "bg-ielts-listening", module === "writing" && "bg-ielts-writing", module === "speaking" && "bg-ielts-speaking", + module === "level" && "bg-ielts-level", )}> {module === "reading" && } {module === "listening" && } {module === "writing" && } {module === "speaking" && } + {module === "level" && } {level.toFixed(1)} ))} @@ -239,11 +246,13 @@ export default function AssignmentView({isOpen, assignment, onClose}: Props) { module === "listening" && "bg-ielts-listening", module === "writing" && "bg-ielts-writing", module === "speaking" && "bg-ielts-speaking", + module === "level" && "bg-ielts-level", )}> {module === "reading" && } {module === "listening" && } {module === "writing" && } {module === "speaking" && } + {module === "level" && } {calculateAverageModuleScore(module) > -1 && ( {calculateAverageModuleScore(module).toFixed(1)} )} diff --git a/src/dashboards/Corporate.tsx b/src/dashboards/Corporate.tsx index 0ba57e3e..ecf8fe40 100644 --- a/src/dashboards/Corporate.tsx +++ b/src/dashboards/Corporate.tsx @@ -147,7 +147,7 @@ export default function CorporateDashboard({user}: Props) { level: calculateBandScore(s.score.correct, s.score.total, s.module, s.focus!), })); - const levels: {[key in Module]: number} = {reading: 0, listening: 0, writing: 0, speaking: 0}; + const levels: {[key in Module]: number} = {reading: 0, listening: 0, writing: 0, speaking: 0, level: 0}; bandScores.forEach((b) => (levels[b.module] += b.level)); return calculateAverageLevel(levels); diff --git a/src/dashboards/Teacher.tsx b/src/dashboards/Teacher.tsx index bcb3c38f..b0c01f0a 100644 --- a/src/dashboards/Teacher.tsx +++ b/src/dashboards/Teacher.tsx @@ -138,7 +138,7 @@ export default function TeacherDashboard({user}: Props) { level: calculateBandScore(s.score.correct, s.score.total, s.module, s.focus!), })); - const levels: {[key in Module]: number} = {reading: 0, listening: 0, writing: 0, speaking: 0}; + const levels: {[key in Module]: number} = {reading: 0, listening: 0, writing: 0, speaking: 0, level: 0}; bandScores.forEach((b) => (levels[b.module] += b.level)); return calculateAverageLevel(levels); diff --git a/src/exams/Finish.tsx b/src/exams/Finish.tsx index 3235cd58..2d4c94c3 100644 --- a/src/exams/Finish.tsx +++ b/src/exams/Finish.tsx @@ -1,6 +1,6 @@ import Button from "@/components/Low/Button"; import ModuleTitle from "@/components/Medium/ModuleTitle"; -import {levelText, LEVEL_TEXT} from "@/constants/ielts"; +import {moduleResultText} from "@/constants/ielts"; import {Module} from "@/interfaces"; import {User} from "@/interfaces/user"; import useExamStore from "@/stores/examStore"; @@ -9,7 +9,7 @@ import clsx from "clsx"; import Link from "next/link"; import {useRouter} from "next/router"; import {Fragment, useEffect, useState} from "react"; -import {BsArrowCounterclockwise, BsBook, BsEyeFill, BsHeadphones, BsMegaphone, BsPen, BsShareFill} from "react-icons/bs"; +import {BsArrowCounterclockwise, BsBook, BsClipboard, BsEyeFill, BsHeadphones, BsMegaphone, BsPen, BsShareFill} from "react-icons/bs"; interface Score { module: Module; @@ -51,6 +51,10 @@ export default function Finish({user, scores, modules, isLoading, onViewResults} progress: "text-ielts-speaking", inner: "bg-ielts-speaking-light", }, + level: { + progress: "text-ielts-level", + inner: "bg-ielts-level-light", + }, }; const getTotalExercises = () => { @@ -117,6 +121,17 @@ export default function Finish({user, scores, modules, isLoading, onViewResults} Speaking )} + {modules.includes("level") && ( +
setSelectedModule("level")} + className={clsx( + "flex gap-2 items-center rounded-xl p-4 cursor-pointer hover:shadow-lg transition duration-300 ease-in-out hover:bg-ielts-level hover:text-white", + selectedModule === "level" ? "bg-ielts-level text-white" : "bg-mti-gray-smoke text-ielts-level", + )}> + + Level +
+ )} {isLoading && (
@@ -127,7 +142,7 @@ export default function Finish({user, scores, modules, isLoading, onViewResults} {!isLoading && (
- {levelText(calculateBandScore(selectedScore.correct, selectedScore.total, selectedModule, user.focus))} + {moduleResultText(calculateBandScore(selectedScore.correct, selectedScore.total, selectedModule, user.focus))}
void; +} + +export default function Level({exam, showSolutions = false, onFinish}: Props) { + const [exerciseIndex, setExerciseIndex] = useState(0); + const [userSolutions, setUserSolutions] = useState(exam.exercises.map((x) => defaultUserSolutions(x, exam))); + + const [hasExamEnded, setHasExamEnded] = useExamStore((state) => [state.hasExamEnded, state.setHasExamEnded]); + + const nextExercise = (solution?: UserSolution) => { + if (solution) { + setUserSolutions((prev) => [...prev.filter((x) => x.exercise !== solution.exercise), solution]); + } + + if (exerciseIndex + 1 < exam.exercises.length) { + setExerciseIndex((prev) => prev + 1); + return; + } + + if (exerciseIndex >= exam.exercises.length) return; + + setHasExamEnded(false); + + if (solution) { + onFinish( + [...userSolutions.filter((x) => x.exercise !== solution.exercise), solution].map((x) => ({...x, module: "level", exam: exam.id})), + ); + } else { + onFinish(userSolutions.map((x) => ({...x, module: "level", exam: exam.id}))); + } + }; + + const previousExercise = (solution?: UserSolution) => { + if (solution) { + setUserSolutions((prev) => [...prev.filter((x) => x.exercise !== solution.exercise), solution]); + } + + if (exerciseIndex > 0) { + setExerciseIndex((prev) => prev - 1); + } + }; + + const getExercise = () => { + const exercise = exam.exercises[exerciseIndex]; + return { + ...exercise, + userSolutions: userSolutions.find((x) => x.exercise === exercise.id)?.solutions || [], + }; + }; + + return ( + <> +
+ + {exerciseIndex > -1 && + exerciseIndex < exam.exercises.length && + !showSolutions && + renderExercise(getExercise(), nextExercise, previousExercise)} + {exerciseIndex > -1 && + exerciseIndex < exam.exercises.length && + showSolutions && + renderSolution(exam.exercises[exerciseIndex], nextExercise, previousExercise)} +
+ + ); +} diff --git a/src/exams/Selection.tsx b/src/exams/Selection.tsx index ebc22f40..2485bb70 100644 --- a/src/exams/Selection.tsx +++ b/src/exams/Selection.tsx @@ -4,7 +4,7 @@ import {Module} from "@/interfaces"; import clsx from "clsx"; import {User} from "@/interfaces/user"; import ProgressBar from "@/components/Low/ProgressBar"; -import {BsBook, BsCheck, BsCheckCircle, BsHeadphones, BsMegaphone, BsPen} from "react-icons/bs"; +import {BsBook, BsCheck, BsCheckCircle, BsClipboard, BsHeadphones, BsMegaphone, BsPen, BsXCircle} from "react-icons/bs"; import {totalExamsByModule} from "@/utils/stats"; import useStats from "@/hooks/useStats"; import Button from "@/components/Low/Button"; @@ -57,6 +57,11 @@ export default function Selection({user, page, onStart, disableSelection = false label: "Speaking", value: totalExamsByModule(stats, "speaking"), }, + { + icon: , + label: "Level", + value: totalExamsByModule(stats, "level"), + }, ]} /> )} @@ -87,11 +92,11 @@ export default function Selection({user, page, onStart, disableSelection = false )} -
+
toggleModule("reading") : undefined} + onClick={!disableSelection && !selectedModules.includes("level") ? () => toggleModule("reading") : undefined} className={clsx( - "relative w-fit max-w-xs flex flex-col items-center bg-mti-white-alt transition duration-300 ease-in-out border p-5 rounded-xl gap-2 pt-12 cursor-pointer", + "relative w-64 max-w-xs flex flex-col items-center bg-mti-white-alt transition duration-300 ease-in-out border p-5 rounded-xl gap-2 pt-12 cursor-pointer", selectedModules.includes("reading") || disableSelection ? "border-mti-purple-light" : "border-mti-gray-platinum", )}>
@@ -101,17 +106,18 @@ export default function Selection({user, page, onStart, disableSelection = false

Expand your vocabulary, improve your reading comprehension and improve your ability to interpret texts in English.

- {!selectedModules.includes("reading") && !disableSelection && ( + {!selectedModules.includes("reading") && !selectedModules.includes("level") && !disableSelection && (
)} {(selectedModules.includes("reading") || disableSelection) && ( )} + {selectedModules.includes("level") && }
toggleModule("listening") : undefined} + onClick={!disableSelection && !selectedModules.includes("level") ? () => toggleModule("listening") : undefined} className={clsx( - "relative w-fit max-w-xs flex flex-col items-center bg-mti-white-alt transition duration-300 ease-in-out border p-5 rounded-xl gap-2 pt-12 cursor-pointer", + "relative w-64 max-w-xs flex flex-col items-center bg-mti-white-alt transition duration-300 ease-in-out border p-5 rounded-xl gap-2 pt-12 cursor-pointer", selectedModules.includes("listening") || disableSelection ? "border-mti-purple-light" : "border-mti-gray-platinum", )}>
@@ -121,17 +127,18 @@ export default function Selection({user, page, onStart, disableSelection = false

Improve your ability to follow conversations in English and your ability to understand different accents and intonations.

- {!selectedModules.includes("listening") && !disableSelection && ( + {!selectedModules.includes("listening") && !selectedModules.includes("level") && !disableSelection && (
)} {(selectedModules.includes("listening") || disableSelection) && ( )} + {selectedModules.includes("level") && }
toggleModule("writing") : undefined} + onClick={!disableSelection && !selectedModules.includes("level") ? () => toggleModule("writing") : undefined} className={clsx( - "relative w-fit max-w-xs flex flex-col items-center bg-mti-white-alt transition duration-300 ease-in-out border p-5 rounded-xl gap-2 pt-12 cursor-pointer", + "relative w-64 max-w-xs flex flex-col items-center bg-mti-white-alt transition duration-300 ease-in-out border p-5 rounded-xl gap-2 pt-12 cursor-pointer", selectedModules.includes("writing") || disableSelection ? "border-mti-purple-light" : "border-mti-gray-platinum", )}>
@@ -141,17 +148,18 @@ export default function Selection({user, page, onStart, disableSelection = false

Allow you to practice writing in a variety of formats, from simple paragraphs to complex essays.

- {!selectedModules.includes("writing") && !disableSelection && ( + {!selectedModules.includes("writing") && !selectedModules.includes("level") && !disableSelection && (
)} {(selectedModules.includes("writing") || disableSelection) && ( )} + {selectedModules.includes("level") && }
toggleModule("speaking") : undefined} + onClick={!disableSelection && !selectedModules.includes("level") ? () => toggleModule("speaking") : undefined} className={clsx( - "relative w-fit max-w-xs flex flex-col items-center bg-mti-white-alt transition duration-300 ease-in-out border p-5 rounded-xl gap-2 pt-12 cursor-pointer", + "relative w-64 max-w-xs flex flex-col items-center bg-mti-white-alt transition duration-300 ease-in-out border p-5 rounded-xl gap-2 pt-12 cursor-pointer", selectedModules.includes("speaking") || disableSelection ? "border-mti-purple-light" : "border-mti-gray-platinum", )}>
@@ -161,13 +169,37 @@ export default function Selection({user, page, onStart, disableSelection = false

You'll have access to interactive dialogs, pronunciation exercises and speech recordings.

- {!selectedModules.includes("speaking") && !disableSelection && ( + {!selectedModules.includes("speaking") && !selectedModules.includes("level") && !disableSelection && (
)} {(selectedModules.includes("speaking") || disableSelection) && ( )} + {selectedModules.includes("level") && }
+ {!disableSelection && ( +
toggleModule("level") : undefined} + className={clsx( + "relative w-64 max-w-xs flex flex-col items-center bg-mti-white-alt transition duration-300 ease-in-out border p-5 rounded-xl gap-2 pt-12 cursor-pointer", + selectedModules.includes("level") || disableSelection ? "border-mti-purple-light" : "border-mti-gray-platinum", + )}> +
+ +
+ Level: +

You'll be able to test your english level with multiple choice questions.

+ {!selectedModules.includes("level") && selectedModules.length === 0 && !disableSelection && ( +
+ )} + {(selectedModules.includes("level") || disableSelection) && ( + + )} + {!selectedModules.includes("level") && selectedModules.length > 0 && ( + + )} +
+ )}
(); diff --git a/src/pages/(exam)/ExamPage.tsx b/src/pages/(exam)/ExamPage.tsx index 424cc806..5ddc0bea 100644 --- a/src/pages/(exam)/ExamPage.tsx +++ b/src/pages/(exam)/ExamPage.tsx @@ -22,6 +22,7 @@ import {evaluateSpeakingAnswer, evaluateWritingAnswer} from "@/utils/evaluation" import {useRouter} from "next/router"; import {getExam} from "@/utils/exams"; import {capitalize} from "lodash"; +import Level from "@/exams/Level"; interface Props { page: "exams" | "exercises"; @@ -182,6 +183,11 @@ export default function ExamPage({page}: Props) { correct: 0, missing: 0, }, + level: { + total: 0, + correct: 0, + missing: 0, + }, }; answers.forEach((x) => { @@ -244,6 +250,10 @@ export default function ExamPage({page}: Props) { return ; } + if (exam && exam.module === "level") { + return ; + } + return <>Loading...; }; diff --git a/src/pages/api/stats/update.ts b/src/pages/api/stats/update.ts index 2b895a1b..1a74a60a 100644 --- a/src/pages/api/stats/update.ts +++ b/src/pages/api/stats/update.ts @@ -49,6 +49,10 @@ async function update(req: NextApiRequest, res: NextApiResponse) { correct: 0, total: 0, }, + level: { + correct: 0, + total: 0, + }, }; MODULES.forEach((module: Module) => { diff --git a/src/pages/record.tsx b/src/pages/record.tsx index f7a890d7..3680bb4d 100644 --- a/src/pages/record.tsx +++ b/src/pages/record.tsx @@ -18,7 +18,7 @@ import {sortByModule} from "@/utils/moduleUtils"; import Layout from "@/components/High/Layout"; import clsx from "clsx"; import {calculateBandScore} from "@/utils/score"; -import {BsBook, BsHeadphones, BsMegaphone, BsPen} from "react-icons/bs"; +import {BsBook, BsClipboard, BsHeadphones, BsMegaphone, BsPen} from "react-icons/bs"; import Select from "react-select"; import useGroups from "@/hooks/useGroups"; import {shouldRedirectHome} from "@/utils/navigation.disabled"; @@ -139,6 +139,11 @@ export default function History({user}: {user: User}) { correct: 0, missing: 0, }, + level: { + total: 0, + correct: 0, + missing: 0, + }, }; stats.forEach((x) => { @@ -224,11 +229,13 @@ export default function History({user}: {user: User}) { module === "listening" && "bg-ielts-listening", module === "writing" && "bg-ielts-writing", module === "speaking" && "bg-ielts-speaking", + module === "level" && "bg-ielts-level", )}> {module === "reading" && } {module === "listening" && } {module === "writing" && } {module === "speaking" && } + {module === "level" && } {level.toFixed(1)}
))} diff --git a/src/resources/colors.ts b/src/resources/colors.ts deleted file mode 100644 index 67ce1bf0..00000000 --- a/src/resources/colors.ts +++ /dev/null @@ -1,15 +0,0 @@ -import {Module} from "@/interfaces"; - -export const OPAQUE: {[key in Module]: string} = { - reading: "#FF6384", - listening: "#36A2EB", - writing: "#FFCE56", - speaking: "#4bc0c0", -}; - -export const SEMI_TRANSPARENT: {[key in Module]: string} = { - reading: "rgba(255, 99, 132, 0.5)", - listening: "rgba(54, 162, 235, 0.5)", - writing: "rgba(255, 206, 86, 0.5)", - speaking: "rgba(75, 192, 192, 0.5)", -}; diff --git a/src/resources/modules.ts b/src/resources/modules.ts deleted file mode 100644 index d5dfda5e..00000000 --- a/src/resources/modules.ts +++ /dev/null @@ -1,9 +0,0 @@ -import {Module} from "@/interfaces"; -import {mdiAccountVoice, mdiBookOpen, mdiHeadphones, mdiPen} from "@mdi/js"; - -export const ICONS: {[key in Module]: string} = { - listening: mdiHeadphones, - reading: mdiBookOpen, - speaking: mdiAccountVoice, - writing: mdiPen, -}; diff --git a/src/utils/exams.ts b/src/utils/exams.ts index cfd522d1..fec331d4 100644 --- a/src/utils/exams.ts +++ b/src/utils/exams.ts @@ -1,15 +1,5 @@ import {Module} from "@/interfaces"; -import { - Exam, - ReadingExam, - ListeningExam, - WritingExam, - SpeakingExam, - Exercise, - UserSolution, - FillBlanksExercise, - MatchSentencesExercise, -} from "@/interfaces/exam"; +import {Exam, ReadingExam, ListeningExam, WritingExam, SpeakingExam, Exercise, UserSolution, LevelExam} from "@/interfaces/exam"; import axios from "axios"; export const getExam = async (module: Module, avoidRepeated: boolean): Promise => { @@ -29,6 +19,8 @@ export const getExam = async (module: Module, avoidRepeated: boolean): Promise { diff --git a/src/utils/score.ts b/src/utils/score.ts index 53fb3a29..18a13c63 100644 --- a/src/utils/score.ts +++ b/src/utils/score.ts @@ -93,6 +93,14 @@ const academicMarking: {[key: number]: number} = { 10: 2.5, }; +const levelMarking: {[key: number]: number} = { + 88: 9, + 64: 8, + 52: 6, + 32: 4, + 16: 2, +}; + const moduleMarkings: {[key in Module]: {[key in Type]: {[key: number]: number}}} = { reading: { academic: academicMarking, @@ -110,6 +118,10 @@ const moduleMarkings: {[key in Module]: {[key in Type]: {[key: number]: number}} academic: writingMarking, general: writingMarking, }, + level: { + academic: levelMarking, + general: levelMarking, + }, }; export const calculateBandScore = (correct: number, total: number, module: Module, type: Type) => { diff --git a/tailwind.config.js b/tailwind.config.js index 0660d164..5b02354e 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -29,6 +29,7 @@ module.exports = { listening: {DEFAULT: "#FF790A", light: "#FFF1E5", transparent: "rgba(54, 162, 235, 0.5)"}, writing: {DEFAULT: "#3D9F11", light: "#E8FCDF", transparent: "rgba(255, 206, 86, 0.5)"}, speaking: {DEFAULT: "#EF5DA8", light: "#FEF6FA", transparent: "rgba(75, 192, 192, 0.5)"}, + level: {DEFAULT: "#414288", light: "#C8C8E4", transparent: "rgba(65, 66, 136, 0.5)"}, }, }, screens: {