From f99d4fc6ef342abc42c34de442506784a6f47fa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Regina=20S=C3=B6derberg?= Date: Sun, 16 Apr 2023 20:33:56 +0200 Subject: [PATCH] added text and styling --- src/ProgressBar.css | 0 src/components/AnswerButton.js | 39 ++++++++ src/components/CurrentQuestion.css | 32 +++++++ src/components/CurrentQuestion.js | 60 +++++++++++-- src/components/NextButton.css | 22 +++++ src/components/NextButton.js | 16 ++++ src/components/ProgressBar.css | 25 ++++++ src/components/ProgressBar.js | 23 +++++ src/components/ResetButton.css | 33 +++++++ src/components/ResetButton.js | 18 ++++ src/components/answerbutton.css | 24 +++++ src/pages/Question.js | 11 +++ src/pages/Summary.js | 38 ++++++++ src/pages/question.css | 6 ++ src/pages/summary.css | 22 +++++ src/reducers/quiz.js | 139 ++++++++++++++++++++--------- 16 files changed, 458 insertions(+), 50 deletions(-) create mode 100644 src/ProgressBar.css create mode 100644 src/components/AnswerButton.js create mode 100644 src/components/CurrentQuestion.css create mode 100644 src/components/NextButton.css create mode 100644 src/components/NextButton.js create mode 100644 src/components/ProgressBar.css create mode 100644 src/components/ProgressBar.js create mode 100644 src/components/ResetButton.css create mode 100644 src/components/ResetButton.js create mode 100644 src/components/answerbutton.css create mode 100644 src/pages/Question.js create mode 100644 src/pages/Summary.js create mode 100644 src/pages/question.css create mode 100644 src/pages/summary.css diff --git a/src/ProgressBar.css b/src/ProgressBar.css new file mode 100644 index 00000000..e69de29b diff --git a/src/components/AnswerButton.js b/src/components/AnswerButton.js new file mode 100644 index 00000000..f546e5fb --- /dev/null +++ b/src/components/AnswerButton.js @@ -0,0 +1,39 @@ +/* eslint-disable max-len */ +/* eslint-disable no-nested-ternary */ +/* eslint-disable no-shadow */ +import React, { useState } from 'react'; +import { useSelector, useDispatch } from 'react-redux'; +import { quiz } from '../reducers/quiz'; + +export const AnswerButton = ({ index, option, setGoToNextButton }) => { + const dispatch = useDispatch(); + const [activeBtn, setActiveBtn] = useState(false); + const question = useSelector((state) => state.quiz.questions[state.quiz.currentQuestionIndex]); + const usersAnswer = useSelector((state) => state.quiz.answers[state.quiz.currentQuestionIndex]); + + const onAnswerSubmit = (questionId, answerIndex) => { + dispatch(quiz.actions.submitAnswer({ + questionId, answerIndex + })); + if (question.correctAnswerIndex === answerIndex) { + window.alert('High five!') + dispatch(quiz.actions.goToNextQuestion()) + } else { + window.alert('Sorry :( !') + } + setActiveBtn(true); + setGoToNextButton(true); + } + + const correctAnswer = usersAnswer && index === question.correctAnswerIndex; + + return ( + + ); +}; \ No newline at end of file diff --git a/src/components/CurrentQuestion.css b/src/components/CurrentQuestion.css new file mode 100644 index 00000000..5cce651c --- /dev/null +++ b/src/components/CurrentQuestion.css @@ -0,0 +1,32 @@ +.eslint-hater h1 { + font-family: futura-pt, 'sans-serif'; + font-weight: 900; + letter-spacing: -0.01em; + color: #df82e2; + text-align: center; + display: flex; + flex-direction: column; + align-items: center; + } + + .answerButton { + place-self: center; + } + + .answer-buttons { + display: flex; + flex-direction: column; + gap: 10px; + } + + .eslint-hater-bottom { + display: flex; + flex-direction: column; + gap: 11px; + } + + .eslint-hater { + display: flex; + flex-direction: column; + align-items: center; + } \ No newline at end of file diff --git a/src/components/CurrentQuestion.js b/src/components/CurrentQuestion.js index 36ee2224..fbcf0fba 100644 --- a/src/components/CurrentQuestion.js +++ b/src/components/CurrentQuestion.js @@ -1,16 +1,58 @@ -import React from 'react' -import { useSelector } from 'react-redux' +import React, { useState } from 'react'; +import { useSelector, useDispatch } from 'react-redux'; +import { NextButton } from './NextButton'; +import { ProgressBar } from './ProgressBar'; +import { AnswerButton } from './AnswerButton'; +import { SummaryPage } from '../pages/Summary'; +import { quiz } from '../reducers/quiz'; +import './CurrentQuestion.css'; export const CurrentQuestion = () => { - const question = useSelector((state) => state.quiz.questions[state.quiz.currentQuestionIndex]) + // const question = useSelector((state) => state.quiz.questions[state.quiz.currentQuestionIndex]) + console.log(quiz); + const dispatch = useDispatch(); + const [goToNextButton, setGoToNextButton] = useState(false); + const question = useSelector( + (state) => state.quiz.questions[state.quiz.currentQuestionIndex] + ); + const quizOver = useSelector((state) => state.quiz.quizOver); if (!question) { - return

Oh no! I could not find the current question!

+ return

Oups, no question here!

+ // return

Oh no! I could not find the current question!

; } + const moveToNext = () => { + dispatch(quiz.actions.goToNextQuestion()); + setGoToNextButton(false); + }; return ( -
-

Question: {question.questionText}

-
- ) -} +//
+//

