Use static props to load leaderboard fast

This commit is contained in:
James Grugett 2022-07-19 15:39:15 -05:00
parent b5ef7490c3
commit 6c070464dd
2 changed files with 76 additions and 80 deletions

View File

@ -275,7 +275,7 @@ export function getTopTraders(period: Period) {
limit(20) limit(20)
) )
return getValues(topTraders) return getValues<User>(topTraders)
} }
export function getTopCreators(period: Period) { export function getTopCreators(period: Period) {
@ -284,7 +284,7 @@ export function getTopCreators(period: Period) {
orderBy('creatorVolumeCached.' + period, 'desc'), orderBy('creatorVolumeCached.' + period, 'desc'),
limit(20) limit(20)
) )
return getValues(topCreators) return getValues<User>(topCreators)
} }
export async function getTopFollowed() { export async function getTopFollowed() {

View File

@ -9,97 +9,96 @@ import {
User, User,
} from 'web/lib/firebase/users' } from 'web/lib/firebase/users'
import { formatMoney } from 'common/util/format' import { formatMoney } from 'common/util/format'
import { fromPropz, usePropz } from 'web/hooks/use-propz'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { LoadingIndicator } from 'web/components/loading-indicator'
import { Title } from 'web/components/title' import { Title } from 'web/components/title'
import { Tabs } from 'web/components/layout/tabs' import { Tabs } from 'web/components/layout/tabs'
import { useTracking } from 'web/hooks/use-tracking' import { useTracking } from 'web/hooks/use-tracking'
export const getStaticProps = fromPropz(getStaticPropz) export async function getStaticProps() {
export async function getStaticPropz() { const props = await fetchProps()
return queryLeaderboardUsers('allTime')
}
const queryLeaderboardUsers = async (period: Period) => {
const [topTraders, topCreators, topFollowed] = await Promise.all([
getTopTraders(period).catch(() => {}),
getTopCreators(period).catch(() => {}),
getTopFollowed().catch(() => {}),
])
return { return {
props: { props,
topTraders,
topCreators,
topFollowed,
},
revalidate: 60, // regenerate after a minute revalidate: 60, // regenerate after a minute
} }
} }
export default function Leaderboards(props: { const fetchProps = async () => {
const [allTime, monthly, weekly, daily] = await Promise.all([
queryLeaderboardUsers('allTime'),
queryLeaderboardUsers('monthly'),
queryLeaderboardUsers('weekly'),
queryLeaderboardUsers('daily'),
])
const topFollowed = await getTopFollowed()
return {
allTime,
monthly,
weekly,
daily,
topFollowed,
}
}
const queryLeaderboardUsers = async (period: Period) => {
const [topTraders, topCreators] = await Promise.all([
getTopTraders(period),
getTopCreators(period),
])
return {
topTraders,
topCreators,
}
}
type leaderboard = {
topTraders: User[] topTraders: User[]
topCreators: User[] topCreators: User[]
}
export default function Leaderboards(_props: {
allTime: leaderboard
monthly: leaderboard
weekly: leaderboard
daily: leaderboard
topFollowed: User[] topFollowed: User[]
}) { }) {
props = usePropz(props, getStaticPropz) ?? { const [props, setProps] = useState<Parameters<typeof Leaderboards>[0]>(_props)
topTraders: [],
topCreators: [],
topFollowed: [],
}
const { topFollowed } = props
const [topTradersState, setTopTraders] = useState(props.topTraders)
const [topCreatorsState, setTopCreators] = useState(props.topCreators)
const [isLoading, setLoading] = useState(false)
const [period, setPeriod] = useState<Period>('allTime')
useEffect(() => { useEffect(() => {
setLoading(true) fetchProps().then((props) => setProps(props))
queryLeaderboardUsers(period).then((res) => { }, [])
setTopTraders(res.props.topTraders as User[])
setTopCreators(res.props.topCreators as User[]) const { topFollowed } = props
setLoading(false)
})
}, [period])
const LeaderboardWithPeriod = (period: Period) => { const LeaderboardWithPeriod = (period: Period) => {
const { topTraders, topCreators } = props[period]
return ( return (
<> <>
<Col className="mx-4 items-center gap-10 lg:flex-row"> <Col className="mx-4 items-center gap-10 lg:flex-row">
{!isLoading ? ( <Leaderboard
<> title="🏅 Top bettors"
{period === 'allTime' || users={topTraders}
period == 'weekly' || columns={[
period === 'daily' ? ( //TODO: show other periods once they're available {
<Leaderboard header: 'Total profit',
title="🏅 Top bettors" renderCell: (user) => formatMoney(user.profitCached[period]),
users={topTradersState} },
columns={[ ]}
{ />
header: 'Total profit',
renderCell: (user) =>
formatMoney(user.profitCached[period]),
},
]}
/>
) : (
<></>
)}
<Leaderboard <Leaderboard
title="🏅 Top creators" title="🏅 Top creators"
users={topCreatorsState} users={topCreators}
columns={[ columns={[
{ {
header: 'Total bet', header: 'Total bet',
renderCell: (user) => renderCell: (user) =>
formatMoney(user.creatorVolumeCached[period]), formatMoney(user.creatorVolumeCached[period]),
}, },
]} ]}
/> />
</>
) : (
<LoadingIndicator spinnerClassName={'border-gray-500'} />
)}
</Col> </Col>
{period === 'allTime' ? ( {period === 'allTime' ? (
<Col className="mx-4 my-10 items-center gap-10 lg:mx-0 lg:w-1/2 lg:flex-row"> <Col className="mx-4 my-10 items-center gap-10 lg:mx-0 lg:w-1/2 lg:flex-row">
@ -128,19 +127,16 @@ export default function Leaderboards(props: {
<Tabs <Tabs
currentPageForAnalytics={'leaderboards'} currentPageForAnalytics={'leaderboards'}
defaultIndex={0} defaultIndex={0}
onClick={(title, index) => {
const period = ['allTime', 'monthly', 'weekly', 'daily'][index]
setPeriod(period as Period)
}}
tabs={[ tabs={[
{ {
title: 'All Time', title: 'All Time',
content: LeaderboardWithPeriod('allTime'), content: LeaderboardWithPeriod('allTime'),
}, },
{ // TODO: Enable this near the end of July!
title: 'Monthly', // {
content: LeaderboardWithPeriod('monthly'), // title: 'Monthly',
}, // content: LeaderboardWithPeriod('monthly'),
// },
{ {
title: 'Weekly', title: 'Weekly',
content: LeaderboardWithPeriod('weekly'), content: LeaderboardWithPeriod('weekly'),