Make Stats Update Live + Deprecate Old v2 Helpers

This commit is contained in:
Sam Poder 2022-02-10 23:47:01 +08:00
parent 8439e7e2df
commit b1ad2fe4e2
5 changed files with 20 additions and 133 deletions

View file

@ -1,9 +1,8 @@
import { useState, useEffect } from 'react'
import { Text, Box } from 'theme-ui'
import Stat from '../stat'
import api from '../../lib/api'
import { timeSince } from '../../lib/helpers'
import { keyframes } from '@emotion/react'
import { timeSince } from '../../lib/helpers'
import useSWR from 'swr'
import Stat from '../stat'
const renderMoney = amount =>
Math.floor(amount / 100)
@ -42,22 +41,16 @@ function Dot() {
}
const Stats = props => {
const [volume, setVolume] = useState(100 * 1000 * 1000) // 1MM default
const [raised, setRaised] = useState(100 * 1000 * 500) // half million default
const [lastUpdated, setLastUpdated] = useState(Date.now()) // now default
useEffect(() => {
loadStats()
const fetcher = (...args) => fetch(...args).then(res => res.json())
const { data } = useSWR('https://bank.hackclub.com/stats', fetcher, {
fallbackData: {
volume: 100 * 1000 * 1000,
raised: 100 * 1000 * 500,
lastUpdated: Date.now()
}
})
const loadStats = () => {
api.get('https://bank.hackclub.com/stats').then(stats => {
setVolume(renderMoney(stats.transactions_volume))
setRaised(renderMoney(stats.raised))
setLastUpdated(stats.last_transaction_date * 1000)
})
}
return (
<Box>
<Text
@ -68,15 +61,14 @@ const Stats = props => {
mb={[2, 3]}
>
<Dot />
As of {timeSince(lastUpdated, false, true)}...
As of {timeSince(data.last_transaction_date * 1000, false, true)}...
</Text>
<Box as="div">
<Stat {...props} value={raised} label="raised on Hack Club Bank" />
<Box>
<Stat {...props} value={renderMoney(data.raised)} label="raised on Hack Club Bank" />
<Stat
{...props}
fontSize={[3, 4, 5]}
value={volume}
value={renderMoney(data.transactions_volume)}
label="total amount transacted"
/>
</Box>

View file

@ -1,78 +0,0 @@
import storage from './storage'
export const url = 'https://api.hackclub.com/'
const methods = ['GET', 'PUT', 'POST', 'PATCH', 'DELETE']
const generateMethod =
method =>
(path, options = {}, fetchOptions = {}) => {
let filteredOptions = {}
const authToken = storage.get('authToken')
if (authToken) {
options.authToken = authToken
}
for (let [key, value] of Object.entries(options)) {
switch (key) {
case 'authToken':
filteredOptions.headers = filteredOptions.headers || {}
filteredOptions.headers['Authorization'] = `Bearer ${value}`
break
case 'data':
if (value instanceof FormData) {
filteredOptions.body = value
} else {
filteredOptions.body = JSON.stringify(value)
filteredOptions.headers = filteredOptions.headers || {}
filteredOptions.headers['Content-Type'] = 'application/json'
}
break
default:
filteredOptions[key] = value
break
}
}
if (fetchOptions.noAuth) {
if (filteredOptions.headers && filteredOptions.headers['Authorization']) {
delete filteredOptions.headers['Authorization']
}
}
const foreignUrl = path.startsWith('http')
const urlPath = foreignUrl ? path : url + path
return fetch(urlPath, { method, ...filteredOptions })
.then(res => {
if (res.ok) {
const contentType = res.headers.get('content-type')
if (contentType && contentType.indexOf('application/json') !== -1) {
return res.json()
} else {
return res.text()
}
} else {
if (res.status === 422) {
return res.json().then(json => {
// eslint-disable-next-line
throw { ...res, errors: json.errors }
})
} else {
throw res
}
}
})
.catch(err => {
throw err
})
}
let api = {}
methods.forEach(method => {
api[method.toLowerCase()] = generateMethod(method)
})
api.currentUser = () => api.get(`v1/users/current`)
export default api

View file

@ -1,33 +0,0 @@
const stubbedStorage = {}
'get set remove keys'
.split(' ')
.forEach(method => (stubbedStorage[method] = () => null))
let localStorage
try {
localStorage = window.localStorage
} catch (e) {
if (e instanceof ReferenceError) {
localStorage = stubbedStorage
}
}
const storage = {
get: key => {
try {
// (max@maxwofford.com) Values that were set before values were stringified might fail to parse, so we return the raw storage item if we can't parse it
return JSON.parse(localStorage.getItem(key))
} catch (e) {
if (e.name === 'SyntaxError') {
return localStorage.getItem(key)
} else {
console.error(e)
}
}
},
set: (key, value) => localStorage.setItem(key, JSON.stringify(value)),
remove: key => localStorage.removeItem(key),
keys: () => Object.keys(localStorage)
}
export default storage

View file

@ -36,6 +36,7 @@
"react-tsparticles": "^1.40.1",
"react-use-websocket": "3.0.0",
"resnow": "^1.0.0",
"swr": "^1.2.1",
"theme-ui": "^0.13",
"tinytime": "^0.2.6",
"turndown": "^7.1.1"

View file

@ -3285,6 +3285,11 @@ supports-preserve-symlinks-flag@^1.0.0:
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
swr@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/swr/-/swr-1.2.1.tgz#c21a4fe2139cb1c4630450589b5b5add947a9d41"
integrity sha512-1cuWXqJqXcFwbgONGCY4PHZ8v05009JdHsC3CIC6u7d00kgbMswNr1sHnnhseOBxtzVqcCNpOHEgVDciRer45w==
tapable@^2.2.0:
version "2.2.0"
resolved "https://registry.npmjs.org/tapable/-/tapable-2.2.0.tgz"