import { errorButtonStyle, infoButtonStyle } from "@/constants/buttonStyles"; import { MatchSentenceExerciseOption, MatchSentenceExerciseSentence, 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"; import { DndContext, DragEndEvent, useDraggable, useDroppable } from "@dnd-kit/core"; function DroppableQuestionArea({ question, answer }: { question: MatchSentenceExerciseSentence; answer?: string }) { const { isOver, setNodeRef } = useDroppable({ id: `droppable_sentence_${question.id}` }); return (
{question.sentence}
{answer && `Paragraph ${answer}`}
); } function DraggableOptionArea({ option }: { option: MatchSentenceExerciseOption }) { const { attributes, listeners, setNodeRef, transform } = useDraggable({ id: `draggable_option_${option.id}`, }); const style = transform ? { transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`, zIndex: 99, } : undefined; return (
); } export default function MatchSentences({ id, options, type, prompt, sentences, userSolutions, onNext, onBack, isPractice = false, disableProgressButtons = false }: MatchSentencesExercise & CommonProps) { const [answers, setAnswers] = useState<{ question: string; option: string }[]>(userSolutions); const hasExamEnded = useExamStore((state) => state.hasExamEnded); const setCurrentSolution = useExamStore((state) => state.setCurrentSolution); useEffect(() => { setCurrentSolution({ exercise: id, solutions: answers, score: calculateScore(), type, isPractice }); // eslint-disable-next-line react-hooks/exhaustive-deps }, [answers, setAnswers]); const handleDragEnd = (event: DragEndEvent) => { if (event.over && event.over.id.toString().startsWith("droppable")) { const optionID = event.active.id.toString().replace("draggable_option_", ""); const sentenceID = event.over.id.toString().replace("droppable_sentence_", ""); setAnswers((prev) => [...prev.filter((x) => x.question.toString() !== sentenceID), { question: sentenceID, option: optionID }]); } }; 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 }; }; useEffect(() => { if (disableProgressButtons) onNext({ exercise: id, solutions: answers, score: calculateScore(), type, isPractice }); // eslint-disable-next-line react-hooks/exhaustive-deps }, [answers, disableProgressButtons]) useEffect(() => { if (hasExamEnded) onNext({ exercise: id, solutions: answers, score: calculateScore(), type, isPractice }); // eslint-disable-next-line react-hooks/exhaustive-deps }, [hasExamEnded]); const progressButtons = () => (
) return (
{!disableProgressButtons && progressButtons()}
{prompt.split("\\n").map((line, index) => ( {line}
))}
{sentences.map((question) => ( x.question.toString() === question.id.toString())?.option} /> ))}
Drag one of these paragraphs into the slots above:
{options.map((option) => ( ))}
{!disableProgressButtons && progressButtons()}
); }