Question: {question.questionText}

+//
+// ) +// } + <> + {quizOver && } + {!quizOver && ( +
+

How well do you know your garden: {question.questionText}

+
+ {question.options.map((option, index) => ( + + ))} +
+
+ {goToNextButton && } + +
+
+ )} + + ); +}; diff --git a/src/components/NextButton.css b/src/components/NextButton.css new file mode 100644 index 00000000..fcf4a9d2 --- /dev/null +++ b/src/components/NextButton.css @@ -0,0 +1,22 @@ +.nextButton { + cursor: pointer; + text-underline-offset: 6px; + font-family: futura-pt, "sans-serif"; + font-weight: 600; + transition: all 0.2s ease 0s; + + padding: 10px 15px; + border-radius: 5px; + text-decoration: none; + font-size: 18px; + border: 5px solid #e33fec; + + color: #f37af1; + background: transparent; + align-self: center; + margin-top:40px; + margin-bottom:40px; + + } + + \ No newline at end of file diff --git a/src/components/NextButton.js b/src/components/NextButton.js new file mode 100644 index 00000000..d4731ef7 --- /dev/null +++ b/src/components/NextButton.js @@ -0,0 +1,16 @@ +import React from 'react'; +import { useDispatch } from 'react-redux'; +import { quiz } from '../reducers/quiz'; +import './NextButton.css'; + +export const NextButton = () => { + const dispatch = useDispatch(); + const goToNextQuestion = () => { + dispatch(quiz.actions.goToNextQuestion()); + }; + return ( + + ); +}; \ No newline at end of file diff --git a/src/components/ProgressBar.css b/src/components/ProgressBar.css new file mode 100644 index 00000000..761110b0 --- /dev/null +++ b/src/components/ProgressBar.css @@ -0,0 +1,25 @@ +.progress-bar { + font-family: futura-pt, 'sans-serif'; + letter-spacing: -0.01em; + font-size: 32px; + line-height: min(max(50px, 6vw), 53px); + color: #8c499e; + } + .progress { + width: 100%; + height: 10px; + appearance: none; + background-color: #f4f4f4; + border-radius: 20px; + overflow: hidden; + } + + .progress::-webkit-progress-bar { + background-color: #f4f4f4; + border-radius: 20px; + } + + .progress::-webkit-progress-value { + background-color: #8c499e; + border-radius: 20px; + } \ No newline at end of file diff --git a/src/components/ProgressBar.js b/src/components/ProgressBar.js new file mode 100644 index 00000000..7e6f1f90 --- /dev/null +++ b/src/components/ProgressBar.js @@ -0,0 +1,23 @@ +import React from 'react'; +import { useSelector } from 'react-redux'; +import './ProgressBar.css'; + +export const ProgressBar = () => { + const questions = useSelector((state) => state.quiz.questions); + const currentQuestionIndex = useSelector((state) => { + return state.quiz.questions[state.quiz.currentQuestionIndex]; + }); + + const progress = (currentQuestionIndex.id / questions.length) * 100; + + return ( +
+

+ Question: {currentQuestionIndex.id} / {questions.length} +

+ + {progress}% + +
+ ); +}; \ No newline at end of file diff --git a/src/components/ResetButton.css b/src/components/ResetButton.css new file mode 100644 index 00000000..42d2ca76 --- /dev/null +++ b/src/components/ResetButton.css @@ -0,0 +1,33 @@ +.resetButton { + cursor: pointer; + text-underline-offset: 6px; + /*font-family: futura-pt, 'sans-serif'; */ + font-weight: 600; + transition: all 0.2s ease 0s; + display: inline-block; + padding: 18px 30px; + border-radius: 50px; + text-decoration: none; + font-size: 18px; + border: 2px solid #e878f3; + place-self: flex-start; + color: rgb(211, 214, 247); + background: #f18bda; + /* animation: bounce 1s infinite alternate; */ + } + + /* @keyframes bounce { + 0% { + transform: translateY(0); + } */ + /* 100% { + transform: translateY(50px); + } + } */ + .resetButtonContainer { + display: flex; + justify-content: center; + align-items: center; + margin-top: 40px; + margin-bottom: 40px; + } \ No newline at end of file diff --git a/src/components/ResetButton.js b/src/components/ResetButton.js new file mode 100644 index 00000000..93b08daa --- /dev/null +++ b/src/components/ResetButton.js @@ -0,0 +1,18 @@ +import React from 'react'; +import { useDispatch } from 'react-redux'; +import { quiz } from '../reducers/quiz'; +import './ResetButton.css'; + +export const ResetButton = () => { + const dispatch = useDispatch(); + const restart = () => { + dispatch(quiz.actions.restart()); + }; + return ( +
+ +
+ ); +}; \ No newline at end of file diff --git a/src/components/answerbutton.css b/src/components/answerbutton.css new file mode 100644 index 00000000..5491b92f --- /dev/null +++ b/src/components/answerbutton.css @@ -0,0 +1,24 @@ +button { + background-color: #3498db; + color: #fff; + font-size: 16px; + padding: 12px 24px; + border-radius: 12px; + border: none; + cursor: pointer; +} +/* button.default:hover { + background-color: #2980b9; +} +button.default:active { + background-color: #21618c; +} +button.correct { + background-color: #2ecc71; +} +button.wrong { + background-color: #e74c3c; +} +button.default { + background-color: #bdc3c7; +} */ diff --git a/src/pages/Question.js b/src/pages/Question.js new file mode 100644 index 00000000..7aaf870c --- /dev/null +++ b/src/pages/Question.js @@ -0,0 +1,11 @@ +import React from 'react'; +import { CurrentQuestion } from 'components/CurrentQuestion'; +import './question.css'; + +export const Question = () => { + return ( +
+ +
+ ); +} \ No newline at end of file diff --git a/src/pages/Summary.js b/src/pages/Summary.js new file mode 100644 index 00000000..c211fcc7 --- /dev/null +++ b/src/pages/Summary.js @@ -0,0 +1,38 @@ +/* eslint-disable implicit-arrow-linebreak */ +/* eslint-disable react/jsx-no-useless-fragment */ +import React from 'react'; +import { ResetButton } from 'components/ResetButton'; +import { useSelector } from 'react-redux'; +import './summary.css'; + +export const SummaryPage = () => { + // Variable to calculate how many correct answer the user has given + const correctAnswer = useSelector( + (state) => + state.quiz.answers.filter((answer) => answer.isCorrect === true).length + ); + const answers = useSelector((state) => state.quiz.answers); + + const userSummary = () => { + if (correctAnswer === 5) { + return 'That is correct!'; + } else if (correctAnswer === 4) { + return 'You nailed it!'; + } else if (correctAnswer === 3) { + return 'Good job!'; + } else { + return 'No, that is not correct'; + } + }; + + return ( +
+

You did great!

+

+ You got: {correctAnswer} of {answers.length} +

+ +

{userSummary()}

+
+ ); +}; \ No newline at end of file diff --git a/src/pages/question.css b/src/pages/question.css new file mode 100644 index 00000000..7e87742f --- /dev/null +++ b/src/pages/question.css @@ -0,0 +1,6 @@ +.questions-background { + height: 100vh; + border-color: #ad67b5; + border-width: 16px 16px 0px 16px; + border-style: solid; +} \ No newline at end of file diff --git a/src/pages/summary.css b/src/pages/summary.css new file mode 100644 index 00000000..3df5b0a4 --- /dev/null +++ b/src/pages/summary.css @@ -0,0 +1,22 @@ +.summary { + height: 100vh; + border-color: #da78e1; + border-width: 16px 16px 16px 16px; + border-style: solid; + display: flex; + flex-direction: column; +} + +.summary h1, h3 { + font-family: futura-pt, "sans-serif"; + font-weight: 900; + letter-spacing: -0.01em; + color: #d463cb; + text-align: center; + padding-top: 40px; +} + +.summary p { + padding-top: 40px; + text-align: center; +} \ No newline at end of file diff --git a/src/reducers/quiz.js b/src/reducers/quiz.js index a38bbf68..5367fd10 100644 --- a/src/reducers/quiz.js +++ b/src/reducers/quiz.js @@ -1,10 +1,70 @@ -import { createSlice } from '@reduxjs/toolkit' +/* eslint-disable comma-dangle */ +import { createSlice } from '@reduxjs/toolkit'; // Change these to your own questions! const questions = [ - { id: 1, questionText: 'Who set the Olympic record for the 100m dash in 2012?', options: ['Usain Bolt', 'Justin Gatlin', 'Tyson Gay', 'Asafa Powell'], correctAnswerIndex: 0 }, - { id: 2, questionText: 'When was Michael Phelps last named male World Swimmer of the Year?', options: ['2012', '2014', '2016', '2018'], correctAnswerIndex: 2 } -] +// { id: 1, questionText: 'Who set the Olympic record for the 100m dash in 2012?', options: +// ['Usain Bolt', 'Justin Gatlin', 'Tyson Gay', 'Asafa Powell'], correctAnswerIndex: 0 }, +// { id: 2, questionText: +// 'When was Michael Phelps last named male World Swimmer of the Year?', options: +// ['2012', '2014', '2016', '2018'], correctAnswerIndex: 2 } +// ] + { + id: 1, + questionText: 'Which of these roses is not white?', + options: [ + 'Desdemona', + 'Louise Bugnet', + 'Winchester Cathedral', + 'Ingrid Bergman', + ], + correctAnswerIndex: 3, + }, + { + id: 2, + questionText: 'What do you pick if you pick Ribes uva-crispa?', + options: [ + 'Cherryberries', + 'Currants', + 'Goosberries', + 'Rhubarbs', + ], + correctAnswerIndex: 2, + }, + { + id: 3, + questionText: 'So beautiful you could just eat them, but which one should you not eat?', + options: [ + 'Marigold', + 'Mezereon', + 'Lilacs', + 'Pansies', + ], + correctAnswerIndex: 1, + }, + { + id: 4, + questionText: 'Three of these gardenherbs are perennial, one is not. Which one is not?', + options: [ + 'Parsley', + 'Thyme', + 'Mint', + 'Chive', + ], + correctAnswerIndex: 0, + }, + { + id: 5, + questionText: 'Early or latebloomer? Three are early, one is late.', + options: [ + 'Coltsfoot', + 'Crocus', + 'Hummingbird', + 'Cowslip', + ], + correctAnswerIndex: 2, + }, +]; const initialState = { questions, @@ -12,37 +72,34 @@ const initialState = { currentQuestionIndex: 0, quizOver: false } +// quizOver: false, +// }; export const quiz = createSlice({ name: 'quiz', initialState, reducers: { - /** - * Use this action when a user selects an answer to the question. - * The answer will be stored in the `quiz.answers` state with the - * following values: - * - * questionId - The id of the question being answered. - * answerIndex - The index of the selected answer from the question's options. - * question - A copy of the entire question object, to make it easier to show - * details about the question in your UI. - * answer - The answer string. - * isCorrect - true/false if the answer was the one which the question says is correct. - * - * When dispatching this action, you should pass an object as the payload with `questionId` - * and `answerIndex` keys. See the readme for more details. - */ submitAnswer: (state, action) => { - const { questionId, answerIndex } = action.payload - const question = state.questions.find((q) => q.id === questionId) + // const { questionId, answerIndex } = action.payload + // const question = state.questions.find((q) => q.id === questionId) + const { questionId, answerIndex } = action.payload; + const question = state.questions.find((q) => q.id === questionId); if (!question) { - throw new Error('Could not find question! Check to make sure you are passing the question id correctly.') + // throw new Error('Could not find question! + // Check to make sure you are passing the question id correctly.') + throw new Error( + 'Could not find question! Check to make sure you are passing the question id correctly.' + ); } if (question.options[answerIndex] === undefined) { - throw new Error(`You passed answerIndex ${answerIndex}, but it is not in the possible answers array!`) + // throw new Error(`You passed answerIndex ${answerIndex}, + // but it is not in the possible answers array!`) + throw new Error( + `You passed answerIndex ${answerIndex}, but it is not in the possible answers array!` + ); } state.answers.push({ @@ -52,33 +109,33 @@ export const quiz = createSlice({ answer: question.options[answerIndex], isCorrect: question.correctAnswerIndex === answerIndex }) + // isCorrect: question.correctAnswerIndex === answerIndex, + // }); }, /** - * Use this action to progress the quiz to the next question. If there's - * no more questions (the user was on the final question), set `quizOver` - * to `true`. - * - * This action does not require a payload. +@@ -63,9 +120,9 @@ export const quiz = createSlice({ */ goToNextQuestion: (state) => { if (state.currentQuestionIndex + 1 === state.questions.length) { - state.quizOver = true + // state.quizOver = true + state.quizOver = true; } else { - state.currentQuestionIndex += 1 + // state.currentQuestionIndex += 1 + state.currentQuestionIndex += 1; } }, - /** - * Use this action to reset the state to the initial state the page had - * when it was loaded. Who doesn't like re-doing a quiz when you know the - * answers?! - * - * This action does not require a payload. - */ + // @@ -77,8 +134,7 @@ export const quiz = createSlice({ + // * This action does not require a payload. + // */ restart: () => { - return initialState - } + // return initialState + // } - } -}) + // } + // }) + return initialState; + }, + }, +});