mango-v4-ui/components/leaderboard/LeaderboardPage.tsx

136 lines
4.2 KiB
TypeScript
Raw Normal View History

2023-03-06 00:59:14 -08:00
import ButtonGroup from '@components/forms/ButtonGroup'
2023-03-19 20:19:53 -07:00
import { LinkButton } from '@components/shared/Button'
import SheenLoader from '@components/shared/SheenLoader'
2023-03-26 05:18:40 -07:00
import { NoSymbolIcon } from '@heroicons/react/20/solid'
import { useInfiniteQuery } from '@tanstack/react-query'
2023-03-06 00:59:14 -08:00
import { useTranslation } from 'next-i18next'
2023-03-26 05:18:40 -07:00
import { useMemo, useState } from 'react'
2023-03-27 03:08:17 -07:00
import { EmptyObject } from 'types'
2023-03-06 00:59:14 -08:00
import { MANGO_DATA_API_URL } from 'utils/constants'
import LeaderboardTable from './LeaderboardTable'
2023-03-27 03:08:17 -07:00
export interface LeaderboardRes {
2023-03-14 03:50:42 -07:00
date_hour: string
mango_account: string
pnl: number
2023-03-27 03:08:17 -07:00
profile_image_url: string | null
profile_name: string
2023-03-14 03:50:42 -07:00
start_date_hour: string
2023-03-27 03:08:17 -07:00
trader_category: string
2023-03-14 03:50:42 -07:00
wallet_pk: string
}
2023-03-26 05:18:40 -07:00
type DaysToShow = '1DAY' | '1WEEK' | 'ALLTIME'
2023-03-27 03:08:17 -07:00
const isLeaderboard = (
response: null | EmptyObject | LeaderboardRes[]
): response is LeaderboardRes[] => {
if (response && Array.isArray(response)) {
return true
}
return false
}
2023-03-26 05:18:40 -07:00
const fetchLeaderboard = async (
daysToShow: DaysToShow,
offset = 0
2023-03-27 03:08:17 -07:00
): Promise<Array<LeaderboardRes>> => {
2023-03-26 05:18:40 -07:00
const data = await fetch(
`${MANGO_DATA_API_URL}/leaderboard-pnl?over_period=${daysToShow}&offset=${offset}`
)
2023-03-27 03:08:17 -07:00
const parsedData: null | EmptyObject | LeaderboardRes[] = await data.json()
let leaderboardData
if (isLeaderboard(parsedData)) {
leaderboardData = parsedData
2023-03-19 20:19:53 -07:00
}
2023-03-27 03:08:17 -07:00
return leaderboardData ?? []
2023-03-26 05:18:40 -07:00
}
const LeaderboardPage = () => {
const { t } = useTranslation(['common', 'leaderboard'])
const [daysToShow, setDaysToShow] = useState<DaysToShow>('ALLTIME')
const { data, isLoading, isFetching, isFetchingNextPage, fetchNextPage } =
useInfiniteQuery(
['leaderboard', daysToShow],
({ pageParam }) => fetchLeaderboard(daysToShow, pageParam),
{
cacheTime: 1000 * 60 * 10,
staleTime: 1000 * 60 * 5,
2023-03-26 05:18:40 -07:00
retry: 3,
refetchOnWindowFocus: false,
keepPreviousData: true,
getNextPageParam: (_lastPage, pages) => pages.length * 20,
}
)
2023-03-06 00:59:14 -08:00
2023-03-26 05:18:40 -07:00
const leaderboardData = useMemo(() => {
if (data?.pages.length) {
return data.pages.flat()
2023-03-14 03:50:42 -07:00
}
2023-03-26 05:18:40 -07:00
return []
}, [data, daysToShow])
2023-03-14 03:50:42 -07:00
2023-03-26 05:18:40 -07:00
const handleDaysToShow = (days: DaysToShow) => {
2023-03-14 03:50:42 -07:00
setDaysToShow(days)
}
2023-03-06 00:59:14 -08:00
return (
2023-03-15 01:35:29 -07:00
<div className="p-4 md:p-10 lg:px-0">
2023-03-06 00:59:14 -08:00
<div className="grid grid-cols-12">
<div className="col-span-12 lg:col-span-8 lg:col-start-3">
2023-03-14 03:50:42 -07:00
<div className="mb-6 flex flex-col md:flex-row md:items-center md:justify-between">
2023-03-15 01:35:29 -07:00
<div>
<h1 className="mb-2">{t('leaderboard')}</h1>
<p className="mb-4 md:mb-0">
{t('leaderboard:leaderboard-desc')}
</p>
</div>
2023-03-14 03:50:42 -07:00
<div className="w-full md:w-48">
<ButtonGroup
activeValue={daysToShow}
disabled={isLoading}
onChange={(v) => handleDaysToShow(v)}
2023-03-27 03:08:17 -07:00
names={['24h', '7d', '30d', t('all')]}
2023-03-14 03:50:42 -07:00
values={['1DAY', '1WEEK', 'ALLTIME']}
2023-03-06 00:59:14 -08:00
/>
2023-03-14 03:50:42 -07:00
</div>
2023-03-06 00:59:14 -08:00
</div>
2023-03-19 20:19:53 -07:00
{leaderboardData.length ? (
2023-03-26 05:18:40 -07:00
<LeaderboardTable
data={leaderboardData}
loading={isFetching && !isFetchingNextPage}
/>
) : !isFetching && !isLoading ? (
<div className="flex flex-col items-center rounded-md border border-th-bkg-3 p-4">
<NoSymbolIcon className="mb-1 h-7 w-7 text-th-fgd-4" />
<p>{t('leaderboard:leaderboard-unavailable')}</p>
</div>
) : null}
{isLoading || isFetchingNextPage ? (
<div className="mt-2 space-y-2">
2023-03-19 20:19:53 -07:00
{[...Array(20)].map((x, i) => (
<SheenLoader className="flex flex-1" key={i}>
<div className="h-16 w-full rounded-md bg-th-bkg-2" />
</SheenLoader>
))}
</div>
) : null}
2023-03-26 05:18:40 -07:00
{leaderboardData.length && leaderboardData.length < 100 ? (
<LinkButton
className="mx-auto mt-6"
onClick={() => fetchNextPage()}
>
2023-03-19 20:19:53 -07:00
{t('show-more')}
</LinkButton>
2023-03-14 03:50:42 -07:00
) : null}
2023-03-06 00:59:14 -08:00
</div>
</div>
</div>
)
}
export default LeaderboardPage