The task is to build a quiz game which has the following sections:
Displaying a question
Answer options
Status of correct and incorrect answers so far
Expected functionality:
A question is displayed. The user clicks on one of the four shown answer options. Afterwards are either the correct or the incorrect answers incremented. The next question is shown.
The game has to have at least 10 questions.
Here's my implementation:
class QuestionPanel extends React.Component {
constructor(props) {
super(props);
}
render() {
if (this.props.activeGame) {
return ( <div className="text-center">
<p className="question-panel">{ this.props.question }</p>
</div> )
} else {
return ( <div className="text-center">
<p className="question-panel message">Game Over</p>
<div className="hyperlink-button">
<a onClick={ this.props.resetGame } href="#">Restart</a>
</div>
</div>);
}
}
}
class Option extends React.Component {
render() {
return <div><a href="#"
onClick={ this.props.triggerProcess }
className="option-card">
{ this.props.optionValue }
</a></div>;
}
}
class StatusDisplay extends React.Component {
render() {
return (<div className="status-display text-center">
<p>Correct: { this.props.correct }</p>
<p>Incorrect: { this.props.incorrect }</p>
</div>)
}
}
class GameBoard extends React.Component {
constructor(props) {
super(props);
this.processGuess = this.processGuess.bind(this);
this.resetGame = this.resetGame.bind(this);
this.state = {
currentIndex: 0,
correct: 0,
incorrect: 0,
activeGame: true,
questionsAnswer: [
{ // 1
question: 'What is 8 x 1 ?',
options: [ 2, 7, 8, 9],
answer: 8
},
{ // 2
question: 'What is 3 + 4 ?',
options: [ 5, 7, 9, 34],
answer: 7
},
{ // 3
question: 'What is 10 - 6 ?',
options: [ 2, 4, 10, 7],
answer: 4
},
{ // 4
question: 'What is 12 / 3 ?',
options: [ 4, 6, 3, 8],
answer: 4
},
{ // 5
question: 'What is 11 + 0 ?',
options: [ 15, 11, 12, 10],
answer: 11
},
{ // 6
question: 'What is 13 + 2 ?',
options: [ 4, 17, 9, 15],
answer: 15
},
{ // 7
question: 'What is 33 / 11 ?',
options: [ 2, 3, 4, 1],
answer: 3
},
{ // 8
question: 'What is 2 + 5 ?',
options: [ 10, 7, 8, 6],
answer: 7
},
{ // 9
question: 'What is 9 - 4 ?',
options: [ 5, 7, 6, 9],
answer: 5
},
{ // 10
question: 'What is 11 * 2 ?',
options: [ 20, 22, 33, 34],
answer: 22
}
]
};
}
resetGame() {
this.setState({
currentIndex: 0,
correct: 0,
incorrect: 0,
activeGame: true
});
}
processGuess(e) {
if (this.state.currentIndex + 1 === this.state.questionsAnswer.length) {
this.setState( { activeGame: false } );
return;
}
// For accomplishing a better readible equality-check.
let answer = parseInt(e.target.textContent);
let correctAnswer =
parseInt(
this.state.questionsAnswer[this.state.currentIndex]['answer']
);
if ( answer === correctAnswer ) {
this.setState( {correct: this.state.correct + 1} );
} else {
this.setState( {incorrect: this.state.incorrect + 1} );
}
this.setState( {currentIndex: this.state.currentIndex + 1} );
}
render() {
var options = [];
if (this.state.activeGame) {
for (let i = 0; i < this.state
.questionsAnswer[0]
.options
.length; i++) {
options.push( <Option optionValue={
this
.state
.questionsAnswer[this.state.currentIndex]
.options[i] }
triggerProcess = { this.processGuess }
activeGame = { this.state.activeGame } /> );
}
}
return ( <div>
<div className="row">
<div className="offset-lg-2 col-lg-7 col-md-12">
<QuestionPanel activeGame={ this.state.activeGame }
question={
this
.state
.questionsAnswer[this.state.currentIndex]
.question }
resetGame = { this.resetGame } />
<div className={ this.state.activeGame
? 'visible'
: 'hidden' } >
{ options }
</div>
</div>
<div className="col-lg-3 col-md-12">
<StatusDisplay
correct={ this.state.correct }
incorrect={ this.state.incorrect } />
</div>
</div>
</div> );
}
}
ReactDOM.render( <GameBoard className="game-board" />,
document.getElementById('board') );
body {
font-family: verdana, sans-serif;
background-color: rgba(150, 150, 150, .6);
}
.container {
margin-top: 15px;
}
.option-card {
height: 50px;
background-color: rgba(240, 240, 240, 1.0);
border: 1px solid;
text-align: center;
line-height: 50px;
display: block;
text-decoration: none;
border-radius: 6px;
margin-bottom: 3px;
box-shadow: 3px 3px 3px rgba(50, 50, 50, 0.5);
color: rgba(20, 20, 20, 1.0);
}
.option-card:hover {
text-decoration: none;
opacity: 0.7;
color: rgba(0, 0, 0, 1.0);
}
.option-card:active {
text-decoration: none;
box-shadow: 1px 1px 2px rgba(50, 50, 50, 0.5);
color: rgba(20, 20, 20, 1.0);
}
.question-panel {
font-size: 1.5rem;
color: crimson;
font-weight: 800;
font-size: 1.6rem;
text-align: center;
}
.question-panel.message {
color: blue;
}
.status-display {
margin-top: 52px;
font-weight: 900;
}
.hyperlink-button {
text-align: center;
}
.hyperlink-button a {
text-decoration: none;
padding: 10px 15px;
border: 2px solid;
color: #000;
margin: 10px 0 15px;
border-radius: 15px;
display: inline-block;
}
.hyperlink-button a:hover {
color: #fff;
}
.hyperlink-button a:active {
opacity: 0.7;
}
.hidden {
display: none;
}
<div id="board" class="container"></div>
Working live-demo on CodePen !
For accomplishing responsive behavior I used Twitter Bootstrap.
It looks rather fine to me. But it has become a lot of code. I have seen solutions of others which were shorter.
Therefore my questions:
Is my implementation done in a good way and fashion?
Where could it be improved? Especially concerning brevity.
Looking forward to reading your hints and suggestions.