diff --git a/src/App.js b/src/App.js index dd73f43..0298ef0 100644 --- a/src/App.js +++ b/src/App.js @@ -65,7 +65,10 @@ function App() { let country = globalDataMap[d.iso3]; if (!country) { globalDataMap[d.iso3] = pick(d, ['countryRegion', 'lastUpdate', 'confirmed', 'recovered', 'deaths', 'active']); - globalDataMap[d.iso3].provinces = { [d.provinceState]: pick(d, fieldsToFilter) }; + globalDataMap[d.iso3].provinces = {}; + if (d.provinceState) { + globalDataMap[d.iso3].provinces[d.provinceState] = pick(d, fieldsToFilter); + } } else { metrics.forEach(m => { country[m] += d[m]; @@ -73,7 +76,9 @@ function App() { if (d.lastUpdate > country.lastUpdate) { country.lastUpdate = d.lastUpdate; } - country.provinces[d.provinceState] = pick(d, fieldsToFilter); + if (d.provinceState) { + country.provinces[d.provinceState] = pick(d, fieldsToFilter); + } } }) window.globalDataMap = globalDataMap; // for debugging purpose diff --git a/src/components/stats-panel.css b/src/components/stats-panel.css index 08fe3ae..433456b 100644 --- a/src/components/stats-panel.css +++ b/src/components/stats-panel.css @@ -6,7 +6,7 @@ } .stats-panel { - width: 450px; + width: 470px; max-width: calc(100vw - 2rem); margin: 1rem; position: absolute; @@ -26,12 +26,14 @@ display: flex; justify-content: space-between; overflow-x: auto; + margin: -1rem; + padding: 1rem; } .stats-group .ant-statistic { cursor: pointer; - padding: 6px; - margin-right: 6px; + padding: 8px; + margin-right: 8px; border-radius: 4px; user-select: none; } @@ -49,21 +51,21 @@ } .stats-list { - height: 40vh; + /* max-height: 40vh; */ margin: 1rem -1rem -1rem -1rem; border-top: 1px solid #f0f0f0; } -.stats-list .ant-spin-nested-loading { +/* .stats-list .ant-spin-nested-loading { height: 100%; } .stats-list .ant-spin-container { height: 100%; -} +} */ .stats-list .ant-list-items { - height: 100%; + max-height: 40vh; overflow: auto; } @@ -73,3 +75,24 @@ display: flex; justify-content: space-between; } + +.clickable { + cursor: pointer; +} + +.clickable:hover { + background-color: rgb(244, 245, 248); +} + + +/* card title */ +.stats-panel .ant-card-head-title { + padding: 0; + display: flex; + flex-direction: column; +} + +.breadcrumb-item:hover { + color: #40a9ff; + cursor: pointer; +} diff --git a/src/components/stats-panel.js b/src/components/stats-panel.js index 35c7650..c32b203 100644 --- a/src/components/stats-panel.js +++ b/src/components/stats-panel.js @@ -1,7 +1,8 @@ import React, { useState } from 'react'; -import { Statistic, Card, List, Button } from 'antd'; +import { Statistic, Card, List, Button, Breadcrumb } from 'antd'; import { LineChartOutlined, CloseOutlined } from '@ant-design/icons'; -import numeral from 'numeral' +import numeral from 'numeral'; +import { isEmpty } from 'lodash'; import './stats-panel.css'; @@ -9,34 +10,53 @@ import './stats-panel.css'; export default function StatsPanel ({ globalData }) { const [minimized, setMinimized] = useState(false); const [metric, setMetric] = useState('active'); + const [countryCode, setCountry] = useState(); // iso3 - const total = { + let total = { active: 0, confirmed: 0, recovered: 0, deaths: 0, } - - const countryList = Object.entries(globalData).map(([iso3, data]) => { - total.confirmed += data.confirmed; - total.active += data.active; - total.recovered += data.recovered; - total.deaths += data.deaths; - return { ...data, iso3 }; - }).sort((c1, c2) => c2[metric] - c1[metric]); const metricList = Object.keys(total); + let areaList = []; + if (countryCode && globalData[countryCode]) { // country + total = globalData[countryCode]; + if (!isEmpty(globalData[countryCode].provinces)) { + areaList = Object.entries(globalData[countryCode].provinces).map(([areaCode, data]) => { + return { ...data, areaCode, name: data.provinceState || 'N/A' }; + }) + } + } else { // global + areaList = Object.entries(globalData).map(([areaCode, data]) => { + total.confirmed += data.confirmed; + total.active += data.active; + total.recovered += data.recovered; + total.deaths += data.deaths; + return { ...data, areaCode, name: data.countryRegion }; + }) + } + areaList.sort((c1, c2) => c2[metric] - c1[metric]); + console.log(areaList); + + const resetPanel = () => { + setMinimized(false); + setCountry(null); + } + if (minimized) { return ( ); return ( - + + )} + className='stats-panel' + extra={collapseBtn} + >
{metricList.map(m => (
setMetric(m)} key={m}> @@ -58,16 +84,38 @@ export default function StatsPanel ({ globalData }) {
))}
- ( - - {country.countryRegion} - {numeral(country[metric]).format('0,0')} - - )} - /> + {areaList && areaList.length > 0 && ( + ( + !countryCode && setCountry(area.areaCode)}> + {area.name} + {numeral(area[metric]).format('0,0')} + + )} + /> + )}
) } + +const CardTitle = ({ country, setCountry }) => { + let title = 'Global Stats'; + if (country) { + title = country; + } + + return ( +
+ { country && ( + + setCountry(null)}>Global Stats + > + + )} +

{title}

+
+ ) +}