├── src
├── index.css
├── main.jsx
├── assets
│ └── react.svg
└── App.jsx
├── vite.config.js
├── .gitignore
├── index.html
├── README.md
├── package.json
├── eslint.config.js
└── public
└── vite.svg
/src/index.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/src/main.jsx:
--------------------------------------------------------------------------------
1 | import { createRoot } from 'react-dom/client';
2 | import App from './App.jsx';
3 | import './index.css';
4 | import 'bootstrap/dist/css/bootstrap.min.css';
5 |
6 | createRoot(document.getElementById('root')).render(
7 |
8 | )
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Quiz
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # React + Vite
2 |
3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4 |
5 | Currently, two official plugins are available:
6 |
7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-quiz-app",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "lint": "eslint .",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "@emotion/react": "^11.13.3",
14 | "@emotion/styled": "^11.13.0",
15 | "@mui/icons-material": "^6.1.0",
16 | "@mui/material": "^6.1.0",
17 | "@mui/styled-engine-sc": "^6.1.0",
18 | "axios": "^1.7.7",
19 | "bootstrap": "^5.3.3",
20 | "react": "^18.3.1",
21 | "react-dom": "^18.3.1",
22 | "styled-components": "^6.1.13"
23 | },
24 | "devDependencies": {
25 | "@eslint/js": "^9.9.0",
26 | "@types/react": "^18.3.3",
27 | "@types/react-dom": "^18.3.0",
28 | "@vitejs/plugin-react": "^4.3.1",
29 | "eslint": "^9.9.0",
30 | "eslint-plugin-react": "^7.35.0",
31 | "eslint-plugin-react-hooks": "^5.1.0-rc.0",
32 | "eslint-plugin-react-refresh": "^0.4.9",
33 | "globals": "^15.9.0",
34 | "vite": "^5.4.1"
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/eslint.config.js:
--------------------------------------------------------------------------------
1 | import js from '@eslint/js'
2 | import globals from 'globals'
3 | import react from 'eslint-plugin-react'
4 | import reactHooks from 'eslint-plugin-react-hooks'
5 | import reactRefresh from 'eslint-plugin-react-refresh'
6 |
7 | export default [
8 | { ignores: ['dist'] },
9 | {
10 | files: ['**/*.{js,jsx}'],
11 | languageOptions: {
12 | ecmaVersion: 2020,
13 | globals: globals.browser,
14 | parserOptions: {
15 | ecmaVersion: 'latest',
16 | ecmaFeatures: { jsx: true },
17 | sourceType: 'module',
18 | },
19 | },
20 | settings: { react: { version: '18.3' } },
21 | plugins: {
22 | react,
23 | 'react-hooks': reactHooks,
24 | 'react-refresh': reactRefresh,
25 | },
26 | rules: {
27 | ...js.configs.recommended.rules,
28 | ...react.configs.recommended.rules,
29 | ...react.configs['jsx-runtime'].rules,
30 | ...reactHooks.configs.recommended.rules,
31 | 'react/jsx-no-target-blank': 'off',
32 | 'react-refresh/only-export-components': [
33 | 'warn',
34 | { allowConstantExport: true },
35 | ],
36 | },
37 | },
38 | ]
39 |
--------------------------------------------------------------------------------
/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/react.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/App.jsx:
--------------------------------------------------------------------------------
1 | import {
2 | Box,
3 | Button,
4 | Typography,
5 | CircularProgress,
6 | Paper,
7 | Radio,
8 | RadioGroup,
9 | FormControlLabel,
10 | FormControl,
11 | } from "@mui/material";
12 | import axios from "axios";
13 | import React, { useEffect, useState } from "react";
14 |
15 | function App() {
16 | const [questions, setQuestions] = useState([]);
17 | const [questionState, setQuestionState] = useState(0);
18 | const [selectedAnswer, setSelectedAnswer] = useState(null);
19 | const [shuffledAnswers, setShuffledAnswers] = useState([]);
20 | const [isQuizComplete, setIsQuizComplete] = useState(false);
21 | const [score, setScore] = useState(0);
22 | const [loading, setLoading] = useState(true);
23 |
24 |
25 | useEffect(() => {
26 | axios
27 | .get("https://the-trivia-api.com/v2/questions")
28 | .then((res) => {
29 | setQuestions(res.data);
30 | setLoading(false);
31 | shuffleAnswers(res.data[0]); // Shuffle answers for the first question
32 | })
33 | .catch((err) => {
34 | console.log(err);
35 | setLoading(false);
36 | });
37 | }, []);
38 |
39 | function shuffleAnswers(question) {
40 | const answers = [
41 | ...question.incorrectAnswers,
42 | question.correctAnswer,
43 | ];
44 | for (let i = answers.length - 1; i > 0; i--) {
45 | const j = Math.floor(Math.random() * (i + 1));
46 | [answers[i], answers[j]] = [answers[j], answers[i]];
47 | }
48 | setShuffledAnswers(answers); // Set shuffled answers in the state
49 | }
50 |
51 | const handleNextQuestion = () => {
52 | if (!selectedAnswer) {
53 | alert("Please select an answer!");
54 | return;
55 | }
56 |
57 | if (selectedAnswer === questions[questionState].correctAnswer) {
58 | setScore(score + 1);
59 | }
60 |
61 | if (questionState < questions.length - 1) {
62 | setQuestionState(questionState + 1);
63 | setSelectedAnswer(null);
64 | shuffleAnswers(questions[questionState + 1]); // Shuffle answers for the next question
65 | } else {
66 | setIsQuizComplete(true);
67 | }
68 | };
69 |
70 | const renderQuestion = () => {
71 | const currentQuestion = questions[questionState];
72 |
73 | return (
74 |
87 |
88 | Question {questionState + 1} of {questions.length}
89 |
90 |
91 | {currentQuestion.question.text}
92 |
93 |
94 |
95 | setSelectedAnswer(e.target.value)}
99 | >
100 | {shuffledAnswers.map((answer, index) => (
101 | }
105 | label={answer}
106 | style={{ marginBottom: "10px" }}
107 | />
108 | ))}
109 |
110 |
111 |
112 |
120 |
121 | );
122 | };
123 |
124 | const renderQuizResult = () => (
125 |
138 |
139 | Quiz Completed!
140 |
141 |
142 | Your score: {score} / {questions.length}
143 |
144 |
152 |
153 | );
154 |
155 | return (
156 |
157 |
158 | Quiz App
159 |
160 |
161 | {loading && }
162 |
163 | {!loading && questions.length > 0 && !isQuizComplete && renderQuestion()}
164 |
165 | {isQuizComplete && renderQuizResult()}
166 |
167 | );
168 | }
169 |
170 | export default App;
171 |
--------------------------------------------------------------------------------