Files
encoach_frontend/src/components/Exercises/MatchSentences.tsx

112 lines
4.0 KiB
TypeScript

import {errorButtonStyle, infoButtonStyle} from "@/constants/buttonStyles";
import {MatchSentencesExercise} from "@/interfaces/exam";
import {mdiArrowLeft, mdiArrowRight} from "@mdi/js";
import Icon from "@mdi/react";
import clsx from "clsx";
import {Fragment, useEffect, useState} from "react";
import LineTo from "react-lineto";
import {CommonProps} from ".";
import Button from "../Low/Button";
import Xarrow from "react-xarrows";
import useExamStore from "@/stores/examStore";
export default function MatchSentences({id, options, type, prompt, sentences, userSolutions, onNext, onBack}: MatchSentencesExercise & CommonProps) {
const [selectedQuestion, setSelectedQuestion] = useState<string>();
const [answers, setAnswers] = useState<{question: string; option: string}[]>(userSolutions);
const hasExamEnded = useExamStore((state) => state.hasExamEnded);
const calculateScore = () => {
const total = sentences.length;
const correct = answers.filter(
(x) => sentences.find((y) => y.id.toString() === x.question.toString())?.solution === x.option || false,
).length;
const missing = total - answers.filter((x) => sentences.find((y) => y.id.toString() === x.question.toString())).length;
return {total, correct, missing};
};
const selectOption = (option: string) => {
if (!selectedQuestion) return;
setAnswers((prev) => [...prev.filter((x) => x.question !== selectedQuestion), {question: selectedQuestion, option}]);
setSelectedQuestion(undefined);
};
useEffect(() => {
if (hasExamEnded) onNext({exercise: id, solutions: answers, score: calculateScore(), type});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [hasExamEnded]);
return (
<>
<div className="flex flex-col gap-4 mt-4 h-full mb-20">
<span className="text-sm w-full leading-6">
{prompt.split("\\n").map((line, index) => (
<Fragment key={index}>
{line}
<br />
</Fragment>
))}
</span>
<div className="flex gap-8 w-full items-center justify-between bg-mti-gray-smoke rounded-xl px-24 py-6">
<div className="flex flex-col gap-4">
{sentences.map(({sentence, id}) => (
<div key={`question_${id}`} className="flex items-center justify-end gap-2 cursor-pointer">
<span>{sentence} </span>
<button
id={id}
onClick={() => setSelectedQuestion((prev) => (prev === id ? undefined : id))}
className={clsx(
"bg-mti-purple-ultralight text-mti-purple hover:text-white hover:bg-mti-purple w-8 h-8 rounded-full z-10",
"transition duration-300 ease-in-out",
selectedQuestion === id && "!text-white !bg-mti-purple",
id,
)}>
{id}
</button>
</div>
))}
</div>
<div className="flex flex-col gap-4">
{options.map(({sentence, id}) => (
<div key={`answer_${id}`} className={clsx("flex items-center justify-start gap-2 cursor-pointer")}>
<button
id={id}
onClick={() => selectOption(id)}
className={clsx(
"bg-mti-purple-ultralight text-mti-purple hover:text-white hover:bg-mti-purple w-8 h-8 rounded-full z-10",
"transition duration-300 ease-in-out",
id,
)}>
{id}
</button>
<span>{sentence}</span>
</div>
))}
</div>
{answers.map((solution, index) => (
<Xarrow key={index} start={solution.question} end={solution.option} lineColor="#7872BF" showHead={false} />
))}
</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: answers, score: calculateScore(), type})}
className="max-w-[200px] w-full">
Back
</Button>
<Button
color="purple"
onClick={() => onNext({exercise: id, solutions: answers, score: calculateScore(), type})}
className="max-w-[200px] self-end w-full">
Next
</Button>
</div>
</>
);
}