manifold/web/pages/leaderboards.tsx
Pico2x ebc4bd6bcf
[PortfolioGraph] Shows a graph of the portfolio value over time (#570)
* [Portfolio Graph] Shows a graph of the portfolio value over time

* [PortfolioGraph] Fix some nits.

* [PortfolioGraph] Comment out portfolio-value-section

Hides the component completely for now, so we can land today. My plan would be to land today, wait for the history to build up, and then revert this commit. As opposed to leaving the PR idle for a while, and then have to deal with conflicts.

* [PortfolioGraph] Rm duplicate firestore rule
2022-06-24 12:14:20 -05:00

154 lines
4.3 KiB
TypeScript

import { Col } from 'web/components/layout/col'
import { Leaderboard } from 'web/components/leaderboard'
import { Page } from 'web/components/page'
import {
getTopCreators,
getTopTraders,
getTopFollowed,
Period,
User,
} from 'web/lib/firebase/users'
import { formatMoney } from 'common/util/format'
import { fromPropz, usePropz } from 'web/hooks/use-propz'
import { useEffect, useState } from 'react'
import { LoadingIndicator } from 'web/components/loading-indicator'
import { Title } from 'web/components/title'
import { Tabs } from 'web/components/layout/tabs'
import { useTracking } from 'web/hooks/use-tracking'
export const getStaticProps = fromPropz(getStaticPropz)
export async function getStaticPropz() {
return queryLeaderboardUsers('allTime')
}
const queryLeaderboardUsers = async (period: Period) => {
const [topTraders, topCreators, topFollowed] = await Promise.all([
getTopTraders(period).catch(() => {}),
getTopCreators(period).catch(() => {}),
getTopFollowed().catch(() => {}),
])
return {
props: {
topTraders,
topCreators,
topFollowed,
},
revalidate: 60, // regenerate after a minute
}
}
export default function Leaderboards(props: {
topTraders: User[]
topCreators: User[]
topFollowed: User[]
}) {
props = usePropz(props, getStaticPropz) ?? {
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(() => {
setLoading(true)
queryLeaderboardUsers(period).then((res) => {
setTopTraders(res.props.topTraders as User[])
setTopCreators(res.props.topCreators as User[])
setLoading(false)
})
}, [period])
const LeaderboardWithPeriod = (period: Period) => {
return (
<>
<Col className="mx-4 items-center gap-10 lg:flex-row">
{!isLoading ? (
<>
{period === 'allTime' ? ( //TODO: show other periods once they're available
<Leaderboard
title="🏅 Top bettors"
users={topTradersState}
columns={[
{
header: 'Total profit',
renderCell: (user) =>
formatMoney(user.profitCached[period]),
},
]}
/>
) : (
<></>
)}
<Leaderboard
title="🏅 Top creators"
users={topCreatorsState}
columns={[
{
header: 'Total bet',
renderCell: (user) =>
formatMoney(user.creatorVolumeCached[period]),
},
]}
/>
</>
) : (
<LoadingIndicator spinnerClassName={'border-gray-500'} />
)}
</Col>
{period === 'allTime' ? (
<Col className="mx-4 my-10 items-center gap-10 lg:mx-0 lg:w-1/2 lg:flex-row">
<Leaderboard
title="🏅 Top followed"
users={topFollowed}
columns={[
{
header: 'Total followers',
renderCell: (user) => user.followerCountCached,
},
]}
/>
</Col>
) : (
<></>
)}
</>
)
}
useTracking('view leaderboards')
return (
<Page>
<Title text={'Leaderboards'} className={'hidden md:block'} />
<Tabs
defaultIndex={0}
onClick={(title, index) => {
const period = ['allTime', 'monthly', 'weekly', 'daily'][index]
setPeriod(period as Period)
}}
tabs={[
{
title: 'All Time',
content: LeaderboardWithPeriod('allTime'),
},
{
title: 'Monthly',
content: LeaderboardWithPeriod('monthly'),
},
{
title: 'Weekly',
content: LeaderboardWithPeriod('weekly'),
},
{
title: 'Daily',
content: LeaderboardWithPeriod('daily'),
},
]}
/>
</Page>
)
}