├── README.md
├── package.json
├── public
└── index.html
└── src
├── App.js
├── Components
├── Country.js
├── CountryCases.js
├── GlobalTotals.js
├── InProgress
│ └── Gauge.js
├── News.js
└── NewsColumn.js
├── State
├── InProgress
│ └── use-maps.js
├── use-backend.js
└── use-news-backend.js
├── background.png
├── index.js
├── layout
└── HomeLayout.js
├── styles.css
└── views
├── CountryView.js
├── HeadingView.js
├── HomeView.js
└── Totals.js
/README.md:
--------------------------------------------------------------------------------
1 | # API_update_corona_app
2 | Created with CodeSandbox
3 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "spa-with-api-corona",
3 | "version": "1.0.0",
4 | "description": "",
5 | "keywords": [],
6 | "main": "src/index.js",
7 | "dependencies": {
8 | "react": "16.12.0",
9 | "react-dom": "16.12.0",
10 | "react-router": "5.1.2",
11 | "react-router-dom": "5.1.2",
12 | "react-scripts": "3.0.1"
13 | },
14 | "devDependencies": {
15 | "typescript": "3.3.3"
16 | },
17 | "scripts": {
18 | "start": "react-scripts start",
19 | "build": "react-scripts build",
20 | "test": "react-scripts test --env=jsdom",
21 | "eject": "react-scripts eject"
22 | },
23 | "browserslist": [
24 | ">0.2%",
25 | "not dead",
26 | "not ie <= 11",
27 | "not op_mini all"
28 | ]
29 | }
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
14 |
23 | React App
24 |
25 |
26 |
27 |
30 |
31 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { HashRouter as Router, Route } from "react-router-dom";
3 | import "./styles.css";
4 | import HomeLayout from "./layout/HomeLayout";
5 | import Country from "./Components/Country";
6 | import CountryView from "./views/CountryView";
7 |
8 | export default function App() {
9 | return (
10 |
11 |
12 |
13 |
14 |
15 |
16 | );
17 | }
18 |
--------------------------------------------------------------------------------
/src/Components/Country.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const Country = (props) => {
4 | console.log("arrived", props);
5 |
6 | return (
7 |
8 |
{props.location.state.country}
9 | {props.location.state.cases}
10 |
11 | );
12 | };
13 |
14 | export default Country;
15 |
--------------------------------------------------------------------------------
/src/Components/CountryCases.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Link } from "react-router-dom";
3 |
4 | const CountryCases = (props) => {
5 | return (
6 |
148 | );
149 | };
150 |
151 | export default CountryCases;
152 |
--------------------------------------------------------------------------------
/src/Components/GlobalTotals.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Cases } from "../State/use-backend";
3 |
4 | const GlobalTotal = () => {
5 | const { data } = Cases();
6 | const stats = { ...data };
7 |
8 | // let totalCritical = 0;
9 | let totalDeaths = 0;
10 | let totalNewCases = 0;
11 | let totalRecoveries = 0;
12 | let totalCases = 0;
13 | let totalNewDeaths = 0;
14 |
15 | Object.entries(stats).map(stat => {
16 | // totalCritical += stat[1].critical;
17 | totalDeaths += stat[1].deaths;
18 | totalNewCases += stat[1].todayCases;
19 | totalRecoveries += stat[1].recovered;
20 | totalCases += stat[1].cases;
21 | totalNewDeaths += stat[1].todayDeaths;
22 | return totalNewDeaths;
23 | });
24 |
25 | return (
26 |
27 |
28 |

33 |
34 | {totalCases.toLocaleString(navigator.language, {
35 | minimumFractionDigits: 0
36 | })}
37 |
38 |
All Global Cases
39 |
40 | {/*
41 |
42 | {totalCritical.toLocaleString(navigator.language, {
43 | minimumFractionDigits: 0
44 | })}
45 |
46 |
Total critical cases
47 |
*/}
48 |
49 |

54 |
55 | {totalDeaths.toLocaleString(navigator.language, {
56 | minimumFractionDigits: 0
57 | })}
58 |
59 |
Global Deceased
60 |
61 |
62 |

67 |
68 | {totalRecoveries.toLocaleString(navigator.language, {
69 | minimumFractionDigits: 0
70 | })}
71 |
72 |
Global Recoveries
73 |
74 |
75 |

80 |
81 | {totalNewCases.toLocaleString(navigator.language, {
82 | minimumFractionDigits: 0
83 | })}
84 |
85 |
Global New Cases
86 |
87 |
88 |

93 |
94 | {totalNewDeaths.toLocaleString(navigator.language, {
95 | minimumFractionDigits: 0
96 | })}
97 |
98 |
Global Deaths Today
99 |
100 |
101 | );
102 | };
103 |
104 | export default GlobalTotal;
105 |
--------------------------------------------------------------------------------
/src/Components/InProgress/Gauge.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VernitaJ/API_update_corona_app/89d48c5866493a8c3a3a27a872139ca3ca00360f/src/Components/InProgress/Gauge.js
--------------------------------------------------------------------------------
/src/Components/News.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { NewsStories } from "../State/use-news-backend";
3 |
4 | const News = () => {
5 | const { news } = NewsStories();
6 | const stories = { ...news };
7 |
8 | return (
9 |
10 |
11 | {Object.entries(stories).map((news, key) => {
12 | return (
13 |
31 | );
32 | })}
33 |
34 |
35 | );
36 | };
37 |
38 | export default News;
39 |
--------------------------------------------------------------------------------
/src/Components/NewsColumn.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import News from "./News";
3 |
4 | const NewsColumn = () => {
5 | return (
6 |
7 |
NEWS AND INFORMATION
8 |
15 |
16 |
17 | );
18 | };
19 |
20 | export default NewsColumn;
21 |
--------------------------------------------------------------------------------
/src/State/InProgress/use-maps.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { geolocated } from "react-geolocated";
3 |
4 | class Demo extends React.Component {
5 | render() {
6 | return !this.props.isGeolocationAvailable ? (
7 | Your browser does not support Geolocation
8 | ) : !this.props.isGeolocationEnabled ? (
9 | Geolocation is not enabled
10 | ) : this.props.coords ? (
11 |
12 |
13 |
14 | latitude |
15 | {this.props.coords.latitude} |
16 |
17 |
18 | longitude |
19 | {this.props.coords.longitude} |
20 |
21 |
22 | altitude |
23 | {this.props.coords.altitude} |
24 |
25 |
26 | heading |
27 | {this.props.coords.heading} |
28 |
29 |
30 | speed |
31 | {this.props.coords.speed} |
32 |
33 |
34 |
35 | ) : (
36 | Getting the location data…
37 | );
38 | }
39 | }
40 |
41 | export default geolocated({
42 | positionOptions: {
43 | enableHighAccuracy: false
44 | },
45 | userDecisionTimeout: 5000
46 | })(Demo);
47 |
--------------------------------------------------------------------------------
/src/State/use-backend.js:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from "react";
2 |
3 | export const Cases = () => {
4 | const [data, setData] = useState(null);
5 | const [error, setError] = useState(null);
6 | const [isLoading, setIsLoading] = useState(true);
7 |
8 | // Fetch user data when the username change
9 | useEffect(() => {
10 | const load = async () => {
11 | setIsLoading(true);
12 | setError(null);
13 | try {
14 | const res = await fetch(`https://corona.lmao.ninja/v2/countries`);
15 | const data = await res.json();
16 | setData(data);
17 | } catch (err) {
18 | console.error(err);
19 | setError(new Error("could not load"));
20 | } finally {
21 | setIsLoading(false);
22 | }
23 | };
24 |
25 | load();
26 | }, []);
27 |
28 | return {
29 | isLoading,
30 | data,
31 | error
32 | };
33 | };
34 |
--------------------------------------------------------------------------------
/src/State/use-news-backend.js:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from "react";
2 |
3 | export const NewsStories = () => {
4 | const [news, setNews] = useState([]);
5 | console.log("news", news);
6 | var proxyUrl = "https://cors-anywhere.herokuapp.com/";
7 | var targetUrl =
8 | "https://newsapi.org/v2/top-headlines?country=gb&apiKey=986a408f8bbe4b628257aaa2367bcf4e";
9 |
10 | // const [error, setError] = useState(null);
11 | // const [isLoading, setIsLoading] = useState(true);
12 | async function fetchData() {
13 | const response = await fetch(proxyUrl + targetUrl);
14 | response
15 | .json()
16 | .then(news => setNews(news))
17 | .catch(err => console.error(err));
18 | }
19 |
20 | useEffect(() => {
21 | fetchData();
22 | }, []);
23 |
24 | return {
25 | news
26 | };
27 | };
28 |
--------------------------------------------------------------------------------
/src/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VernitaJ/API_update_corona_app/89d48c5866493a8c3a3a27a872139ca3ca00360f/src/background.png
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom";
3 |
4 | import App from "./App";
5 |
6 | const rootElement = document.getElementById("root");
7 | ReactDOM.render(
8 |
9 |
10 | ,
11 | rootElement
12 | );
13 |
--------------------------------------------------------------------------------
/src/layout/HomeLayout.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import HomeView from "../views/HomeView";
3 | import Totals from "../views/Totals";
4 | import HeadingView from "../views/HeadingView";
5 |
6 | const HomeLayout = () => {
7 | return (
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | );
18 | };
19 |
20 | export default HomeLayout;
21 |
--------------------------------------------------------------------------------
/src/styles.css:
--------------------------------------------------------------------------------
1 | .App {
2 | font-family: sans-serif;
3 | color: white;
4 | }
5 |
6 | body {
7 | background-color: rgb(0, 0, 77);
8 | }
9 |
10 | .home-view__heading {
11 | font-size: 40px;
12 | display: block;
13 | margin-top: 0;
14 | padding: 30px;
15 | margin-left: 30px;
16 | margin-right: auto;
17 | width: 20%;
18 | }
19 |
20 | .home-view__heading-image {
21 | display: block;
22 | margin-top: 20px;
23 | padding: 30px;
24 | margin-right: 70px;
25 | width: 15%;
26 | }
27 |
28 | .home-view__heading-WHO {
29 | margin-top: 50px;
30 | width: 70px;
31 | color: rgb(252, 252, 90);
32 | }
33 |
34 | .home-view__first-column {
35 | font-size: 10px;
36 | margin-right: 20px;
37 | left: 0;
38 | }
39 |
40 | h2.home-view__first-column {
41 | font-size: 30px;
42 | }
43 |
44 | .home-view__column {
45 | margin-right: 20px;
46 | font-size: 10px;
47 | }
48 |
49 | .home-view__total-count {
50 | color: rgb(196, 94, 94);
51 | }
52 |
53 | .home-view__heading-container {
54 | display: flex;
55 | justify-content: space-around;
56 | }
57 |
58 | .home-view__container {
59 | display: flex;
60 | width: 40px;
61 | }
62 |
63 | .container {
64 | display: flex;
65 | flex-direction: row;
66 | border: solid darkred 4px;
67 | border-radius: 10px 10px;
68 | background-color: rgb(0, 0, 51, 0.95);
69 | font-family: Helvetica, sans-serif;
70 | height: auto;
71 | padding: 15px;
72 | margin-top: 40px;
73 | margin-left: 25px;
74 | }
75 |
76 | .home-view__total-row {
77 | display: flex;
78 | margin-left: 40px;
79 | }
80 |
81 | .home-view__total-container {
82 | border: solid whitesmoke 2px;
83 | background-color: rgb(0, 0, 51, 0.95);
84 | border-radius: 10px 10px;
85 | display: block;
86 | margin-right: 20px;
87 | width: 190px;
88 | height: auto;
89 | }
90 |
91 | .home-view__total-new-container {
92 | border: solid lightyellow 2px;
93 | background-color: rgb(0, 0, 51, 0.95);
94 | border-radius: 10px 10px;
95 | display: block;
96 | margin-left: 150px;
97 | margin-right: 20px;
98 | width: 180px;
99 | height: auto;
100 | }
101 |
102 | h3.total__info {
103 | margin-top: 0;
104 | text-align: center !important;
105 | }
106 |
107 | p.total__info {
108 | margin-block-start: 15px;
109 | margin-block-end: 20px;
110 | font-size: 14px;
111 | text-align: center !important;
112 | }
113 |
114 | .total__div-image {
115 | height: 40px;
116 | display: block;
117 | padding: 10px;
118 | margin-left: auto;
119 | margin-right: auto;
120 | width: 40%;
121 | }
122 |
123 | .home-view__data {
124 | font-size: 14px;
125 | color: white;
126 | }
127 |
128 | .cases-table__row {
129 | display: flex;
130 | text-align: left;
131 | }
132 |
133 | .cases-table__column-heading {
134 | width: 120px;
135 | font-size: 18px;
136 | margin-bottom: 20px;
137 | }
138 |
139 | .cases-table__column-country,
140 | a {
141 | font-size: 18px;
142 | text-decoration: none;
143 | width: 120px;
144 | height: 50px;
145 | margin-left: 3px;
146 | color: white;
147 | }
148 |
149 | .cases-table__column-cases {
150 | font-size: 18px;
151 | width: 120px;
152 | height: 50px;
153 | margin-left: 10px;
154 | color: lightcoral;
155 | }
156 |
157 | .cases-table__column-deceased {
158 | font-size: 18px;
159 | width: 120px;
160 | height: 50px;
161 | color: red;
162 | }
163 |
164 | .cases-table__column-recovered {
165 | font-size: 18px;
166 | width: 120px;
167 | height: 50px;
168 | color: green;
169 | }
170 |
171 | .cases-table__column-critical {
172 | font-size: 18px;
173 | width: 120px;
174 | height: 50px;
175 | margin-left: 0px;
176 | color: orange;
177 | }
178 |
179 | .cases-table__column-newCases {
180 | font-size: 18px;
181 | width: 120px;
182 | height: 50px;
183 | color: lightblue;
184 | }
185 |
186 | .home-view__news-column {
187 | display: flex;
188 | align-items: flex-end;
189 | flex-direction: column;
190 | margin-right: 10px;
191 | margin-left: 30px;
192 | }
193 |
194 | .home-view__news-item {
195 | width: 400px;
196 | height: 250px;
197 | background-color: rgb(0, 0, 51, 0.95);
198 | margin-top: 44px;
199 | position: relative;
200 | border: 2px solid white;
201 | border-radius: 5px 5px;
202 | }
203 |
204 | .container__stats-and-news {
205 | display: flex;
206 | justify-content: space-between;
207 | }
208 |
209 | .news-column__heading {
210 | margin-right: 40px;
211 | color: rgb(241, 241, 88);
212 | margin-top: 40px;
213 | margin-bottom: 0;
214 | letter-spacing: 2px;
215 | }
216 |
217 | .news-column__article-heading {
218 | margin: 15px;
219 | color: lightyellow;
220 | }
221 |
222 | .news-column__article-link {
223 | display: flex;
224 | justify-content: space-around;
225 | text-decoration: none;
226 | }
227 |
228 | .news-column__article-image {
229 | height: auto;
230 | width: 220px;
231 | display: block;
232 | margin-left: 0;
233 | }
234 |
235 | .news-column__article-text {
236 | position: absolute;
237 | font-size: 14px;
238 | bottom: 20px;
239 | right: 20px;
240 | background-color: rgb(0, 0, 51, 0.5);
241 | color: white;
242 | padding-left: 20px;
243 | padding-right: 20px;
244 | }
245 |
246 | .sort-button {
247 | display: flex;
248 | background-color: transparent;
249 | border: none;
250 | margin-left: -7px;
251 | font-weight: bold;
252 | font-size: 15px;
253 | color: white;
254 | }
255 |
256 | .sort-button__svg {
257 | width: 10px;
258 | height: 10px;
259 | margin-top: 4px;
260 | margin-left: 7px;
261 | }
262 |
--------------------------------------------------------------------------------
/src/views/CountryView.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import Country from "../Components/Country";
3 | import NewsColumn from "../Components/NewsColumn";
4 | import { Cases } from "../State/use-backend";
5 |
6 | class CountryView extends React.Component {
7 | state = {
8 | stat: null
9 | };
10 |
11 | componentDidMount() {
12 | const { country } = this.props.match.params;
13 | const { stat } = this.props.location.state;
14 |
15 | fetch(`https://corona.lmao.ninja/v3/covid-19/countries/${country}`).then(
16 | (stat) => {
17 | this.setState(() => ({ stat }));
18 | }
19 | );
20 | }
21 |
22 | render() {
23 | return ;
24 | }
25 | }
26 |
27 | export default CountryView;
28 |
--------------------------------------------------------------------------------
/src/views/HeadingView.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const HeadingView = () => {
4 | return (
5 |
6 |
7 |
8 |
Corona Outbreak Live Stats
9 |
10 | Updates on the global pandemic{" "}
11 |
12 |
18 |
22 |
23 |
24 |
25 |
26 | );
27 | };
28 |
29 | export default HeadingView;
30 |
--------------------------------------------------------------------------------
/src/views/HomeView.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import CountryCases from "../Components/CountryCases";
3 | import NewsColumn from "../Components/NewsColumn";
4 | // import { Cases } from "../State/use-backend";
5 |
6 | const HomeView = () => {
7 | const [data, setData] = useState({});
8 | const [error, setError] = useState(null);
9 | const [isLoading, setIsLoading] = useState(true);
10 |
11 | // Fetch user data when the username change
12 | useEffect(() => {
13 | const load = async () => {
14 | setIsLoading(true);
15 | setError(null);
16 | try {
17 | const res = await fetch(`https://corona.lmao.ninja/v2/countries`);
18 | const data = await res.json();
19 | console.log("changing data");
20 | setData(data);
21 | } catch (err) {
22 | console.error(err);
23 | setError(new Error("could not load"));
24 | } finally {
25 | setIsLoading(false);
26 | }
27 | };
28 | load();
29 | }, []);
30 | // // const { data, isLoading } = Cases();
31 | // const [stats, setStats] = useState(data);
32 |
33 | const sortBy = sortField => {
34 | let sorting;
35 | if (sortField === "country") {
36 | sorting = [...data].sort((a, b) => {
37 | if (a[sortField] > b[sortField]) {
38 | return 1;
39 | } else {
40 | return -1;
41 | }
42 | });
43 | } else {
44 | sorting = [...data].sort((a, b) => {
45 | if (a[sortField] < b[sortField]) {
46 | return 1;
47 | } else {
48 | return -1;
49 | }
50 | });
51 | }
52 | setData(sorting);
53 | createBody();
54 | };
55 |
56 | const createBody = () => {
57 | if (isLoading) {
58 | return "Loading";
59 | } else {
60 | return ;
61 | }
62 | };
63 |
64 | return (
65 |
66 | {createBody()}
67 |
68 |
69 | );
70 | };
71 |
72 | export default HomeView;
73 |
--------------------------------------------------------------------------------
/src/views/Totals.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import GlobalTotal from "../Components/GlobalTotals";
3 |
4 | const Totals = () => {
5 | return (
6 |
7 |
8 |
9 | );
10 | };
11 |
12 | export default Totals;
13 |
--------------------------------------------------------------------------------