├── _config.yml
├── .firebaserc
├── public
├── favicon.ico
└── index.html
├── src
├── images
│ └── image.png
├── components
│ ├── CountryPicker
│ │ ├── CountryPicker.module.css
│ │ └── CountryPicker.jsx
│ ├── Cards
│ │ ├── Card
│ │ │ ├── Card.module.css
│ │ │ └── Card.jsx
│ │ ├── Cards.module.css
│ │ └── Cards.jsx
│ ├── index.js
│ └── Chart
│ │ ├── Chart.module.css
│ │ └── Chart.jsx
├── index.js
├── App.module.css
├── App.js
└── api
│ └── index.js
├── firebase.json
├── .gitignore
├── README.md
├── package.json
├── .firebase
└── hosting.YnVpbGQ.cache
└── .eslintrc.js
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-cayman
--------------------------------------------------------------------------------
/.firebaserc:
--------------------------------------------------------------------------------
1 | {
2 | "projects": {
3 | "default": "alanbinu-covid19-tracker"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlanBinu007/React-Covid19-Tracker/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/src/images/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlanBinu007/React-Covid19-Tracker/HEAD/src/images/image.png
--------------------------------------------------------------------------------
/src/components/CountryPicker/CountryPicker.module.css:
--------------------------------------------------------------------------------
1 | .formControl {
2 | width: 30%;
3 | margin-bottom: 30px !important;
4 | }
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 |
4 | import App from './App';
5 |
6 | ReactDOM.render(, document.getElementById('root'));
7 |
--------------------------------------------------------------------------------
/src/components/Cards/Card/Card.module.css:
--------------------------------------------------------------------------------
1 | .card {
2 | margin: 0 2% !important;
3 | }
4 | @media only screen and (max-width: 770px) {
5 | .card {
6 | margin: 2% 0 !important;
7 | }
8 | }
--------------------------------------------------------------------------------
/src/components/index.js:
--------------------------------------------------------------------------------
1 | export { default as Chart } from './Chart/Chart';
2 | export { default as CountryPicker } from './CountryPicker/CountryPicker';
3 | export { default as Cards } from './Cards/Cards';
4 |
--------------------------------------------------------------------------------
/src/components/Chart/Chart.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | display: flex;
3 | justify-content: center;
4 | width: 65%;
5 | }
6 |
7 | @media only screen and (max-width: 770px) {
8 | .container {
9 | width: 100%;
10 | }
11 | }
--------------------------------------------------------------------------------
/firebase.json:
--------------------------------------------------------------------------------
1 | {
2 | "hosting": {
3 | "public": "build",
4 | "ignore": [
5 | "firebase.json",
6 | "**/.*",
7 | "**/node_modules/**"
8 | ],
9 | "rewrites": [
10 | {
11 | "source": "**",
12 | "destination": "/index.html"
13 | }
14 | ]
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/components/Cards/Cards.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | display: flex;
3 | flex-direction: column;
4 | align-items: center;
5 | margin: 50px 0;
6 | }
7 |
8 | .infected {
9 | border-bottom: 10px solid rgba(0, 0, 255, 0.5);
10 | }
11 |
12 | .recovered{
13 | border-bottom: 10px solid rgba(0, 255, 0, 0.5);
14 | }
15 |
16 | .deaths{
17 | border-bottom: 10px solid rgba(255, 0, 0, 0.5);
18 | }
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/src/App.module.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: rgb(250, 250,250);
3 | }
4 |
5 | .container {
6 | display: flex;
7 | align-items: center;
8 | flex-direction: column;
9 | }
10 |
11 | .image {
12 | width: 370px;
13 | margin-top: 50px;
14 | }
15 |
16 | @media only screen and (max-width: 770px) {
17 | .container {
18 | margin: 0 10%;
19 | }
20 |
21 | .image {
22 | width: 100%;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Covid-19 Traker
2 |
3 | **Project Link** - ***https://alanbinu-covid19-tracker.web.app/***
4 |
5 | ## Tech We Used
6 |
7 | - ReactJs
8 | - React Routing
9 | - Firebase Hosting
10 | - Firebase Storage
11 | - Basic HTML5 and CSS
12 |
13 | ## Features
14 |
15 | - Search by country
16 | - Sort options
17 | - Easy visualization
18 | - Neat and clean UI
19 |
20 | ## Steps to run in your machine
21 |
22 | #### Run the following commands
23 | ```
24 | npm i
25 | npm run start
26 | ```
27 |
28 |
29 |
30 |
31 | #### Hope you liked this project, dont forget to ⭐ the repo.
32 |
--------------------------------------------------------------------------------
/src/components/CountryPicker/CountryPicker.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import { NativeSelect, FormControl } from '@material-ui/core';
3 |
4 | import { fetchCountries } from '../../api';
5 |
6 | import styles from './CountryPicker.module.css';
7 |
8 | const Countries = ({ handleCountryChange }) => {
9 | const [countries, setCountries] = useState([]);
10 |
11 | useEffect(() => {
12 | const fetchAPI = async () => {
13 | setCountries(await fetchCountries());
14 | };
15 |
16 | fetchAPI();
17 | }, []);
18 |
19 | return (
20 |
21 | handleCountryChange(e.target.value)}>
22 |
23 | {countries.map((country, i) => )}
24 |
25 |
26 | );
27 | };
28 |
29 | export default Countries;
30 |
--------------------------------------------------------------------------------
/src/components/Cards/Card/Card.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Card, CardContent, Typography, Grid } from '@material-ui/core';
3 | import CountUp from 'react-countup';
4 | import cx from 'classnames';
5 |
6 | import styles from './Card.module.css';
7 |
8 | const CardComponent = ({ className, cardTitle, value, lastUpdate, cardSubtitle }) => (
9 |
10 |
11 |
12 | {cardTitle}
13 |
14 |
15 |
16 |
17 |
18 | {new Date(lastUpdate).toDateString()}
19 |
20 |
21 | {cardSubtitle}
22 |
23 |
24 |
25 | );
26 |
27 | export default CardComponent;
28 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import { Cards, CountryPicker, Chart } from './components';
4 | import { fetchData } from './api/';
5 | import styles from './App.module.css';
6 |
7 | import image from './images/image.png';
8 |
9 | class App extends React.Component {
10 | state = {
11 | data: {},
12 | country: '',
13 | }
14 |
15 | async componentDidMount() {
16 | const data = await fetchData();
17 |
18 | this.setState({ data });
19 | }
20 |
21 | handleCountryChange = async (country) => {
22 | const data = await fetchData(country);
23 |
24 | this.setState({ data, country: country });
25 | }
26 |
27 | render() {
28 | const { data, country } = this.state;
29 |
30 | return (
31 |
32 |

33 |
34 |
35 |
36 |
37 | );
38 | }
39 | }
40 |
41 | export default App;
--------------------------------------------------------------------------------
/src/api/index.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 |
3 |
4 | // new api url
5 |
6 | const url = 'https://covid19.mathdro.id/api';
7 |
8 | export const fetchData = async (country) => {
9 | let changeableUrl = url;
10 |
11 | if (country) {
12 | changeableUrl = `${url}/countries/${country}`;
13 | }
14 |
15 | try {
16 | const { data: { confirmed, recovered, deaths, lastUpdate } } = await axios.get(changeableUrl);
17 |
18 | return { confirmed, recovered, deaths, lastUpdate };
19 | } catch (error) {
20 | return error;
21 | }
22 | };
23 |
24 | export const fetchDailyData = async () => {
25 | try {
26 | const { data } = await axios.get('https://api.covidtracking.com/v1/us/daily.json');
27 |
28 | return data.map(({ positive, recovered, death, dateChecked: date }) => ({ confirmed: positive, recovered, deaths: death, date }));
29 | } catch (error) {
30 | return error;
31 | }
32 | };
33 |
34 | export const fetchCountries = async () => {
35 | try {
36 | const { data: { countries } } = await axios.get(`${url}/countries`);
37 |
38 | return countries.map((country) => country.name);
39 | } catch (error) {
40 | return error;
41 | }
42 | };
43 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "corona_app",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@material-ui/core": "^4.9.7",
7 | "@testing-library/jest-dom": "^4.2.4",
8 | "@testing-library/react": "^9.5.0",
9 | "@testing-library/user-event": "^7.2.1",
10 | "axios": "^0.19.2",
11 | "chart.js": "^2.9.3",
12 | "classnames": "^2.2.6",
13 | "react": "^16.13.1",
14 | "react-chartjs-2": "^2.9.0",
15 | "react-countup": "^4.3.3",
16 | "react-dom": "^16.13.1",
17 | "react-scripts": "3.4.1"
18 | },
19 | "scripts": {
20 | "start": "react-scripts start",
21 | "build": "react-scripts build",
22 | "test": "react-scripts test",
23 | "eject": "react-scripts eject"
24 | },
25 | "eslintConfig": {
26 | "extends": "react-app"
27 | },
28 | "browserslist": {
29 | "production": [
30 | ">0.2%",
31 | "not dead",
32 | "not op_mini all"
33 | ],
34 | "development": [
35 | "last 1 chrome version",
36 | "last 1 firefox version",
37 | "last 1 safari version"
38 | ]
39 | },
40 | "devDependencies": {
41 | "eslint": "^6.8.0",
42 | "eslint-config-airbnb": "^18.1.0",
43 | "eslint-plugin-import": "^2.20.2",
44 | "eslint-plugin-jsx-a11y": "^6.2.3",
45 | "eslint-plugin-react": "^7.19.0",
46 | "eslint-plugin-react-hooks": "^2.5.1"
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/components/Cards/Cards.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Typography, Grid } from '@material-ui/core';
3 | import CardComponent from './Card/Card';
4 | import styles from './Cards.module.css';
5 |
6 | const Info = ({ data: { confirmed, recovered, deaths, lastUpdate } }) => {
7 | if (!confirmed) {
8 | return 'Loading...';
9 | }
10 |
11 | return (
12 |
13 | Global
14 |
15 |
22 |
29 |
36 |
37 |
38 | );
39 | };
40 |
41 | export default Info;
42 |
--------------------------------------------------------------------------------
/.firebase/hosting.YnVpbGQ.cache:
--------------------------------------------------------------------------------
1 | asset-manifest.json,1631344553719,1e5bc2a6e3b8e498ebb170d513ad42b248ad0518a6b067c94ec2313bac6e1b2f
2 | favicon.ico,1631343641691,65e87e033f11e13e46eed5b6fce9c2cb507aa6d6481c82a2168f50c5c654b2f8
3 | precache-manifest.7e7879c4dbf90b24d7ceaaaa24cad34e.js,1631344553719,7efd7139939e9b90ca766dd56a299a346f395fec11346d4f4d57c67fae9c60c3
4 | index.html,1631344553719,01209522b20398b0c29dc9f40d0fc0810f86dd10f9a27ee0a7902221695659a6
5 | service-worker.js,1631344553719,7b5c5205eea5976b0c83f76382cc4d9c8d6fc0f01e0936c9c377bb2d6360fba5
6 | static/js/2.ea59d149.chunk.js.LICENSE.txt,1631344553728,c859aeea5c8f5e9ac1f434469ea188ddb57eec02441a3d618d373bf705dcf549
7 | static/css/main.26cbd97d.chunk.css.map,1631344553728,0eedbef9f9bf31f18187f62e82d6e252ee023a3fd23a87c9c7feb8f823ae5d22
8 | static/css/main.26cbd97d.chunk.css,1631344553720,b6df2b3ca8d919ecf416847237f676171315e0b35f4a015fdf2dc1c84d4c94e5
9 | static/js/main.69f1b8a0.chunk.js,1631344553721,302e7d358b9cc1fabad89d25b494617f3a689bb60f8b17b0eb62efd6f6f801cf
10 | static/js/runtime-main.20a4ba51.js,1631344553728,11f11f2c7503af11635eaa157a24f60a4b4e2880d9d0d4f8a3270e54bf7ee157
11 | static/js/runtime-main.20a4ba51.js.map,1631344553728,fc879e4a0264dc83be83988d85df6ac59d07b55ef9de3e4de2e0623499d5f740
12 | static/js/main.69f1b8a0.chunk.js.map,1631344553728,4df4b1fb34afd0502b6922cfee453123052fefbef4d78045c20a1cc869cc9a90
13 | static/media/image.d7265326.png,1631344553720,9088a185740b8a9ea070bbb1d5a5572aa3a53c0a8fff7676afd57b297187df4b
14 | static/js/2.ea59d149.chunk.js,1631344553728,7e9d721115c6fd04dba79745498eada375b38ac239452ee906be03d6833a5686
15 | static/js/2.ea59d149.chunk.js.map,1631344553729,874ac5eaacaf6ca79b4c92952b1fd37560122cb046b9d48a05bab0cb6eea301e
16 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | browser: true,
4 | es6: true,
5 | },
6 | extends: [
7 | 'plugin:react/recommended',
8 | 'airbnb',
9 | ],
10 | globals: {
11 | Atomics: 'readonly',
12 | SharedArrayBuffer: 'readonly',
13 | },
14 | parserOptions: {
15 | ecmaFeatures: {
16 | jsx: true,
17 | },
18 | ecmaVersion: 2018,
19 | sourceType: 'module',
20 | },
21 | plugins: [
22 | 'react',
23 | ],
24 | rules: {
25 | "import/prefer-default-export": 0,
26 | "max-len": [
27 | 2,
28 | 250
29 | ],
30 | "no-multiple-empty-lines": [
31 | "error",
32 | {
33 | "max": 1,
34 | "maxEOF": 1
35 | }
36 | ],
37 | "no-underscore-dangle": [
38 | "error",
39 | {
40 | "allow": [
41 | "_d",
42 | "_dh",
43 | "_h",
44 | "_id",
45 | "_m",
46 | "_n",
47 | "_t",
48 | "_text"
49 | ]
50 | }
51 | ],
52 | "object-curly-newline": 0,
53 | "react/prop-types": 0,
54 | "react/jsx-filename-extension": 0,
55 | "react/jsx-one-expression-per-line": 0,
56 | "jsx-a11y/click-events-have-key-events": 0,
57 | "jsx-a11y/alt-text": 0,
58 | "jsx-a11y/no-autofocus": 0,
59 | "jsx-a11y/no-static-element-interactions": 0,
60 | "react/no-array-index-key": 0,
61 | "jsx-a11y/anchor-is-valid": [
62 | "error",
63 | {
64 | "components": [
65 | "Link"
66 | ],
67 | "specialLink": [
68 | "to",
69 | "hrefLeft",
70 | "hrefRight"
71 | ],
72 | "aspects": [
73 | "noHref",
74 | "invalidHref",
75 | "preferButton"
76 | ]
77 | }
78 | ]
79 | }
80 | };
81 |
--------------------------------------------------------------------------------
/src/components/Chart/Chart.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import { Line, Bar } from 'react-chartjs-2';
3 |
4 | import { fetchDailyData } from '../../api';
5 |
6 | import styles from './Chart.module.css';
7 |
8 | const Chart = ({ data: { confirmed, recovered, deaths }, country }) => {
9 | const [dailyData, setDailyData] = useState({});
10 |
11 | useEffect(() => {
12 | const fetchMyAPI = async () => {
13 | const initialDailyData = await fetchDailyData();
14 |
15 | setDailyData(initialDailyData);
16 | };
17 |
18 | fetchMyAPI();
19 | }, []);
20 |
21 | const barChart = (
22 | confirmed ? (
23 |
39 | ) : null
40 | );
41 |
42 | const lineChart = (
43 | dailyData[0] ? (
44 | new Date(date).toLocaleDateString()),
47 | datasets: [{
48 | data: dailyData.map((data) => data.confirmed),
49 | label: 'Infected',
50 | borderColor: '#3333ff',
51 | fill: true,
52 | }, {
53 | data: dailyData.map((data) => data.deaths),
54 | label: 'Deaths',
55 | borderColor: 'red',
56 | backgroundColor: 'rgba(255, 0, 0, 0.5)',
57 | fill: true,
58 | }, {
59 | data: dailyData.map((data) => data.recovered),
60 | label: 'Recovered',
61 | borderColor: 'green',
62 | backgroundColor: 'rgba(0, 255, 0, 0.5)',
63 | fill: true,
64 | },
65 | ],
66 | }}
67 | />
68 | ) : null
69 | );
70 |
71 | return (
72 |
73 | {country ? barChart : lineChart}
74 |
75 | );
76 | };
77 |
78 | export default Chart;
79 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Corona Virus Tracker
10 |
11 |
12 |
13 |
14 |
72 |
73 |
74 |
--------------------------------------------------------------------------------