add projected next season tier

This commit is contained in:
saml33 2023-10-25 22:23:41 +11:00
parent 3aa65f7f75
commit 1b45a5f677
3 changed files with 137 additions and 21 deletions

View File

@ -18,7 +18,7 @@ const RewardsPage = () => {
const { showClaim } = useIsAllClaimed(prevSeason, publicKey) const { showClaim } = useIsAllClaimed(prevSeason, publicKey)
return !showLeaderboards ? ( return !showLeaderboards ? (
showClaim ? ( !showClaim ? (
<ClaimPage /> <ClaimPage />
) : ( ) : (
<Season setShowLeaderboards={setShowLeaderboards} /> <Season setShowLeaderboards={setShowLeaderboards} />

View File

@ -26,6 +26,38 @@ import MedalIcon from '@components/icons/MedalIcon'
import FormatNumericValue from '@components/shared/FormatNumericValue' import FormatNumericValue from '@components/shared/FormatNumericValue'
import { usePlausible } from 'next-plausible' import { usePlausible } from 'next-plausible'
import { TelemetryEvents } from 'utils/telemetry' import { TelemetryEvents } from 'utils/telemetry'
import { useQuery } from '@tanstack/react-query'
import { MANGO_DATA_API_URL } from 'utils/constants'
import {
ActivityFeed,
isSpotTradeActivityFeedItem,
isSwapActivityFeedItem,
} from 'types'
import Tooltip from '@components/shared/Tooltip'
const fetchSeasonTradesData = async (
startDate: string,
mangoAccountPk: string,
) => {
try {
const response = await fetch(
`${MANGO_DATA_API_URL}/stats/activity-feed?mango-account=${mangoAccountPk}&start-date=${startDate}`,
)
const parsedResponse = await response.json()
if (parsedResponse && parsedResponse?.length) {
const swapsAndSpot = parsedResponse.filter(
(data: ActivityFeed) =>
data.activity_type === 'swap' ||
data.activity_type === 'openbook_trade',
)
return swapsAndSpot
} else return []
} catch (e) {
console.error('Failed to load season trades data', e)
return []
}
}
const Season = ({ const Season = ({
setShowLeaderboards, setShowLeaderboards,
@ -48,6 +80,47 @@ const Season = ({
refetch, refetch,
} = useAccountPointsAndRank(mangoAccountAddress, seasonData?.season_id) } = useAccountPointsAndRank(mangoAccountAddress, seasonData?.season_id)
const { data: seasonTradesData } = useQuery(
['season-trades-data', seasonData?.season_start],
() => fetchSeasonTradesData(seasonData!.season_start, mangoAccountAddress),
{
cacheTime: 1000 * 60 * 10,
staleTime: 1000 * 60,
retry: 3,
refetchOnWindowFocus: false,
enabled: !!(seasonData?.season_start && mangoAccountAddress),
},
)
const averageTradeValue = useMemo(() => {
if (!seasonTradesData || !seasonTradesData?.length) return 0
const notionalValues = []
for (const trade of seasonTradesData) {
const { activity_details } = trade
if (isSwapActivityFeedItem(trade)) {
const value =
activity_details.swap_in_amount * activity_details.swap_in_price_usd
notionalValues.push(value)
}
if (isSpotTradeActivityFeedItem(trade)) {
const value = activity_details.size * activity_details.price
notionalValues.push(value)
}
}
const totalValue = notionalValues.reduce((a, c) => a + c, 0)
const averageValue = totalValue / notionalValues.length
return averageValue
}, [seasonTradesData])
const projectedTier = useMemo(() => {
if (!accountTier?.tier) return ''
if (accountTier.tier === 'bot') {
return 'bot'
} else if (averageTradeValue > 1000) {
return 'whale'
} else return 'mango'
}, [accountTier, averageTradeValue])
useEffect(() => { useEffect(() => {
if (!topAccountsTier && !loadingAccountTier) { if (!topAccountsTier && !loadingAccountTier) {
setTopAccountsTier(accountTier?.tier.toLowerCase() || 'mango') setTopAccountsTier(accountTier?.tier.toLowerCase() || 'mango')
@ -171,9 +244,7 @@ const Season = ({
</div> </div>
<div className="order-1 col-span-12 lg:order-2 lg:col-span-5"> <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 rounded-2xl border border-th-bkg-3 p-6">
<div className="mb-4 flex items-center justify-between"> <h2 className="rewards-h2 mb-4">Your Points</h2>
<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"> <div className="mb-4 flex h-14 w-full items-center rounded-xl bg-th-bkg-2 px-3">
{!loadingAccountPointsAndRank ? ( {!loadingAccountPointsAndRank ? (
accountPointsAndRank?.total_points ? ( accountPointsAndRank?.total_points ? (
@ -264,6 +335,35 @@ const Season = ({
</div> </div>
</div> </div>
</div> </div>
<div className="mb-4 rounded-2xl border border-th-bkg-3 p-6">
<h2 className="rewards-h2 mb-4">Activity</h2>
<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">Average Trade Value</p>
<span className="font-rewards text-lg text-th-active">
<FormatNumericValue value={averageTradeValue} isUsd />
</span>
</div>
<div className="flex items-center justify-between border-t border-th-bkg-3 px-3 py-2">
<Tooltip content="Your projected tier for next season. This is based on your average trade value">
<p className="rewards-p tooltip-underline">Projected Tier</p>
</Tooltip>
<span className="font-rewards text-lg text-th-active">
{!loadingAccountTier ? (
projectedTier ? (
<span className="capitalize">{projectedTier}</span>
) : (
''
)
) : (
<SheenLoader>
<div className="h-4 w-12 rounded-sm bg-th-bkg-3" />
</SheenLoader>
)}
</span>
</div>
</div>
</div>
<div className="rounded-2xl border border-th-bkg-3 p-6"> <div className="rounded-2xl border border-th-bkg-3 p-6">
<div className="mb-4 flex items-center justify-between"> <div className="mb-4 flex items-center justify-between">
<h2 className="rewards-h2">Top Accounts</h2> <h2 className="rewards-h2">Top Accounts</h2>

View File

@ -285,6 +285,28 @@ export interface SpotTradeActivity {
symbol: string symbol: string
} }
export interface SwapHistoryItem {
block_datetime: string
mango_account: string
signature: string
swap_in_amount: number
swap_in_loan: number
swap_in_loan_origination_fee: number
swap_in_price_usd: number
swap_in_symbol: string
swap_out_amount: number
loan: number
loan_origination_fee: number
swap_out_price_usd: number
swap_out_symbol: string
}
export interface SwapActivity {
activity_details: SwapHistoryItem
block_datetime: string
activity_type: string
}
export function isLiquidationActivityFeedItem( export function isLiquidationActivityFeedItem(
item: ActivityFeed, item: ActivityFeed,
): item is LiquidationActivity { ): item is LiquidationActivity {
@ -312,6 +334,16 @@ export function isSpotTradeActivityFeedItem(
return false return false
} }
export function isSwapActivityFeedItem(
item: ActivityFeed,
): item is SwapActivity {
console.log(item)
if (item.activity_type === 'swap') {
return true
}
return false
}
export function isPerpLiquidation( export function isPerpLiquidation(
activityDetails: SpotOrPerpLiquidationItem, activityDetails: SpotOrPerpLiquidationItem,
): activityDetails is PerpLiquidationFeedItem { ): activityDetails is PerpLiquidationFeedItem {
@ -321,22 +353,6 @@ export function isPerpLiquidation(
return false return false
} }
export interface SwapHistoryItem {
block_datetime: string
mango_account: string
signature: string
swap_in_amount: number
swap_in_loan: number
swap_in_loan_origination_fee: number
swap_in_price_usd: number
swap_in_symbol: string
swap_out_amount: number
loan: number
loan_origination_fee: number
swap_out_price_usd: number
swap_out_symbol: string
}
export interface NFT { export interface NFT {
address: string address: string
collectionAddress?: string collectionAddress?: string
@ -375,7 +391,7 @@ export type GroupedDataItem = PerpStatsItem & Record<string, any>
export type ActivityFeed = { export type ActivityFeed = {
activity_type: string activity_type: string
block_datetime: string block_datetime: string
symbol: string symbol?: string
activity_details: activity_details:
| DepositWithdrawFeedItem | DepositWithdrawFeedItem
| SpotLiquidationFeedItem | SpotLiquidationFeedItem