import fetch from 'node-fetch' ; import isSameHour from 'date-fns/isSameHour' ; import mapValues from 'lodash/mapValues' ; type CaseRecord = { date : string ; confirmed : number ; deaths : number ; recovered : number ; } ; type EnhancedCaseRecord = CaseRecord & { active : number ; } & { added : number ; } ; let cached = { data : undefined , date : undefined , } ; function calcGlobalDate ( data ) { const records = Object . values ( data ) . flat ( ) ; return records . reduce ( ( acc , curr ) => { const index = acc . findIndex ( ( record ) => record . date === curr . date ) ; if ( index === - 1 ) { return [ ... acc , curr ] ; } const targetRecord = acc [ index ] ; return [ ... acc . slice ( 0 , index ) , { date : targetRecord . date , confirmed : targetRecord . confirmed + curr . confirmed , deaths : targetRecord . deaths + curr . deaths , recovered : targetRecord . recovered + curr . recovered , } , ... acc . slice ( index + 1 , acc . length ) , ] ; } , [ ] ) ; } function enhanceData ( data ) { const globalData = calcGlobalDate ( data ) ; const dataWithGlobalData = { ... data , global : globalData , } ; return mapValues ( dataWithGlobalData , ( records ) => records . map ( ( record ) => ( { ... record , active : record . confirmed - record . recovered - record . deaths , } ) ) . reduce ( ( acc , curr ) => { if ( acc . length === 0 ) return [ { ... curr , added : 0 } ] ; const prev = acc [ acc . length - 1 ] ; return [ ... acc , { ... curr , added : curr . confirmed - prev . confirmed } ] ; } , [ ] ) ) ; } async function refetchDataHourly ( ) { const now = new Date ( ) ; if ( ! cached . data || ! cached . date || ! isSameHour ( cached . date , now ) ) { const response = await fetch ( 'https://pomber.github.io/covid19/timeseries.json' ) ; const data = await response . json ( ) ; cached = { data : enhanceData ( data ) , date : now , } ; } } export async function queryCountryCases ( { country , date , } ) { await refetchDataHourly ( ) ; if ( ! cached . data ) return ; const countryData = cached . data [ country ] ; const foundRecord = date ? countryData . find ( ( record ) => record . date === date ) : countryData [ countryData . length - 1 ] ; if ( ! foundRecord ) return ; return foundRecord ; } export async function queryMostCasesTopNCountries ( { type , n = 3 , } ) { await refetchDataHourly ( ) ; if ( ! cached . data ) return ; return Object . entries ( cached . data ) . map ( ( [ country , records ] ) => ( { country , record : records [ records . length - 1 ] , } ) ) . filter ( ( { country } ) => country !== 'global' ) . sort ( ( a , b ) => b . record [ type ] - a . record [ type ] ) . slice ( 0 , n ) ; }