frontend_adaptive_learning/src/roles/user/review/views/components/MatchingPairsQuestion.jsx

244 lines
7.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState, useEffect } from 'react';
import MediaViewer from './MediaViewer';
import { MEDIA_URL } from '../../../../../utils/Constant';
// const colors = ['#E9342D', '#FACC15', '#1FBC2F', '#0090FF', '#ED27D9'];
// const colors = ['#0090FF', '#FC6454', '#46E59A', '#FBD025', '#E355D5'];
const colors = ['#FC6454', '#FBD025', '#46E59A', '#0090FF','#E355D5'];
const shuffleArray = (array) => {
return array
.map((value) => ({ value, sort: Math.random() }))
.sort((a, b) => a.sort - b.sort)
.map(({ value }) => value);
};
function arrayToString(arr) {
return arr.join(', ');
}
function stringToArray(str) {
return str.split(', ');
}
function extractAnswer(input) {
const lines = input.split('|');
const descriptions = lines.map(line => {
const parts = line.split('>');
return parts[1]?.trim();
});
return descriptions;
}
const MatchingPairsQuestion = ({ question, studentAnswer, index }) => {
const savedAnswer = studentAnswer !== null ? studentAnswer : null;
const [pairs, setPairs] = useState([]);
const [selectedLeft, setSelectedLeft] = useState(null);
const [selectedRight, setSelectedRight] = useState(null);
const [rightOptions, setRightOptions] = useState([]);
const [isComplete, setIsComplete] = useState(false);
const [isShuffled, setIsShuffled] = useState(false);
useEffect(() => {
const handleClickOutside = (event) => {
if (!event.target.closest('.mp-choice')) {
setSelectedLeft(null);
setSelectedRight(null);
}
};
document.addEventListener('click', handleClickOutside);
return () => {
document.removeEventListener('click', handleClickOutside);
};
}, []);
useEffect(() => {
const initialPairs = question.matchingPairs.map((pair) => ({
left: pair.LEFT_PAIR,
right: '',
color: colors[question.matchingPairs.indexOf(pair) % colors.length],
}));
if (savedAnswer !== null) {
//if use "," as separator
// const arrSavedAnswer = stringToArray(savedAnswer);
//if use ">" as separator
const arrSavedAnswer = extractAnswer(savedAnswer);
const updatedPairs = initialPairs.map((pair, index) => ({
...pair,
right: arrSavedAnswer[index],
}));
setPairs(updatedPairs);
} else {
setPairs(initialPairs);
}
}, [question, savedAnswer]);
useEffect(() => {
setIsShuffled(true);
setRightOptions(shuffleArray(question.matchingPairs.map((pair) => pair.RIGHT_PAIR)));
}, [question]);
const handleLeftClick = (index) => {
setSelectedLeft(index);
const status = pairs.findIndex(item => item.right === rightOptions[selectedRight]);
if (selectedRight !== null) {
makePair(index, selectedRight, status);
}
};
const handleRightClick = (index) => {
setSelectedRight(index);
const status = pairs.findIndex(item => item.right === rightOptions[index]);
if (selectedLeft !== null) {
makePair(selectedLeft, index, status);
}
};
const makePair = (leftIndex, rightIndex, changePair) => {
const newPairs = [...pairs];
if (changePair > -1) {
setIsComplete(false);
pairs[changePair].right = '';
}
const selectedRightValue = rightOptions[rightIndex];
newPairs[leftIndex].right = selectedRightValue;
setPairs(newPairs);
// console.log(newPairs);
setSelectedLeft(null);
setSelectedRight(null);
const allPairsMatched = newPairs.every((pair) => pair.right !== '');
if (allPairsMatched && !isComplete) {
setIsComplete(true);
const rightAnswers = newPairs.map((pair) => pair.right);
onAnswer(index, arrayToString(rightAnswers), question.ID_ADMIN_EXERCISE);
}
};
const mediaUrls = [];
const mediaPath = `${MEDIA_URL}/exercise`;
if (question.IMAGE) mediaUrls.push(`${mediaPath}/image/${question.IMAGE}`);
if (question.AUDIO) mediaUrls.push(`${mediaPath}/audio/${question.AUDIO}`);
if (question.VIDEO) mediaUrls.push(question.VIDEO);
return (
<div>
<div className={`correction-label ${question.IS_CORRECT === 1 ? `correct` : `incorrect` }`}>
<i className={`me-2 bi ${question.IS_CORRECT === 1 ? `bi-check-circle-fill` : `bi-x-circle-fill` }`}></i>
Your matching pairs answers are {question.RESULT_SCORE_STUDENT}/{question.SCORE_WEIGHT} correct.
</div>
{mediaUrls.length > 0 && <MediaViewer mediaUrls={mediaUrls} />}
<p>{question.QUESTION.split('\n').map((line, index) => (
<React.Fragment key={index}>
{line}
<br />
</React.Fragment>
))}</p>
<div className="w-100 options-mp d-flex justify-content-between">
{/* Bagian kiri */}
<div>
{pairs.map((pair, index) => (
<div
key={index}
className={`p-0 mb-3 form-check mp-choice`}
style={{
display: 'flex', alignItems: 'center',
}}
>
<span
className="option-label"
style={{
color: "#fff",
backgroundColor: pair.color,
border: selectedLeft === index ? '2px dashed #ffffff' : '2px solid #ffffff',
}}
>
{index + 1}
</span>
<span
className="ms-2 option-text"
style={{
color:
selectedLeft === index
? "#ffffff"
: (pair.right === '' ? '#000000' : "#ffffff"),
backgroundColor:
selectedLeft === index
? pair.color
: (pair.right === '' ? '#ffffff' : pair.color),
border:
selectedLeft === index
? '2px dashed #ffffff'
: (pair.right === '' ? '1px solid #000000' : '2px solid #ffffff'),
}}
>
{pair.left}
</span>
</div>
))}
</div>
{/* Bagian kanan */}
<div>
{rightOptions.map((right, index) => (
<div
key={index}
className={`p-0 mb-3 form-check mp-choice`}
style={{
display: 'flex', alignItems: 'center',
}}
>
<span
className="option-label"
style={{
color: pairs.find((pair) => pair.right === right) ? '#ffffff' : '#000000',
backgroundColor:
pairs.find((pair) => pair.right === right)?.color ||
(selectedRight === index ? '#ccc' : '#ffffff'),
border:
pairs.find((pair) => pair.right === right)?.color ||
(selectedRight === index ? '2px dashed #ffffff' : '1px solid #000000'),
}}
>
{index + 1}
</span>
<span
className="ms-2 option-text"
style={{
color: (pairs.find((pair) => pair.right === right) ? '#ffffff' : '#000000'),
backgroundColor:
pairs.find((pair) => pair.right === right)?.color ||
(selectedRight === index ? '#ccc' : '#ffffff'),
border:
pairs.find((pair) => pair.right === right)?.color ||
(selectedRight === index ? '2px dashed #ffffff' : '1px solid #000000'),
}}
>
{right}
</span>
</div>
))}
</div>
</div>
</div>
);
};
export default MatchingPairsQuestion;