Covid-19 Tracker Website With React, Material.UI And Chart.js

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
  1. import React from 'react';  
  2. import ReactDom from 'react-dom';  
  3. import App from './App';  
  4.   
  5. //first component is App, second parameter is the element we want to render it on  
  6. ReactDom.render(<App />, document.getElementById('root')); 
Step 5
 
Let's Add App.js in the src folder.
  1. import React from 'react';  
  2. class App extends React.Component {  
  3.      
  4.     render(){  
  5.        return(  
  6.        <H1>Covid-19</H1>  
  7.     )  
  8. }  
  9. }  
  10.   
  11. export default App; 
Step 6
 
Let's install all dependencies.
  1. we need Axios: this will make a get request to an API
  2. react-chartjs-2: libraries for making charts
  3. 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.
  1. import axios from 'axios';  
  2.   
  3. const url ='https://covid19.mathdro.id/api';  
  4.   
  5. export const fetchData = async (country) => {  
  6.     let changableurl = url;  
  7.     if(country){  
  8.         changableurl = `${url}/countries/${country}`  
  9.     }  
  10.     try {  
  11.         const { data: {confirmed, recovered, deaths, lastUpdate} } = await axios.get(changableurl);  
  12.         return {confirmed, recovered, deaths, lastUpdate};  
  13.     }  
  14.     catch(error){  
  15.         console.log(error);  
  16.     }  
  17. };  
  18.   
  19. export const fetchDailyData = async () =>{  
  20.     try{  
  21.         const {data}  = await axios.get(`${url}/daily`);  
  22.         return data.map(({ confirmed, deaths, reportDate: date }) => ({ confirmed: confirmed.total, deaths: deaths.total, date }));  
  23.     }  
  24.     catch(error){  
  25.         return error  
  26.     }  
  27. };  
  28.   
  29. export const fetchCountries = async () =>{  
  30.     try{  
  31.     const {data:{countries}} = await axios.get(`${url}/countries`);  
  32.     return countries.map((country)=> country.name);  
  33.     }     
  34.     catch(error){  
  35.         return error  
  36.     }  
  37. }; 
Step 9
 
src\Components\Cards\Cards.jsx : This js loads 3 cards : Infected, Recovered & deaths on the top of the website.
  1. import React from 'react';  
  2. import styles from './Cards.module.css'  
  3. import {Card, CardContent, Typography, Grid, StylesProvider} from '@material-ui/core';  
  4. import CountUp from 'react-countup';  
  5. import cx from 'classnames';  
  6. import Button from '@material-ui/core/Button';  
  7.   
  8.   
  9.   
  10. const Cards = ({ data: { confirmed, recovered, deaths, lastUpdate } } ) => {  
  11.      if(!confirmed){  
  12.         return 'Please wait..';  
  13.     }  
  14.    console.log(lastUpdate);  
  15.     return (  
  16.         <div className={styles.container}>  
  17.             <Grid container spacing = {3} justify="center">  
  18.                 <Grid style={{backgroundColor: 'rgba(208, 208, 241, 0.5)'}} item component={Card} xs={12} md={3} className={cx(styles.card, styles.infected)}>  
  19.                     <CardContent >  
  20.                         <Typography color="textSecondary" gutterBottom>Infected</Typography>  
  21.                         <Typography variant="h5" >  
  22.                             <CountUp start={0} end={confirmed.value} duration={3} separator="," />  
  23.                         </Typography>  
  24.                         <Typography color="textSecondary">{new Date(lastUpdate).toDateString()}</Typography>                
  25.                         <Typography variant="body2">Number of active cases of Covid-19</Typography>  
  26.                     </CardContent>  
  27.                 </Grid>  
  28.   
  29.                 <Grid style={{backgroundColor: 'rgba(188, 253, 188, 0.5)'}} item component={Card} xs={12} md={3} className={cx(styles.card, styles.recovered)}>  
  30.                     <CardContent>  
  31.                         <Typography color="textSecondary" gutterBottom>Recovered</Typography>  
  32.                         <Typography variant="h5" >  
  33.                             <CountUp start={0} end={recovered.value} duration={3} separator="," />  
  34.                         </Typography>  
  35.                         <Typography color="textSecondary" >{new Date(lastUpdate).toDateString()}</Typography>  
  36.                         <Typography variant="body2">Number of recoveries from Covid-19</Typography>  
  37.                     </CardContent>  
  38.                 </Grid>  
  39.   
  40.                 <Grid style={{backgroundColor: 'rgba(245, 192, 192, 0.5)'}}  item component={Card} xs={12} md={3} className={cx(styles.card, styles.deaths)}>  
  41.                     <CardContent>  
  42.                         <Typography color="textSecondary" gutterBottom>Deaths</Typography>  
  43.                         <Typography variant="h5" >  
  44.                             <CountUp start={0} end={deaths.value} duration={3} separator="," />  
  45.                         </Typography>  
  46.                         <Typography color="textSecondary" >{new Date(lastUpdate).toDateString()}</Typography>  
  47.                         <Typography variant="body2">Number of deaths caused by Covid-19</Typography>  
  48.                     </CardContent>  
  49.                 </Grid>  
  50.   
  51.                 <Grid className={styles.btnGrid} >   
  52.                  <Button  style={{backgroundColor: '#4A148C'}} className={styles.btnMyGov}  variant="contained" color="primary" href="https://www.mohfw.gov.in/">  
  53.                 mohfw  
  54.                 </Button>   
  55.                 <Button style={{backgroundColor: '#004D40'}} className={styles.btnMyGov}  variant="contained" color="primary" href="https://www.mygov.in/covid-19">  
  56.                  mygov  
  57.                 </Button>  
  58.                  <Button style={{backgroundColor: '#900C3F'}} className={styles.btnMyGov}  variant="contained" color="primary" href="https://twitter.com/who?lang=en">  
  59.                  WHO  
  60.                 </Button>  
  61.                 <Button style={{backgroundColor: '#581845'}} className={styles.btnMyGov}  variant="contained" color="primary" href="https://twitter.com/PIB_India">  
  62.                  PIB:IN  
  63.                 </Button>  
  64.                 </Grid>  
  65.             </Grid>  
  66.         </div>  
  67.         )  
  68. }  
  69. export default Cards; 
