From 09e7ead7722c704e6dcf95be534d997fdb7ea2c7 Mon Sep 17 00:00:00 2001 From: ChefMomota <98292246+ChefMomota@users.noreply.github.com> Date: Mon, 10 Jul 2023 15:08:11 +0800 Subject: [PATCH] feat: New trading reward UI (#7296) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### 🤖 Generated by Copilot at 8d25515 ### Summary 🏆🔄📱 This pull request adds features to the `TradingReward` view and its components to show multiple rounds of the trading competition leaderboard and rewards breakdown. It also refactors and improves the data fetching, rendering, and layout logic of the components. It updates the useUserTradeRank hook to return more user rank data and a loading indicator. It removes unused props and translations and adds new translations for the new features. > _`Leaderboard` of doom, show me the ranks of the best_ > _`RewardsBreakdown` of despair, reveal the prizes of the rest_ > _`MyRank` of hope, inspire me to rise and compete_ > _`useUserTradeRank` of power, load the data and make it complete_ ### Walkthrough * Add new features to the Leaderboard and the RewardsBreakdown components to allow the user to switch between the current and previous rounds of the leaderboard and the rewards breakdown and show the round information for each round ([link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-5fd07b53fd6d3e6d1762ae5cd1d0b3ac32bdef19353c7d95340934d8359cf130L22),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-5fd07b53fd6d3e6d1762ae5cd1d0b3ac32bdef19353c7d95340934d8359cf130L28-R27),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-5fd07b53fd6d3e6d1762ae5cd1d0b3ac32bdef19353c7d95340934d8359cf130L37-R35),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-5fd07b53fd6d3e6d1762ae5cd1d0b3ac32bdef19353c7d95340934d8359cf130L43-R43),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-5fd07b53fd6d3e6d1762ae5cd1d0b3ac32bdef19353c7d95340934d8359cf130L60-R60),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-94382753793192a4edd427aba2521b380c88958dbcc9821b7f456a923c67847aL1-R2),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-94382753793192a4edd427aba2521b380c88958dbcc9821b7f456a923c67847aL11-R19),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-94382753793192a4edd427aba2521b380c88958dbcc9821b7f456a923c67847aL23-R96),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-94382753793192a4edd427aba2521b380c88958dbcc9821b7f456a923c67847aL47-R171),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-84dcb226924a4df52e63f545677d1d57610612105558abb2c22e78aa35cc8a13L1-R12),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-84dcb226924a4df52e63f545677d1d57610612105558abb2c22e78aa35cc8a13L12),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-84dcb226924a4df52e63f545677d1d57610612105558abb2c22e78aa35cc8a13L28),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-84dcb226924a4df52e63f545677d1d57610612105558abb2c22e78aa35cc8a13R47),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-84dcb226924a4df52e63f545677d1d57610612105558abb2c22e78aa35cc8a13R57),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-84dcb226924a4df52e63f545677d1d57610612105558abb2c22e78aa35cc8a13L63-R96),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-84dcb226924a4df52e63f545677d1d57610612105558abb2c22e78aa35cc8a13L84-R136),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-84dcb226924a4df52e63f545677d1d57610612105558abb2c22e78aa35cc8a13L98),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-905d0511435088804181a66cc5ab45ff12f7236f3e07a3d752c1c2cdfa3b4247L88-R90)) * Create a new component called MyRank, which displays the user's own rank separately from the top 50 users, and use it in the Leaderboard component ([link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-162db74c38bd881f81ea3cac99f47db4187271b391e0d9c51d9bfab08cd5ce43R1-R68),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-94382753793192a4edd427aba2521b380c88958dbcc9821b7f456a923c67847aL47-R171)) * Modify the useUserTradeRank hook to return more properties of the user's rank data and an isFetching property to indicate the loading state ([link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-7daaf106864f93b18f65961b19005f1a0facbc3c4dfdd7f766e697d3824e5aefL8-R15),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-7daaf106864f93b18f65961b19005f1a0facbc3c4dfdd7f766e697d3824e5aefR26-R28),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-7daaf106864f93b18f65961b19005f1a0facbc3c4dfdd7f766e697d3824e5aefL38-R47)) * Modify the Leaderboard and the RewardsBreakdown components to handle the loading state and the undefined data more gracefully ([link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-5fd07b53fd6d3e6d1762ae5cd1d0b3ac32bdef19353c7d95340934d8359cf130L43-R43),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-5fd07b53fd6d3e6d1762ae5cd1d0b3ac32bdef19353c7d95340934d8359cf130L60-R60),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-4bf926d7d5e072659dfcf6f3db3ea66aa5958caa1849f1b86096c094fcc95d16L23-R27),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-4bf926d7d5e072659dfcf6f3db3ea66aa5958caa1849f1b86096c094fcc95d16L40-R53),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-f220411cac4174fd35a3d24356555fc08bb11f1ab78349cdceabc7f55ee45d5aL33-R33),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-f220411cac4174fd35a3d24356555fc08bb11f1ab78349cdceabc7f55ee45d5aL41-R41),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-f220411cac4174fd35a3d24356555fc08bb11f1ab78349cdceabc7f55ee45d5aL48-R50),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-d0cf24bc78fd41475144556445d7673e34f1d792bcda3efd5e624bab6631ced1L46-R46),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-d0cf24bc78fd41475144556445d7673e34f1d792bcda3efd5e624bab6631ced1L54-R54),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-cf88c6203950e52a3f8ea80d48d574d1ce87b9695f6965cf3e812ebda2d5119fL36-R36),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-cf88c6203950e52a3f8ea80d48d574d1ce87b9695f6965cf3e812ebda2d5119fL44-R44)) * Modify the table headers and the layout of the Leaderboard component to simplify the table and match the design of the mobile view ([link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-4b8800b925873b06295e95f7b8ab1cdb221b8d7898355d43b84d79c9116fa730L27-R31),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-5fd07b53fd6d3e6d1762ae5cd1d0b3ac32bdef19353c7d95340934d8359cf130L28-R27),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-4bf926d7d5e072659dfcf6f3db3ea66aa5958caa1849f1b86096c094fcc95d16L40-R53)) * Modify the CurrentPeriod component of the YourTradingReward component to destructure the data and the isFetching properties from the useUserTradeRank hook ([link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-cbc3dee4b1e1855ef521248a8dd17f1361a02964cd534ad687427b1ee69bed28L45-R45)) * Remove some unused props and translations from the RewardsBreakdown and the Leaderboard components ([link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-84dcb226924a4df52e63f545677d1d57610612105558abb2c22e78aa35cc8a13L12),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-84dcb226924a4df52e63f545677d1d57610612105558abb2c22e78aa35cc8a13L28),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-8899ffb1860eb76dfa9555198ba793b2cd223454ddb9d53864b20d5a1ac094a7L95),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-905d0511435088804181a66cc5ab45ff12f7236f3e07a3d752c1c2cdfa3b4247L88-R90),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-eb2ab983e2cefc22516cb7814c86346f4b2bd2b971980952868173095d48f459L2449-L2450),[link](https://github.com/pancakeswap/pancake-frontend/pull/7296/files?diff=unified&w=0#diff-eb2ab983e2cefc22516cb7814c86346f4b2bd2b971980952868173095d48f459L2583)) --- .../components/Leaderboard/DesktopResult.tsx | 8 +- .../components/Leaderboard/DesktopView.tsx | 14 +- .../components/Leaderboard/MobileResult.tsx | 20 +- .../components/Leaderboard/MobileView.tsx | 8 +- .../components/Leaderboard/MyRank.tsx | 68 +++++++ .../components/Leaderboard/RankingCard.tsx | 48 +++-- .../components/Leaderboard/index.tsx | 181 ++++++++++++++---- .../RewardsBreakdown/DesktopView.tsx | 4 +- .../RewardsBreakdown/MobileView.tsx | 4 +- .../components/RewardsBreakdown/index.tsx | 77 ++++++-- .../YourTradingReward/CurrentPeriod.tsx | 2 +- .../views/TradingReward/hooks/useRankList.tsx | 12 +- .../TradingReward/hooks/useUserTradeRank.tsx | 19 +- apps/web/src/views/TradingReward/index.tsx | 1 - .../src/views/TradingReward/top-traders.tsx | 3 +- .../localization/src/config/translations.json | 10 +- 16 files changed, 366 insertions(+), 113 deletions(-) create mode 100644 apps/web/src/views/TradingReward/components/Leaderboard/MyRank.tsx diff --git a/apps/web/src/views/TradingReward/components/Leaderboard/DesktopResult.tsx b/apps/web/src/views/TradingReward/components/Leaderboard/DesktopResult.tsx index 9788b52437acd..381d0799a5361 100644 --- a/apps/web/src/views/TradingReward/components/Leaderboard/DesktopResult.tsx +++ b/apps/web/src/views/TradingReward/components/Leaderboard/DesktopResult.tsx @@ -24,13 +24,11 @@ const DesktopResult: React.FC> = ({ return ( - - - {`#${rank.rank}`} - - + + {rank.rank === 0 ? '--' : `#${rank.rank}`} + {profile?.username || domainName || truncateHash(rank.origin)} diff --git a/apps/web/src/views/TradingReward/components/Leaderboard/DesktopView.tsx b/apps/web/src/views/TradingReward/components/Leaderboard/DesktopView.tsx index efe3a3b8b9d2a..b7daf061fc9e5 100644 --- a/apps/web/src/views/TradingReward/components/Leaderboard/DesktopView.tsx +++ b/apps/web/src/views/TradingReward/components/Leaderboard/DesktopView.tsx @@ -19,14 +19,12 @@ const LeaderBoardDesktopView: React.FC { const { t } = useTranslation() - return ( - - + @@ -34,15 +32,15 @@ const LeaderBoardDesktopView: React.FC {isLoading ? ( - ) : ( <> - {data?.length === 0 ? ( + {!data || data?.length === 0 ? ( - @@ -57,7 +55,9 @@ const LeaderBoardDesktopView: React.FC
 {t('User')}{t('Rank (Top 50 users)')} {t('Trading Volume')} {t('Total Reward')}
+ {t('Loading...')}
+ {t('No results')}
- + {data?.length > 0 && ( + + )}
) } diff --git a/apps/web/src/views/TradingReward/components/Leaderboard/MobileResult.tsx b/apps/web/src/views/TradingReward/components/Leaderboard/MobileResult.tsx index 267616e40fde4..e52a25ee9f24a 100644 --- a/apps/web/src/views/TradingReward/components/Leaderboard/MobileResult.tsx +++ b/apps/web/src/views/TradingReward/components/Leaderboard/MobileResult.tsx @@ -20,10 +20,11 @@ export const StyledMobileRow = styled(Box)` ` interface MobileResultProps { + isMyRank?: boolean rank: RankListDetail } -const MobileResult: React.FC> = ({ rank }) => { +const MobileResult: React.FC> = ({ isMyRank, rank }) => { const { t } = useTranslation() const cakePriceBusd = usePriceCakeUSD() const { profile, isLoading: isProfileLoading } = useProfileForAddress(rank.origin) @@ -37,10 +38,19 @@ const MobileResult: React.FC> = ({ ra return ( - - {`#${rank.rank}`} - - + + + {isMyRank && ( + + {t('My Rank')} + + )} + + {rank.rank === 0 ? '--' : `#${rank.rank}`} + + + + {profile?.username || domainName || truncateHash(rank.origin)} diff --git a/apps/web/src/views/TradingReward/components/Leaderboard/MobileView.tsx b/apps/web/src/views/TradingReward/components/Leaderboard/MobileView.tsx index 1d93e40dfc691..8233d9e27304a 100644 --- a/apps/web/src/views/TradingReward/components/Leaderboard/MobileView.tsx +++ b/apps/web/src/views/TradingReward/components/Leaderboard/MobileView.tsx @@ -30,7 +30,7 @@ const LeaderBoardMobileView: React.FC ) : ( <> - {data?.length === 0 ? ( + {!data || data?.length === 0 ? ( {t('No results')} @@ -38,14 +38,16 @@ const LeaderBoardMobileView: React.FC ) : ( <> - {data.map((rank) => ( + {data?.map((rank) => ( ))} )} )} - + {data?.length > 0 && ( + + )} ) } diff --git a/apps/web/src/views/TradingReward/components/Leaderboard/MyRank.tsx b/apps/web/src/views/TradingReward/components/Leaderboard/MyRank.tsx new file mode 100644 index 0000000000000..9ef8d731d8ca0 --- /dev/null +++ b/apps/web/src/views/TradingReward/components/Leaderboard/MyRank.tsx @@ -0,0 +1,68 @@ +import { useMemo } from 'react' +import { Card, Table, Th, Td, Box, useMatchBreakpoints } from '@pancakeswap/uikit' +import { useWeb3React } from '@pancakeswap/wagmi' +import { useTranslation } from '@pancakeswap/localization' +import { useUserTradeRank } from 'views/TradingReward/hooks/useUserTradeRank' +import DesktopResult from 'views/TradingReward/components/Leaderboard/DesktopResult' +import MobileResult from 'views/TradingReward/components/Leaderboard/MobileResult' + +interface MyRankProps { + campaignId: string +} + +const MyRank: React.FC> = ({ campaignId }) => { + const { t } = useTranslation() + const { account } = useWeb3React() + const { isDesktop } = useMatchBreakpoints() + const { data: userRank, isFetching } = useUserTradeRank({ campaignId }) + + const rank = useMemo( + () => ({ + origin: account, + rank: userRank.topTradersIndex, + tradingFee: userRank.tradingFee, + volume: userRank.volume, + estimateRewardUSD: userRank.estimateRewardUSD, + }), + [account, userRank], + ) + + if (!account) { + return null + } + + return ( + + + {isDesktop ? ( + + + + + + + + + + {isFetching ? ( + + + + ) : ( + + )} + +
+ {t('My Rank')} + {t('Trading Volume')}{t('Total Reward')}
+ {t('Loading...')} +
+ ) : ( + + )} +
+
+ ) +} + +export default MyRank diff --git a/apps/web/src/views/TradingReward/components/Leaderboard/RankingCard.tsx b/apps/web/src/views/TradingReward/components/Leaderboard/RankingCard.tsx index 8d3f22afcff6d..ab518096d60e7 100644 --- a/apps/web/src/views/TradingReward/components/Leaderboard/RankingCard.tsx +++ b/apps/web/src/views/TradingReward/components/Leaderboard/RankingCard.tsx @@ -9,6 +9,7 @@ import { LaurelRightIcon, Text, SubMenu, + Skeleton, } from '@pancakeswap/uikit' import styled from 'styled-components' import { useTranslation } from '@pancakeswap/localization' @@ -51,11 +52,11 @@ const RankingCard: React.FC> = ({ rank const { t } = useTranslation() const rankColor = getRankingColor(rank) const cakePriceBusd = usePriceCakeUSD() - const { profile, isLoading: isProfileLoading } = useProfileForAddress(user.origin) - const { domainName, avatar } = useDomainNameForAddress(user.origin, !profile && !isProfileLoading) + const { profile, isLoading: isProfileLoading } = useProfileForAddress(user?.origin) + const { domainName, avatar } = useDomainNameForAddress(user?.origin, !profile && !isProfileLoading) const cakeAmount = useMemo( - () => new BigNumber(user?.estimateRewardUSD).div(cakePriceBusd).toNumber(), + () => new BigNumber(user?.estimateRewardUSD).div(cakePriceBusd).toNumber() ?? 0, [cakePriceBusd, user?.estimateRewardUSD], ) @@ -87,9 +88,13 @@ const RankingCard: React.FC> = ({ rank
- - {profile?.username || domainName || truncateHash(user.origin)} - + {!user ? ( + + ) : ( + + {profile?.username || domainName || truncateHash(user?.origin)} + + )}
} options={{ placement: 'bottom' }} @@ -100,21 +105,34 @@ const RankingCard: React.FC> = ({ rank {t('Total Reward')}
- - {`$${formatNumber(user.estimateRewardUSD)}`} - - - {`~${formatNumber(cakeAmount)} CAKE`} - + {!user ? ( + <> + + + + ) : ( + <> + + {`$${formatNumber(user?.estimateRewardUSD)}`} + + + {`~${formatNumber(cakeAmount)} CAKE`} + + + )}
{t('Trading Volume')} - - {`$${formatNumber(user.volume)}`} - + {!user ? ( + + ) : ( + + {`$${formatNumber(user?.volume)}`} + + )} diff --git a/apps/web/src/views/TradingReward/components/Leaderboard/index.tsx b/apps/web/src/views/TradingReward/components/Leaderboard/index.tsx index 5c039217e03f9..8793743f3b94a 100644 --- a/apps/web/src/views/TradingReward/components/Leaderboard/index.tsx +++ b/apps/web/src/views/TradingReward/components/Leaderboard/index.tsx @@ -1,5 +1,5 @@ -import { useState, useEffect } from 'react' -import { Box, Grid, Text, useMatchBreakpoints } from '@pancakeswap/uikit' +import { useState, useEffect, useMemo, useCallback } from 'react' +import { Box, Grid, Text, useMatchBreakpoints, PaginationButton, ButtonMenu, ButtonMenuItem } from '@pancakeswap/uikit' import { useTranslation } from '@pancakeswap/localization' import Container from 'components/Layout/Container' import { timeFormat } from 'views/TradingReward/utils/timeFormat' @@ -8,23 +8,95 @@ import { useRankList, MAX_PER_PAGE } from 'views/TradingReward/hooks/useRankList import LeaderBoardDesktopView from './DesktopView' import LeaderBoardMobileView from './MobileView' import RankingCard from './RankingCard' +import MyRank from './MyRank' interface LeaderboardProps { - campaignId: string - incentives: Incentives + campaignIdsIncentive: Incentives[] } -const Leaderboard: React.FC> = ({ campaignId, incentives }) => { +const MAX_CAMPAIGN_PER_PAGE = 1 + +const Leaderboard: React.FC> = ({ campaignIdsIncentive }) => { const { t, currentLanguage: { locale }, } = useTranslation() const { isDesktop } = useMatchBreakpoints() + const [index, setIndex] = useState(0) + const [campaignPage, setCampaignPage] = useState(1) + const [campaignMaxPage, setCampaignMaxPages] = useState(1) + const [campaignLeaderBoardList, setCampaignLeaderBoardList] = useState({ + campaignId: '0', + campaignStart: 0, + campaignClaimTime: 0, + }) + const [currentPage, setCurrentPage] = useState(1) const [maxPage, setMaxPages] = useState(1) - const { total, topTradersArr, topThreeTraders, isLoading } = useRankList({ campaignId, currentPage }) + const { total, topTradersArr, topThreeTraders, isLoading } = useRankList({ + campaignId: campaignLeaderBoardList.campaignId, + currentPage, + }) const [first, second, third] = topThreeTraders + const allLeaderBoard = useMemo( + () => + campaignIdsIncentive + .map((i) => ({ + campaignId: i.campaignId, + campaignStart: i.campaignStart, + campaignClaimTime: i.campaignClaimTime, + })) + .sort((a, b) => Number(b.campaignId) - Number(a.campaignId)), + [campaignIdsIncentive], + ) + const currentLeaderBoard = useMemo( + () => allLeaderBoard.find((i) => i.campaignClaimTime >= Date.now() / 1000), + [allLeaderBoard], + ) + + const round = useMemo(() => campaignMaxPage - (campaignPage - 1), [campaignMaxPage, campaignPage]) + + const sliceAllLeaderBoard = useCallback(() => { + const slice = allLeaderBoard.slice(MAX_CAMPAIGN_PER_PAGE * (campaignPage - 1), MAX_CAMPAIGN_PER_PAGE * campaignPage) + setCampaignLeaderBoardList({ ...slice[0] }) + }, [allLeaderBoard, campaignPage]) + + useEffect(() => { + if (allLeaderBoard.length > 0) { + const max = Math.ceil(allLeaderBoard?.length / MAX_CAMPAIGN_PER_PAGE) + setCampaignMaxPages(max) + } + + return () => { + setCampaignPage(1) + setCampaignMaxPages(1) + } + }, [allLeaderBoard.length]) + + useEffect(() => { + const getActivitySlice = () => { + setCurrentPage(1) + + if (currentLeaderBoard?.campaignId) { + if (index === 0) { + setCampaignPage(1) + setCampaignLeaderBoardList(currentLeaderBoard) + } else { + setCampaignPage(2) + sliceAllLeaderBoard() + } + } else { + setIndex(1) + sliceAllLeaderBoard() + } + } + + if (allLeaderBoard.length > 0) { + getActivitySlice() + } + }, [index, allLeaderBoard, currentLeaderBoard, sliceAllLeaderBoard, campaignMaxPage]) + useEffect(() => { if (total > 0) { const max = Math.ceil(total / MAX_PER_PAGE) @@ -44,42 +116,69 @@ const Leaderboard: React.FC> = ({ camp {t('Leaderboard')} - {`${timeFormat( - locale, - incentives?.campaignStart, - )} - ${timeFormat(locale, incentives?.campaignClaimTime)}`} - - {t('Top #50 Winners')} - - - - - {first && } - {second && } - {third && } - - - - {isDesktop ? ( - - ) : ( - + {currentLeaderBoard && ( + + + {t('Current Round')} + {t('Previous Rounds')} + + + )} + {round > 0 && ( + <> + + {t('Round #%round% | %startTime% - %endTime%', { + round, + startTime: timeFormat(locale, campaignLeaderBoardList?.campaignStart), + endTime: timeFormat(locale, campaignLeaderBoardList?.campaignClaimTime), + })} + + {index === 1 && ( + + )} + + )} + {campaignLeaderBoardList.campaignStart > 0 && ( + + + {(topTradersArr?.length > 0 || isLoading) && ( + <> + + + + + )} + + )} + + + {isDesktop ? ( + + ) : ( + + )} + ) diff --git a/apps/web/src/views/TradingReward/components/RewardsBreakdown/DesktopView.tsx b/apps/web/src/views/TradingReward/components/RewardsBreakdown/DesktopView.tsx index efb903bba1d80..d5c4e4d8325bd 100644 --- a/apps/web/src/views/TradingReward/components/RewardsBreakdown/DesktopView.tsx +++ b/apps/web/src/views/TradingReward/components/RewardsBreakdown/DesktopView.tsx @@ -43,7 +43,7 @@ const DesktopView: React.FC ) : ( <> - {list.pairs.length === 0 ? ( + {!list?.pairs || list?.pairs?.length === 0 ? ( {t('No results')} @@ -51,7 +51,7 @@ const DesktopView: React.FC ) : ( <> - {list.pairs.map((pair) => ( + {list?.pairs?.map((pair) => ( ) : ( <> - {list?.pairs?.length === 0 ? ( + {!list?.pairs || list?.pairs?.length === 0 ? ( {t('No results')} @@ -41,7 +41,7 @@ const MobileView: React.FC ) : ( <> - {list.pairs.map((pair) => ( + {list?.pairs?.map((pair) => ( } } @@ -25,7 +33,6 @@ const initList: RewardBreakdownDetail = { } const RewardsBreakdown: React.FC> = ({ - latestCampaignId, allUserCampaignInfo, allTradingRewardPairData, campaignPairs, @@ -37,6 +44,7 @@ const RewardsBreakdown: React.FC> const { isDesktop } = useMatchBreakpoints() const [currentPage, setCurrentPage] = useState(1) const [maxPage, setMaxPages] = useState(1) + const [index, setIndex] = useState(0) const [list, setList] = useState(initList) const { data, isFetching } = useRewardBreakdown({ @@ -46,6 +54,7 @@ const RewardsBreakdown: React.FC> }) const sortData = useMemo(() => data.sort((a, b) => Number(b.campaignId) - Number(a.campaignId)), [data]) + const currentList = useMemo(() => sortData.find((i) => i.campaignClaimTime >= Date.now() / 1000), [sortData]) useEffect(() => { if (sortData.length > 0) { @@ -60,15 +69,31 @@ const RewardsBreakdown: React.FC> } }, [sortData]) + const sliceData = useCallback(() => { + const slice = sortData.slice(MAX_PER_PAGE * (currentPage - 1), MAX_PER_PAGE * currentPage) + setList({ ...slice[0] }) + }, [currentPage, sortData]) + useEffect(() => { const getActivitySlice = () => { - const slice = sortData.slice(MAX_PER_PAGE * (currentPage - 1), MAX_PER_PAGE * currentPage) - setList({ ...slice[0] }) + if (currentList?.campaignId) { + if (index === 0) { + setCurrentPage(1) + setList(currentList) + } else { + setCurrentPage(2) + sliceData() + } + } else { + setIndex(1) + sliceData() + } } + if (sortData.length > 0) { getActivitySlice() } - }, [currentPage, sortData]) + }, [index, currentPage, sortData, currentList, sliceData]) return ( > {t('Rewards Breakdown')} - - {`${timeFormat(locale, list.campaignStart)} - ${timeFormat(locale, list.campaignClaimTime)}`} - - - {`${t('Campaign')} ${list.campaignId} ${ - list.campaignId?.toLowerCase() === latestCampaignId?.toLowerCase() ? t('(latest)') : '' - }`} - - + {currentList && ( + + + {t('Current Round')} + {t('Previous Rounds')} + + + )} + {list?.pairs?.length > 0 && ( + + {t('Round #%round% | %startTime% - %endTime%', { + round: maxPage - (currentPage - 1), + startTime: timeFormat(locale, list.campaignStart), + endTime: timeFormat(locale, list.campaignClaimTime), + })} + + )} + {index === 1 && list?.pairs?.length && ( + + + + )} + {isDesktop ? ( ) : ( )} - ) diff --git a/apps/web/src/views/TradingReward/components/TopTraders/YourTradingReward/CurrentPeriod.tsx b/apps/web/src/views/TradingReward/components/TopTraders/YourTradingReward/CurrentPeriod.tsx index d067776268243..454a9e7c7b2b2 100644 --- a/apps/web/src/views/TradingReward/components/TopTraders/YourTradingReward/CurrentPeriod.tsx +++ b/apps/web/src/views/TradingReward/components/TopTraders/YourTradingReward/CurrentPeriod.tsx @@ -42,7 +42,7 @@ const CurrentPeriod: React.FC> = ({ currentLanguage: { locale }, } = useTranslation() const cakePriceBusd = usePriceCakeUSD() - const rank = useUserTradeRank({ campaignId: currentUserCampaignInfo?.campaignId }) + const { data: rank } = useUserTradeRank({ campaignId: currentUserCampaignInfo?.campaignId }) const currentDate = Date.now() / 1000 const timeRemaining = campaignClaimTime - currentDate diff --git a/apps/web/src/views/TradingReward/hooks/useRankList.tsx b/apps/web/src/views/TradingReward/hooks/useRankList.tsx index 4a99ae0db4175..2ac0f8b1bd80d 100644 --- a/apps/web/src/views/TradingReward/hooks/useRankList.tsx +++ b/apps/web/src/views/TradingReward/hooks/useRankList.tsx @@ -1,6 +1,7 @@ import useSWR from 'swr' import { useState } from 'react' import { TRADING_REWARD_API } from 'config/constants/endpoints' +import { RewardType } from 'views/TradingReward/hooks/useAllTradingRewardPair' interface UseRankListProps { campaignId: string @@ -35,15 +36,21 @@ const TOP_RANK_NUMBER = 3 export const useRankList = ({ campaignId, currentPage }: UseRankListProps): RankList => { const [isLoading, setIsLoading] = useState(false) + const [lastCampaignId, setLastCampaignId] = useState('') const [topThreeTraders, setTopThreeTraders] = useState([]) const { data } = useSWR( - campaignId && currentPage && ['/trader-rank-list', campaignId, currentPage], + Number(campaignId) > 0 && currentPage && ['/trader-rank-list', campaignId, currentPage], async () => { try { setIsLoading(true) + setLastCampaignId(campaignId) + if (campaignId !== lastCampaignId) { + setTopThreeTraders([]) + } + const response = await fetch( - `${TRADING_REWARD_API}/rank_list/campaignId/${campaignId}/type/tt/page/${currentPage}/size/${MAX_PER_PAGE}`, + `${TRADING_REWARD_API}/rank_list/campaignId/${campaignId}/type/${RewardType.TOP_TRADERS}/page/${currentPage}/size/${MAX_PER_PAGE}`, ) const result: RankListResponse = await response.json() @@ -73,7 +80,6 @@ export const useRankList = ({ campaignId, currentPage }: UseRankListProps): Rank }, { revalidateOnFocus: false, - revalidateIfStale: false, revalidateOnReconnect: false, revalidateOnMount: true, }, diff --git a/apps/web/src/views/TradingReward/hooks/useUserTradeRank.tsx b/apps/web/src/views/TradingReward/hooks/useUserTradeRank.tsx index e5143911ac298..cf208dc9e83bc 100644 --- a/apps/web/src/views/TradingReward/hooks/useUserTradeRank.tsx +++ b/apps/web/src/views/TradingReward/hooks/useUserTradeRank.tsx @@ -1,25 +1,32 @@ import useSWR from 'swr' import { useAccount } from 'wagmi' import { TRADING_REWARD_API } from 'config/constants/endpoints' +import { RewardType } from 'views/TradingReward/hooks/useAllTradingRewardPair' const initialState = { topTradersIndex: 0, totalUsers: 0, + tradingFee: 0, + volume: 0, + estimateRewardUSD: 0, } export const useUserTradeRank = ({ campaignId }: { campaignId: string }) => { const { address: account } = useAccount() - const { data } = useSWR( - campaignId && account && ['/user-trade-rank', campaignId, account], + const { data, isLoading } = useSWR( + Number(campaignId) > 0 && account && ['/user-trade-rank', campaignId, account], async () => { try { const response = await fetch( - `${TRADING_REWARD_API}/rank_index/campaignId/${campaignId}/address/${account}/type/tt`, + `${TRADING_REWARD_API}/rank_index/campaignId/${campaignId}/address/${account}/type/${RewardType.TOP_TRADERS}`, ) const result = await response.json() return { topTradersIndex: result?.data?.topTradersIndex ?? 0, totalUsers: result?.data?.totalUsers ?? 0, + tradingFee: result?.data?.tradingFee ?? 0, + volume: result?.data?.volume ?? 0, + estimateRewardUSD: result?.data?.estimateRewardUSD ?? 0, } } catch (error) { console.info(`Fetch User Rank Error: ${error}`) @@ -28,12 +35,14 @@ export const useUserTradeRank = ({ campaignId }: { campaignId: string }) => { }, { revalidateOnFocus: false, - revalidateIfStale: false, revalidateOnReconnect: false, revalidateOnMount: true, fallbackData: initialState, }, ) - return data + return { + data, + isFetching: isLoading, + } } diff --git a/apps/web/src/views/TradingReward/index.tsx b/apps/web/src/views/TradingReward/index.tsx index 0716c620b911a..d211af9426656 100644 --- a/apps/web/src/views/TradingReward/index.tsx +++ b/apps/web/src/views/TradingReward/index.tsx @@ -92,7 +92,6 @@ const TradingReward = () => { /> { currentUserCampaignInfo={currentUserCampaignInfo} /> - +