From 09dd8188cd7824aae0b117e05a9b13d993315e19 Mon Sep 17 00:00:00 2001 From: Areeb Ahmed <135235925+areebahmeddd@users.noreply.github.com> Date: Mon, 27 May 2024 23:44:04 +0530 Subject: [PATCH 1/2] FIXED:#44 Allowed Shuffling Of Quiz Questions and MCQ Options All questions and its options are shuffled before loading. --- app/[quizid]/page.tsx | 158 ++++++++++++++++++++---------------------- 1 file changed, 77 insertions(+), 81 deletions(-) diff --git a/app/[quizid]/page.tsx b/app/[quizid]/page.tsx index 367eb39..2c2681c 100644 --- a/app/[quizid]/page.tsx +++ b/app/[quizid]/page.tsx @@ -2,15 +2,11 @@ import React, { useState, useEffect } from 'react'; import { onAuthStateChanged } from 'firebase/auth'; import { useRouter, useSearchParams } from 'next/navigation'; -import { collection, getDocs , arrayUnion , addDoc , doc , updateDoc} from 'firebase/firestore'; +import { collection, getDocs, arrayUnion, updateDoc, doc } from 'firebase/firestore'; import { auth, db } from '../firebase'; // Import Firestore and auth -import {formatDateTime} from '../Date'; +import { formatDateTime } from '../Date'; import toast from 'react-hot-toast'; - - - - // Define a type for your quiz question type QuizQuestion = { question: string; @@ -19,15 +15,13 @@ type QuizQuestion = { }; function Quiz() { - const quizTime = 600000; // This can be updated to allow for custom quiz times - const router = useRouter(); - const SearchParams = useSearchParams(); - const quizId : any = SearchParams.get('id') - const quizName : any = SearchParams.get('name') - const course : any = SearchParams.get('course') - const courseCode : any = SearchParams.get('coursecode') + const searchParams = useSearchParams(); + const quizId: any = searchParams.get('id'); + const quizName: any = searchParams.get('name'); + const course: any = searchParams.get('course'); + const courseCode: any = searchParams.get('coursecode'); const [user, setUser] = useState(null); // User authentication state const [questions, setQuestions] = useState([]); // Provide type annotation for questions const [currentQuestionIndex, setCurrentQuestionIndex] = useState(0); @@ -35,11 +29,18 @@ function Quiz() { const [score, setScore] = useState(0); const [isFinalQuestion, setIsFinalQuestion] = useState(false); const [isTimeUp, setIsTimeUp] = useState(false); - const [timeLeft, setTimeLeft] = useState(quizTime/1000); // Time limit in seconds + const [timeLeft, setTimeLeft] = useState(quizTime / 1000); // Time limit in seconds + // Function to shuffle an array + function shuffleArray(array: any[]) { + for (let i = array.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [array[i], array[j]] = [array[j], array[i]]; + } + } async function fetchQuizData() { - let toReturn : any = null; + let toReturn: any = null; const quizRef = collection(db, 'quizzes'); const quizDoc = await getDocs(quizRef); if (quizDoc) { @@ -48,35 +49,35 @@ function Quiz() { const reqQuiz = quizData.data.id; if (reqQuiz == quizId) { toReturn = quizData.data; - // console.log(quizData.data) + // Shuffle options array for each question + toReturn.quizData.forEach((question: QuizQuestion) => { + shuffleArray(question.options); + }); } - - }); - return toReturn - } - else{ - return null + }); + return toReturn; + } else { + return null; } - } // Update the useEffect hook where the timer is set -useEffect(() => { - const timer = setTimeout(() => { - setIsTimeUp(true); - }, quizTime); - - const interval = setInterval(() => { - setTimeLeft((prevTimeLeft) => prevTimeLeft - 1); - }, 1000); // Decrease timeLeft by 1 every second + useEffect(() => { + const timer = setTimeout(() => { + setIsTimeUp(true); + }, quizTime); + + const interval = setInterval(() => { + setTimeLeft((prevTimeLeft) => prevTimeLeft - 1); + }, 1000); // Decrease timeLeft by 1 every second + + // Clear the timer and the interval when the component unmounts or when the time is up + return () => { + clearTimeout(timer); + clearInterval(interval); + }; + }, []); - // Clear the timer and the interval when the component unmounts or when the time is up - return () => { - clearTimeout(timer); - clearInterval(interval); - }; -}, []); - useEffect(() => { if (isTimeUp) { console.log('Time is up!'); @@ -96,14 +97,16 @@ useEffect(() => { } }); - async function fetchData() { - const data = await fetchQuizData().then((data) => { return data }); - // console.log(data.quizData) - setQuestions(data.quizData); + async function fetchData() { + const data = await fetchQuizData(); + if (data) { + // Shuffle the questions before setting them in state + shuffleArray(data.quizData); + setQuestions(data.quizData); } - fetchData(); + } + fetchData(); }, []); - useEffect(() => { setIsFinalQuestion(currentQuestionIndex === questions.length - 1); @@ -120,7 +123,7 @@ useEffect(() => { // Increase the score if the selected option is correct setScore((prevScore) => prevScore + 1); } - + if (currentQuestionIndex < questions.length - 1) { setCurrentQuestionIndex(currentQuestionIndex + 1); } @@ -132,36 +135,33 @@ useEffect(() => { } } - - - const handleQuizSubmit = async () => { + const handleQuizSubmit = async () => { const user = auth.currentUser; if (!user) { console.error('User not authenticated'); - toast.error("User not authenticated") + toast.error("User not authenticated"); return; } - - let myScore = 0 - const correctAnswers = questions.map((question : any) => question.correctAnswer) - - //check if all questions are attempted - if (selectedOptions.length !== correctAnswers.length && !isTimeUp){ - toast.error("Please attempt all of the questions") - return + let myScore = 0; + const correctAnswers = questions.map((question: any) => question.correctAnswer); + + // Check if all questions are attempted + if (selectedOptions.length !== correctAnswers.length && !isTimeUp) { + toast.error("Please attempt all of the questions"); + return; } - - for(let i = 0; i < selectedOptions.length; i++){ - if(selectedOptions[i] == correctAnswers[i]){ - myScore = myScore + 1 + + for (let i = 0; i < selectedOptions.length; i++) { + if (selectedOptions[i] == correctAnswers[i]) { + myScore = myScore + 1; } } var d = new Date(); var n = formatDateTime(d); const quizResults = { - score : myScore, + score: myScore, totalQuestions: questions.length, selectedOptions, correctAnswers: questions.map((question) => question.correctAnswer), @@ -173,31 +173,28 @@ useEffect(() => { time: n }; - try { - // Create a reference to the user's document - const userDocRef = doc(db, 'users', user.uid); + try { + // Create a reference to the user's document + const userDocRef = doc(db, 'users', user.uid); - await updateDoc(userDocRef as any, { - quizData: arrayUnion(quizResults), - }); - console.log(`Quiz Completed! Your Score: ${score}/${questions.length}`); - toast.success('Quiz Submitted Succesfully!'); - // Redirect to the results page - router.push(`/results`); + await updateDoc(userDocRef as any, { + quizData: arrayUnion(quizResults), + }); + console.log(`Quiz Completed! Your Score: ${score}/${questions.length}`); + toast.success('Quiz Submitted Successfully!'); + // Redirect to the results page + router.push(`/results`); } catch (error) { console.error('Error storing quiz results:', error); toast.error('Error storing quiz results, Check Console'); } } - - const currentQuestion = questions[currentQuestionIndex]; - + const currentQuestion = questions[currentQuestionIndex]; return (
- {currentQuestion ? (

Question {currentQuestionIndex + 1}:

@@ -206,11 +203,10 @@ useEffect(() => { {currentQuestion.options.map((option, index) => (
handleOptionSelect(option)} > {option} @@ -227,8 +223,8 @@ useEffect(() => { )}
- Time left: {timeLeft} seconds -
+ Time left: {timeLeft} seconds +
{isFinalQuestion ? ( )}
- Time left: {timeLeft} seconds + Time left: {Math.floor(timeLeft / 60)} minutes {timeLeft % 60} seconds
{isFinalQuestion ? (