Step 10
 
src\Components\Cards\Cards.module.css : It is a CSS for cards, @media tag is responsible for responsive view. 
  1. .container {  
  2. margin20px 0;  
  3. }  
  4.   
  5. .card {  
  6.     margin0 1% !important;  
  7. }  
  8.   
  9. .infected {  
  10.     border-bottom10px solid rgba(002550.5);  
  11. }  
  12.   
  13. .recovered {  
  14.     border-bottom10px solid rgba(025500.5);  
  15. }  
  16.   
  17. .deaths {  
  18.     border-bottom10px solid rgba(255000.5);  
  19. }  
  20.   
  21. .links {  
  22.     border-bottom10px solid rgba(01581970.5);  
  23. }  
  24.   
  25. .btnMyGov{  
  26.     height30px;      
  27.     margin-right5px !important;  
  28.     width95px;  
  29. }  
  30.   
  31. .btnGrid{  
  32.     margin-top10px !important;  
  33. }  
  34. @media only screen and (max-width770px) {  
  35.     .card{  
  36.       margin2% 0 !important;  
  37.     }  
  38.   } 
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
  1. import React,{useState, useEffect} from 'react';  
  2. import { fetchDailyData } from '../../API';  
  3. import { Line, Bar } from 'react-chartjs-2';  
  4. import styles from './Chart.module.css'  
  5. import { Container } from '@material-ui/core';  
  6.   
  7. const Chart = ({data:{confirmed, recovered, deaths}, country}) => {  
  8.     //this is a set representation with setter method of a state  
  9.     const [dailyData, setDailyData] = useState([]);  
  10.       
  11.     useEffect(() => {  
  12.     const fetchAPI = async()=>{  
  13.         setDailyData(await fetchDailyData());  
  14.         }  
  15.         fetchAPI();  
  16.     },[]);  
  17.   
  18. const lineChart =(  
  19.     dailyData.length ? (   
  20.         <Line data={{  
  21.                         labels: dailyData.map(({date}) =>  date),  
  22.                         datasets :[{  
  23.                             data :  dailyData.map(({confirmed}) =>  confirmed),  
  24.                             label: 'Infected',  
  25.                             borderColor: '#3333ff',  
  26.                             fill: true,  
  27.                         },  
  28.                         {  
  29.                             data :  dailyData.map(({deaths}) =>  deaths),  
  30.                             label: 'Deaths',  
  31.                             borderColor: 'red',  
  32.                             backgroundColor: 'rgba(255, 0, 0, 0.5)',  
  33.                             fill: true,  
  34.                         }]  
  35.                     }}  
  36.                     options={ {  
  37.                         scales : { xAxes : [ { gridLines : { display : false } } ], yAxes : [ { gridLines : { display : false } } ] }  
  38.                     } }  
  39.                     />):null  
  40.                     );  
  41.   
  42. const BarChart  =(  
  43.        confirmed?(  
  44.         <Bar  
  45.         data={{  
  46.             labels: ['Infected''Recovered''Deaths'],  
  47.             datasets:[{  
  48.                 label:'People',  
  49.                 backgroundColor:['rgba(0, 0, 255, 0.5)','rgba(0, 255, 0, 0.5)''rgba(255, 0, 0, 0.5)' ],  
  50.                 data:[confirmed.value, recovered.value, deaths.value]  
  51.             }]  
  52.         }}  
  53.         options={{  
  54.             legend:{display:false},  
  55.             title: {display:true, text:`current state in ${country}`}  
  56.         }}  
  57.         />             
  58.         ): null  
  59.     )  
  60.     return (  
  61.      <div className={styles.container}>  
  62.          {country? BarChart : lineChart}  
  63.      </div>  
  64.     )  
  65. }  
  66. export default Chart; 
