diff --git a/code/13 Demo Project - React Quiz/08-finished/.gitignore b/code/13 Demo Project - React Quiz/08-finished/.gitignore
deleted file mode 100644
index a547bf36d..000000000
--- a/code/13 Demo Project - React Quiz/08-finished/.gitignore
+++ /dev/null
@@ -1,24 +0,0 @@
-# Logs
-logs
-*.log
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-pnpm-debug.log*
-lerna-debug.log*
-
-node_modules
-dist
-dist-ssr
-*.local
-
-# Editor directories and files
-.vscode/*
-!.vscode/extensions.json
-.idea
-.DS_Store
-*.suo
-*.ntvs*
-*.njsproj
-*.sln
-*.sw?
diff --git a/code/13 Demo Project - React Quiz/08-finished/index.html b/code/13 Demo Project - React Quiz/08-finished/index.html
deleted file mode 100644
index 9ae9a44e2..000000000
--- a/code/13 Demo Project - React Quiz/08-finished/index.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
- ReactQuiz
-
-
-
-
-
-
diff --git a/code/13 Demo Project - React Quiz/08-finished/package.json b/code/13 Demo Project - React Quiz/08-finished/package.json
deleted file mode 100644
index f7646cbb5..000000000
--- a/code/13 Demo Project - React Quiz/08-finished/package.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
- "name": "effects-adv-prj",
- "private": true,
- "version": "0.0.0",
- "type": "module",
- "scripts": {
- "dev": "vite",
- "build": "vite build",
- "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
- "preview": "vite preview"
- },
- "dependencies": {
- "react": "^18.2.0",
- "react-dom": "^18.2.0"
- },
- "devDependencies": {
- "@types/react": "^18.2.15",
- "@types/react-dom": "^18.2.7",
- "@vitejs/plugin-react": "^4.0.3",
- "eslint": "^8.45.0",
- "eslint-plugin-react": "^7.32.2",
- "eslint-plugin-react-hooks": "^4.6.0",
- "eslint-plugin-react-refresh": "^0.4.3",
- "vite": "^4.4.5"
- }
-}
diff --git a/code/13 Demo Project - React Quiz/08-finished/public/quiz-logo.png b/code/13 Demo Project - React Quiz/08-finished/public/quiz-logo.png
deleted file mode 100644
index dbcd77059..000000000
Binary files a/code/13 Demo Project - React Quiz/08-finished/public/quiz-logo.png and /dev/null differ
diff --git a/code/13 Demo Project - React Quiz/08-finished/src/App.jsx b/code/13 Demo Project - React Quiz/08-finished/src/App.jsx
deleted file mode 100644
index 6e001d8a6..000000000
--- a/code/13 Demo Project - React Quiz/08-finished/src/App.jsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import Header from './components/Header.jsx';
-import Quiz from './components/Quiz.jsx';
-
-function App() {
- return (
- <>
-
-
-
-
- >
- );
-}
-
-export default App;
diff --git a/code/13 Demo Project - React Quiz/08-finished/src/assets/quiz-complete.png b/code/13 Demo Project - React Quiz/08-finished/src/assets/quiz-complete.png
deleted file mode 100644
index 4e235aea8..000000000
Binary files a/code/13 Demo Project - React Quiz/08-finished/src/assets/quiz-complete.png and /dev/null differ
diff --git a/code/13 Demo Project - React Quiz/08-finished/src/assets/quiz-logo.png b/code/13 Demo Project - React Quiz/08-finished/src/assets/quiz-logo.png
deleted file mode 100644
index dbcd77059..000000000
Binary files a/code/13 Demo Project - React Quiz/08-finished/src/assets/quiz-logo.png and /dev/null differ
diff --git a/code/13 Demo Project - React Quiz/08-finished/src/components/Answers.jsx b/code/13 Demo Project - React Quiz/08-finished/src/components/Answers.jsx
deleted file mode 100644
index 5a6114aad..000000000
--- a/code/13 Demo Project - React Quiz/08-finished/src/components/Answers.jsx
+++ /dev/null
@@ -1,47 +0,0 @@
-import { useRef } from 'react';
-
-export default function Answers({
- answers,
- selectedAnswer,
- answerState,
- onSelect,
-}) {
- const shuffledAnswers = useRef();
-
- if (!shuffledAnswers.current) {
- shuffledAnswers.current = [...answers];
- shuffledAnswers.current.sort(() => Math.random() - 0.5);
- }
-
- return (
-
- {shuffledAnswers.current.map((answer) => {
- const isSelected = selectedAnswer === answer;
- let cssClass = '';
-
- if (answerState === 'answered' && isSelected) {
- cssClass = 'selected';
- }
-
- if (
- (answerState === 'correct' || answerState === 'wrong') &&
- isSelected
- ) {
- cssClass = answerState;
- }
-
- return (
- -
-
-
- );
- })}
-
- );
-}
diff --git a/code/13 Demo Project - React Quiz/08-finished/src/components/Header.jsx b/code/13 Demo Project - React Quiz/08-finished/src/components/Header.jsx
deleted file mode 100644
index 0d2d8a37a..000000000
--- a/code/13 Demo Project - React Quiz/08-finished/src/components/Header.jsx
+++ /dev/null
@@ -1,10 +0,0 @@
-import logoImg from '../assets/quiz-logo.png';
-
-export default function Header() {
- return (
-
-
- ReactQuiz
-
- );
-}
diff --git a/code/13 Demo Project - React Quiz/08-finished/src/components/Question.jsx b/code/13 Demo Project - React Quiz/08-finished/src/components/Question.jsx
deleted file mode 100644
index f80550fab..000000000
--- a/code/13 Demo Project - React Quiz/08-finished/src/components/Question.jsx
+++ /dev/null
@@ -1,66 +0,0 @@
-import { useState } from 'react';
-
-import QuestionTimer from './QuestionTimer.jsx';
-import Answers from './Answers.jsx';
-import QUESTIONS from '../questions.js';
-
-export default function Question({ index, onSelectAnswer, onSkipAnswer }) {
- const [answer, setAnswer] = useState({
- selectedAnswer: '',
- isCorrect: null,
- });
-
- let timer = 10000;
-
- if (answer.selectedAnswer) {
- timer = 1000;
- }
-
- if (answer.isCorrect !== null) {
- timer = 2000;
- }
-
- function handleSelectAnswer(answer) {
- setAnswer({
- selectedAnswer: answer,
- isCorrect: null,
- });
-
- setTimeout(() => {
- setAnswer({
- selectedAnswer: answer,
- isCorrect: QUESTIONS[index].answers[0] === answer,
- });
-
- setTimeout(() => {
- onSelectAnswer(answer);
- }, 2000);
- }, 1000);
- }
-
- let answerState = '';
-
- if (answer.selectedAnswer && answer.isCorrect !== null) {
- answerState = answer.isCorrect ? 'correct' : 'wrong';
- } else if (answer.selectedAnswer) {
- answerState = 'answered';
- }
-
- return (
-
-
-
{QUESTIONS[index].text}
-
-
- );
-}
diff --git a/code/13 Demo Project - React Quiz/08-finished/src/components/QuestionTimer.jsx b/code/13 Demo Project - React Quiz/08-finished/src/components/QuestionTimer.jsx
deleted file mode 100644
index a82728716..000000000
--- a/code/13 Demo Project - React Quiz/08-finished/src/components/QuestionTimer.jsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import { useState, useEffect } from 'react';
-
-export default function QuestionTimer({ timeout, onTimeout, mode }) {
- const [remainingTime, setRemainingTime] = useState(timeout);
-
- useEffect(() => {
- console.log('SETTING TIMEOUT');
- const timer = setTimeout(onTimeout, timeout);
-
- return () => {
- clearTimeout(timer);
- };
- }, [timeout, onTimeout]);
-
- useEffect(() => {
- console.log('SETTING INTERVAL');
- const interval = setInterval(() => {
- setRemainingTime((prevRemainingTime) => prevRemainingTime - 100);
- }, 100);
-
- return () => {
- clearInterval(interval);
- };
- }, []);
-
- return (
-
- );
-}
diff --git a/code/13 Demo Project - React Quiz/08-finished/src/components/Quiz.jsx b/code/13 Demo Project - React Quiz/08-finished/src/components/Quiz.jsx
deleted file mode 100644
index 51da1f7c0..000000000
--- a/code/13 Demo Project - React Quiz/08-finished/src/components/Quiz.jsx
+++ /dev/null
@@ -1,41 +0,0 @@
-import { useState, useCallback } from 'react';
-
-import QUESTIONS from '../questions.js';
-import Question from './Question.jsx';
-import Summary from './Summary.jsx';
-
-export default function Quiz() {
- const [userAnswers, setUserAnswers] = useState([]);
-
- const activeQuestionIndex = userAnswers.length;
- const quizIsComplete = activeQuestionIndex === QUESTIONS.length;
-
- const handleSelectAnswer = useCallback(function handleSelectAnswer(
- selectedAnswer
- ) {
- setUserAnswers((prevUserAnswers) => {
- return [...prevUserAnswers, selectedAnswer];
- });
- },
- []);
-
- const handleSkipAnswer = useCallback(
- () => handleSelectAnswer(null),
- [handleSelectAnswer]
- );
-
- if (quizIsComplete) {
- return
- }
-
- return (
-
-
-
- );
-}
diff --git a/code/13 Demo Project - React Quiz/08-finished/src/components/Summary.jsx b/code/13 Demo Project - React Quiz/08-finished/src/components/Summary.jsx
deleted file mode 100644
index 74b54fcc7..000000000
--- a/code/13 Demo Project - React Quiz/08-finished/src/components/Summary.jsx
+++ /dev/null
@@ -1,59 +0,0 @@
-import quizCompleteImg from '../assets/quiz-complete.png';
-import QUESTIONS from '../questions.js';
-
-export default function Summary({ userAnswers }) {
- const skippedAnswers = userAnswers.filter((answer) => answer === null);
- const correctAnswers = userAnswers.filter(
- (answer, index) => answer === QUESTIONS[index].answers[0]
- );
-
- const skippedAnswersShare = Math.round(
- (skippedAnswers.length / userAnswers.length) * 100
- );
- const correctAnswersShare = Math.round(
- (correctAnswers.length / userAnswers.length) * 100
- );
- const wrongAnswersShare = 100 - skippedAnswersShare - correctAnswersShare;
-
- return (
-
-

-
Quiz Completed!
-
-
- {skippedAnswersShare}%
- skipped
-
-
- {correctAnswersShare}%
- answered correctly
-
-
- {wrongAnswersShare}%
- answered incorrectly
-
-
-
- {userAnswers.map((answer, index) => {
- let cssClass = 'user-answer';
-
- if (answer === null) {
- cssClass += ' skipped';
- } else if (answer === QUESTIONS[index].answers[0]) {
- cssClass += ' correct';
- } else {
- cssClass += ' wrong';
- }
-
- return (
- -
-
{index + 1}
- {QUESTIONS[index].text}
- {answer ?? 'Skipped'}
-
- );
- })}
-
-
- );
-}
diff --git a/code/13 Demo Project - React Quiz/08-finished/src/index.css b/code/13 Demo Project - React Quiz/08-finished/src/index.css
deleted file mode 100644
index 0825029aa..000000000
--- a/code/13 Demo Project - React Quiz/08-finished/src/index.css
+++ /dev/null
@@ -1,336 +0,0 @@
-@import url('https://fonts.googleapis.com/css2?family=Roboto+Condensed:wght@400;700&family=Roboto:wght@400;700&display=swap');
-
-* {
- box-sizing: border-box;
-}
-
-html {
- font-family: 'Roboto', sans-serif;
- line-height: 1.5;
-
- color: #ebe7ef;
-
- font-synthesis: none;
- text-rendering: optimizeLegibility;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
- -webkit-text-size-adjust: 100%;
- height: 100%;
- /* min-height: 100rem; */
-}
-
-body {
- margin: 0;
- padding: 2rem;
- /* background: linear-gradient(180deg, #22182f 0%, #2c2437 100%); */
- background-color: #1d0433;
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100%25' height='100%25' viewBox='0 0 800 400'%3E%3Cdefs%3E%3CradialGradient id='a' cx='396' cy='281' r='514' gradientUnits='userSpaceOnUse'%3E%3Cstop offset='0' stop-color='%237616DD'/%3E%3Cstop offset='1' stop-color='%231D0433'/%3E%3C/radialGradient%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='400' y1='148' x2='400' y2='333'%3E%3Cstop offset='0' stop-color='%2318E0FF' stop-opacity='0'/%3E%3Cstop offset='1' stop-color='%2318E0FF' stop-opacity='0.5'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect fill='url(%23a)' width='800' height='400'/%3E%3Cg fill-opacity='0.4'%3E%3Ccircle fill='url(%23b)' cx='267.5' cy='61' r='300'/%3E%3Ccircle fill='url(%23b)' cx='532.5' cy='61' r='300'/%3E%3Ccircle fill='url(%23b)' cx='400' cy='30' r='300'/%3E%3C/g%3E%3C/svg%3E");
- background-attachment: fixed;
- background-size: cover;
- background-position: center;
-}
-
-header {
- margin: 2rem 0;
- text-align: center;
-}
-
-header img {
- width: 3rem;
- height: 3rem;
- filter: drop-shadow(0 0 4px rgba(0, 0, 0, 0.6));
-}
-
-header h1 {
- font-family: 'Roboto Condensed', sans-serif;
- font-weight: bold;
- font-size: 2.5rem;
- letter-spacing: 0.6rem;
- margin: 0;
- text-transform: uppercase;
- background: linear-gradient(90deg, #e781fb 40%, #8e76fa 60%);
- -webkit-background-clip: text;
- -webkit-text-fill-color: transparent;
-}
-
-#last-try {
- max-width: 40rem;
- margin: 2rem auto;
- font-size: 0.8rem;
- font-family: 'Roboto Condensed', sans-serif;
- text-align: center;
-}
-
-#last-try h2 {
- margin: 0;
- font-size: 1rem;
- color: #9c7fd3;
- text-transform: uppercase;
-}
-
-#last-try ul {
- list-style: none;
- margin: 0;
- padding: 0;
- display: flex;
- gap: 1rem;
- font-size: 1.25rem;
- color: #a690c5;
-}
-
-#quiz {
- max-width: 50rem;
- margin: auto;
- padding: 2rem;
- background: linear-gradient(180deg, #3e2a60 0%, #321061 100%);
- border-radius: 8px;
- /* box-shadow: 1px 1px 4px 1px rgba(0, 0, 0, 0.6); */
- box-shadow: 1px 1px 8px 4px rgba(12, 5, 32, 0.6);
- text-align: center;
-}
-
-#question-overview {
- font-family: 'Roboto Condensed', sans-serif;
- font-size: 0.8rem;
- color: #9082a3;
- margin: 0;
- text-transform: uppercase;
-}
-
-#question progress {
- width: 50%;
- height: 0.5rem;
- border-radius: 24px;
- background: #9e5ef8;
- margin: 0;
-}
-
-#question progress::-webkit-progress-bar {
- background: #6a558a;
- border-radius: 24px;
-}
-
-#question progress::-webkit-progress-value {
- background: #9e5ef8;
- border-radius: 24px;
-}
-
-#question progress.answered {
- background: #f8e59c;
-}
-
-#question progress.answered::-webkit-progress-value {
- background: #f8e59c;
-}
-
-#question progress.answered::-webkit-progress-bar {
- background: #6a558a;
-}
-
-#question h2 {
- font-family: 'Roboto', sans-serif;
- font-size: 1.5rem;
- font-weight: normal;
- margin: 0.5rem 0 2.5rem 0;
- color: #c1b2dd;
-}
-
-#answers {
- list-style: none;
- margin: 0;
- padding: 0;
- display: flex;
- flex-direction: column;
- align-items: center;
- gap: 0.5rem;
-}
-
-.answer {
- width: 90%;
- margin: 0 auto;
-}
-
-.answer button {
- display: inline-block;
- width: 100%;
- font-family: 'Roboto Condensed', sans-serif;
- font-size: 0.9rem;
- padding: 1rem 2rem;
- border: none;
- border-radius: 24px;
- /* background: linear-gradient(180deg, #81f1fb 0%, #73d2f8 100%); */
- background: #6cb7f5;
- cursor: pointer;
- transition: all 0.2s ease-in-out;
-}
-
-.answer button:hover,
-.answer button:focus {
- /* background: linear-gradient(180deg, #bf48f6 0%, #9b50f2 100%); */
- background: #9d5af5;
- color: white;
- /* box-shadow: 0 0 4px 2px rgba(255, 200, 60, 0.8); */
-}
-
-.answer button.selected {
- /* background: linear-gradient(180deg, #fbda81 0%, #f8b173 100%); */
- background: #f5a76c;
- color: #2c203d;
-}
-
-.answer button.correct {
- /* background: linear-gradient(180deg, #a1fa61 0%, #52d482 100%); */
- background: #5af59d;
- color: #2c203d;
-}
-
-.answer button.wrong {
- /* background: linear-gradient(180deg, #f96fb1 0%, #f52b8c 100%); */
- background: #f55a98;
- color: #2c203d;
-}
-
-#skip-action {
- margin-top: 2rem;
-}
-
-#skip-action button {
- font-family: 'Roboto Condensed', sans-serif;
- font-size: 1rem;
- border: none;
- background: transparent;
- color: #9082a3;
- cursor: pointer;
-}
-
-#skip-action button:hover,
-#skip-action button:focus {
- color: #c7bfd6;
-}
-
-#summary {
- max-width: 40rem;
- margin: 2rem auto;
- padding: 2rem;
- background: linear-gradient(180deg, #a17eda 0%, #895fc4 100%);
- color: #191321;
- border-radius: 8px;
- box-shadow: 1px 1px 8px 1px rgba(0, 0, 0, 0.6);
- animation: slide-in-from-bottom 0.7s ease-out;
-}
-
-#summary img {
- display: block;
- width: 8rem;
- height: 8rem;
- object-fit: contain;
- margin: 0 auto 1rem auto;
- padding: 1rem;
- filter: drop-shadow(0 0 4px rgba(0, 0, 0, 0.6));
- border: 2px solid #3a2353;
- border-radius: 50%;
- background: #c18cfa;
-}
-
-#summary h2 {
- font-family: 'Roboto', sans-serif;
- font-size: 3rem;
- text-align: center;
- margin: 0;
- text-transform: uppercase;
- color: #3a2353;
-}
-
-#summary ol {
- list-style: none;
- margin: 2rem auto;
- padding: 0;
- text-align: center;
-}
-
-#summary li {
- margin: 2rem 0;
-}
-
-#summary h3 {
- font-family: 'Roboto Condensed', sans-serif;
- font-size: 1rem;
- margin: 0 auto;
- display: flex;
- justify-content: center;
- align-items: center;
- background: #2c203d;
- color: #d8cde8;
- width: 2rem;
- height: 2rem;
- border-radius: 50%;
-}
-
-#summary .question {
- margin: 0.25rem 0;
- font-size: 1rem;
- color: #30273a;
-}
-
-#summary .user-answer {
- margin: 0.25rem 0;
- font-family: 'Roboto Condensed', sans-serif;
- font-weight: bold;
- color: #251e2f;
-}
-
-#summary .user-answer.correct {
- color: #054e37;
-}
-
-#summary .user-answer.wrong {
- color: #730b4b;
-}
-
-#summary .user-answer.skipped {
- color: #d1baf2;
- font-weight: normal;
-}
-
-#summary-stats {
- display: flex;
- gap: 3rem;
- width: 60%;
- margin: 2rem auto;
- padding-bottom: 2rem;
- border-bottom: 2px solid #594276;
-}
-
-#summary-stats p {
- flex: 1;
- display: flex;
- flex-direction: column;
- margin: 0;
-}
-
-#summary-stats .number {
- font-family: 'Roboto Condensed', sans-serif;
- font-size: 3rem;
- color: #594276;
-}
-
-#summary-stats .text {
- font-family: 'Roboto Condensed', sans-serif;
- text-transform: uppercase;
- font-size: 0.8rem;
- color: #30273a;
- margin-top: -0.7rem;
- margin-left: 0.2rem;
- letter-spacing: 0.1rem;
-}
-
-@keyframes slide-in-from-bottom {
- 0% {
- opacity: 0;
- transform: translateY(10%);
- }
- 100% {
- opacity: 1;
- transform: translateY(0);
- }
-}
diff --git a/code/13 Demo Project - React Quiz/08-finished/src/main.jsx b/code/13 Demo Project - React Quiz/08-finished/src/main.jsx
deleted file mode 100644
index 54b39dd1d..000000000
--- a/code/13 Demo Project - React Quiz/08-finished/src/main.jsx
+++ /dev/null
@@ -1,10 +0,0 @@
-import React from 'react'
-import ReactDOM from 'react-dom/client'
-import App from './App.jsx'
-import './index.css'
-
-ReactDOM.createRoot(document.getElementById('root')).render(
-
-
- ,
-)
diff --git a/code/13 Demo Project - React Quiz/08-finished/src/questions.js b/code/13 Demo Project - React Quiz/08-finished/src/questions.js
deleted file mode 100644
index a8828069d..000000000
--- a/code/13 Demo Project - React Quiz/08-finished/src/questions.js
+++ /dev/null
@@ -1,72 +0,0 @@
-export default [
- {
- id: 'q1',
- text: 'Which of the following definitions best describes React.js?',
- answers: [
- 'A library to build user interfaces with help of declarative code.',
- 'A library for managing state in web applications.',
- 'A framework to build user interfaces with help of imperative code.',
- 'A library used for building mobile applications only.',
- ],
- },
- {
- id: 'q2',
- text: 'What purpose do React hooks serve?',
- answers: [
- 'Enabling the use of state and other React features in functional components.',
- 'Creating responsive layouts in React applications.',
- 'Handling errors within the application.',
- 'Part of the Redux library for managing global state.',
- ],
- },
- {
- id: 'q3',
- text: 'Can you identify what JSX is?',
- answers: [
- 'A JavaScript extension that adds HTML-like syntax to JavaScript.',
- 'A JavaScript library for building dynamic user interfaces.',
- 'A specific HTML version that was explicitly created for React.',
- 'A tool for making HTTP requests in a React application.',
- ],
- },
- {
- id: 'q4',
- text: 'What is the most common way to create a component in React?',
- answers: [
- 'By defining a JavaScript function that returns a renderable value.',
- 'By defining a custom HTML tag in JavaScript.',
- 'By creating a file with a .jsx extension.',
- 'By using the "new" keyword followed by the component name.',
- ],
- },
- {
- id: 'q5',
- text: 'What does the term "React state" imply?',
- answers: [
- 'An object in a component that holds values and may cause the component to render on change.',
- 'The lifecycle phase a React component is in.',
- 'The overall status of a React application, including all props and components.',
- 'A library for managing global state in React applications.',
- ],
- },
- {
- id: 'q6',
- text: 'How do you typically render list content in React apps?',
- answers: [
- 'By using the map() method to iterate over an array of data and returning JSX.',
- 'By using the for() loop to iterate over an array of data and returning JSX.',
- 'By using the forEach() method to iterate over an array of data and returning JSX.',
- 'By using the loop() method to iterate over an array of data and returning JSX.',
- ],
- },
- {
- id: 'q7',
- text: 'Which approach can NOT be used to render content conditionally?',
- answers: [
- 'Using the #if template syntax.',
- 'Using a ternary operator.',
- 'Using the && operator.',
- 'Using an if-else statement.',
- ],
- },
-];
diff --git a/code/13 Demo Project - React Quiz/08-finished/vite.config.js b/code/13 Demo Project - React Quiz/08-finished/vite.config.js
deleted file mode 100644
index 5a33944a9..000000000
--- a/code/13 Demo Project - React Quiz/08-finished/vite.config.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import { defineConfig } from 'vite'
-import react from '@vitejs/plugin-react'
-
-// https://vitejs.dev/config/
-export default defineConfig({
- plugins: [react()],
-})