ENCOA-149, ENCOA-150, ENCOA-152, ENCOA-153, ENCOA-155, ENCOA-156, ENCOA-157, ENCOA-158, ENCOA-161 -> Updated the mc buttons, no longer shows a context only div on parts that have context, removed line numbers on lines between paragraphs, applied bold and underline to 'not correct' in underline prompts, added another pop up to confirm submission.

This commit is contained in:
Carlos Mesquita
2024-09-04 02:26:22 +01:00
parent 60554d8e16
commit 5168e70edc
8 changed files with 106 additions and 94 deletions

View File

@@ -14,6 +14,7 @@ import PartDivider from "./PartDivider";
import Timer from "@/components/Medium/Timer";
import shuffleExamExercise from "./Shuffle";
import { Tab } from "@headlessui/react";
import Modal from "@/components/Modal";
interface Props {
exam: LevelExam;
@@ -51,7 +52,10 @@ export default function Level({ exam, showSolutions = false, onFinish, editing =
setCurrentSolution
} = useExamStore((state) => state);
const [multipleChoicesDone, setMultipleChoicesDone] = useState<{ id: string; amount: number }[]>([]);
// In case client want to switch back
const textRenderDisabled = true;
const [showSubmissionModal, setShowSubmissionModal] = useState(false);
const [showQuestionsModal, setShowQuestionsModal] = useState(false);
const [continueAnyways, setContinueAnyways] = useState(false);
const [textRender, setTextRender] = useState(false);
@@ -59,7 +63,7 @@ export default function Level({ exam, showSolutions = false, onFinish, editing =
const [nextExerciseCalled, setNextExerciseCalled] = useState(false);
const [currentSolutionSet, setCurrentSolutionSet] = useState(false);
const [seenParts, setSeenParts] = useState<number[]>(showSolutions ? exam.parts.map((_, index) => index) : [0]);
const [seenParts, setSeenParts] = useState<Set<number>>(new Set(showSolutions ? exam.parts.map((_, index) => index) : [0]));
const [questionModalKwargs, setQuestionModalKwargs] = useState<{
type?: "module" | "blankQuestions" | "submit"; unanswered?: boolean | undefined; onClose: (next?: boolean) => void | undefined;
@@ -147,24 +151,25 @@ export default function Level({ exam, showSolutions = false, onFinish, editing =
}
if (partIndex + 1 < exam.parts.length && !hasExamEnded) {
if (!answeredEveryQuestion(partIndex) && !continueAnyways && !showSolutions && !seenParts.includes(partIndex + 1)) {
if (!answeredEveryQuestion(partIndex) && !continueAnyways && !showSolutions && !seenParts.has(partIndex + 1)) {
modalKwargs();
setShowQuestionsModal(true);
return;
}
if (!showSolutions && exam.parts[0].intro && !seenParts.includes(partIndex + 1)) {
if (!showSolutions && exam.parts[0].intro && !seenParts.has(partIndex + 1)) {
setShowPartDivider(true);
setBgColor(levelBgColor);
}
setSeenParts((prev) => [...prev, partIndex + 1])
if (partIndex < exam.parts.length - 1 && exam.parts[partIndex + 1].context) {
setSeenParts(prev => new Set(prev).add(partIndex + 1));
if (partIndex < exam.parts.length - 1 && exam.parts[partIndex + 1].context && !textRenderDisabled) {
setTextRender(true);
}
setPartIndex(partIndex + 1);
setExerciseIndex(0);
setQuestionIndex(0);
setMultipleChoicesDone((prev) => [...prev.filter((x) => x.id !== currentExercise!.id), { id: currentExercise!.id, amount: currentExercise?.type == "fillBlanks" ? currentExercise.words.length - 1 : questionIndex }]);
setCurrentSolutionSet(false);
return;
}
@@ -194,7 +199,7 @@ export default function Level({ exam, showSolutions = false, onFinish, editing =
const previousExercise = (solution?: UserSolution) => {
scrollToTop();
if (exam.parts[partIndex].context && questionIndex === 0 && !textRender) {
if (exam.parts[partIndex].context && questionIndex === 0 && !textRender && !textRenderDisabled) {
setTextRender(true);
return;
}
@@ -221,31 +226,6 @@ export default function Level({ exam, showSolutions = false, onFinish, editing =
if (previousExercise.type === "multipleChoice") {
setQuestionIndex(previousExercise.questions.length - 1)
}
const multipleChoiceQuestionsDone = [];
for (let i = 0; i < exam.parts.length; i++) {
if (i == (partIndex - 1)) break;
for (let j = 0; j < exam.parts[i].exercises.length; j++) {
const exercise = exam.parts[i].exercises[j];
switch(exercise.type) {
case 'multipleChoice':
multipleChoiceQuestionsDone.push({ id: exercise.id, amount: exercise.questions.length - 1 })
break;
case 'fillBlanks':
multipleChoiceQuestionsDone.push({ id: exercise.id, amount: exercise.words.length - 1 })
break;
case 'writeBlanks':
multipleChoiceQuestionsDone.push({ id: exercise.id, amount: exercise.solutions.length - 1 })
break;
case 'matchSentences':
multipleChoiceQuestionsDone.push({ id: exercise.id, amount: exercise.sentences.length - 1})
break;
case 'trueFalse':
multipleChoiceQuestionsDone.push({ id: exercise.id, amount: exercise.questions.length - 1})
break;
}
}
}
setMultipleChoicesDone(multipleChoiceQuestionsDone);
}
};
@@ -264,7 +244,7 @@ export default function Level({ exam, showSolutions = false, onFinish, editing =
<div className={clsx("flex flex-col gap-6 w-full bg-mti-gray-seasalt rounded-xl mt-4 relative py-8 px-16")}>
<>
<div className="flex flex-col w-full gap-2">
{textRender ? (
{textRender && !textRenderDisabled ? (
<>
<h4 className="text-xl font-semibold">
Please read the following excerpt attentively, you will then be asked questions about the text you&apos;ve read.
@@ -286,7 +266,7 @@ export default function Level({ exam, showSolutions = false, onFinish, editing =
</div>
</>
</div>
{textRender && (
{textRender && !textRenderDisabled && (
<div className="self-end flex justify-between w-full gap-8 absolute bottom-8 left-0 px-8">
<Button
color="purple"
@@ -306,23 +286,24 @@ export default function Level({ exam, showSolutions = false, onFinish, editing =
);
const partLabel = () => {
const partCategory = exam.parts[partIndex].category ? ` (${exam.parts[partIndex].category})` : '';
if (currentExercise?.type === "fillBlanks" && typeCheckWordsMC(currentExercise.words))
return `Part ${partIndex + 1} (Questions ${currentExercise.words[0].id} - ${currentExercise.words[currentExercise.words.length - 1].id})\n\n${currentExercise.prompt}`
return `Part ${partIndex + 1} (Questions ${currentExercise.words[0].id} - ${currentExercise.words[currentExercise.words.length - 1].id})${partCategory}\n\n${currentExercise.prompt}`
if (currentExercise?.type === "multipleChoice") {
return `Part ${partIndex + 1} (Questions ${currentExercise.questions[0].id} - ${currentExercise.questions[currentExercise.questions.length - 1].id})\n\n${currentExercise.prompt}`
return `Part ${partIndex + 1} (Questions ${currentExercise.questions[0].id} - ${currentExercise.questions[currentExercise.questions.length - 1].id})${partCategory}\n\n${currentExercise.prompt}`
}
if (typeof exam.parts[partIndex].context === "string") {
const nextExercise = exam.parts[partIndex].exercises[0] as MultipleChoiceExercise;
return `Part ${partIndex + 1} (Questions ${nextExercise.questions[0].id} - ${nextExercise.questions[nextExercise.questions.length - 1].id})\n\n${nextExercise.prompt}`
return `Part ${partIndex + 1} (Questions ${nextExercise.questions[0].id} - ${nextExercise.questions[nextExercise.questions.length - 1].id})${partCategory}\n\n${nextExercise.prompt}`
}
}
const answeredEveryQuestion = (partIndex: number) => {
return exam.parts[partIndex].exercises.every((exercise) => {
const userSolution = userSolutions.find(x => x.exercise === exercise.id);
switch(exercise.type) {
switch (exercise.type) {
case 'multipleChoice':
return userSolution?.solutions.length === exercise.questions.length;
case 'fillBlanks':
@@ -388,7 +369,7 @@ export default function Level({ exam, showSolutions = false, onFinish, editing =
if (partIndex === exam.parts.length - 1) {
kwargs.type = "submit"
kwargs.unanswered = !exam.parts.every((_, partIndex) => answeredEveryQuestion(partIndex));
kwargs.onClose = function (x: boolean | undefined) { if (x) { setContinueAnyways(true); setShowQuestionsModal(false); } else { setShowQuestionsModal(false) } };
kwargs.onClose = function (x: boolean | undefined) { if (x) { setShowSubmissionModal(true); setShowQuestionsModal(false); } else { setShowQuestionsModal(false) } };
}
setQuestionModalKwargs(kwargs);
}
@@ -408,7 +389,7 @@ export default function Level({ exam, showSolutions = false, onFinish, editing =
setChangedPrompt(false);
return (
<>
{textRender ?
{textRender && !textRenderDisabled ?
renderText() :
<>
{exam.parts[partIndex].context && renderText()}
@@ -425,6 +406,25 @@ export default function Level({ exam, showSolutions = false, onFinish, editing =
return (
<>
<div className={clsx("flex flex-col h-full w-full gap-8 items-center", showPartDivider && "justify-center")}>
<Modal
className={"!w-2/6 !p-8"}
titleClassName={"font-bold text-3xl text-mti-rose-light"}
isOpen={showSubmissionModal}
onClose={() => { }}
title={"Confirm Submission"}
>
<>
<p className="text-xl mt-8 mb-12">Are you sure you want to proceed with the submission?</p>
<div className="w-full flex justify-between">
<Button color="purple" onClick={() => setShowSubmissionModal(false)} variant="outline" className="max-w-[200px] self-end w-full !text-xl">
Cancel
</Button>
<Button color="rose" onClick={() => { setShowSubmissionModal(false); setContinueAnyways(true)}} className="max-w-[200px] self-end w-full !text-xl">
Confirm
</Button>
</div>
</>
</Modal>
<QuestionsModal isOpen={showQuestionsModal} {...questionModalKwargs} />
{
!(partIndex === 0 && questionIndex === 0 && (showPartDivider || startNow)) &&
@@ -438,20 +438,27 @@ export default function Level({ exam, showSolutions = false, onFinish, editing =
<Tab.List className="flex space-x-1 rounded-xl bg-ielts-level/20 p-1">
{exam.parts.map((_, index) =>
<Tab key={index} onClick={(e) => {
if (!seenParts.includes(index)) {
e.preventDefault();
} else {
setExerciseIndex(0);
setQuestionIndex(0);
/*
// If client wants to revert uncomment and remove the added if statement
if (!seenParts.has(index)) {
e.preventDefault();
} else {
*/
setExerciseIndex(0);
setQuestionIndex(0);
if (!seenParts.has(index)) {
setShowPartDivider(true);
setBgColor(levelBgColor);
setSeenParts(prev => new Set(prev).add(index));
}
}}
className={({ selected }) =>
clsx(
"w-full rounded-lg py-2.5 text-sm font-medium leading-5 text-ielts-level/80",
"ring-white ring-opacity-60 focus:outline-none",
"transition duration-300 ease-in-out",
"transition duration-300 ease-in-out hover:bg-white/70",
selected && "bg-white shadow",
seenParts.includes(index) ? "hover:bg-white/70" : "cursor-not-allowed"
// seenParts.includes(index) ? "hover:bg-white/70" : "cursor-not-allowed"
)
}
>{`Part ${index + 1}`}</Tab>