Introduction
Hi everyone, in this time of crisis let's do something for society. Let's make a COVID-19 tracking website which can show real-time data in the form of charts. Also, we will add filters as per the country.
Features of the website: Easy to use, Attractive UI, Charts speaks more than text, real-time data, and last but not least, it is a responsive website for both desktop & mobile view.
Tools & language used: VS Code, Node.js (has to be installed), React, Material.UI & Chart.js
This is what our final product will look like:
- 3 cards showing Infected, Recovered & Deaths count
- Line chart representing the global count, separating the infected & death count line over the last 3 months.
- Filter as per country, the selected country's results will be displayed by the bar chart.
- Mobile view: responsive to both Auto-Rotate.
- Cards in the mobile view.
- The bar chart in the mobile view.
Let's get into coding.
Step 1
Install VS-Code & Node.js to begin.
Step 2
Create an empty folder and name as you desire: e.g. covid19tracker
Step 3
Open VS code go to the terminal then navigate to the folder that you just created
Now type this command in PowerShell : npx create-react-app ./ (this will create an empty React app in into your folder).
After successful installation, delete everything inside the src folder. Let's build everything from scratch.
Step 4
Add index.js
- import React from 'react';
- import ReactDom from 'react-dom';
- import App from './App';
-
-
- ReactDom.render(<App />, document.getElementById('root'));
Step 5
Let's Add App.js in the src folder.
- import React from 'react';
- class App extends React.Component {
-
- render(){
- return(
- <H1>Covid-19</H1>
- )
- }
- }
-
- export default App;
Step 6
Let's install all dependencies.
- we need Axios: this will make a get request to an API
- react-chartjs-2: libraries for making charts
- react-countup: Animation for counting numbers
Final command: npm install --save axios react-chartjs-2 react-countup classnames
After successful installation, use this command: npm start, It will run your application on localhost: port 3000
Step 7
Now create a Components folder: and create 3 new folders inside the component folder.
Cards, 2. Charts & 3.CountryPicker: each folder is responsible for its own style & component
Go inside 1st folder Cards and create Cards.jsx & Cards.module.css, then follow the same with both of the folders follow the proper naming conventions. It is very important to load CSS.
Also, create a folder name API & Add index.js inside the API folder, as shown.
Step 8
API/Index.js: it loads Axios, which is responsible for REST calls. As you can see, we are making 3 different calls for charts, cards & country picker.
- import axios from 'axios';
-
- const url ='https://covid19.mathdro.id/api';
-
- export const fetchData = async (country) => {
- let changableurl = url;
- if(country){
- changableurl = `${url}/countries/${country}`
- }
- try {
- const { data: {confirmed, recovered, deaths, lastUpdate} } = await axios.get(changableurl);
- return {confirmed, recovered, deaths, lastUpdate};
- }
- catch(error){
- console.log(error);
- }
- };
-
- export const fetchDailyData = async () =>{
- try{
- const {data} = await axios.get(`${url}/daily`);
- return data.map(({ confirmed, deaths, reportDate: date }) => ({ confirmed: confirmed.total, deaths: deaths.total, date }));
- }
- catch(error){
- return error
- }
- };
-
- export const fetchCountries = async () =>{
- try{
- const {data:{countries}} = await axios.get(`${url}/countries`);
- return countries.map((country)=> country.name);
- }
- catch(error){
- return error
- }
- };
Step 9
src\Components\Cards\Cards.jsx : This js loads 3 cards : Infected, Recovered & deaths on the top of the website.
- import React from 'react';
- import styles from './Cards.module.css'
- import {Card, CardContent, Typography, Grid, StylesProvider} from '@material-ui/core';
- import CountUp from 'react-countup';
- import cx from 'classnames';
- import Button from '@material-ui/core/Button';
-
-
-
- const Cards = ({ data: { confirmed, recovered, deaths, lastUpdate } } ) => {
- if(!confirmed){
- return 'Please wait..';
- }
- console.log(lastUpdate);
- return (
- <div className={styles.container}>
- <Grid container spacing = {3} justify="center">
- <Grid style={{backgroundColor: 'rgba(208, 208, 241, 0.5)'}} item component={Card} xs={12} md={3} className={cx(styles.card, styles.infected)}>
- <CardContent >
- <Typography color="textSecondary" gutterBottom>Infected</Typography>
- <Typography variant="h5" >
- <CountUp start={0} end={confirmed.value} duration={3} separator="," />
- </Typography>
- <Typography color="textSecondary">{new Date(lastUpdate).toDateString()}</Typography>
- <Typography variant="body2">Number of active cases of Covid-19</Typography>
- </CardContent>
- </Grid>
-
- <Grid style={{backgroundColor: 'rgba(188, 253, 188, 0.5)'}} item component={Card} xs={12} md={3} className={cx(styles.card, styles.recovered)}>
- <CardContent>
- <Typography color="textSecondary" gutterBottom>Recovered</Typography>
- <Typography variant="h5" >
- <CountUp start={0} end={recovered.value} duration={3} separator="," />
- </Typography>
- <Typography color="textSecondary" >{new Date(lastUpdate).toDateString()}</Typography>
- <Typography variant="body2">Number of recoveries from Covid-19</Typography>
- </CardContent>
- </Grid>
-
- <Grid style={{backgroundColor: 'rgba(245, 192, 192, 0.5)'}} item component={Card} xs={12} md={3} className={cx(styles.card, styles.deaths)}>
- <CardContent>
- <Typography color="textSecondary" gutterBottom>Deaths</Typography>
- <Typography variant="h5" >
- <CountUp start={0} end={deaths.value} duration={3} separator="," />
- </Typography>
- <Typography color="textSecondary" >{new Date(lastUpdate).toDateString()}</Typography>
- <Typography variant="body2">Number of deaths caused by Covid-19</Typography>
- </CardContent>
- </Grid>
-
- <Grid className={styles.btnGrid} >
- <Button style={{backgroundColor: '#4A148C'}} className={styles.btnMyGov} variant="contained" color="primary" href="https://www.mohfw.gov.in/">
- mohfw
- </Button>
- <Button style={{backgroundColor: '#004D40'}} className={styles.btnMyGov} variant="contained" color="primary" href="https://www.mygov.in/covid-19">
- mygov
- </Button>
- <Button style={{backgroundColor: '#900C3F'}} className={styles.btnMyGov} variant="contained" color="primary" href="https://twitter.com/who?lang=en">
- WHO
- </Button>
- <Button style={{backgroundColor: '#581845'}} className={styles.btnMyGov} variant="contained" color="primary" href="https://twitter.com/PIB_India">
- PIB:IN
- </Button>
- </Grid>
- </Grid>
- </div>
- )
- }
- export default Cards;
Step 10
src\Components\Cards\Cards.module.css : It is a CSS for cards, @media tag is responsible for responsive view.
- .container {
- margin: 20px 0;
- }
-
- .card {
- margin: 0 1% !important;
- }
-
- .infected {
- border-bottom: 10px solid rgba(0, 0, 255, 0.5);
- }
-
- .recovered {
- border-bottom: 10px solid rgba(0, 255, 0, 0.5);
- }
-
- .deaths {
- border-bottom: 10px solid rgba(255, 0, 0, 0.5);
- }
-
- .links {
- border-bottom: 10px solid rgba(0, 158, 197, 0.5);
- }
-
- .btnMyGov{
- height: 30px;
- margin-right: 5px !important;
- width: 95px;
- }
-
- .btnGrid{
- margin-top: 10px !important;
- }
- @media only screen and (max-width: 770px) {
- .card{
- margin: 2% 0 !important;
- }
- }
Step 11
src\Components\Charts\Chart.jsx: This loads both bar and line chart: Line chart to show global data & bar chart to represent a single country.
Fire this command: npm install --save chart.js
This will install chart.js into your react app
Then, fire this command: npm install --save @material-ui/core
After successful installation: fire : npm start
- import React,{useState, useEffect} from 'react';
- import { fetchDailyData } from '../../API';
- import { Line, Bar } from 'react-chartjs-2';
- import styles from './Chart.module.css'
- import { Container } from '@material-ui/core';
-
- const Chart = ({data:{confirmed, recovered, deaths}, country}) => {
-
- const [dailyData, setDailyData] = useState([]);
-
- useEffect(() => {
- const fetchAPI = async()=>{
- setDailyData(await fetchDailyData());
- }
- fetchAPI();
- },[]);
-
- const lineChart =(
- dailyData.length ? (
- <Line data={{
- labels: dailyData.map(({date}) => date),
- datasets :[{
- data : dailyData.map(({confirmed}) => confirmed),
- label: 'Infected',
- borderColor: '#3333ff',
- fill: true,
- },
- {
- data : dailyData.map(({deaths}) => deaths),
- label: 'Deaths',
- borderColor: 'red',
- backgroundColor: 'rgba(255, 0, 0, 0.5)',
- fill: true,
- }]
- }}
- options={ {
- scales : { xAxes : [ { gridLines : { display : false } } ], yAxes : [ { gridLines : { display : false } } ] }
- } }
- />):null
- );
-
- const BarChart =(
- confirmed?(
- <Bar
- data={{
- labels: ['Infected', 'Recovered', 'Deaths'],
- datasets:[{
- label:'People',
- backgroundColor:['rgba(0, 0, 255, 0.5)','rgba(0, 255, 0, 0.5)', 'rgba(255, 0, 0, 0.5)' ],
- data:[confirmed.value, recovered.value, deaths.value]
- }]
- }}
- options={{
- legend:{display:false},
- title: {display:true, text:`current state in ${country}`}
- }}
- />
- ): null
- )
- return (
- <div className={styles.container}>
- {country? BarChart : lineChart}
- </div>
- )
- }
- export default Chart;
Step 12
src\Components\Charts\Chart.module.css: css for charts.
- .container{
- display: flex;
- justify-content: center;
- width: 85%;
- }
-
-
- @media only screen and (max-width: 770px) {
- .container{
- width: 100%;
- }
- }
Step 13
src\Components\CountryPicker\CountryPicker.jsx : Drop down to select a country based on the selected the country showing a bar chart.
- import React, {useState, useEffect} from 'react';
- import {NativeSelect, FormControl} from '@material-ui/core';
- import styles from './CountryPicker.module.css';
- import {fetchCountries} from '../../API';
- const CountryPicker = ({handleCountryChange}) => {
- const [fetchedCountires, setFetchedCountires] = useState([]);
-
- useEffect(()=>{
- const fetchAPI = async () =>{
- setFetchedCountires(await fetchCountries());
- }
- fetchAPI();
- }, [setFetchedCountires])
- console.log(fetchedCountires);
- return (
- <FormControl className={styles.formControl}>
- <NativeSelect defaultValue="" onChange ={(e) => handleCountryChange(e.target.value)} variant="filled">
- <option value="">Global</option>
- {fetchedCountires.map((country,i) => <option key={i} value={country}>{country}</option>)}
- </NativeSelect>
- </FormControl >
- )
- }
- export default CountryPicker;
Step 14
src\Components\CountryPicker\CountryPicker.module.css, css for country picker.
- .formControl{
- width: 30%;
- margin-bottom: 30px !important;
- }
- @media only screen and (max-width: 700px) {
- .formControl{
- width: 100%;
- }
- }
Step 15
src\Components\index.js: we need to create one more index.js inside component folder, to load all this 3 components into API/index.js
- export {default as Cards } from './Cards/Cards';
- export {default as Charts } from './Charts/Chart';
- export {default as CountryPicker } from './CountryPicker/CountryPicker';
Step 16
src\App.js, after adding all the functionalities we need to update App.js: responsible for sending country & data together in to single view so website can dnamically change based on country's selection whether to show a bar chart or line chart.
- import React from 'react';
- import styles from './App.module.css'
- import {Cards, Charts, CountryPicker } from './Components'
- import {fetchData} from './API';
- import coronaImage from './Images/Covid19Tracker.png';
- class App extends React.Component {
- state = {
- data: {},
- country: '',
- }
- async componentDidMount(){
- const data = await fetchData();
-
- this.setState({data});
- }
-
- handleCountryChange = async (country) => {
- const data = await fetchData(country);
- this.setState({data: data, country: country});
- }
-
- render(){
- const {data, country } = this.state;
- return(
- <div className={styles.container} >
- <img className={styles.image} src={coronaImage} alt="Covid-19"/>
- <Cards data={data}/>
- <CountryPicker handleCountryChange={this.handleCountryChange}/>
- <Charts data={data} country={country}/>
- </div>
- )
- }
- }
-
- export default App;
Step 17
src\App.module.css: CSS for our App.js
- body{
- background-color: rgb(250 , 250, 250);
- }
-
- .container{
- display: flex;
- align-items: center;
- justify-content: center;
- flex-direction: column;
- }
-
- .image{
- width: 370px;
- margin-top: 20px;
- }
-
- @media only screen and (max-width: 770px) {
- .container{
- margin: 0 10%;
- }
-
- .image{
- width: 100%;
- }
- }
Last step
We also need to add one image at the top of the page, Image is free to reuse. You can download images and source code from the GitHub
link.
Try something new today. Feel good about yourself.
Happy coding!
Give some stars to the repository if you liked the project.
You can connect with me.
References - https://www.youtube.com/watch?v=khJlrj3Y6Ls&t=3s
API used - https://covid19.mathdro.id/api