Navigation rework, added prompt edit to components that were missing

This commit is contained in:
Carlos-Mesquita
2024-11-25 16:50:46 +00:00
parent e9b7bd14cc
commit 114da173be
105 changed files with 3761 additions and 3728 deletions

View File

@@ -2,48 +2,12 @@ import { FillBlanksExercise, FillBlanksMCOption, ShuffleMap } from "@/interfaces
import clsx from "clsx";
import reactStringReplace from "react-string-replace";
import { CommonProps } from ".";
import { Fragment } from "react";
import Button from "../Low/Button";
import useExamStore from "@/stores/examStore";
import useExamStore from "@/stores/exam";
import { typeCheckWordsMC } from "@/utils/type.check";
export default function FillBlanksSolutions({ id, type, prompt, solutions, words, text, onNext, onBack, disableProgressButtons = false }: FillBlanksExercise & CommonProps) {
const storeUserSolutions = useExamStore((state) => state.userSolutions);
const { questionIndex, setQuestionIndex, partIndex, exam } = useExamStore((state) => state);
const correctUserSolutions = storeUserSolutions.find((solution) => solution.exercise === id)?.solutions;
const shuffles = useExamStore((state) => state.shuffles);
const calculateScore = () => {
const total = text.match(/({{\d+}})/g)?.length || 0;
const correct = correctUserSolutions!.filter((x) => {
const solution = solutions.find((y) => x.id.toString() === y.id.toString())?.solution;
if (!solution) return false;
const option = words.find((w) => {
if (typeof w === "string") {
return w.toLowerCase() === x.solution.toLowerCase();
} else if ("letter" in w) {
return w.letter.toLowerCase() === x.solution.toLowerCase();
} else {
return w.id.toString() === x.id.toString();
}
});
if (!option) return false;
if (typeof option === "string") {
return solution.toLowerCase() === option.toLowerCase();
} else if ("letter" in option) {
return solution.toLowerCase() === option.word.toLowerCase();
} else if ("options" in option) {
return option.options[solution as keyof typeof option.options] == x.solution;
}
return false;
}).length;
const missing = total - correctUserSolutions!.filter((x) => solutions.find((y) => x.id.toString() === y.id.toString())).length;
return { total, correct, missing };
};
const FillBlanksSolutions: React.FC<FillBlanksExercise & CommonProps> = ({ id, solutions, words, text, headerButtons, footerButtons}) => {
const {userSolutions, shuffles} = useExamStore();
const correctUserSolutions = userSolutions.find((solution) => solution.exercise === id)?.solutions;
const renderLines = (line: string) => {
return (
@@ -149,31 +113,10 @@ export default function FillBlanksSolutions({ id, type, prompt, solutions, words
);
};
const progressButtons = () => (
<div className="flex justify-between w-full gap-8">
<Button
color="purple"
variant="outline"
onClick={() => onBack({ exercise: id, solutions: correctUserSolutions!, score: calculateScore(), type })}
className="max-w-[200px] w-full"
disabled={exam && typeof partIndex !== "undefined" && exam.module === "level" && questionIndex === 0 && partIndex === 0}>
Back
</Button>
<Button
color="purple"
onClick={() => onNext({ exercise: id, solutions: correctUserSolutions!, score: calculateScore(), type })}
className="max-w-[200px] self-end w-full">
Next
</Button>
</div>
)
return (
<div className="flex flex-col gap-4">
{!disableProgressButtons && progressButtons()}
<div className={clsx("flex flex-col gap-4 mt-4 h-full w-full", !disableProgressButtons && "mb-20")}>
{headerButtons}
<div className={clsx("flex flex-col gap-4 mt-4 h-full w-full", (!headerButtons || !footerButtons) && "mb-20")}>
<span className="bg-mti-gray-smoke rounded-xl px-5 py-6">
{correctUserSolutions &&
text.split("\\n").map((line, index) => (
@@ -197,9 +140,10 @@ export default function FillBlanksSolutions({ id, type, prompt, solutions, words
Wrong
</div>
</div>
{footerButtons}
</div>
{!disableProgressButtons && progressButtons()}
</div>
);
}
export default FillBlanksSolutions;

View File

@@ -14,14 +14,11 @@ import ReactDiffViewer, {DiffMethod} from "react-diff-viewer";
const Waveform = dynamic(() => import("../Waveform"), {ssr: false});
export default function InteractiveSpeaking({
id,
type,
title,
text,
prompts,
userSolutions,
onNext,
onBack,
headerButtons,
footerButtons,
}: InteractiveSpeakingExercise & CommonProps) {
const [solutionsURL, setSolutionsURL] = useState<string[]>([]);
const [diffNumber, setDiffNumber] = useState(0);
@@ -56,40 +53,7 @@ export default function InteractiveSpeaking({
return (
<div className="flex flex-col gap-4 mt-4 w-full">
<div className="flex justify-between w-full gap-8">
<Button
color="purple"
variant="outline"
onClick={() =>
onBack({
exercise: id,
solutions: userSolutions,
score: {total: 100, missing: 0, correct: speakingReverseMarking[userSolutions[0]!.evaluation!.overall] || 0},
type,
})
}
className="max-w-[200px] self-end w-full">
Back
</Button>
<Button
color="purple"
onClick={() =>
onNext({
exercise: id,
solutions: userSolutions,
score: {
total: 100,
missing: 0,
correct: userSolutions[0]?.evaluation ? speakingReverseMarking[userSolutions[0]!.evaluation!.overall] || 0 : 0,
},
type,
})
}
className="max-w-[200px] self-end w-full">
Next
</Button>
</div>
{headerButtons}
<Modal title={`Correction (Prompt ${diffNumber})`} isOpen={diffNumber !== 0} onClose={() => setDiffNumber(0)}>
<>
{userSolutions &&
@@ -291,40 +255,7 @@ export default function InteractiveSpeaking({
)}
</div>
</div>
<div className="self-end flex justify-between w-full gap-8 absolute bottom-8 left-0 px-8">
<Button
color="purple"
variant="outline"
onClick={() =>
onBack({
exercise: id,
solutions: userSolutions,
score: {total: 100, missing: 0, correct: speakingReverseMarking[userSolutions[0]!.evaluation!.overall] || 0},
type,
})
}
className="max-w-[200px] self-end w-full">
Back
</Button>
<Button
color="purple"
onClick={() =>
onNext({
exercise: id,
solutions: userSolutions,
score: {
total: 100,
missing: 0,
correct: userSolutions[0]?.evaluation ? speakingReverseMarking[userSolutions[0]!.evaluation!.overall] || 0 : 0,
},
type,
})
}
className="max-w-[200px] self-end w-full">
Next
</Button>
</div>
{footerButtons}
</div>
);
}

View File

@@ -1,14 +1,7 @@
import { MatchSentenceExerciseSentence, MatchSentencesExercise } from "@/interfaces/exam";
import clsx from "clsx";
import LineTo from "react-lineto";
import { CommonProps } from ".";
import { errorButtonStyle, infoButtonStyle } from "@/constants/buttonStyles";
import { mdiArrowLeft, mdiArrowRight } from "@mdi/js";
import Icon from "@mdi/react";
import { Fragment } from "react";
import Button from "../Low/Button";
import Xarrow from "react-xarrows";
import useExamStore from "@/stores/examStore";
function QuestionSolutionArea({
question,
@@ -22,7 +15,7 @@ function QuestionSolutionArea({
<div className="flex items-center gap-3 cursor-pointer col-span-2">
<button
className={clsx(
"text-white w-8 h-8 rounded-full z-10",
"text-white p-2 rounded-full z-10",
!userSolution
? "bg-mti-gray-davy"
: userSolution.option.toString() === question.solution.toString()
@@ -55,51 +48,16 @@ function QuestionSolutionArea({
export default function MatchSentencesSolutions({
id,
type,
options,
prompt,
sentences,
userSolutions,
onNext,
onBack,
disableProgressButtons = false
headerButtons,
footerButtons,
}: MatchSentencesExercise & CommonProps) {
const { questionIndex, setQuestionIndex, partIndex, exam } = useExamStore((state) => state);
const calculateScore = () => {
const total = sentences.length;
const correct = userSolutions.filter(
(x) => sentences.find((y) => y.id.toString() === x.question.toString())?.solution === x.option || false,
).length;
const missing = total - userSolutions.filter((x) => sentences.find((y) => y.id.toString() === x.question.toString())).length;
return { total, correct, missing };
};
const progressButtons = () => (
<div className="flex justify-between w-full gap-8">
<Button
color="purple"
variant="outline"
onClick={() => onBack({ exercise: id, solutions: userSolutions, score: calculateScore(), type })}
className="max-w-[200px] w-full"
disabled={exam && typeof partIndex !== "undefined" && exam.module === "level" && questionIndex === 0 && partIndex === 0}>
Back
</Button>
<Button
color="purple"
onClick={() => onNext({ exercise: id, solutions: userSolutions, score: calculateScore(), type })}
className="max-w-[200px] self-end w-full">
Next
</Button>
</div>
)
return (
<div className="flex flex-col gap-4 mt-4">
{!disableProgressButtons && progressButtons()}
<div className={clsx("flex flex-col gap-4 mt-4 h-full w-full", !disableProgressButtons && "mb-20")}>
{headerButtons}
<div className={clsx("flex flex-col gap-4 mt-4 h-full w-full", (!headerButtons || !footerButtons) && "mb-20")}>
<span className="text-sm w-full leading-6">
{prompt.split("\\n").map((line, index) => (
<Fragment key={index}>
@@ -131,9 +89,8 @@ export default function MatchSentencesSolutions({
<div className="w-4 h-4 rounded-full bg-mti-rose" /> Wrong
</div>
</div>
{footerButtons}
</div>
{!disableProgressButtons && progressButtons()}
</div>
);
}

View File

@@ -1,6 +1,6 @@
/* eslint-disable @next/next/no-img-element */
import { MultipleChoiceExercise, MultipleChoiceQuestion, ShuffleMap } from "@/interfaces/exam";
import useExamStore from "@/stores/examStore";
import useExamStore from "@/stores/exam";
import clsx from "clsx";
import reactStringReplace from "react-string-replace";
import { CommonProps } from ".";
@@ -89,7 +89,7 @@ function Question({
);
}
export default function MultipleChoice({ id, type, prompt, questions, userSolutions, onNext, onBack, disableProgressButtons = false }: MultipleChoiceExercise & CommonProps) {
export default function MultipleChoice({ id, type, prompt, questions, userSolutions, headerButtons, footerButtons}: MultipleChoiceExercise & CommonProps) {
const { questionIndex, setQuestionIndex, partIndex, exam } = useExamStore((state) => state);
const stats = useExamStore((state) => state.userSolutions);
@@ -110,39 +110,6 @@ export default function MultipleChoice({ id, type, prompt, questions, userSoluti
return { total, correct, missing };
};
const next = () => {
if (questionIndex + 1 >= questions.length - 1) {
onNext({ exercise: id, solutions: userSolutions, score: calculateScore(), type });
} else {
setQuestionIndex(questionIndex + 2);
}
};
const back = () => {
if (questionIndex === 0) {
onBack({ exercise: id, solutions: userSolutions, score: calculateScore(), type });
} else {
setQuestionIndex(questionIndex - 2);
}
};
const progressButtons = () => (
<div className="flex justify-between w-full gap-8">
<Button
color="purple"
variant="outline"
onClick={back}
className="max-w-[200px] w-full"
disabled={exam && typeof partIndex !== "undefined" && exam.module === "level" && questionIndex === 0 && partIndex === 0}>
Back
</Button>
<Button color="purple" onClick={next} className="max-w-[200px] self-end w-full">
Next
</Button>
</div>
)
const renderAllQuestions = () =>
questions.map(question => (
<div
@@ -178,10 +145,10 @@ export default function MultipleChoice({ id, type, prompt, questions, userSoluti
return (
<div className="flex flex-col gap-4">
{!disableProgressButtons && progressButtons()}
{headerButtons}
<div className={clsx("flex flex-col gap-4 mt-4", !disableProgressButtons && "mb-20")}>
{disableProgressButtons ? renderAllQuestions() : renderTwoQuestions()}
<div className={clsx("flex flex-col gap-4 mt-4", (!headerButtons || !footerButtons) && "mb-20")}>
{(!headerButtons || !footerButtons) ? renderAllQuestions() : renderTwoQuestions()}
<div className="flex gap-4 items-center">
<div className="flex gap-2 items-center">
@@ -197,9 +164,8 @@ export default function MultipleChoice({ id, type, prompt, questions, userSoluti
Wrong
</div>
</div>
{footerButtons}
</div>
{!disableProgressButtons && progressButtons()}
</div>
);
}

View File

@@ -14,7 +14,7 @@ import ReactDiffViewer, {DiffMethod} from "react-diff-viewer";
const Waveform = dynamic(() => import("../Waveform"), {ssr: false});
export default function Speaking({id, type, title, video_url, text, prompts, userSolutions, onNext, onBack}: SpeakingExercise & CommonProps) {
export default function Speaking({id, type, title, video_url, text, prompts, userSolutions, headerButtons, footerButtons}: SpeakingExercise & CommonProps) {
const [solutionURL, setSolutionURL] = useState<string>();
const [showDiff, setShowDiff] = useState(false);
@@ -45,40 +45,7 @@ export default function Speaking({id, type, title, video_url, text, prompts, use
return (
<div className="flex flex-col gap-4 mt-4 w-full">
<div className="flex justify-between w-full gap-8">
<Button
color="purple"
variant="outline"
onClick={() =>
onBack({
exercise: id,
solutions: userSolutions,
score: {total: 100, missing: 0, correct: speakingReverseMarking[userSolutions[0]!.evaluation!.overall] || 0},
type,
})
}
className="max-w-[200px] self-end w-full">
Back
</Button>
<Button
color="purple"
onClick={() =>
onNext({
exercise: id,
solutions: userSolutions,
score: {
total: 100,
missing: 0,
correct: userSolutions[0]?.evaluation ? speakingReverseMarking[userSolutions[0]!.evaluation!.overall] || 0 : 0,
},
type,
})
}
className="max-w-[200px] self-end w-full">
Next
</Button>
</div>
{headerButtons}
<Modal title="Correction" isOpen={showDiff} onClose={() => setShowDiff(false)}>
<>
{userSolutions &&
@@ -275,40 +242,7 @@ export default function Speaking({id, type, title, video_url, text, prompts, use
)}
</div>
</div>
<div className="self-end flex justify-between w-full gap-8 absolute bottom-8 left-0 px-8">
<Button
color="purple"
variant="outline"
onClick={() =>
onBack({
exercise: id,
solutions: userSolutions,
score: {total: 100, missing: 0, correct: speakingReverseMarking[userSolutions[0]!.evaluation!.overall] || 0},
type,
})
}
className="max-w-[200px] self-end w-full">
Back
</Button>
<Button
color="purple"
onClick={() =>
onNext({
exercise: id,
solutions: userSolutions,
score: {
total: 100,
missing: 0,
correct: userSolutions[0]?.evaluation ? speakingReverseMarking[userSolutions[0]!.evaluation!.overall] || 0 : 0,
},
type,
})
}
className="max-w-[200px] self-end w-full">
Next
</Button>
</div>
{footerButtons}
</div>
);
}

View File

@@ -4,23 +4,10 @@ import reactStringReplace from "react-string-replace";
import { CommonProps } from ".";
import { Fragment } from "react";
import Button from "../Low/Button";
import useExamStore from "@/stores/examStore";
type Solution = "true" | "false" | "not_given";
export default function TrueFalseSolution({ prompt, type, id, questions, userSolutions, onNext, onBack, disableProgressButtons = false }: TrueFalseExercise & CommonProps) {
const { questionIndex, setQuestionIndex, partIndex, exam } = useExamStore((state) => state);
const calculateScore = () => {
const total = questions.length || 0;
const correct = userSolutions.filter(
(x) => questions.find((y) => x.id.toString() === y.id.toString())?.solution === x.solution.toLowerCase() || false,
).length;
const missing = total - userSolutions.filter((x) => questions.find((y) => x.id.toString() === y.id.toString())).length;
return { total, correct, missing };
};
export default function TrueFalseSolution({ prompt, type, id, questions, userSolutions, headerButtons, footerButtons }: TrueFalseExercise & CommonProps) {
const getButtonColor = (buttonSolution: Solution, solution: Solution, userSolution: Solution | undefined) => {
if (buttonSolution !== userSolution && buttonSolution !== solution) return "purple";
@@ -39,31 +26,11 @@ export default function TrueFalseSolution({ prompt, type, id, questions, userSol
return "gray";
};
const progressButtons = () => (
<div className="flex justify-between w-full gap-8">
<Button
color="purple"
variant="outline"
onClick={() => onBack({ exercise: id, solutions: userSolutions, score: calculateScore(), type })}
className="max-w-[200px] w-full"
disabled={exam && typeof partIndex !== "undefined" && exam.module === "level" && questionIndex === 0 && partIndex === 0}>
Back
</Button>
<Button
color="purple"
onClick={() => onNext({ exercise: id, solutions: userSolutions, score: calculateScore(), type })}
className="max-w-[200px] self-end w-full">
Next
</Button>
</div>
)
return (
<div className="flex flex-col gap-4 mt-4">
{!disableProgressButtons && progressButtons()}
{headerButtons}
<div className={clsx("flex flex-col gap-4 mt-4 h-full w-full", !disableProgressButtons && "mb-20")}>
<div className={clsx("flex flex-col gap-4 mt-4 h-full w-full", (!headerButtons || !footerButtons) && "mb-20")}>
<span className="text-sm w-full leading-6">
{prompt.split("\\n").map((line, index) => (
<Fragment key={index}>
@@ -139,9 +106,8 @@ export default function TrueFalseSolution({ prompt, type, id, questions, userSol
Wrong
</div>
</div>
{footerButtons}
</div>
{!disableProgressButtons && progressButtons()}
</div>
);
}

View File

@@ -6,9 +6,6 @@ import clsx from "clsx";
import { Fragment, useEffect, useState } from "react";
import reactStringReplace from "react-string-replace";
import { CommonProps } from ".";
import { toast } from "react-toastify";
import Button from "../Low/Button";
import useExamStore from "@/stores/examStore";
function Blank({
id,
@@ -50,11 +47,11 @@ function Blank({
{userSolution && !isUserSolutionCorrect() && (
<div
className="py-2 px-3 rounded-2xl w-fit focus:outline-none my-2 bg-mti-rose-ultralight text-mti-rose-light"
contentEditable={disabled}>
>
{userSolution}
</div>
)}
<div className={clsx("py-2 px-3 rounded-2xl w-fit focus:outline-none my-2", getSolutionStyling())} contentEditable={disabled}>
<div className={clsx("py-2 px-3 rounded-2xl w-fit focus:outline-none my-2", getSolutionStyling())} >
{!solutions ? userInput : solutions.join(" / ")}
</div>
</span>
@@ -62,33 +59,14 @@ function Blank({
}
export default function WriteBlanksSolutions({
id,
type,
prompt,
maxWords,
solutions,
userSolutions,
text,
onNext,
onBack,
disableProgressButtons = false
headerButtons,
footerButtons,
}: WriteBlanksExercise & CommonProps) {
const { questionIndex, setQuestionIndex, partIndex, exam } = useExamStore((state) => state);
const calculateScore = () => {
const total = text.match(/({{\d+}})/g)?.length || 0;
const correct = userSolutions.filter(
(x) =>
solutions
.find((y) => x.id.toString() === y.id.toString())
?.solution.map((y) => y.toLowerCase().trim())
.includes(x.solution.toLowerCase().trim()) || false,
).length;
const missing = total - userSolutions.filter((x) => solutions.find((y) => x.id.toString() === y.id.toString())).length;
return { total, correct, missing };
};
const renderLines = (line: string) => {
return (
<span className="text-base leading-5">
@@ -105,31 +83,11 @@ export default function WriteBlanksSolutions({
);
};
const progressButtons = () => (
<div className="flex justify-between w-full gap-8">
<Button
color="purple"
variant="outline"
onClick={() => onBack({ exercise: id, solutions: userSolutions, score: calculateScore(), type })}
className="max-w-[200px] w-full"
disabled={exam && typeof partIndex !== "undefined" && exam.module === "level" && questionIndex === 0 && partIndex === 0}>
Back
</Button>
<Button
color="purple"
onClick={() => onNext({ exercise: id, solutions: userSolutions, score: calculateScore(), type })}
className="max-w-[200px] self-end w-full">
Next
</Button>
</div>
)
return (
<div className="flex flex-col gap-4">
{!disableProgressButtons && progressButtons()}
{headerButtons}
<div className={clsx("flex flex-col gap-4 mt-4 h-full w-full", !disableProgressButtons && "mb-20")}>
<div className={clsx("flex flex-col gap-4 mt-4 h-full w-full", (!headerButtons || !footerButtons) && "mb-20")}>
<span className="text-sm w-full leading-6">
{prompt.split("\\n").map((line, index) => (
<Fragment key={index}>
@@ -161,9 +119,8 @@ export default function WriteBlanksSolutions({
Wrong
</div>
</div>
{footerButtons}
</div>
{!disableProgressButtons && progressButtons()}
</div>
);
}

View File

@@ -10,7 +10,7 @@ import ReactDiffViewer, {DiffMethod} from "react-diff-viewer";
import useUser from "@/hooks/useUser";
import AIDetection from "../AIDetection";
export default function Writing({id, type, prompt, attachment, userSolutions, onNext, onBack}: WritingExercise & CommonProps) {
export default function Writing({id, type, prompt, attachment, userSolutions, headerButtons, footerButtons}: WritingExercise & CommonProps) {
const [isModalOpen, setIsModalOpen] = useState(false);
const [showDiff, setShowDiff] = useState(false);
@@ -31,40 +31,7 @@ export default function Writing({id, type, prompt, attachment, userSolutions, on
return (
<div className="flex flex-col gap-4 mt-4">
<div className="self-end flex justify-between w-full gap-8 absolute bottom-8 left-0 px-8">
<Button
color="purple"
variant="outline"
onClick={() =>
onBack({
exercise: id,
solutions: userSolutions,
score: {total: 100, missing: 0, correct: writingReverseMarking[userSolutions[0]!.evaluation!.overall] || 0},
type,
})
}
className="max-w-[200px] self-end w-full">
Back
</Button>
<Button
color="purple"
onClick={() =>
onNext({
exercise: id,
solutions: userSolutions,
score: {
total: 100,
missing: 0,
correct: userSolutions[0]?.evaluation ? writingReverseMarking[userSolutions[0]!.evaluation!.overall] || 0 : 0,
},
type,
})
}
className="max-w-[200px] self-end w-full">
Next
</Button>
</div>
{headerButtons}
{attachment && (
<Transition show={isModalOpen} as={Fragment}>
<Dialog onClose={() => setIsModalOpen(false)} className="relative z-50">
@@ -286,40 +253,7 @@ export default function Writing({id, type, prompt, attachment, userSolutions, on
)}
</div>
</div>
<div className="self-end flex justify-between w-full gap-8 absolute bottom-8 left-0 px-8">
<Button
color="purple"
variant="outline"
onClick={() =>
onBack({
exercise: id,
solutions: userSolutions,
score: {total: 100, missing: 0, correct: writingReverseMarking[userSolutions[0]!.evaluation!.overall] || 0},
type,
})
}
className="max-w-[200px] self-end w-full">
Back
</Button>
<Button
color="purple"
onClick={() =>
onNext({
exercise: id,
solutions: userSolutions,
score: {
total: 100,
missing: 0,
correct: userSolutions[0]?.evaluation ? writingReverseMarking[userSolutions[0]!.evaluation!.overall] || 0 : 0,
},
type,
})
}
className="max-w-[200px] self-end w-full">
Next
</Button>
</div>
{footerButtons}
</div>
);
}

View File

@@ -22,29 +22,36 @@ import Writing from "./Writing";
const MatchSentences = dynamic(() => import("@/components/Solutions/MatchSentences"), { ssr: false });
export interface CommonProps {
onNext: (userSolutions: UserSolution) => void;
onBack: (userSolutions: UserSolution) => void;
disableProgressButtons?: boolean,
headerButtons?: React.ReactNode,
footerButtons?: React.ReactNode,
}
export const renderSolution = (exercise: Exercise, onNext: () => void, onBack: () => void, updateIndex?: (internalIndex: number) => void,
disableProgressButtons?: boolean) => {
export const renderSolution = (
exercise: Exercise,
headerButtons?: React.ReactNode,
footerButtons?: React.ReactNode,
) => {
const sharedProps = {
key: exercise.id,
headerButtons,
footerButtons,
}
switch (exercise.type) {
case "fillBlanks":
return <FillBlanks disableProgressButtons={disableProgressButtons} key={exercise.id} {...(exercise as FillBlanksExercise)} onNext={onNext} onBack={onBack} />;
return <FillBlanks {...(exercise as FillBlanksExercise)} {...sharedProps}/>;
case "trueFalse":
return <TrueFalseSolution disableProgressButtons={disableProgressButtons} key={exercise.id} {...(exercise as TrueFalseExercise)} onNext={onNext} onBack={onBack} />;
return <TrueFalseSolution {...(exercise as TrueFalseExercise)} {...sharedProps}/>;
case "matchSentences":
return <MatchSentences disableProgressButtons={disableProgressButtons} key={exercise.id} {...(exercise as MatchSentencesExercise)} onNext={onNext} onBack={onBack} />;
return <MatchSentences {...(exercise as MatchSentencesExercise)} {...sharedProps}/>;
case "multipleChoice":
return <MultipleChoice disableProgressButtons={disableProgressButtons} key={exercise.id} {...(exercise as MultipleChoiceExercise)} onNext={onNext} onBack={onBack} />;
return <MultipleChoice {...(exercise as MultipleChoiceExercise)} {...sharedProps}/>;
case "writeBlanks":
return <WriteBlanks disableProgressButtons={disableProgressButtons} key={exercise.id} {...(exercise as WriteBlanksExercise)} onNext={onNext} onBack={onBack} />;
return <WriteBlanks {...(exercise as WriteBlanksExercise)} {...sharedProps}/>;
case "writing":
return <Writing key={exercise.id} {...(exercise as WritingExercise)} onNext={onNext} onBack={onBack} />;
return <Writing {...(exercise as WritingExercise)} {...sharedProps}/>;
case "speaking":
return <Speaking key={exercise.id} {...(exercise as SpeakingExercise)} onNext={onNext} onBack={onBack} />;
return <Speaking {...(exercise as SpeakingExercise)} {...sharedProps}/>;
case "interactiveSpeaking":
return <InteractiveSpeaking key={exercise.id} {...(exercise as InteractiveSpeakingExercise)} onNext={onNext} onBack={onBack} />;
return <InteractiveSpeaking {...(exercise as InteractiveSpeakingExercise)} {...sharedProps}/>;
}
};