mango-v4-ui/components/rewards/Season.tsx

329 lines
13 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import Select from '@components/forms/Select'
import AcornIcon from '@components/icons/AcornIcon'
import MangoIcon from '@components/icons/MangoIcon'
import RobotIcon from '@components/icons/RobotIcon'
import WhaleIcon from '@components/icons/WhaleIcon'
import SheenLoader from '@components/shared/SheenLoader'
import { useWallet } from '@solana/wallet-adapter-react'
import { PublicKey } from '@solana/web3.js'
import useMangoAccount from 'hooks/useMangoAccount'
import {
useCurrentSeason,
useAccountTier,
useWalletPoints,
useTopAccountsLeaderBoard,
} from 'hooks/useRewards'
import { useState, useEffect, useMemo, useRef } from 'react'
import { useTranslation } from 'react-i18next'
import { abbreviateAddress } from 'utils/formatting'
import { formatNumericValue } from 'utils/numbers'
import { tiers } from './RewardsPage'
import RewardsTierCard from './RewardsTierCard'
import Faqs from './Faqs'
import dayjs from 'dayjs'
import relativeTime from 'dayjs/plugin/relativeTime'
dayjs.extend(relativeTime)
import MedalIcon from '@components/icons/MedalIcon'
const Season = ({
setShowLeaderboards,
}: {
setShowLeaderboards: (x: string) => void
}) => {
const { t } = useTranslation(['common', 'rewards'])
const { wallet } = useWallet()
const faqRef = useRef<HTMLDivElement>(null)
const [topAccountsTier, setTopAccountsTier] = useState('mango')
const { mangoAccountAddress } = useMangoAccount()
const { data: seasonData, isLoading: loadingSeasonData } = useCurrentSeason()
const { data: accountTier } = useAccountTier(
mangoAccountAddress,
seasonData?.season_id,
)
const {
data: walletPoints,
isFetching: fetchingWalletRewardsData,
isLoading: loadingWalletRewardsData,
refetch,
} = useWalletPoints(mangoAccountAddress, seasonData?.season_id, wallet)
const seasonEndsIn = useMemo(() => {
if (!seasonData?.season_end) return
return dayjs().to(seasonData.season_end)
}, [seasonData])
const {
data: topAccountsLeaderboardData,
isFetching: fetchingTopAccountsLeaderboardData,
isLoading: loadingTopAccountsLeaderboardData,
} = useTopAccountsLeaderBoard(seasonData?.season_id)
const leadersForTier =
topAccountsLeaderboardData?.find((x) => x.tier === topAccountsTier)
?.leaderboard || []
const isLoadingWalletData =
fetchingWalletRewardsData || loadingWalletRewardsData
const isLoadingLeaderboardData =
fetchingTopAccountsLeaderboardData || loadingTopAccountsLeaderboardData
useEffect(() => {
if (mangoAccountAddress) {
refetch()
}
}, [mangoAccountAddress])
const scrollToFaqs = () => {
if (faqRef.current) {
faqRef.current.scrollIntoView({
behavior: 'smooth',
block: 'start', // or 'end' or 'center'
})
}
}
return (
<>
<div className="banner-wrapper relative mx-auto mb-6 flex flex-col items-center justify-center border-b border-th-bkg-3 p-8 lg:mb-8 lg:px-10 lg:py-12">
<div className="absolute left-0 top-0 mt-3 h-[64px] w-[200%] animate-[moveRightLeft_240s_linear_infinite] bg-[url('/images/rewards/mints-banner-bg-1.png')] bg-contain bg-center bg-repeat-x opacity-30" />
<div className="absolute bottom-0 right-0 mb-3 h-[64px] w-[200%] animate-[moveLeftRight_300s_linear_infinite] bg-[url('/images/rewards/mints-banner-bg-2.png')] bg-contain bg-center bg-repeat-x opacity-30" />
<div className="relative">
<div className="flex items-center justify-center pb-6">
<div className="flex items-center justify-center rounded-full bg-gradient-to-br from-yellow-400 to-red-400 px-4 py-1">
<div className="font-rewards flex items-center text-lg text-black">
Season {seasonData?.season_id} ends
<span className="ml-1">
{seasonEndsIn ? (
seasonEndsIn
) : loadingSeasonData ? (
<SheenLoader className="mb-0.5 ml-1">
<div className="h-5 w-12 bg-th-bkg-2" />
</SheenLoader>
) : (
''
)}
</span>
</div>
</div>
</div>
<h1 className="font-rewards my-2 text-center text-5xl lg:text-6xl">
Mango Mints
</h1>
<p className="mb-6 max-w-2xl text-center text-base leading-snug lg:text-xl">
Earn points by performing actions on Mango. More points equals more
chances to win big.
</p>
<button
className="raised-button font-rewards mx-auto block rounded-lg px-6 py-2 text-xl focus:outline-none lg:py-3"
onClick={scrollToFaqs}
>
<span className="mt-1">How it Works</span>
</button>
</div>
</div>
<div className="mx-auto grid max-w-[1140px] grid-cols-12 gap-4 p-8 pt-0 lg:p-10 lg:pt-0">
<div className="order-2 col-span-12 lg:order-1 lg:col-span-7">
<div className="mb-4 rounded-2xl border border-th-bkg-3 p-6 pb-0">
<h2 className="rewards-h2 mb-4">Rewards Tiers</h2>
<div className="mb-6 space-y-2">
<RewardsTierCard
icon={<AcornIcon className="h-8 w-8 text-th-fgd-1" />}
name="seed"
desc="All new participants start here"
setShowLeaderboards={setShowLeaderboards}
status={
accountTier?.mango_account === 'seed' ? 'Your Tier' : ''
}
/>
<RewardsTierCard
icon={<MangoIcon className="h-8 w-8 text-th-fgd-1" />}
name="mango"
desc="Average swap/trade value less than $1,000"
setShowLeaderboards={setShowLeaderboards}
status={
accountTier?.mango_account === 'mango' ? 'Your Tier' : ''
}
/>
<RewardsTierCard
icon={<WhaleIcon className="h-8 w-8 text-th-fgd-1" />}
name="whale"
desc="Average swap/trade value greater than $1,000"
setShowLeaderboards={setShowLeaderboards}
status={
accountTier?.mango_account === 'whale' ? 'Your Tier' : ''
}
/>
<RewardsTierCard
icon={<RobotIcon className="h-8 w-8 text-th-fgd-1" />}
name="bot"
desc="All bots"
setShowLeaderboards={setShowLeaderboards}
status={accountTier?.mango_account === 'bot' ? 'Your Tier' : ''}
/>
</div>
</div>
<div ref={faqRef}>
<Faqs />
</div>
</div>
<div className="order-1 col-span-12 lg:order-2 lg:col-span-5">
<div className="mb-4 rounded-2xl border border-th-bkg-3 p-6">
<div className="mb-4 flex items-center justify-between">
<h2 className="rewards-h2">Your Points</h2>
</div>
<div className="mb-4 flex h-14 w-full items-center rounded-xl bg-th-bkg-2 px-3">
{!isLoadingWalletData ? (
walletPoints ? (
<span className="font-rewards -mb-1 w-full text-5xl text-th-fgd-1">
{formatNumericValue(walletPoints)}
</span>
) : wallet?.adapter.publicKey ? (
<span className="font-rewards -mb-1 w-full text-5xl text-th-fgd-1">
0
</span>
) : (
<span className="flex items-center justify-center text-center font-body text-sm text-th-fgd-3">
{t('connect-wallet')}
</span>
)
) : (
<SheenLoader>
<div className="h-8 w-32 rounded-md bg-th-bkg-3" />
</SheenLoader>
)}
</div>
<div className="border-b border-th-bkg-3">
<div className="flex items-center justify-between border-t border-th-bkg-3 px-3 py-2">
<p className="rewards-p">Points Earned</p>
<div className="font-rewards text-lg text-th-active">
{!isLoadingWalletData ? (
walletPoints ? (
formatNumericValue(walletPoints)
) : wallet?.adapter.publicKey ? (
0
) : (
''
)
) : (
<SheenLoader>
<div className="h-4 w-12 rounded-sm bg-th-bkg-3" />
</SheenLoader>
)}
</div>
</div>
<div className="flex items-center justify-between border-t border-th-bkg-3 px-3 py-2">
<p className="rewards-p">Streak Bonus</p>
<p className="font-rewards text-lg text-th-active">0x</p>
</div>
<div className="flex items-center justify-between border-t border-th-bkg-3 px-3 py-2">
<p className="rewards-p">Rewards Tier</p>
<div className="font-rewards text-lg text-th-active">
{!isLoadingWalletData ? (
accountTier?.mango_account ? (
<span className="capitalize">
{accountTier?.mango_account}
</span>
) : (
''
)
) : (
<SheenLoader>
<div className="h-4 w-12 rounded-sm bg-th-bkg-3" />
</SheenLoader>
)}
</div>
</div>
<div className="flex items-center justify-between border-t border-th-bkg-3 px-3 py-2">
<p className="rewards-p">Rank</p>
<p className="font-rewards text-lg text-th-active"></p>
</div>
</div>
</div>
<div className="rounded-2xl border border-th-bkg-3 p-6">
<div className="mb-4 flex items-center justify-between">
<h2 className="rewards-h2">Top Accounts</h2>
<Select
value={t(`rewards:${topAccountsTier}`)}
onChange={(tier) => setTopAccountsTier(tier)}
>
{tiers.map((tier) => (
<Select.Option key={tier} value={tier}>
<div className="flex w-full items-center justify-between">
{t(`rewards:${tier}`)}
</div>
</Select.Option>
))}
</Select>
</div>
<div className="mb-6 border-b border-th-bkg-3">
{!isLoadingLeaderboardData ? (
leadersForTier && leadersForTier.length ? (
leadersForTier.slice(0, 5).map((user, i: number) => {
const rank = i + 1
return (
<div
className="flex items-center justify-between border-t border-th-bkg-3 p-3"
key={i + user.mango_account}
>
<div className="flex items-center space-x-2 font-mono">
<div
className={`relative flex h-6 w-6 flex-shrink-0 items-center justify-center rounded-full ${
rank < 4 ? '' : 'bg-th-bkg-3'
}`}
>
<p
className={`font-rewards relative z-10 text-base ${
rank < 4 ? 'text-th-bkg-1' : 'text-th-fgd-1'
}`}
>
{rank}
</p>
{rank < 4 ? (
<MedalIcon className="absolute" rank={rank} />
) : null}
</div>
<span className="text-th-fgd-3">
{abbreviateAddress(
new PublicKey(user.mango_account),
)}
</span>
</div>
<span className="font-mono text-th-fgd-1">
{formatNumericValue(user.total_points, 0)}
</span>
</div>
)
})
) : (
<div className="flex justify-center border-t border-th-bkg-3 py-4">
<span className="text-th-fgd-3">
Leaderboard not available
</span>
</div>
)
) : (
<div className="space-y-0.5">
{[...Array(5)].map((x, i) => (
<SheenLoader className="flex flex-1" key={i}>
<div className="h-10 w-full bg-th-bkg-2" />
</SheenLoader>
))}
</div>
)}
</div>
<button
className="raised-button font-rewards mx-auto block w-full rounded-lg px-6 py-1 text-lg focus:outline-none"
onClick={() => setShowLeaderboards(topAccountsTier)}
>
<span className="mt-1.5 text-xl">Full Leaderboard</span>
</button>
</div>
</div>
</div>
</>
)
}
export default Season