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

228 lines
7.3 KiB
React
Raw Normal View History

2024-12-05 08:30:22 +00:00
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(', ');
}
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) {
const arrSavedAnswer = stringToArray(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;