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

346 lines
14 KiB
TypeScript
Raw Normal View History

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,
useTopAccountsLeaderBoard,
2023-10-05 04:10:29 -07:00
useAccountPointsAndRank,
} from 'hooks/useRewards'
2023-09-28 05:10:05 -07:00
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'
2023-09-28 06:49:25 -07:00
const Season = ({
setShowLeaderboards,
}: {
setShowLeaderboards: (x: string) => void
}) => {
const { t } = useTranslation(['common', 'rewards'])
const { wallet } = useWallet()
2023-09-28 05:10:05 -07:00
const faqRef = useRef<HTMLDivElement>(null)
const { mangoAccountAddress } = useMangoAccount()
2023-10-05 04:10:29 -07:00
const [topAccountsTier, setTopAccountsTier] = useState('')
const { data: seasonData, isLoading: loadingSeasonData } = useCurrentSeason()
2023-10-05 04:10:29 -07:00
const { data: accountTier, isLoading: loadingAccountTier } = useAccountTier(
mangoAccountAddress,
seasonData?.season_id,
)
const {
2023-10-05 04:10:29 -07:00
data: accountPointsAndRank,
isLoading: loadingAccountPointsAndRank,
refetch,
2023-10-05 04:10:29 -07:00
} = useAccountPointsAndRank(mangoAccountAddress, seasonData?.season_id)
useEffect(() => {
if (!topAccountsTier && !loadingAccountTier) {
setTopAccountsTier(accountTier?.tier.toLowerCase() || 'mango')
}
}, [loadingAccountTier, topAccountsTier])
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 =
2023-10-05 04:10:29 -07:00
topAccountsLeaderboardData && topAccountsLeaderboardData.length
? topAccountsLeaderboardData?.find((x) => x.tier === topAccountsTier)
?.leaderboard || []
: []
const isLoadingLeaderboardData =
fetchingTopAccountsLeaderboardData || loadingTopAccountsLeaderboardData
useEffect(() => {
if (mangoAccountAddress) {
refetch()
}
}, [mangoAccountAddress])
2023-09-28 05:10:05 -07:00
const scrollToFaqs = () => {
if (faqRef.current) {
faqRef.current.scrollIntoView({
behavior: 'smooth',
block: 'start', // or 'end' or 'center'
})
}
}
return (
<>
2023-09-28 06:49:25 -07:00
<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" />
2023-09-28 06:34:56 -07:00
<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="flex items-center font-rewards text-lg text-black">
2023-09-28 06:34:56 -07:00
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>
2023-09-28 05:10:05 -07:00
</div>
</div>
<h1 className="my-2 text-center font-rewards text-5xl lg:text-6xl">
2023-09-28 06:34:56 -07:00
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 mx-auto block rounded-lg px-6 py-2 font-rewards text-xl focus:outline-none lg:py-3"
2023-09-28 06:34:56 -07:00
onClick={scrollToFaqs}
>
<span className="mt-1">How it Works</span>
</button>
</div>
</div>
2023-09-27 21:54:13 -07:00
<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}
2023-10-05 04:10:29 -07:00
status={accountTier?.tier === '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}
2023-10-05 04:10:29 -07:00
status={accountTier?.tier === '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}
2023-10-05 04:10:29 -07:00
status={accountTier?.tier === 'whale' ? 'Your Tier' : ''}
/>
<RewardsTierCard
icon={<RobotIcon className="h-8 w-8 text-th-fgd-1" />}
name="bot"
desc="All bots"
setShowLeaderboards={setShowLeaderboards}
2023-10-05 04:10:29 -07:00
status={accountTier?.tier === '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">
2023-10-05 04:10:29 -07:00
{!loadingAccountPointsAndRank ? (
accountPointsAndRank?.total_points ? (
<span className="-mb-1 w-full font-rewards text-5xl text-th-fgd-1">
2023-10-05 04:10:29 -07:00
{formatNumericValue(accountPointsAndRank.total_points)}
</span>
) : wallet?.adapter.publicKey ? (
<span className="-mb-1 w-full font-rewards 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">
2023-10-05 04:10:29 -07:00
{!loadingAccountPointsAndRank ? (
accountPointsAndRank?.total_points_pre_multiplier ? (
formatNumericValue(
accountPointsAndRank.total_points_pre_multiplier,
)
) : 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>
2023-10-05 04:10:29 -07:00
<p className="font-rewards text-lg text-th-active">
{accountTier?.streak_multiplier_percent}%
</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">
2023-10-05 04:10:29 -07:00
{!loadingAccountTier ? (
accountTier?.tier ? (
<span className="capitalize">{accountTier.tier}</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>
2023-10-05 04:10:29 -07:00
<div className="font-rewards text-lg text-th-active">
{!loadingAccountPointsAndRank ? (
accountPointsAndRank?.rank ? (
<span className="capitalize">
{accountPointsAndRank.rank +
accountPointsAndRank?.total_season_accounts
? `/${accountPointsAndRank.total_season_accounts}`
: ''}
</span>
) : (
''
)
) : (
<SheenLoader>
<div className="h-4 w-12 rounded-sm bg-th-bkg-3" />
</SheenLoader>
)}
</div>
</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={`relative z-10 font-rewards 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>
2023-09-28 05:10:05 -07:00
<button
className="raised-button mx-auto block w-full rounded-lg px-6 py-1 font-rewards text-lg focus:outline-none"
onClick={() => setShowLeaderboards(topAccountsTier)}
>
<span className="mt-1.5 text-xl">Full Leaderboard</span>
2023-09-28 05:10:05 -07:00
</button>
</div>
</div>
</div>
</>
)
}
export default Season