Skip to content

Commit

Permalink
functionality to skip quizzes & be able to submit without responses (#16
Browse files Browse the repository at this point in the history
)

* add a feature to submit quiz automatically if no responses are made

* add a skip button at top right of quiz card

* trigger the CI
  • Loading branch information
HarshCasper authored Nov 26, 2024
1 parent 578b692 commit 84f9d65
Showing 1 changed file with 104 additions and 49 deletions.
153 changes: 104 additions & 49 deletions frontend/src/components/QuizPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ import {
LinearProgress,
Grid2 as Grid,
Alert,
IconButton,
} from '@mui/material';

import CloseIcon from '@mui/icons-material/Close';
import MainLayout from './QuizLayout';
import Mascot1 from '../Mascot1.svg';
import Mascot2 from '../Mascot2.svg';
Expand All @@ -29,6 +32,7 @@ function QuizPage() {
const [isSubmitting, setIsSubmitting] = useState(false);
const timerRef = useRef(null);
const questionStartTimeRef = useRef(null);
const hasSubmittedRef = useRef(false);

useEffect(() => {
if (!quizID || !username) {
Expand All @@ -52,41 +56,77 @@ function QuizPage() {
});
}, [quizID, username, navigate]);

const handleSubmit = useCallback(() => {
setIsSubmitting(true);
const submissionData = {
Username: username,
QuizID: quizID,
Answers: answers,
};
if (email) {
submissionData.Email = email;
}
const handleSubmit = useCallback(
(timerExceeded = false) => {
if (hasSubmittedRef.current) return;
hasSubmittedRef.current = true;

fetch(`${process.env.REACT_APP_API_ENDPOINT}/submitquiz`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(submissionData),
})
.then((res) => res.json())
.then((data) => {
navigate('/result', {
state: { submissionID: data.SubmissionID, quizID },
});
setIsSubmitting(true);
const submissionData = {
Username: username,
QuizID: quizID,
Answers: answers,
};
if (email) {
submissionData.Email = email;
}
if (timerExceeded) {
submissionData.TimerExceeded = true;
}

fetch(`${process.env.REACT_APP_API_ENDPOINT}/submitquiz`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(submissionData),
})
.catch((err) => {
console.error('Error submitting quiz:', err);
alert('Failed to submit quiz. Please try again.');
setIsSubmitting(false);
});
}, [username, quizID, answers, email, navigate]);
.then((res) => res.json())
.then((data) => {
navigate('/result', {
state: { submissionID: data.SubmissionID, quizID },
});
})
.catch((err) => {
console.error('Error submitting quiz:', err);
alert('Failed to submit quiz. Please try again.');
setIsSubmitting(false);
hasSubmittedRef.current = false;
});
},
[username, quizID, answers, email, navigate]
);

const moveToNextQuestion = useCallback(() => {
if (quizData && currentQuestionIndex < quizData.Questions.length - 1) {
setCurrentQuestionIndex((prevIndex) => prevIndex + 1);
}
}, [quizData, currentQuestionIndex]);

const handleSkip = () => {
const timeTaken =
quizData && quizData.EnableTimer ? quizData.TimerSeconds - timeLeft : 0;

setAnswers((prevAnswers) => ({
...prevAnswers,
[currentQuestionIndex]: {
Answer: '',
TimeTaken: timeTaken,
Skipped: true,
},
}));

if (quizData && quizData.EnableTimer && timerRef.current) {
clearInterval(timerRef.current);
}

if (currentQuestionIndex < quizData.Questions.length - 1) {
moveToNextQuestion();
} else {
if (!hasSubmittedRef.current) {
handleSubmit();
}
}
};

useEffect(() => {
if (quizData && quizData.EnableTimer) {
if (timerRef.current) {
Expand All @@ -109,6 +149,9 @@ function QuizPage() {
if (currentQuestionIndex < quizData.Questions.length - 1) {
moveToNextQuestion();
} else {
if (!hasSubmittedRef.current) {
handleSubmit(true);
}
}
};

Expand All @@ -125,7 +168,7 @@ function QuizPage() {

return () => clearInterval(timerRef.current);
}
}, [currentQuestionIndex, quizData, moveToNextQuestion]);
}, [currentQuestionIndex, quizData, moveToNextQuestion, handleSubmit]);

const handleOptionChange = (e) => {
const selectedOption = e.target.value;
Expand All @@ -140,11 +183,16 @@ function QuizPage() {
},
}));

if (quizData && quizData.EnableTimer && timerRef.current) {
clearInterval(timerRef.current);
}

if (currentQuestionIndex < quizData.Questions.length - 1) {
if (quizData && quizData.EnableTimer && timerRef.current) {
clearInterval(timerRef.current);
}
moveToNextQuestion();
} else {
if (!hasSubmittedRef.current) {
handleSubmit();
}
}
};

Expand All @@ -168,7 +216,19 @@ function QuizPage() {

return (
<MainLayout>
<Container maxWidth="sm" className="main-quiz-container">
<Container maxWidth="sm" className="main-quiz-container" sx={{ position: 'relative' }}>
{/* Skip Button at Top Right */}
{!isSubmitting && (
<IconButton
onClick={handleSkip}
disabled={isSubmitting || isTimeUp}
sx={{ position: 'absolute', top: 8, right: 8 }}
aria-label="Skip"
>
<CloseIcon />
</IconButton>
)}

<Typography variant="h6" gutterBottom align="left" width={'100%'}>
Question {currentQuestionIndex + 1} / {quizData.Questions.length}
</Typography>
Expand Down Expand Up @@ -227,32 +287,27 @@ function QuizPage() {
))}
</RadioGroup>

{isSubmitting && (
{!isSubmitting && currentQuestionIndex === quizData.Questions.length - 1 && (
<Box sx={{ textAlign: 'center', marginTop: 4 }}>
<CircularProgress />
<Typography variant="h6" sx={{ marginTop: 2 }}>
Submitting your answers...
</Typography>
</Box>
)}

{!isSubmitting &&
quizData &&
currentQuestionIndex === quizData.Questions.length - 1 && (
<Button
variant="contained"
color="primary"
onClick={handleSubmit}
disabled={
Object.keys(answers).length !== quizData.Questions.length ||
isSubmitting ||
isTimeUp
}
sx={{ marginTop: 4 }}
disabled={isSubmitting || isTimeUp}
>
Submit Quiz
</Button>
)}
</Box>
)}

{isSubmitting && (
<Box sx={{ textAlign: 'center', marginTop: 4 }}>
<CircularProgress />
<Typography variant="h6" sx={{ marginTop: 2 }}>
Submitting your answers...
</Typography>
</Box>
)}
</Container>
<div className="character-container">
{currentQuestionIndex % 3 === 0 && (
Expand Down

0 comments on commit 84f9d65

Please sign in to comment.