332 lines
15 KiB
JavaScript
332 lines
15 KiB
JavaScript
import React, { useState, useEffect } from 'react';
|
|
import { Container, Row, Col, ListGroup, Button, Modal, Alert, OverlayTrigger, Popover } from 'react-bootstrap';
|
|
import { useNavigate, useParams } from 'react-router-dom';
|
|
import useExercises from '../hooks/useExercises';
|
|
import ilustration from '../../../../assets/images/illustration/submitExercise.png';
|
|
import Skeleton from 'react-loading-skeleton';
|
|
import MatchingPairs from './components/MatchingPair';
|
|
|
|
const Exercise = () => {
|
|
const [showModal, setShowModal] = useState(false);
|
|
const [showAlert, setShowAlert] = useState(false);
|
|
|
|
const [activeIndex, setActiveIndex] = useState(null);
|
|
|
|
const { section, topic, level } = useParams();
|
|
const navigate = useNavigate();
|
|
|
|
const {
|
|
questions,
|
|
loading,
|
|
error,
|
|
answers,
|
|
currentQuestion,
|
|
popover,
|
|
setAnswers,
|
|
setCurrentQuestion,
|
|
handleAnswerSelect,
|
|
handleNextQuestion,
|
|
handlePrevQuestion,
|
|
handleSubmit,
|
|
getCurrentQuestionData,
|
|
handleConfirmSubmit
|
|
} = useExercises( topic, level );
|
|
|
|
const handleSubmitWrapper = () => {
|
|
if (handleSubmit()) {
|
|
setShowModal(true);
|
|
} else {
|
|
setShowAlert(true);
|
|
}
|
|
};
|
|
|
|
// const handleConfirmSubmit = () => {
|
|
// setShowModal(false);
|
|
// navigate(`/learning/module/${section}/${topic}/${level}/result`, {
|
|
// state: { answers }
|
|
// });
|
|
// };
|
|
|
|
const handleCloseModal = () => setShowModal(false);
|
|
|
|
const currentQuestionData = getCurrentQuestionData();
|
|
const questionId = currentQuestionData.id || '';
|
|
|
|
|
|
const handleSelectLeft = (index) => {
|
|
setActiveIndex(index);
|
|
};
|
|
|
|
|
|
|
|
if (loading) {
|
|
return (
|
|
<div className="row">
|
|
<div className="col-2">
|
|
<Skeleton containerClassName='w-100' className='w-100 mb-1 rounded-3' count={6} style={{height:"4vh"}} />
|
|
</div>
|
|
<div className="col-10">
|
|
<Skeleton containerClassName='w-100' className='w-100 mb-1 rounded-3' style={{height:"5vh"}} />
|
|
<Skeleton containerClassName='w-100' className='w-50 mb-1 rounded-3' style={{height:"20vh"}} />
|
|
<Skeleton containerClassName='w-100' className='w-100 mb-1 rounded-3' style={{height:"30vh"}} />
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Container fluid className='exercise-page'>
|
|
<Row>
|
|
<Col sm={2}>
|
|
<div className='p-3 rounded-4 bg-white'>
|
|
<div className="mb-3 d-flex justify-content-between align-items-center">
|
|
<h4 className='mb-0 text-gd fw-bold'>Pretest</h4>
|
|
<OverlayTrigger trigger="click" placement="right" overlay={popover}>
|
|
<i className=" bi bi-info-circle cursor-pointer text-secondary"></i>
|
|
</OverlayTrigger>
|
|
</div>
|
|
<ListGroup variant="flush" className='number-list'>
|
|
{questions.map((q, index) => (
|
|
<ListGroup.Item
|
|
key={q.ID_ADMIN_EXERCISE}
|
|
active={index === currentQuestion}
|
|
onClick={() => setCurrentQuestion(index)}
|
|
className={`border-0 rounded-3 number-label ${answers[index] !== null ? 'answered fw-bold' : ''}`}
|
|
style={{ cursor: 'pointer' }}
|
|
>
|
|
<i className={`me-2 bi bi-circle ${answers[index] !== null ? 'd-none' : 'd-block'}`}></i>
|
|
<i className={`me-2 bi bi-check2-circle ${answers[index] !== null ? 'd-block' : 'd-none'}`}></i>
|
|
{index+1}
|
|
</ListGroup.Item>
|
|
))}
|
|
</ListGroup>
|
|
</div>
|
|
</Col>
|
|
|
|
<Col sm={10}>
|
|
<div className='p-4 rounded-4 bg-white'>
|
|
<div className="pb-4 d-flex justify-content-between align-items-center">
|
|
<Button
|
|
variant='outline-blue'
|
|
className={`rounded-35 ${currentQuestion === 0 ? 'invisible' : 'visible'}`}
|
|
onClick={handlePrevQuestion}
|
|
disabled={currentQuestion === 0}
|
|
>
|
|
<i className="bi bi-arrow-left"></i>
|
|
</Button>
|
|
<h5 className='m-0'>{`Questions ${currentQuestion + 1} of ${questions.length}`}</h5>
|
|
<Button
|
|
variant="blue"
|
|
className={`rounded-35 ${currentQuestion === questions.length - 1 ? 'd-none' : ''}`}
|
|
onClick={handleNextQuestion}
|
|
disabled={currentQuestion === questions.length - 1}
|
|
>
|
|
Next Questions <i className="bi bi-arrow-right"></i>
|
|
</Button>
|
|
<Button
|
|
variant="blue"
|
|
className={`rounded-35 px-4 ${currentQuestion === questions.length - 1 ? 'd-inline-block' : 'd-none'}`}
|
|
onClick={handleSubmitWrapper}
|
|
>
|
|
Submit <i className="bi bi-send"></i>
|
|
</Button>
|
|
</div>
|
|
<div className='p-3 border rounded-3'>
|
|
{currentQuestionData.image && (
|
|
<div className="mb-2">
|
|
<img
|
|
src={currentQuestionData.image}
|
|
alt="question illustration"
|
|
className="img-fluid"
|
|
/>
|
|
</div>
|
|
)}
|
|
{currentQuestionData.IMAGE !== null && (
|
|
<div className='my-1'>
|
|
{/* <img src={currentQuestionData.source} alt="" /> */}
|
|
<h3>{currentQuestionData.IMAGE}</h3>
|
|
</div>
|
|
)}
|
|
{currentQuestionData.AUDIO !== null && (
|
|
<div className='my-1'>
|
|
{/* <AudioPlayer audioSrc={currentQuestionData.source} /> */}
|
|
{/* <audio controls>
|
|
<source src={currentQuestionData.source} type="audio/mpeg" />
|
|
Your browser does not support the audio element.
|
|
</audio> */}
|
|
<h3>{currentQuestionData.AUDIO}</h3>
|
|
</div>
|
|
)}
|
|
{currentQuestionData.VIDEO !== null && (
|
|
// <video src={currentQuestionData.source} controls className='my-1'></video>
|
|
<div className="my-1">
|
|
<h3>{currentQuestionData.VIDEO}</h3>
|
|
</div>
|
|
)}
|
|
<p className='mb-4'>{currentQuestionData.QUESTION}</p>
|
|
{currentQuestionData.QUESTION_TYPE === "MCQ" && (
|
|
<div className="options">
|
|
{/* {currentQuestionData.options?.map((option, idx) => (
|
|
<div
|
|
key={idx}
|
|
className={`p-0 mb-3 form-check ${answers[currentQuestion] === idx ? 'selected-answer' : ''}`}
|
|
style={{ display: 'flex', alignItems: 'center', cursor: 'pointer' }}
|
|
onClick={() => handleAnswerSelect(idx)}
|
|
>
|
|
<span className="option-label">{String.fromCharCode(65 + idx)}</span>
|
|
<span className="ms-2 option-text">{option}</span>
|
|
</div>
|
|
))} */}
|
|
<div
|
|
key={0}
|
|
className={`p-0 mb-3 form-check ${answers[currentQuestion] === 0 ? 'selected-answer' : ''}`}
|
|
style={{ display: 'flex', alignItems: 'center', cursor: 'pointer' }}
|
|
onClick={() => handleAnswerSelect(0)}
|
|
>
|
|
<span className="option-label">A</span>
|
|
<span className="ms-2 option-text">{currentQuestionData.multipleChoices[0].OPTION_A}</span>
|
|
</div>
|
|
<div
|
|
key={1}
|
|
className={`p-0 mb-3 form-check ${answers[currentQuestion] === 1 ? 'selected-answer' : ''}`}
|
|
style={{ display: 'flex', alignItems: 'center', cursor: 'pointer' }}
|
|
onClick={() => handleAnswerSelect(1)}
|
|
>
|
|
<span className="option-label">B</span>
|
|
<span className="ms-2 option-text">{currentQuestionData.multipleChoices[0].OPTION_B}</span>
|
|
</div>
|
|
<div
|
|
key={2}
|
|
className={`p-0 mb-3 form-check ${answers[currentQuestion] === 2 ? 'selected-answer' : ''}`}
|
|
style={{ display: 'flex', alignItems: 'center', cursor: 'pointer' }}
|
|
onClick={() => handleAnswerSelect(2)}
|
|
>
|
|
<span className="option-label">C</span>
|
|
<span className="ms-2 option-text">{currentQuestionData.multipleChoices[0].OPTION_C}</span>
|
|
</div>
|
|
<div
|
|
key={3}
|
|
className={`p-0 mb-3 form-check ${answers[currentQuestion] === 3 ? 'selected-answer' : ''}`}
|
|
style={{ display: 'flex', alignItems: 'center', cursor: 'pointer' }}
|
|
onClick={() => handleAnswerSelect(3)}
|
|
>
|
|
<span className="option-label">D</span>
|
|
<span className="ms-2 option-text">{currentQuestionData.multipleChoices[0].OPTION_D}</span>
|
|
</div>
|
|
{currentQuestionData.multipleChoices[0].OPTION_E && (
|
|
<div
|
|
key={4}
|
|
className={`p-0 mb-3 form-check ${answers[currentQuestion] === 4 ? 'selected-answer' : ''}`}
|
|
style={{ display: 'flex', alignItems: 'center', cursor: 'pointer' }}
|
|
onClick={() => handleAnswerSelect(4)}
|
|
>
|
|
<span className="option-label">E</span>
|
|
<span className="ms-2 option-text">{currentQuestionData.multipleChoices[0].OPTION_E}</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
)}
|
|
{currentQuestionData.QUESTION_TYPE === "TFQ" && (
|
|
<div className="options-tf">
|
|
<div
|
|
key={0}
|
|
className={`p-0 mb-3 form-check ${answers[currentQuestion] === 0 ? 'selected-answer' : ''}`}
|
|
style={{ display: 'flex', alignItems: 'center', cursor: 'pointer' }}
|
|
onClick={() => handleAnswerSelect(0)}
|
|
>
|
|
<span className="option-label">A</span>
|
|
<span className="ms-2 option-text">TRUE</span>
|
|
</div>
|
|
<div
|
|
key={1}
|
|
className={`p-0 mb-3 form-check ${answers[currentQuestion] === 1 ? 'selected-answer' : ''}`}
|
|
style={{ display: 'flex', alignItems: 'center', cursor: 'pointer' }}
|
|
onClick={() => handleAnswerSelect(1)}
|
|
>
|
|
<span className="option-label">B</span>
|
|
<span className="ms-2 option-text">FALSE</span>
|
|
</div>
|
|
</div>
|
|
)}
|
|
{currentQuestionData.QUESTION_TYPE === "MPQ" &&(
|
|
// <div className="w-100 options-mp d-flex justify-content-between">
|
|
// <div>
|
|
// {currentQuestionData.matchingPairs?.map((option, idx) => (
|
|
// <div
|
|
// key={idx}
|
|
// className={`p-0 mb-3 form-check ${answers[currentQuestion] === idx ? 'selected-answer' : ''}`}
|
|
// style={{ display: 'flex', alignItems: 'center', cursor: 'pointer' }}
|
|
// onClick={() => handleLeftChoose(idx)}
|
|
// >
|
|
// <span className={`option-label left label-${idx + 1}${activeIndex === idx ? " active" : ""}`}>{idx + 1}</span>
|
|
// {/* <span className="option-label">{idx + 1}</span> */}
|
|
// {/* <span className="ms-2 option-text">{option.LEFT_PAIR}</span> */}
|
|
// <span className={`ms-2 option-text left label-${idx + 1}${activeIndex === idx ? " active" : ""}`}>{option.LEFT_PAIR}</span>
|
|
// </div>
|
|
// ))}
|
|
// </div>
|
|
// <div>
|
|
// {currentQuestionData.matchingPairs?.map((option, idx) => (
|
|
// <div
|
|
// key={idx}
|
|
// className={`p-0 mb-3 form-check ${answers[currentQuestion] === idx ? 'selected-answer' : ''}`}
|
|
// style={{ display: 'flex', alignItems: 'center', cursor: 'pointer' }}
|
|
// onClick={() => handleRightChoose(idx)}
|
|
// >
|
|
// <span className={`option-label label-${idx + 1}${activeIndex === idx ? " active" : ""}`}>{idx + 1}</span>
|
|
// {/* <span className="option-label">{idx + 1}</span> */}
|
|
// {/* <span className="ms-2 option-text">{option.LEFT_PAIR}</span> */}
|
|
// <span className={`ms-2 option-text label-${idx + 1}${activeIndex === idx ? " active" : ""}`}>{option.RIGHT_PAIR}</span>
|
|
// </div>
|
|
// ))}
|
|
// </div>
|
|
// </div>
|
|
<MatchingPairs pairData={currentQuestionData.matchingPairs} numberQuestion={currentQuestion} />
|
|
)}
|
|
</div>
|
|
</div>
|
|
</Col>
|
|
</Row>
|
|
|
|
<Alert show={showAlert} variant="danger" className="custom-alert" onClose={() => setShowAlert(false)} dismissible>
|
|
<Alert.Heading>ATTENTION!</Alert.Heading>
|
|
<span>Please answer all questions before submitting.</span>
|
|
</Alert>
|
|
|
|
{/* <Modal show={showModal} onHide={handleCloseModal} centered>
|
|
<Modal.Header closeButton>
|
|
<Modal.Title>Confirmation</Modal.Title>
|
|
</Modal.Header>
|
|
<Modal.Body>
|
|
<p>Are you sure you want to submit your answer?</p>
|
|
</Modal.Body>
|
|
<Modal.Footer>
|
|
<Button variant="secondary" onClick={handleCloseModal}>
|
|
Cancel
|
|
</Button>
|
|
<Button variant="primary" onClick={handleConfirmSubmit}>
|
|
Yes, Submit <i className="bi bi-send"></i>
|
|
</Button>
|
|
</Modal.Footer>
|
|
</Modal> */}
|
|
|
|
<Modal show={showModal} onHide={handleCloseModal} centered>
|
|
<Modal.Body className='p-4 d-flex flex-column items-center'>
|
|
<h4 className='mb-4 fw-bold text-dark'>Proceed with <span className='text-blue'>Submission</span>?</h4>
|
|
<img src={ilustration} alt="" />
|
|
<p className='my-3 text-muted fw-light'>Confirm submission? There's no going back.</p>
|
|
<div className="mt-4 w-100 d-flex justify-content-center">
|
|
<Button variant="outline-blue" className="w-50 py-2 px-5 mx-1 rounded-35" onClick={handleCloseModal}>Check Again</Button>
|
|
<Button variant="gd" className="w-50 py-2 px-5 mx-1 rounded-35" onClick={handleConfirmSubmit}>Confirm</Button>
|
|
</div>
|
|
</Modal.Body>
|
|
</Modal>
|
|
</Container>
|
|
);
|
|
};
|
|
|
|
export default Exercise;
|
|
|
|
|
|
|