2023-06-13 05:52:58 -07:00
|
|
|
import MedalIcon from '@components/icons/MedalIcon'
|
|
|
|
import ProfileImage from '@components/profile/ProfileImage'
|
|
|
|
import { ArrowLeftIcon, ChevronRightIcon } from '@heroicons/react/20/solid'
|
|
|
|
import { useViewport } from 'hooks/useViewport'
|
|
|
|
import { useState } from 'react'
|
|
|
|
import Select from '@components/forms/Select'
|
|
|
|
import { IconButton } from '@components/shared/Button'
|
|
|
|
import AcornIcon from '@components/icons/AcornIcon'
|
|
|
|
import WhaleIcon from '@components/icons/WhaleIcon'
|
|
|
|
import RobotIcon from '@components/icons/RobotIcon'
|
|
|
|
import MangoIcon from '@components/icons/MangoIcon'
|
2023-06-18 20:47:25 -07:00
|
|
|
import { useQuery } from '@tanstack/react-query'
|
|
|
|
import SheenLoader from '@components/shared/SheenLoader'
|
|
|
|
import { abbreviateAddress } from 'utils/formatting'
|
|
|
|
import { PublicKey } from '@solana/web3.js'
|
|
|
|
import { formatNumericValue } from 'utils/numbers'
|
2023-06-19 05:41:51 -07:00
|
|
|
import { useTranslation } from 'next-i18next'
|
2023-09-25 04:33:34 -07:00
|
|
|
import { fetchLeaderboard } from 'apis/rewards'
|
|
|
|
import { useCurrentSeason } from 'hooks/useRewards'
|
|
|
|
import Badge from './Badge'
|
|
|
|
import { tiers } from './RewardsPage'
|
2023-06-13 05:52:58 -07:00
|
|
|
|
|
|
|
const Leaderboards = ({
|
|
|
|
goBack,
|
|
|
|
leaderboard,
|
|
|
|
}: {
|
|
|
|
goBack: () => void
|
|
|
|
leaderboard: string
|
|
|
|
}) => {
|
2023-06-19 05:41:51 -07:00
|
|
|
const { t } = useTranslation('rewards')
|
2023-06-13 05:52:58 -07:00
|
|
|
const [topAccountsTier, setTopAccountsTier] = useState<string>(leaderboard)
|
|
|
|
const renderTierIcon = (tier: string) => {
|
2023-06-18 20:47:25 -07:00
|
|
|
if (tier === 'bot') {
|
2023-06-13 05:52:58 -07:00
|
|
|
return <RobotIcon className="mr-2 h-5 w-5" />
|
2023-06-18 20:47:25 -07:00
|
|
|
} else if (tier === 'mango') {
|
2023-06-13 05:52:58 -07:00
|
|
|
return <MangoIcon className="mr-2 h-5 w-5" />
|
2023-06-18 20:47:25 -07:00
|
|
|
} else if (tier === 'whale') {
|
2023-06-13 05:52:58 -07:00
|
|
|
return <WhaleIcon className="mr-2 h-5 w-5" />
|
|
|
|
} else return <AcornIcon className="mr-2 h-5 w-5" />
|
|
|
|
}
|
2023-09-25 04:33:34 -07:00
|
|
|
const { data: seasonData } = useCurrentSeason()
|
2023-06-18 20:47:25 -07:00
|
|
|
|
|
|
|
const {
|
2023-09-25 04:33:34 -07:00
|
|
|
data: topAccountsLeaderboardData,
|
2023-06-18 20:47:25 -07:00
|
|
|
isFetching: fetchingRewardsLeaderboardData,
|
|
|
|
isLoading: loadingRewardsLeaderboardData,
|
|
|
|
} = useQuery(
|
|
|
|
['rewards-leaderboard-data', topAccountsTier],
|
2023-09-25 04:33:34 -07:00
|
|
|
() => fetchLeaderboard(seasonData!.season_id),
|
2023-06-18 20:47:25 -07:00
|
|
|
{
|
|
|
|
cacheTime: 1000 * 60 * 10,
|
|
|
|
staleTime: 1000 * 60,
|
|
|
|
retry: 3,
|
|
|
|
refetchOnWindowFocus: false,
|
2023-09-25 04:33:34 -07:00
|
|
|
enabled: !!seasonData,
|
2023-07-21 11:47:53 -07:00
|
|
|
},
|
2023-06-18 20:47:25 -07:00
|
|
|
)
|
2023-09-25 04:33:34 -07:00
|
|
|
const leadersForTier =
|
|
|
|
topAccountsLeaderboardData?.find((x) => x.tier === topAccountsTier)
|
|
|
|
?.leaderboard || []
|
2023-06-18 20:47:25 -07:00
|
|
|
|
|
|
|
const isLoading =
|
|
|
|
fetchingRewardsLeaderboardData || loadingRewardsLeaderboardData
|
|
|
|
|
2023-06-13 05:52:58 -07:00
|
|
|
return (
|
|
|
|
<div className="mx-auto max-w-[1140px] flex-col items-center p-8 lg:p-10">
|
|
|
|
<div className="mb-4 flex items-center justify-between">
|
|
|
|
<div className="flex items-center">
|
|
|
|
<IconButton className="mr-2" hideBg onClick={goBack} size="small">
|
|
|
|
<ArrowLeftIcon className="h-5 w-5" />
|
|
|
|
</IconButton>
|
|
|
|
<h2 className="mr-4">Leaderboard</h2>
|
|
|
|
<Badge
|
2023-09-25 04:33:34 -07:00
|
|
|
label={`Season ${seasonData?.season_id}`}
|
2023-06-13 05:52:58 -07:00
|
|
|
borderColor="var(--active)"
|
|
|
|
shadowColor="var(--active)"
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
<Select
|
|
|
|
className="w-32"
|
|
|
|
icon={renderTierIcon(topAccountsTier)}
|
2023-06-19 05:41:51 -07:00
|
|
|
value={t(topAccountsTier)}
|
2023-06-13 05:52:58 -07:00
|
|
|
onChange={(tier) => setTopAccountsTier(tier)}
|
|
|
|
>
|
|
|
|
{tiers.map((tier) => (
|
|
|
|
<Select.Option key={tier} value={tier}>
|
|
|
|
<div className="flex w-full items-center">
|
|
|
|
{renderTierIcon(tier)}
|
2023-06-19 05:41:51 -07:00
|
|
|
{t(tier)}
|
2023-06-13 05:52:58 -07:00
|
|
|
</div>
|
|
|
|
</Select.Option>
|
|
|
|
))}
|
|
|
|
</Select>
|
|
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
2023-06-18 20:47:25 -07:00
|
|
|
{!isLoading ? (
|
2023-09-25 04:33:34 -07:00
|
|
|
leadersForTier && leadersForTier.length ? (
|
|
|
|
leadersForTier.map((wallet, i: number) => (
|
|
|
|
<LeaderboardCard rank={i + 1} key={i} wallet={wallet} />
|
|
|
|
))
|
2023-06-18 20:47:25 -07:00
|
|
|
) : (
|
2023-06-19 05:41:51 -07:00
|
|
|
<div className="flex justify-center rounded-lg border border-th-bkg-3 p-8">
|
|
|
|
<span className="text-th-fgd-3">Leaderboard not available</span>
|
|
|
|
</div>
|
2023-06-18 20:47:25 -07:00
|
|
|
)
|
|
|
|
) : (
|
|
|
|
<div className="space-y-2">
|
|
|
|
{[...Array(20)].map((x, i) => (
|
|
|
|
<SheenLoader className="flex flex-1" key={i}>
|
|
|
|
<div className="h-16 w-full bg-th-bkg-2" />
|
|
|
|
</SheenLoader>
|
|
|
|
))}
|
|
|
|
</div>
|
|
|
|
)}
|
2023-06-13 05:52:58 -07:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
export default Leaderboards
|
|
|
|
|
2023-06-18 20:47:25 -07:00
|
|
|
const LeaderboardCard = ({
|
|
|
|
rank,
|
|
|
|
wallet,
|
|
|
|
}: {
|
|
|
|
rank: number
|
2023-09-25 04:33:34 -07:00
|
|
|
wallet: {
|
|
|
|
mango_account: string
|
|
|
|
tier: string
|
|
|
|
total_points: number
|
|
|
|
}
|
2023-06-18 20:47:25 -07:00
|
|
|
}) => {
|
2023-08-31 20:22:50 -07:00
|
|
|
const { isTablet } = useViewport()
|
2023-06-13 05:52:58 -07:00
|
|
|
return (
|
|
|
|
<a
|
|
|
|
className="flex w-full items-center justify-between rounded-md border border-th-bkg-3 px-3 py-3 md:px-4 md:hover:bg-th-bkg-2"
|
|
|
|
href={`/?address=${'account'}`}
|
|
|
|
rel="noopener noreferrer"
|
|
|
|
target="_blank"
|
|
|
|
>
|
|
|
|
<div className="flex items-center space-x-3">
|
|
|
|
<div
|
|
|
|
className={`relative flex h-6 w-6 flex-shrink-0 items-center justify-center rounded-full ${
|
|
|
|
rank < 4 ? '' : 'bg-th-bkg-3'
|
|
|
|
} md:mr-2`}
|
|
|
|
>
|
|
|
|
<p
|
|
|
|
className={`relative z-10 font-bold ${
|
|
|
|
rank < 4 ? 'text-th-bkg-1' : 'text-th-fgd-3'
|
|
|
|
}`}
|
|
|
|
>
|
|
|
|
{rank}
|
|
|
|
</p>
|
|
|
|
{rank < 4 ? <MedalIcon className="absolute" rank={rank} /> : null}
|
|
|
|
</div>
|
|
|
|
<ProfileImage
|
2023-08-31 20:22:50 -07:00
|
|
|
imageSize={isTablet ? '32' : '40'}
|
2023-06-13 05:52:58 -07:00
|
|
|
imageUrl={''}
|
2023-08-31 20:22:50 -07:00
|
|
|
placeholderSize={isTablet ? '20' : '24'}
|
2023-06-13 05:52:58 -07:00
|
|
|
/>
|
|
|
|
<div className="text-left">
|
|
|
|
<p className="capitalize text-th-fgd-2 md:text-base">
|
2023-09-25 04:33:34 -07:00
|
|
|
{abbreviateAddress(new PublicKey(wallet.mango_account))}
|
2023-06-13 05:52:58 -07:00
|
|
|
</p>
|
2023-06-18 20:47:25 -07:00
|
|
|
{/* <p className="text-xs text-th-fgd-4">
|
2023-06-13 05:52:58 -07:00
|
|
|
Acc: {'A1at5'.slice(0, 4) + '...' + 'tt45eU'.slice(-4)}
|
2023-06-18 20:47:25 -07:00
|
|
|
</p> */}
|
2023-06-13 05:52:58 -07:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div className="flex items-center">
|
2023-06-18 20:47:25 -07:00
|
|
|
<span className="mr-3 text-right font-mono md:text-base">
|
2023-09-25 04:33:34 -07:00
|
|
|
{formatNumericValue(wallet.total_points)}
|
2023-06-18 20:47:25 -07:00
|
|
|
</span>
|
2023-06-13 05:52:58 -07:00
|
|
|
<ChevronRightIcon className="h-5 w-5 text-th-fgd-3" />
|
|
|
|
</div>
|
|
|
|
</a>
|
|
|
|
)
|
|
|
|
}
|