diff --git a/src/App.tsx b/src/App.tsx index b4dc964e..31c9c37c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,225 +1,15 @@ -import React, { useState, useEffect } from "react"; -import SelectQuestionsTotal from "./pages/SelectQuestionsTotal"; -import SelectCategory from "./pages/SelectCategory"; -import { ALL_CATEGORIES, QUESTION_NUMS } from "./constants"; -import Results from "./pages/Results"; -import shuffle from "./shuffle-arr"; - -import FCCLogo from "./components/FCCLogo"; -import Questions from "./pages/Questions"; -import "./stylesheets/App.css"; -import { - correctModalResponses, - incorrectModalResponses -} from "./data/modal-responses"; -import ButtonLink from "./components/ButtonLink"; -import { Route, Routes, useNavigate } from "react-router-dom"; - -const Main: React.FC = () => { - const navigate = useNavigate(); - const [quiz, setQuiz] = useState(ALL_CATEGORIES); - const [questionNumber, setQuestionNumber] = useState(1); - const [points, setPoints] = useState(0); - const [message, setMessage] = useState(""); - const [correct, setCorrect] = useState(false); - const [displayExplanation, setDisplayExplanation] = useState(""); - const [showReference, setShowReference] = useState(""); - const [selectedOption, setSelectedOption] = useState(""); - const [chosenAnswer, setChosenAnswer] = useState(""); - const [chooseAnswer, setChooseAnswer] = useState(false); - const [show, setShowModal] = useState(false); - - const [choicesArr, setChoicesArr] = useState([]); - const currQuestion = quiz[questionNumber - 1]; - const totalQuestions = quiz.length; - const [filteredQuestions, setFilteredQuestions] = useState(ALL_CATEGORIES); - - //detects if the user tries the refresh the page in the middle of the quiz - useEffect(() => { - window.addEventListener("beforeunload", alertUser); - return () => { - window.removeEventListener("beforeunload", alertUser); - }; - }, []); - - const alertUser = (e: { - preventDefault: () => void; - returnValue: string; - }) => { - e.preventDefault(); - e.returnValue = ""; - }; - const [selectedCategory, setSelectedCategory] = useState(""); - const [, setSelectedQuiz] = useState(0); - - const selectQuiz = (category: string, index: number) => { - setSelectedCategory(category); - setSelectedQuiz(QUESTION_NUMS[index]); - // Filter questions based on the selected category - const filteredQuiz = ALL_CATEGORIES.filter(q => q.Category === category); - setFilteredQuestions(filteredQuiz); - navigate(`/quizzes/${category}/questionsTotal`); - }; - - const startQuiz = (quizQuestionsCount: number) => { - const shuffledQuiz = shuffle(filteredQuestions).slice( - 0, - quizQuestionsCount - ); - - // Shuffle the answer options - const choicesArr: string[][] = shuffledQuiz.map(obj => { - const arr = [ - obj.Answer, - obj.Distractor1, - obj.Distractor2, - obj.Distractor3 - ]; - return shuffle(arr); - }); - - setQuiz(shuffledQuiz); - setChoicesArr(choicesArr); - navigate( - `/quizzes/${selectedCategory}/questions/1/of/${quizQuestionsCount}` - ); - }; - - // Function to start a random quiz - const startRandomQuiz = () => { - setSelectedCategory("Random"); // Set the selected category to "Random" - const randomIndex = Math.floor(Math.random() * QUESTION_NUMS.length); - setSelectedQuiz(QUESTION_NUMS[randomIndex]); - // Generate a random set of questions - const randomQuestions = shuffle(ALL_CATEGORIES).slice( - 0, - QUESTION_NUMS[randomIndex] - ); - setQuiz(randomQuestions); - navigate(`/quizzes/Random/questionsTotal`); - }; - - const nextQuestion = () => { - if (questionNumber >= quiz.length) { - navigate(`/quizzes/${selectedCategory}/results`); - return; - } - setQuestionNumber(curr => curr + 1); - setChooseAnswer(false); - navigate( - `/quizzes/${selectedCategory}/questions/${questionNumber + 1}/of/${ - quiz.length - }` - ); - }; - - const resetQuiz = () => { - setSelectedCategory(""); // Reset selected category - setSelectedQuiz(0); // Reset selected quiz - setShowModal(false); - setChooseAnswer(false); - setPoints(0); - setQuestionNumber(1); - navigate(`/quizzes`); - }; - - const shuffleModalResponses = (responses: string[]) => { - const shuffleModalArr = shuffle(responses); - return shuffleModalArr[0]; - }; - - const selectOption = (option: string) => setSelectedOption(option); - - const checkAnswer = () => { - const userAnswer = selectedOption; - - // Ensure option was selected before checking answer - if (!userAnswer) { - return; - } - - setSelectedOption(""); - setChooseAnswer(true); - setChosenAnswer(userAnswer); - if (userAnswer !== currQuestion.Answer) { - setCorrect(false); - setMessage(shuffleModalResponses(incorrectModalResponses)); - setDisplayExplanation(currQuestion.Explanation); - setShowReference(currQuestion.Link); - setShowModal(true); - } else { - setCorrect(true); - setPoints(curr => curr + 1); - setMessage(shuffleModalResponses(correctModalResponses)); - setDisplayExplanation(currQuestion.Explanation); - setShowReference(currQuestion.Link); - setShowModal(true); - } - }; - - const modalProps = { - correct, - chosenAnswer, - message, - points, - displayExplanation, - showReference, - show, - nextQuestion - }; - - const resultsProps = { - points, - totalQuestions, - resetQuiz - }; - - const questionProps = { - currQuestion, - questionNumber, - totalQuestions, - modalProps, - chooseAnswer, - points, - choicesArr, - selectedOption, - selectOption, - checkAnswer - }; +import WelcomePage from "./pages/WelcomePage"; +import QuizTemplate from "./QuizTemplate"; +import React from "react"; +import { Route, Routes } from "react-router-dom"; +const App: React.FC = () => { return ( - <> - Home - - - - } - /> - - } - /> - } - /> - } - /> - - + + } /> + } /> + ); }; -export default Main; + +export default App; diff --git a/src/QuizTemplate.tsx b/src/QuizTemplate.tsx new file mode 100644 index 00000000..b4dc964e --- /dev/null +++ b/src/QuizTemplate.tsx @@ -0,0 +1,225 @@ +import React, { useState, useEffect } from "react"; +import SelectQuestionsTotal from "./pages/SelectQuestionsTotal"; +import SelectCategory from "./pages/SelectCategory"; +import { ALL_CATEGORIES, QUESTION_NUMS } from "./constants"; +import Results from "./pages/Results"; +import shuffle from "./shuffle-arr"; + +import FCCLogo from "./components/FCCLogo"; +import Questions from "./pages/Questions"; +import "./stylesheets/App.css"; +import { + correctModalResponses, + incorrectModalResponses +} from "./data/modal-responses"; +import ButtonLink from "./components/ButtonLink"; +import { Route, Routes, useNavigate } from "react-router-dom"; + +const Main: React.FC = () => { + const navigate = useNavigate(); + const [quiz, setQuiz] = useState(ALL_CATEGORIES); + const [questionNumber, setQuestionNumber] = useState(1); + const [points, setPoints] = useState(0); + const [message, setMessage] = useState(""); + const [correct, setCorrect] = useState(false); + const [displayExplanation, setDisplayExplanation] = useState(""); + const [showReference, setShowReference] = useState(""); + const [selectedOption, setSelectedOption] = useState(""); + const [chosenAnswer, setChosenAnswer] = useState(""); + const [chooseAnswer, setChooseAnswer] = useState(false); + const [show, setShowModal] = useState(false); + + const [choicesArr, setChoicesArr] = useState([]); + const currQuestion = quiz[questionNumber - 1]; + const totalQuestions = quiz.length; + const [filteredQuestions, setFilteredQuestions] = useState(ALL_CATEGORIES); + + //detects if the user tries the refresh the page in the middle of the quiz + useEffect(() => { + window.addEventListener("beforeunload", alertUser); + return () => { + window.removeEventListener("beforeunload", alertUser); + }; + }, []); + + const alertUser = (e: { + preventDefault: () => void; + returnValue: string; + }) => { + e.preventDefault(); + e.returnValue = ""; + }; + const [selectedCategory, setSelectedCategory] = useState(""); + const [, setSelectedQuiz] = useState(0); + + const selectQuiz = (category: string, index: number) => { + setSelectedCategory(category); + setSelectedQuiz(QUESTION_NUMS[index]); + // Filter questions based on the selected category + const filteredQuiz = ALL_CATEGORIES.filter(q => q.Category === category); + setFilteredQuestions(filteredQuiz); + navigate(`/quizzes/${category}/questionsTotal`); + }; + + const startQuiz = (quizQuestionsCount: number) => { + const shuffledQuiz = shuffle(filteredQuestions).slice( + 0, + quizQuestionsCount + ); + + // Shuffle the answer options + const choicesArr: string[][] = shuffledQuiz.map(obj => { + const arr = [ + obj.Answer, + obj.Distractor1, + obj.Distractor2, + obj.Distractor3 + ]; + return shuffle(arr); + }); + + setQuiz(shuffledQuiz); + setChoicesArr(choicesArr); + navigate( + `/quizzes/${selectedCategory}/questions/1/of/${quizQuestionsCount}` + ); + }; + + // Function to start a random quiz + const startRandomQuiz = () => { + setSelectedCategory("Random"); // Set the selected category to "Random" + const randomIndex = Math.floor(Math.random() * QUESTION_NUMS.length); + setSelectedQuiz(QUESTION_NUMS[randomIndex]); + // Generate a random set of questions + const randomQuestions = shuffle(ALL_CATEGORIES).slice( + 0, + QUESTION_NUMS[randomIndex] + ); + setQuiz(randomQuestions); + navigate(`/quizzes/Random/questionsTotal`); + }; + + const nextQuestion = () => { + if (questionNumber >= quiz.length) { + navigate(`/quizzes/${selectedCategory}/results`); + return; + } + setQuestionNumber(curr => curr + 1); + setChooseAnswer(false); + navigate( + `/quizzes/${selectedCategory}/questions/${questionNumber + 1}/of/${ + quiz.length + }` + ); + }; + + const resetQuiz = () => { + setSelectedCategory(""); // Reset selected category + setSelectedQuiz(0); // Reset selected quiz + setShowModal(false); + setChooseAnswer(false); + setPoints(0); + setQuestionNumber(1); + navigate(`/quizzes`); + }; + + const shuffleModalResponses = (responses: string[]) => { + const shuffleModalArr = shuffle(responses); + return shuffleModalArr[0]; + }; + + const selectOption = (option: string) => setSelectedOption(option); + + const checkAnswer = () => { + const userAnswer = selectedOption; + + // Ensure option was selected before checking answer + if (!userAnswer) { + return; + } + + setSelectedOption(""); + setChooseAnswer(true); + setChosenAnswer(userAnswer); + if (userAnswer !== currQuestion.Answer) { + setCorrect(false); + setMessage(shuffleModalResponses(incorrectModalResponses)); + setDisplayExplanation(currQuestion.Explanation); + setShowReference(currQuestion.Link); + setShowModal(true); + } else { + setCorrect(true); + setPoints(curr => curr + 1); + setMessage(shuffleModalResponses(correctModalResponses)); + setDisplayExplanation(currQuestion.Explanation); + setShowReference(currQuestion.Link); + setShowModal(true); + } + }; + + const modalProps = { + correct, + chosenAnswer, + message, + points, + displayExplanation, + showReference, + show, + nextQuestion + }; + + const resultsProps = { + points, + totalQuestions, + resetQuiz + }; + + const questionProps = { + currQuestion, + questionNumber, + totalQuestions, + modalProps, + chooseAnswer, + points, + choicesArr, + selectedOption, + selectOption, + checkAnswer + }; + + return ( + <> + Home + + + + } + /> + + } + /> + } + /> + } + /> + + + ); +}; +export default Main; diff --git a/src/__tests__/App.test.tsx b/src/__tests__/App.test.tsx index 46a1c759..43c759f5 100644 --- a/src/__tests__/App.test.tsx +++ b/src/__tests__/App.test.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { App } from "../index"; +import App from "../App"; import { cleanup, render } from "@testing-library/react"; import { HashRouter as Router } from "react-router-dom"; import { afterEach, describe, it } from "vitest"; diff --git a/src/index.tsx b/src/index.tsx index 10daa3a1..eca80c7f 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,22 +1,11 @@ import React from "react"; import { createRoot } from "react-dom/client"; -import { Route, Routes } from "react-router-dom"; -import WelcomePage from "./pages/WelcomePage"; -import App from "./App"; - -import reportWebVitals from "./reportWebVitals"; import { RouterProvider, createHashRouter } from "react-router-dom"; -export const MainApp: React.FC = () => { - return ( - - } /> - } /> - - ); -}; +import reportWebVitals from "./reportWebVitals"; +import App from "./App"; -const router = createHashRouter([{ path: "*", Component: MainApp }]); +const router = createHashRouter([{ path: "*", Component: App }]); const root = document.getElementById("root"); createRoot(root || document.createElement("div")).render(