diff --git a/src/pages/Covid.jsx b/src/pages/Covid.jsx index 59695c1..3b65806 100644 --- a/src/pages/Covid.jsx +++ b/src/pages/Covid.jsx @@ -2,15 +2,15 @@ * COVID-19 DASHBOARD TODOs * ------------------------ * Easy: - * - [ ] Show date of summary data (API provides Date field) - * - [ ] Format numbers with abbreviation utility - * - [ ] Add refresh button - * - [ ] Add note/link about data source & potential delays + * - [x] Show date of summary data (API provides Date field) + * - [x] Format numbers with abbreviation utility + * - [x] Add refresh button + * - [x] Add note/link about data source & potential delays * Medium: - * - [ ] Country search input (filter dropdown) - * - [ ] Sort countries (Total Confirmed, New Confirmed, Deaths) + * - [x] Country search input (filter dropdown) + * - [x] Sort countries (Total Confirmed, New Confirmed, Deaths) * - [ ] Persist last selected country - * - [ ] Basic trend chart (cases over time) for selected country + * - [x] Basic trend chart (cases over time) for selected country * Advanced: * - [ ] Multi-country comparison chart * - [ ] Data normalization per million population (needs population API) @@ -18,6 +18,8 @@ * - [ ] Extract service + hook (useCovidSummary, useCountryTrends) */ import { useEffect, useState, useCallback, useRef } from 'react'; +import { LineChart, Line, BarChart, Bar, PieChart, Pie, Cell, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts'; +import { Activity, Users, AlertCircle, TrendingUp, Globe, RefreshCw, Calendar } from 'lucide-react'; import Loading from '../components/Loading.jsx'; import ErrorMessage from '../components/ErrorMessage.jsx'; import Card from '../components/Card.jsx'; @@ -27,9 +29,12 @@ import Corona from '../Images/Corona.jpg'; export default function Covid() { const [summary, setSummary] = useState(null); + const [historical, setHistorical] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [country, setCountry] = useState(''); + const [searchTerm, setSearchTerm] = useState(''); + const [sortBy, setSortBy] = useState('cases'); const isFetchingRef = useRef(false); const fetchSummary = useCallback(async () => { @@ -51,11 +56,40 @@ export default function Covid() { } }, []); + const fetchHistorical = useCallback(async (countryName) => { + if (!countryName) return; + try { + const res = await fetch(`https://disease.sh/v3/covid-19/historical/${countryName}?lastdays=30`); + if (!res.ok) throw new Error('Failed to fetch historical data'); + const json = await res.json(); + setHistorical(json); + } catch (e) { + console.error('Historical data error:', e); + } + }, []); + useEffect(() => { fetchSummary(); }, [fetchSummary]); + useEffect(() => { + if (country) { + fetchHistorical(country); + } + }, [country, fetchHistorical]); + const countries = summary || []; + + // Filter and sort countries + const filteredCountries = countries + .filter(c => c.country.toLowerCase().includes(searchTerm.toLowerCase())) + .sort((a, b) => { + if (sortBy === 'cases') return b.cases - a.cases; + if (sortBy === 'todayCases') return b.todayCases - a.todayCases; + if (sortBy === 'deaths') return b.deaths - a.deaths; + return 0; + }); + const selected = countries.find(c => c.countryInfo.iso3 === country || c.country === country); // Compute simple global summary (sum across all countries) @@ -65,63 +99,284 @@ export default function Covid() { acc.todayCases += c.todayCases; acc.deaths += c.deaths; acc.todayDeaths += c.todayDeaths; + acc.recovered += c.recovered || 0; + acc.active += c.active || 0; return acc; }, - { cases: 0, todayCases: 0, deaths: 0, todayDeaths: 0 } + { cases: 0, todayCases: 0, deaths: 0, todayDeaths: 0, recovered: 0, active: 0 } ); + // Format numbers with abbreviation utility + const formatNumber = (num) => { + if (num >= 1000000) return (num / 1000000).toFixed(1) + 'M'; + if (num >= 1000) return (num / 1000).toFixed(1) + 'K'; + return num.toLocaleString(); + }; + + const topCountries = [...countries] + .sort((a, b) => b.cases - a.cases) + .slice(0, 10) + .map(c => ({ + name: c.country, + cases: c.cases, + deaths: c.deaths, + recovered: c.recovered || 0 + })); + + const globalPieData = [ + { name: 'Active', value: global.active, color: '#f59e0b' }, + { name: 'Recovered', value: global.recovered, color: '#10b981' }, + { name: 'Deaths', value: global.deaths, color: '#ef4444' } + ]; + + const historicalChartData = historical?.timeline ? + Object.keys(historical.timeline.cases).map(date => ({ + date: new Date(date).toLocaleDateString('en-US', { month: 'short', day: 'numeric' }), + cases: historical.timeline.cases[date], + deaths: historical.timeline.deaths[date], + recovered: historical.timeline.recovered?.[date] || 0 + })) : []; + return ( -
Real-time global pandemic statistics
+New Confirmed: {global.todayCases.toLocaleString()}
-Total Confirmed: {global.cases.toLocaleString()}
-Total Deaths: {global.deaths.toLocaleString()}
-New Confirmed: {selected.todayCases.toLocaleString()}
-Total Confirmed: {selected.cases.toLocaleString()}
-Total Deaths: {selected.deaths.toLocaleString()}
-Updated: {new Date(selected.updated).toLocaleString()}
-{formatNumber(global.cases)}
++{formatNumber(global.todayCases)} today
+{formatNumber(global.active)}
+Currently infected
+{formatNumber(global.recovered)}
++ {global.cases > 0 ? ((global.recovered/global.cases)*100).toFixed(1) : 0}% recovery rate +
+{formatNumber(global.deaths)}
++{formatNumber(global.todayDeaths)} today
+New Confirmed: {global.todayCases.toLocaleString()}
+Total Confirmed: {global.cases.toLocaleString()}
+Total Deaths: {global.deaths.toLocaleString()}
+Total Cases
+{formatNumber(selected.cases)}
++{formatNumber(selected.todayCases)} today
+Active
+{formatNumber(selected.active)}
+Recovered
+{formatNumber(selected.recovered || 0)}
+Deaths
+{formatNumber(selected.deaths)}
++{formatNumber(selected.todayDeaths)} today
+New Confirmed: {selected.todayCases.toLocaleString()}
+Total Confirmed: {selected.cases.toLocaleString()}
+Total Deaths: {selected.deaths.toLocaleString()}
+Updated: {new Date(selected.updated).toLocaleString()}
+Data source: disease.sh API
+Data may have delays. For official information, consult WHO and local health authorities.
+