Trividado Number is a web application where the user must answer 10 questions related to random numbers.
The questions are generated through the API http://numbersapi.com/.
For each question, 4 answer options will be given and the player will have two options to answer, between Confirm and Skip to the next question.
Each answer will be kept in history. The user will be able to see the questions with the status of the answer. After finishing the game, a summary page with the results obtained and an option is presented to return to the game.
- ReactJs
- Jest y Enzyme
- Styled-Components
After cloning the repository in your local machine, you should do the following steps to run the app in your machine:
npm install npm start
If you want to run the suite of test:
jest --watchAll
- Correctly structure the state of the application and its transitions.
- Differentiate responsibilities for each component.
- Control the different error cases that may arise (errors in the API, etc.)
- Testing: All layers should have at least one test (unit, integration). 100% coverage is not required.
- Add a progress bar for the remaining time of each question that, as it progresses, changes color.
- Implement a responsive design.
- Persist the state of the game, so that when reloading the page everything continues where it left off.
- Use Redux to manage the state of the application.
- The use of hooks will be valued
- The use of styled-components will be valued
Sprint 1 | Sprint 2 | Sprint 3 | Sprint 4 | Sprint 5 | Sprint 6 |
---|---|---|---|---|---|
Initialize the project with creat-react-project and prepare the basic structure of the folders and the App component. | Get one question rendered. For it: Create a switch between the "Welcome" and "Questions" components. | Program the composition of the API URL. | "Confirm" and "Skip" buttons | Records of questions answered. | Tests |
Analyze the API. | Send a generic question to render on the “Questions” component by props. | Do the fetching and render questions with real data from the API. | Play Again button. |
-
index.js
:- Apply "ThemeProvider", from Styled-Component, with the application colors and spacing;
- "HashRouter" is used.
-
App.js
:- Global reset styles are applied with “createGlobalStyle”, from Styled-Component.
- Switch between Welcome page and the game page.
-
Welcome.js
:- Button with link to game start.
- Include a home page subtitle, that will omit with the button when the user click on Start.
-
Questions.js
:- Receives API data formatted for questions;
- Stores in the state the answer selected by the user in the child component.
- Keeps in the state the list of questions answered to generate the history.
- Disables the 'confirm' and 'skip' buttons when the limit of questions is reached.
-
Question.js
:- Receives questions information sent by props from Question component.
- Render the question and the answers options.
- Send user answer selected to Questions component by lifting.
-
AnswerRecords.js
:- Receives answers list by props from Questions component.
- Render the answer, the status (correct, error, or skipped).
- Render the solution (in error or skipped situation).
To get the data from the API, three components are organized to:
- Make the call and get the response promise (src/services/fetchApi.js);
- Format the received data (src/services/parserQuestions.js);
- Intermediate between the call to the API and that sends the response formatted src/services/fetchQuestions.js to the App component).
In the game Trividado the player must answer questions about 10 random numbers. Instead to rerun a call to the server for each question round, in this project it was chosen to make a single call to the API when loading the page, which directly brings the data of 10 numbers chosen to the azer. And for that it was necessary to program the construction of the URL with 10 aleatory numbers. The advantages are:
- Reduce the amount of data consumed by the user's device;
- Decrease the time to load the application;
- Reduce the risk of server crashes in the middle of the game;
fetchApi.js:
const ENDPOINT = 'http://numbersapi.com/';
const qtyQuestions = 10;
const fetchApi = () => {
const randomNumbers = generateRandomNumbers(qtyQuestions).join();
return fetch(ENDPOINT + randomNumbers)
.then(response => response.json());
}
const generateRandomNumbers = (qty) => {
let numbers = [];
while (numbers.length < qty) {
let random = Math.floor(Math.random() * 100);
if (!numbers.includes(random))
numbers.push(random);
}
return numbers;
}
In addition, there is another challenge with the API. The data received from the server has the following standard, and it is not enough to generate the questions.
{
"1": "1 is the number of dimensions of a line.",
"2": "2 is the number of polynucleotide strands in a DNA double helix.",
"3": "3 is the number of sets needed to be won to win the whole match in volleyball.",
"10": "10 is the highest score possible in Olympics gymnastics competitions."
}
For the API data to have been used, it is necessary to format to this standard:
const questions = [
{ "question": "Is the number of dimensions of a line.", "solution": "1", "options": ["3", "1", "0", "4"] },
{ "question": "Is the number of polynucleotide strands in a DNA double helix.", "answer": "2", "options": ["2", "4", "0", "5"] },
{ "question": "Is the number of sets needed to be won to win the whole match in volleyball.", "answer": "3", "options": ["2", "4", "3", "5"] },
{ "question": "Is the highest score possible in Olympics gymnastics competitions.", "answer": "10", "options": ["9", "14", "20", "10"] }
]
That is:
- Eliminate the number that comes in the question and transform the first letter of the question into a capital letter:
parserQuestions.js:
const formatFact = (number, fact) => {
const parseFact = fact.replace(number + " ", "");
return parseFact[0].toUpperCase() + parseFact.slice(1);
}
- Save the solution on a variable and define the other answers options, shuffling:
parserQuestions.js:
const generateOptions = (solution) => {
let numbers = [solution];
while (numbers.length < 4) {
let random = Math.floor(Math.random() * 100);
if (!numbers.includes(random))
numbers.push(random);
}
return numbers.sort(() => Math.random() - 0.5);
}
- Generate the question final structure:
parserQuestions.js:
const generateQuestion = (number, fact) => {
return {
"question": formatFact(number, fact),
"solution": number,
"options": generateOptions(number)
};
}
Once you have all the data ready, fetchQuestions.js
takes care of passing this information to the App
component, where the list of questions will be sent to the Questions
component through hooks.
- Progress bar and timer I have been able to do the progress bar component. It worked well for the first and second questions but did not skip to the others questions.
- Testing components with hooks and styled-component I have troubles to mount properly the components with the right context using the theme configuration and hooks.
- Issue storing state in local storage related with async For any reason, I can´t start storing the status of the answers in a sync way. It is storing the status without the last answer. For example, if the current status is the user answered until the questions 8, the local storage has stored the status until the question 7.