From f6166ca9e16219dddc8328b99aaba936ffe302b5 Mon Sep 17 00:00:00 2001 From: Tiago Ribeiro Date: Mon, 5 Feb 2024 14:52:35 +0000 Subject: [PATCH] Added an "instructions" panel to the Listening before it actually starts --- src/exams/Finish.tsx | 517 +++++++++++++++++----------------------- src/exams/Listening.tsx | 57 ++++- 2 files changed, 268 insertions(+), 306 deletions(-) diff --git a/src/exams/Finish.tsx b/src/exams/Finish.tsx index a8c0e810..cff00c5a 100644 --- a/src/exams/Finish.tsx +++ b/src/exams/Finish.tsx @@ -1,318 +1,247 @@ import Button from "@/components/Low/Button"; import ModuleTitle from "@/components/Medium/ModuleTitle"; -import { moduleResultText } from "@/constants/ielts"; -import { Module } from "@/interfaces"; -import { User } from "@/interfaces/user"; +import {moduleResultText} from "@/constants/ielts"; +import {Module} from "@/interfaces"; +import {User} from "@/interfaces/user"; import useExamStore from "@/stores/examStore"; -import { calculateBandScore } from "@/utils/score"; +import {calculateBandScore} from "@/utils/score"; import clsx from "clsx"; import Link from "next/link"; -import { useRouter } from "next/router"; -import { Fragment, useEffect, useState } from "react"; -import { - BsArrowCounterclockwise, - BsBook, - BsClipboard, - BsEyeFill, - BsHeadphones, - BsMegaphone, - BsPen, - BsShareFill, -} from "react-icons/bs"; -import { LevelScore } from "@/constants/ielts"; -import { getLevelScore } from "@/utils/score"; +import {useRouter} from "next/router"; +import {Fragment, useEffect, useState} from "react"; +import {BsArrowCounterclockwise, BsBook, BsClipboard, BsEyeFill, BsHeadphones, BsMegaphone, BsPen, BsShareFill} from "react-icons/bs"; +import {LevelScore} from "@/constants/ielts"; +import {getLevelScore} from "@/utils/score"; interface Score { - module: Module; - correct: number; - total: number; - missing: number; + module: Module; + correct: number; + total: number; + missing: number; } interface Props { - user: User; - modules: Module[]; - scores: Score[]; - isLoading: boolean; - onViewResults: () => void; + user: User; + modules: Module[]; + scores: Score[]; + isLoading: boolean; + onViewResults: () => void; } -export default function Finish({ - user, - scores, - modules, - isLoading, - onViewResults, -}: Props) { - const [selectedModule, setSelectedModule] = useState(modules[0]); - const [selectedScore, setSelectedScore] = useState( - scores.find((x) => x.module === modules[0])!, - ); +export default function Finish({user, scores, modules, isLoading, onViewResults}: Props) { + const [selectedModule, setSelectedModule] = useState(modules[0]); + const [selectedScore, setSelectedScore] = useState(scores.find((x) => x.module === modules[0])!); - const exams = useExamStore((state) => state.exams); + const exams = useExamStore((state) => state.exams); - useEffect( - () => setSelectedScore(scores.find((x) => x.module === selectedModule)!), - [scores, selectedModule], - ); - useEffect(() => console.log(scores), [scores]); + useEffect(() => setSelectedScore(scores.find((x) => x.module === selectedModule)!), [scores, selectedModule]); - const moduleColors: { [key in Module]: { progress: string; inner: string } } = - { - reading: { - progress: "text-ielts-reading", - inner: "bg-ielts-reading-light", - }, - listening: { - progress: "text-ielts-listening", - inner: "bg-ielts-listening-light", - }, - writing: { - progress: "text-ielts-writing", - inner: "bg-ielts-writing-light", - }, - speaking: { - progress: "text-ielts-speaking", - inner: "bg-ielts-speaking-light", - }, - level: { - progress: "text-ielts-level", - inner: "bg-ielts-level-light", - }, - }; + const moduleColors: {[key in Module]: {progress: string; inner: string}} = { + reading: { + progress: "text-ielts-reading", + inner: "bg-ielts-reading-light", + }, + listening: { + progress: "text-ielts-listening", + inner: "bg-ielts-listening-light", + }, + writing: { + progress: "text-ielts-writing", + inner: "bg-ielts-writing-light", + }, + speaking: { + progress: "text-ielts-speaking", + inner: "bg-ielts-speaking-light", + }, + level: { + progress: "text-ielts-level", + inner: "bg-ielts-level-light", + }, + }; - const getTotalExercises = () => { - const exam = exams.find((x) => x.module === selectedModule)!; - if (exam.module === "reading" || exam.module === "listening") { - return exam.parts.flatMap((x) => x.exercises).length; - } + const getTotalExercises = () => { + const exam = exams.find((x) => x.module === selectedModule)!; + if (exam.module === "reading" || exam.module === "listening") { + return exam.parts.flatMap((x) => x.exercises).length; + } - return exam.exercises.length; - }; + return exam.exercises.length; + }; - const bandScore: number = calculateBandScore( - selectedScore.correct, - selectedScore.total, - selectedModule, - user.focus, - ); + const bandScore: number = calculateBandScore(selectedScore.correct, selectedScore.total, selectedModule, user.focus); - const showLevel = (level: number) => { - if (selectedModule === "level") { - const [levelStr, grade] = getLevelScore(level); - return ( -
- {grade} -
- ); - } + const showLevel = (level: number) => { + if (selectedModule === "level") { + const [levelStr, grade] = getLevelScore(level); + return ( +
+ {grade} +
+ ); + } - return {level}; - }; + return {level}; + }; - return ( - <> -
- x.module === selectedModule)!.minTimer} - disableTimer - /> -
- {modules.includes("reading") && ( -
setSelectedModule("reading")} - className={clsx( - "hover:bg-ielts-reading flex cursor-pointer items-center gap-2 rounded-xl p-4 transition duration-300 ease-in-out hover:text-white hover:shadow-lg", - selectedModule === "reading" - ? "bg-ielts-reading text-white" - : "bg-mti-gray-smoke text-ielts-reading", - )} - > - - Reading -
- )} - {modules.includes("listening") && ( -
setSelectedModule("listening")} - className={clsx( - "hover:bg-ielts-listening flex cursor-pointer items-center gap-2 rounded-xl p-4 transition duration-300 ease-in-out hover:text-white hover:shadow-lg", - selectedModule === "listening" - ? "bg-ielts-listening text-white" - : "bg-mti-gray-smoke text-ielts-listening", - )} - > - - Listening -
- )} - {modules.includes("writing") && ( -
setSelectedModule("writing")} - className={clsx( - "hover:bg-ielts-writing flex cursor-pointer items-center gap-2 rounded-xl p-4 transition duration-300 ease-in-out hover:text-white hover:shadow-lg", - selectedModule === "writing" - ? "bg-ielts-writing text-white" - : "bg-mti-gray-smoke text-ielts-writing", - )} - > - - Writing -
- )} - {modules.includes("speaking") && ( -
setSelectedModule("speaking")} - className={clsx( - "hover:bg-ielts-speaking flex cursor-pointer items-center gap-2 rounded-xl p-4 transition duration-300 ease-in-out hover:text-white hover:shadow-lg", - selectedModule === "speaking" - ? "bg-ielts-speaking text-white" - : "bg-mti-gray-smoke text-ielts-speaking", - )} - > - - Speaking -
- )} - {modules.includes("level") && ( -
setSelectedModule("level")} - className={clsx( - "hover:bg-ielts-level flex cursor-pointer items-center gap-2 rounded-xl p-4 transition duration-300 ease-in-out hover:text-white hover:shadow-lg", - selectedModule === "level" - ? "bg-ielts-level text-white" - : "bg-mti-gray-smoke text-ielts-level", - )} - > - - Level -
- )} -
- {isLoading && ( -
- - - Evaluating your answers, please be patient... -
- You can also check it later on your records page! -
-
- )} - {!isLoading && ( -
- - {moduleResultText(selectedModule, bandScore)} - -
-
-
- Level - {showLevel(bandScore)} -
-
-
-
-
-
- - {( - ((selectedScore.total - selectedScore.missing) / - selectedScore.total) * - 100 - ).toFixed(0)} - % - - Completion -
-
-
-
-
- - {selectedScore.correct.toString().padStart(2, "0")} - - Correct -
-
-
-
-
- - {(selectedScore.total - selectedScore.correct) - .toString() - .padStart(2, "0")} - - Wrong -
-
-
-
-
- )} -
+ return ( + <> +
+ x.module === selectedModule)!.minTimer} + disableTimer + /> +
+ {modules.includes("reading") && ( +
setSelectedModule("reading")} + className={clsx( + "hover:bg-ielts-reading flex cursor-pointer items-center gap-2 rounded-xl p-4 transition duration-300 ease-in-out hover:text-white hover:shadow-lg", + selectedModule === "reading" ? "bg-ielts-reading text-white" : "bg-mti-gray-smoke text-ielts-reading", + )}> + + Reading +
+ )} + {modules.includes("listening") && ( +
setSelectedModule("listening")} + className={clsx( + "hover:bg-ielts-listening flex cursor-pointer items-center gap-2 rounded-xl p-4 transition duration-300 ease-in-out hover:text-white hover:shadow-lg", + selectedModule === "listening" ? "bg-ielts-listening text-white" : "bg-mti-gray-smoke text-ielts-listening", + )}> + + Listening +
+ )} + {modules.includes("writing") && ( +
setSelectedModule("writing")} + className={clsx( + "hover:bg-ielts-writing flex cursor-pointer items-center gap-2 rounded-xl p-4 transition duration-300 ease-in-out hover:text-white hover:shadow-lg", + selectedModule === "writing" ? "bg-ielts-writing text-white" : "bg-mti-gray-smoke text-ielts-writing", + )}> + + Writing +
+ )} + {modules.includes("speaking") && ( +
setSelectedModule("speaking")} + className={clsx( + "hover:bg-ielts-speaking flex cursor-pointer items-center gap-2 rounded-xl p-4 transition duration-300 ease-in-out hover:text-white hover:shadow-lg", + selectedModule === "speaking" ? "bg-ielts-speaking text-white" : "bg-mti-gray-smoke text-ielts-speaking", + )}> + + Speaking +
+ )} + {modules.includes("level") && ( +
setSelectedModule("level")} + className={clsx( + "hover:bg-ielts-level flex cursor-pointer items-center gap-2 rounded-xl p-4 transition duration-300 ease-in-out hover:text-white hover:shadow-lg", + selectedModule === "level" ? "bg-ielts-level text-white" : "bg-mti-gray-smoke text-ielts-level", + )}> + + Level +
+ )} +
+ {isLoading && ( +
+ + + Evaluating your answers, please be patient... +
+ You can also check it later on your records page! +
+
+ )} + {!isLoading && ( +
+ {moduleResultText(selectedModule, bandScore)} +
+
+
+ Level + {showLevel(bandScore)} +
+
+
+
+
+
+ + {(((selectedScore.total - selectedScore.missing) / selectedScore.total) * 100).toFixed(0)}% + + Completion +
+
+
+
+
+ {selectedScore.correct.toString().padStart(2, "0")} + Correct +
+
+
+
+
+ + {(selectedScore.total - selectedScore.correct).toString().padStart(2, "0")} + + Wrong +
+
+
+
+
+ )} +
- {!isLoading && ( -
-
-
- - Play Again -
-
- - Review Answers -
-
+ {!isLoading && ( +
+
+
+ + Play Again +
+
+ + Review Answers +
+
- - - -
- )} - - ); + + + +
+ )} + + ); } diff --git a/src/exams/Listening.tsx b/src/exams/Listening.tsx index 56ee61d1..89d8ca9b 100644 --- a/src/exams/Listening.tsx +++ b/src/exams/Listening.tsx @@ -16,11 +16,14 @@ interface Props { onFinish: (userSolutions: UserSolution[]) => void; } +const INSTRUCTIONS_AUDIO_SRC = + "https://firebasestorage.googleapis.com/v0/b/storied-phalanx-349916.appspot.com/o/listening_recordings%2Fgeneric_intro.mp3?alt=media&token=9b9cfdb8-e90d-40d1-854b-51c4378a5c4b"; + export default function Listening({exam, showSolutions = false, onFinish}: Props) { const [questionIndex, setQuestionIndex] = useState(0); const [currentQuestionIndex, setCurrentQuestionIndex] = useState(0); const [exerciseIndex, setExerciseIndex] = useState(showSolutions ? 0 : -1); - const [partIndex, setPartIndex] = useState(0); + const [partIndex, setPartIndex] = useState(exam.variant === "partial" ? 0 : -1); const [timesListened, setTimesListened] = useState(0); const [userSolutions, setUserSolutions] = useState( exam.parts.flatMap((x) => x.exercises).map((x) => defaultUserSolutions(x, exam)), @@ -104,6 +107,17 @@ export default function Listening({exam, showSolutions = false, onFinish}: Props }; }; + const renderAudioInstructionsPlayer = () => ( +
+
+

Please listen to the instructions audio attentively.

+
+
+ +
+
+ ); + const renderAudioPlayer = () => (
@@ -133,36 +147,49 @@ export default function Listening({exam, showSolutions = false, onFinish}: Props
x.exercises) - .findIndex( - (x) => x.id === exam.parts[partIndex].exercises[exerciseIndex === -1 ? exerciseIndex + 1 : exerciseIndex]?.id, - ) || 0) + - (exerciseIndex === -1 ? 0 : 1) + - questionIndex + - currentQuestionIndex + partIndex === -1 + ? 0 + : (exam.parts + .flatMap((x) => x.exercises) + .findIndex( + (x) => x.id === exam.parts[partIndex].exercises[exerciseIndex === -1 ? exerciseIndex + 1 : exerciseIndex]?.id, + ) || 0) + + (exerciseIndex === -1 ? 0 : 1) + + questionIndex + + currentQuestionIndex } minTimer={exam.minTimer} module="listening" totalExercises={countExercises(exam.parts.flatMap((x) => x.exercises))} disableTimer={showSolutions} /> - {renderAudioPlayer()} + {/* Audio Player for the Instructions */} + {partIndex === -1 && renderAudioInstructionsPlayer()} + + {/* Part's audio player */} + {partIndex > -1 && renderAudioPlayer()} + + {/* Exercise renderer */} {exerciseIndex > -1 && exerciseIndex < exam.parts[partIndex].exercises.length && !showSolutions && renderExercise(getExercise(), nextExercise, previousExercise, setCurrentQuestionIndex)} + + {/* Solution renderer */} {exerciseIndex > -1 && exerciseIndex < exam.parts[partIndex].exercises.length && showSolutions && renderSolution(exam.parts[partIndex].exercises[exerciseIndex], nextExercise, previousExercise, setCurrentQuestionIndex)}
- {exerciseIndex === -1 && partIndex > 0 && ( + + {exerciseIndex === -1 && partIndex > -1 && exam.variant !== "partial" && (
)} - {exerciseIndex === -1 && partIndex === 0 && ( + + {exerciseIndex === -1 && partIndex === -1 && exam.variant !== "partial" && ( + + )} + {exerciseIndex === -1 && partIndex === 0 && exam.variant === "partial" && (