Skip to content

Commit

Permalink
feat: New trading reward UI (#7296)
Browse files Browse the repository at this point in the history
<!--
Before opening a pull request, please read the [contributing
guidelines](https://github.com/pancakeswap/pancake-frontend/blob/develop/CONTRIBUTING.md)
first
-->

<!--
copilot:all
-->
### <samp>🤖 Generated by Copilot at 8d25515</samp>

### Summary
🏆🔄📱

<!--
1. 🏆 - This emoji represents the leaderboard and rewards breakdown
features, which show the user's rank and rewards for each round of the
trading competition. It also conveys a sense of achievement and
competition.
2. 🔄 - This emoji represents the multiple rounds of the leaderboard and
rewards breakdown, which let the user switch between the current and
previous rounds of the trading competition. It also conveys a sense of
continuity and progress.
3. 📱 - This emoji represents the mobile view of the leaderboard and
rewards breakdown, which was improved and aligned with the desktop view.
It also conveys a sense of accessibility and responsiveness.
-->
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))
  • Loading branch information
ChefMomota authored Jul 10, 2023
1 parent 0534655 commit 09e7ead
Show file tree
Hide file tree
Showing 16 changed files with 366 additions and 113 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,11 @@ const DesktopResult: React.FC<React.PropsWithChildren<DesktopResultProps>> = ({

return (
<tr>
<Td>
<Text bold color="secondary">
{`#${rank.rank}`}
</Text>
</Td>
<Td textAlign="left">
<Flex>
<Text bold mr="4px" width="56px" color="secondary" style={{ alignSelf: 'center' }}>
{rank.rank === 0 ? '--' : `#${rank.rank}`}
</Text>
<ProfileAvatar width={42} height={42} src={profile?.nft?.image?.thumbnail ?? avatar} />
<Text style={{ alignSelf: 'center' }} color="primary" bold ml="8px">
{profile?.username || domainName || truncateHash(rank.origin)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,30 +19,28 @@ const LeaderBoardDesktopView: React.FC<React.PropsWithChildren<LeaderBoardDeskto
setCurrentPage,
}) => {
const { t } = useTranslation()

return (
<Card margin="0 24px">
<Table>
<thead>
<tr>
<Th width="60px">&nbsp;</Th>
<Th textAlign="left">{t('User')}</Th>
<Th textAlign="left">{t('Rank (Top 50 users)')}</Th>
<Th textAlign="left">{t('Trading Volume')}</Th>
<Th textAlign="right">{t('Total Reward')}</Th>
</tr>
</thead>
<tbody>
{isLoading ? (
<tr>
<Td colSpan={4} textAlign="center">
<Td colSpan={3} textAlign="center">
{t('Loading...')}
</Td>
</tr>
) : (
<>
{data?.length === 0 ? (
{!data || data?.length === 0 ? (
<tr>
<Td colSpan={4} textAlign="center">
<Td colSpan={3} textAlign="center">
{t('No results')}
</Td>
</tr>
Expand All @@ -57,7 +55,9 @@ const LeaderBoardDesktopView: React.FC<React.PropsWithChildren<LeaderBoardDeskto
)}
</tbody>
</Table>
<PaginationButton showMaxPageText currentPage={currentPage} maxPage={maxPage} setCurrentPage={setCurrentPage} />
{data?.length > 0 && (
<PaginationButton showMaxPageText currentPage={currentPage} maxPage={maxPage} setCurrentPage={setCurrentPage} />
)}
</Card>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ export const StyledMobileRow = styled(Box)`
`

interface MobileResultProps {
isMyRank?: boolean
rank: RankListDetail
}

const MobileResult: React.FC<React.PropsWithChildren<MobileResultProps>> = ({ rank }) => {
const MobileResult: React.FC<React.PropsWithChildren<MobileResultProps>> = ({ isMyRank, rank }) => {
const { t } = useTranslation()
const cakePriceBusd = usePriceCakeUSD()
const { profile, isLoading: isProfileLoading } = useProfileForAddress(rank.origin)
Expand All @@ -37,10 +38,19 @@ const MobileResult: React.FC<React.PropsWithChildren<MobileResultProps>> = ({ ra
return (
<StyledMobileRow p="16px">
<Flex justifyContent="space-between" mb="16px">
<Text fontWeight="bold" color="secondary" mr="auto">
{`#${rank.rank}`}
</Text>
<Flex width="100%" justifyContent="flex-end">
<Flex width="30%" alignSelf="center">
<Flex flexDirection="column" width="100%">
{isMyRank && (
<Text fontSize={20} fontWeight="bold" color="secondary">
{t('My Rank')}
</Text>
)}
<Text fontWeight="bold" color="secondary">
{rank.rank === 0 ? '--' : `#${rank.rank}`}
</Text>
</Flex>
</Flex>
<Flex width="70%" justifyContent="flex-end" alignSelf="center">
<Text color="primary" fontWeight="bold" style={{ alignSelf: 'center' }} mr="8px">
{profile?.username || domainName || truncateHash(rank.origin)}
</Text>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,24 @@ const LeaderBoardMobileView: React.FC<React.PropsWithChildren<LeaderBoardMobileV
</StyledMobileRow>
) : (
<>
{data?.length === 0 ? (
{!data || data?.length === 0 ? (
<StyledMobileRow>
<Text padding="48px 0px" textAlign="center">
{t('No results')}
</Text>
</StyledMobileRow>
) : (
<>
{data.map((rank) => (
{data?.map((rank) => (
<MobileResult key={rank.rank} rank={rank} />
))}
</>
)}
</>
)}
<PaginationButton showMaxPageText currentPage={currentPage} maxPage={maxPage} setCurrentPage={setCurrentPage} />
{data?.length > 0 && (
<PaginationButton showMaxPageText currentPage={currentPage} maxPage={maxPage} setCurrentPage={setCurrentPage} />
)}
</Box>
)
}
Expand Down
68 changes: 68 additions & 0 deletions apps/web/src/views/TradingReward/components/Leaderboard/MyRank.tsx
Original file line number Diff line number Diff line change
@@ -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<React.PropsWithChildren<MyRankProps>> = ({ 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 (
<Box mb="16px">
<Card isActive margin="0 24px">
{isDesktop ? (
<Table>
<thead>
<tr>
<Th textAlign="left" width="45%">
{t('My Rank')}
</Th>
<Th textAlign="left">{t('Trading Volume')}</Th>
<Th textAlign="right">{t('Total Reward')}</Th>
</tr>
</thead>
<tbody>
{isFetching ? (
<tr>
<Td colSpan={3} textAlign="center">
{t('Loading...')}
</Td>
</tr>
) : (
<DesktopResult key={rank.rank} rank={rank} />
)}
</tbody>
</Table>
) : (
<MobileResult rank={rank} isMyRank />
)}
</Card>
</Box>
)
}

export default MyRank
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
LaurelRightIcon,
Text,
SubMenu,
Skeleton,
} from '@pancakeswap/uikit'
import styled from 'styled-components'
import { useTranslation } from '@pancakeswap/localization'
Expand Down Expand Up @@ -51,11 +52,11 @@ const RankingCard: React.FC<React.PropsWithChildren<RankingCardProps>> = ({ 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],
)

Expand Down Expand Up @@ -87,9 +88,13 @@ const RankingCard: React.FC<React.PropsWithChildren<RankingCardProps>> = ({ rank
</Box>
<RotatedLaurelRightIcon color={rankColor} width="32px" />
</Flex>
<Text color="primary" fontWeight="bold" textAlign="center">
{profile?.username || domainName || truncateHash(user.origin)}
</Text>
{!user ? (
<Skeleton width="60px" m="0 auto" />
) : (
<Text color="primary" fontWeight="bold" textAlign="center">
{profile?.username || domainName || truncateHash(user?.origin)}
</Text>
)}
</Flex>
}
options={{ placement: 'bottom' }}
Expand All @@ -100,21 +105,34 @@ const RankingCard: React.FC<React.PropsWithChildren<RankingCardProps>> = ({ rank
{t('Total Reward')}
</Text>
<Box>
<Text textAlign="right" bold color="text" fontSize="20px" lineHeight="110%">
{`$${formatNumber(user.estimateRewardUSD)}`}
</Text>
<Text textAlign="right" color="textSubtle" fontSize="12px">
{`~${formatNumber(cakeAmount)} CAKE`}
</Text>
{!user ? (
<>
<Skeleton width="60px" mb="2px" />
<Skeleton width="60px" />
</>
) : (
<>
<Text textAlign="right" bold color="text" fontSize="20px" lineHeight="110%">
{`$${formatNumber(user?.estimateRewardUSD)}`}
</Text>
<Text textAlign="right" color="textSubtle" fontSize="12px">
{`~${formatNumber(cakeAmount)} CAKE`}
</Text>
</>
)}
</Box>
</Flex>
<Flex justifyContent="space-between">
<Text bold color="textSubtle">
{t('Trading Volume')}
</Text>
<Text textAlign="right" bold color="text" fontSize="20px">
{`$${formatNumber(user.volume)}`}
</Text>
{!user ? (
<Skeleton width="100px" />
) : (
<Text textAlign="right" bold color="text" fontSize="20px">
{`$${formatNumber(user?.volume)}`}
</Text>
)}
</Flex>
</CardBody>
</Card>
Expand Down
Loading

2 comments on commit 09e7ead

@vercel
Copy link

@vercel vercel bot commented on 09e7ead Jul 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

uikit – ./packages/uikit

uikit.pancake.run
uikit-git-develop.pancake.run

@vercel
Copy link

@vercel vercel bot commented on 09e7ead Jul 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.