Step 12
 
src\Components\Charts\Chart.module.css: css for charts.
  1. .container{  
  2.     display: flex;  
  3.     justify-contentcenter;  
  4.     width85%;  
  5. }  
  6.   
  7.   
  8. @media only screen and (max-width770px) {  
  9.     .container{  
  10.       width100%;  
  11.     }  
  12.   } 
Step 13
 
src\Components\CountryPicker\CountryPicker.jsx : Drop down to select a country based on the selected the country showing a bar chart.
  1. import React, {useState, useEffect} from 'react';  
  2. import {NativeSelect, FormControl} from '@material-ui/core';  
  3. import styles from './CountryPicker.module.css';  
  4. import {fetchCountries} from '../../API';  
  5. const CountryPicker = ({handleCountryChange}) => {  
  6. const [fetchedCountires, setFetchedCountires] = useState([]);  
  7.   
  8. useEffect(()=>{  
  9.     const fetchAPI = async () =>{  
  10.         setFetchedCountires(await fetchCountries());  
  11.     }  
  12.     fetchAPI();  
  13. }, [setFetchedCountires])  
  14. console.log(fetchedCountires);  
  15.     return (  
  16.         <FormControl  className={styles.formControl}>      
  17.         <NativeSelect defaultValue="" onChange ={(e) => handleCountryChange(e.target.value)}  variant="filled">  
  18.             <option value="">Global</option>  
  19.     {fetchedCountires.map((country,i) => <option key={i} value={country}>{country}</option>)}  
  20.         </NativeSelect>  
  21.         </FormControl >  
  22.     )  
  23. }  
  24. export default CountryPicker; 
Step 14
 
src\Components\CountryPicker\CountryPicker.module.css, css for country picker.
  1. .formControl{  
  2.     width30%;  
  3.     margin-bottom30px !important;  
  4. }  
  5. @media only screen and (max-width700px) {  
  6.     .formControl{  
  7.       width100%;  
  8.     }  
  9.   } 
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 
  1. export {default as Cards } from './Cards/Cards';  
  2. export {default as Charts } from './Charts/Chart';  
  3. 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.
  1. import React from 'react';  
  2. import styles from './App.module.css'  
  3. import {Cards, Charts, CountryPicker } from './Components'  
  4. import {fetchData} from './API';//we dont have to specify index file name if your file name is index  
  5. import coronaImage from './Images/Covid19Tracker.png';  
  6. class App extends React.Component {  
  7.     state = {         
  8.     data: {},  
  9.     country: '',  
  10.     }  
  11.     async componentDidMount(){  
  12.         const data = await fetchData();  
  13.         //console.log(fetchedData);  
  14.         this.setState({data});  
  15.     }  
  16.   
  17.      handleCountryChange = async (country) => {          
  18.         const data = await fetchData(country);  
  19.         this.setState({data: data, country: country});  
  20.      }  
  21.   
  22.     render(){  
  23.         const {data, country } = this.state;  
  24.         return(  
  25.         <div  className={styles.container} >  
  26.             <img className={styles.image} src={coronaImage} alt="Covid-19"/>  
  27.             <Cards data={data}/>  
  28.             <CountryPicker handleCountryChange={this.handleCountryChange}/>  
  29.             <Charts data={data} country={country}/>  
  30.         </div>  
  31.     )  
  32. }  
  33. }  
  34.   
  35. export default App; 
Step 17
 
src\App.module.css: CSS for our App.js
  1. body{  
  2.     background-color:  rgb(250 , 250250);  
  3. }  
  4.   
  5. .container{  
  6.     display: flex;  
  7.     align-items: center;  
  8.     justify-contentcenter;  
  9.     flex-direction: column;  
  10. }  
  11.   
  12. .image{  
  13.      width370px;  
  14.      margin-top20px;  
  15. }  
  16.   
  17. @media only screen and (max-width770px) {  
  18.     .container{  
  19.       margin0 10%;  
  20.     }  
  21.     
  22.     .image{  
  23.       width100%;  
  24.     }  
  25.   } 
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


Similar Articles