Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

David Gridley Quiz app #5

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,31 +33,31 @@ See [https://opentdb.com/api\_config.php](https://opentdb.com/api_config.php) fo

## Instructions

* Fork and clone this repo. Run `npm install` to get all dependencies.
<!-- * Fork and clone this repo. Run `npm install` to get all dependencies.

* Load the first question automatically at the beginning using `componentDidMount` and display it to the user. Alongside buttons for the answers.

* If the user clicks a correct answer, notify the user and increment the score by 1. On an incorrect answer, notify the user and reset the score to 0. You are welcome to use an alternative scoring system if you prefer.

* If the user answers the question correctly load the next question.

* Each correct answer should increment the score. It's up to you how you want to score answers. You could apply a different score for different difficulty grades. After each correct answer display the next question
* Each correct answer should increment the score. It's up to you how you want to score answers. You could apply a different score for different difficulty grades. After each correct answer display the next question -->

* Make the app responsive and look good at all screen sizes.
<!-- * ------ Make the app responsive and look good at all screen sizes. -->

## Stretch goals - feel free to pick

* Show the user a 'happy' animated gif on a correct answer and a 'sad' gif on incorrect answer.
<!-- * Show the user a 'happy' animated gif on a correct answer and a 'sad' gif on incorrect answer. -->

* Allow user to select question category

* Allow user to select difficulty level
<!-- * Allow user to select difficulty level -->

* Add some unit tests

* Implement a scoring system that gives higher scores for more difficult questions
<!-- * Implement a scoring system that gives higher scores for more difficult questions -->

* Create a high score table. When a user finishes the game, for example answers a question incorrectly, allow them to enter their name and add it along with score to a high score table.
<!-- * Create a high score table. When a user finishes the game, for example answers a question incorrectly, allow them to enter their name and add it along with score to a high score table. -->

* Display statistics about player performance such as total questions played, average score, most popular category, category with highest percentage of correct etc.

Expand All @@ -71,7 +71,7 @@ See [https://opentdb.com/api\_config.php](https://opentdb.com/api_config.php) fo
* Make frequent commits
* Create a pull request at the end

## Redux getting started guide
<!-- ## Redux getting started guide

![](/redux.png)

Expand Down Expand Up @@ -100,4 +100,4 @@ If you are using planning to use Redux, use the steps below to help you get star

- Implement `mapStateToProps` in `QuestionContainer` which should take the `question` from reducer state and pass it as a `question` prop to the `Question` component. Add a console.log to `mapStateToProps` which outputs `Step 6 - calling mapStateToProps in QuestionContainer`.

- Add some conditional rendering that checks if the question object received as `props` is not just an empty object to ensure it can be rendered without errors.
- Add some conditional rendering that checks if the question object received as `props` is not just an empty object to ensure it can be rendered without errors. -->
28 changes: 17 additions & 11 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<title>Redux intro</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div id="root">

</div>
<script src="dist/bundle.js"></script>
</body>
</html>

<head>
<title>Quizness Time</title>
<link rel="stylesheet" type="text/css" href="style.css">
<link href="https://fonts.googleapis.com/css?family=Encode+Sans+Condensed|Lobster" rel="stylesheet">
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
</head>

<body>
<div id="root">

</div>
<script src="dist/bundle.js"></script>
</body>

</html>
10 changes: 10 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@
"classnames": "^2.2.6",
"enzyme": "^3.3.0",
"enzyme-adapter-react-16": "^1.1.1",
"he": "^1.2.0",
"prop-types": "^15.6.2",
"react": "^16.2.0",
"react-dom": "^16.2.0",
"react-redux": "^5.0.7",
"redux": "^4.0.0",
"redux-thunk": "^2.3.0"
"redux-thunk": "^2.3.0",
"shuffle-array": "^1.0.1"
},
"devDependencies": {
"babel-jest": "^22.4.1",
Expand Down
96 changes: 94 additions & 2 deletions src/actions/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,97 @@
export function fetchQuestion(){
return function(dispatch){
import shuffle from "shuffle-array";

export function fetchQuestion(difficulty) {
return function(dispatch) {
fetch(`https://opentdb.com/api.php?amount=1&type=multiple${difficulty}`)
.then(response => response.json())
.then(result => {
const questionObj = result.results[0];
dispatch(receiveQuestion(questionObj));
})
.catch(error => console.log(error));
};
}

export function receiveQuestion(question) {
question.answerArr = shuffle(
question.incorrect_answers.concat(question.correct_answer)
);
return {
type: "RECEIVE_QUESTION",
question,
correct: ""
};
}

export function receiveAnswer(answer, question, quizDifficulty) {
const correctAnswer = question.correct_answer;
if (answer === correctAnswer) {
return {
type: "CORRECT_ANSWER",
quizDifficulty,
questionDifficulty: question.difficulty
};
} else {
return {
type: "INCORRECT_ANSWER"
};
}
}

export function receiveView(view) {
return {
type: "RECEIVE_VIEW",
view
};
}

export function receiveDifficulty(difficulty) {
return {
type: "RECEIVE_DIFFICULTY",
difficulty
};
}

export function receivePlayerName(name) {
return {
type: "RECEIVE_PLAYER_NAME",
name
};
}


export function fetchScoreboard(difficulty) {
const scoreboard = JSON.parse(localStorage.getItem(difficulty))
return {
scoreboard
}
}

export function initializeStateScoreboard(difficulty){
const scoreboard = JSON.parse(localStorage.getItem(difficulty))
return {
type: "RECEIVE_SCOREBOARD",
scoreboard: scoreboard,
formVisible: "yes"
}
}

export function submitScore(name, points, difficulty) {
const quizDifficulty = !difficulty ? "random" : difficulty;
const scoreboardArray = fetchScoreboard(quizDifficulty);
const playerScoreObject = { name: name, points: points };
if (scoreboardArray.scoreboard === null) {
localStorage.setItem(quizDifficulty, JSON.stringify([playerScoreObject]));
} else if (scoreboardArray) {
const newScoreboard = scoreboardArray.scoreboard.concat(playerScoreObject)
newScoreboard.sort((a, b) => b.points - a.points);
localStorage.setItem(difficulty, JSON.stringify(newScoreboard))
}
const updatedScoreboard = fetchScoreboard(quizDifficulty);
return {
type: "RECEIVE_SCOREBOARD",
scoreboard: updatedScoreboard.scoreboard,
formVisible: "no"
}
}

3 changes: 2 additions & 1 deletion src/components/App.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import React from 'react';
import ContentContainer from '../containers/ContentContainer'

class App extends React.Component {
render(){
return (
<div>
App contents go here
<ContentContainer />
</div>
)
}
Expand Down
21 changes: 21 additions & 0 deletions src/components/Content.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from "react";
import QuestionContainer from "../containers/QuestionContainer";
import PointsContainer from "../containers/PointsContainer";
import MenuContainer from "../containers/MenuContainer";
import ScoreboardContainer from "../containers/ScoreboardContainer";

function Content({ view }) {
return (
<div>
{view === "menu" && <MenuContainer />}
{view === "quiz" && (
<React.Fragment>
<QuestionContainer /> <PointsContainer />
</React.Fragment>
)}
{view === "scoreboard" && <ScoreboardContainer />}
</div>
);
}

export default Content;
43 changes: 43 additions & 0 deletions src/components/Menu.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from "react";

function Menu({ difficulty, receiveView, receiveDifficulty }) {
return (
<div className="menu__container">
<h1 className="menu__title">It's Quizness Time!</h1>
<label className="menu__select__label">Please select difficulty:</label>
<select
value={difficulty}
onChange={event => {
receiveDifficulty(event.target.value);
}}
className="menu__select__dropdown"
>
<option value="&difficulty=easy">Easy</option>
<option value="&difficulty=medium">Medium</option>
<option value="&difficulty=hard">Hard</option>
<option value="">Random</option>
</select>
{difficulty === "&difficulty=easy" && (
<p className="menu__select__description">Just the basics, easy questions for easy going players.</p>
)}
{difficulty === "&difficulty=medium" && (
<p className="menu__select__description">Not quite easy, not quite hard.</p>
)}
{difficulty === "&difficulty=hard" && (
<p className="menu__select__description">Challenging to say the least.</p>
)}
{difficulty === "" && (
<p className="menu__select__description">
A mixed bag of question difficulties! Easy questions are worth 1
point, medium questions are worth 2 points and hard questions are
worth 3 points.
</p>
)}
<button className="menu__select__button" onClick={() => receiveView("quiz")}>
Lets get down to Quizness!
</button>
</div>
);
}

export default Menu;
12 changes: 12 additions & 0 deletions src/components/Points.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react';

function Points({ points }) {

return(
<div className="points__container">
<p className="points__number">POINTS: {points} </p>
</div>
)
}

export default Points;
Loading