Skip to content

Commit

Permalink
Merge pull request #177 from dappforce/deploy/leaderboard-page
Browse files Browse the repository at this point in the history
Leaderboard Page
  • Loading branch information
olehmell authored Jan 24, 2024
2 parents af0d21d + 41a2fec commit d6ac0ef
Show file tree
Hide file tree
Showing 59 changed files with 1,939 additions and 423 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,5 @@ out
# cypress videos
cypress/videos
cypress/screenshots

tsconfig.tsbuildinfo
15 changes: 11 additions & 4 deletions src/components/common/balances/Balance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,21 @@ function format(
_isShort?: boolean,
precision?: number,
withMutedDecimals = true,
alwaysShowDecimals = false,
): React.ReactNode {
const [prefix, postfix] = formatBalance(value, {
// Remove any excess decimals, because this expects big integers
const balanceValue = value.toString().split('.')[0]

const [prefix, postfix] = formatBalance(balanceValue, {
forceUnit: '-',
decimals,
withSi: false,
withZero: true,
}).split('.')
const isShort = _isShort || (withSi && prefix.length >= K_LENGTH)
const isShort = _isShort || (withSi && prefix.length >= K_LENGTH && !alwaysShowDecimals)

if (prefix.length > M_LENGTH) {
const balance = formatBalance(value, { decimals, withUnit: false })
if (prefix.length > M_LENGTH && !alwaysShowDecimals) {
const balance = formatBalance(balanceValue, { decimals, withUnit: false })
return (
<>
{balance}&nbsp;{currency}
Expand Down Expand Up @@ -70,6 +74,7 @@ type FormatBalanceProps = BareProps & {
isShort?: boolean
precision?: number
withMutedDecimals?: boolean
alwaysShowDecimals?: boolean
}

export const FormatBalance = ({
Expand All @@ -80,6 +85,7 @@ export const FormatBalance = ({
className,
precision,
withMutedDecimals = true,
alwaysShowDecimals,
...bareProps
}: FormatBalanceProps) => {
if (!value) return null
Expand All @@ -94,6 +100,7 @@ export const FormatBalance = ({
isShort,
precision,
withMutedDecimals,
alwaysShowDecimals,
)

return (
Expand Down
7 changes: 6 additions & 1 deletion src/components/creators/MobileStakerRewardDashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,12 @@ function StakerRewardDashboard(props: MobileStakerRewardDashboardProps) {
<div className={clsx(styles.Gradient, isOpenClassName)} />
</div>
<div className={clsx(styles.RewardInfo, isOpenClassName)}>
<StakerRewardInfo size='small' className='pt-1 position-relative' style={{ zIndex: 1 }} />
<StakerRewardInfo
withOffsetForFooterButton
size='small'
className='pt-1 position-relative'
style={{ zIndex: 1 }}
/>
<div className={clsx(styles.GradientOuter, isOpenClassName)} />
</div>
</div>
Expand Down
90 changes: 90 additions & 0 deletions src/components/creators/RewardHistoryModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { ModalProps, Skeleton } from 'antd'
import clsx from 'clsx'
import { ComponentProps, useMemo } from 'react'
import { FormatBalance } from 'src/components/common/balances'
import { formatDate } from 'src/components/utils'
import CustomModal from 'src/components/utils/CustomModal'
import { MutedSpan } from 'src/components/utils/MutedText'
import { useFetchUserRewardHistory } from 'src/rtk/features/activeStaking/hooks'
import { RewardHistory } from 'src/rtk/features/activeStaking/rewardHistorySlice'

export type RewardHistoryModalProps = Pick<ModalProps, 'visible' | 'onCancel'>

export default function RewardHistoryModal({ onCancel, visible }: RewardHistoryModalProps) {
const { data, loading } = useFetchUserRewardHistory(undefined, { enabled: visible })
const creatorRewards = data?.rewards.filter(reward => BigInt(reward.creatorReward) > 0)

return (
<CustomModal title='Active Staking History' visible={visible} onCancel={onCancel}>
<RewardHistoryPanel
title='Staker Rewards'
loading={loading}
rewardHistory={data}
rewardType='staker'
/>

{(creatorRewards?.length ?? 0) > 0 && (
<RewardHistoryPanel
title='Creator Rewards'
rewardHistory={data}
loading={loading}
rewardType='creator'
/>
)}
</CustomModal>
)
}

export function RewardHistoryPanel({
loading,
rewardHistory,
rewardType,
title,
...props
}: {
title: string
rewardHistory: RewardHistory | undefined
loading: boolean | undefined
rewardType: 'staker' | 'creator'
} & ComponentProps<'div'>) {
const rewards = useMemo(() => {
if (rewardType === 'staker') return rewardHistory?.rewards ?? []
return rewardHistory?.rewards.filter(reward => BigInt(reward.creatorReward) > 0) ?? []
}, [rewardHistory, rewardType])

return (
<div {...props} className={clsx('d-flex flex-column', props.className)}>
<MutedSpan className='mb-1 FontWeightSemibold'>{title}</MutedSpan>
<div className='d-flex flex-column GapTiny'>
{(() => {
if (loading) return <Skeleton />
if (rewards.length === 0) return <span className='ColorMuted'>No rewards yet</span>

return rewards.map(reward => {
const usedRewardValue = rewardType === 'creator' ? reward.creatorReward : reward.reward
return (
<div
className='d-flex align-items-center justify-content-between GapSmall'
key={reward.week}
>
<span className='ColorMuted FontSmall'>
{formatDate(reward.startDate, 'DD.MM.YY')} -{' '}
{formatDate(reward.endDate, 'DD.MM.YY')}
</span>
<span className='FontWeightSemibold' style={{ whiteSpace: 'nowrap' }}>
+{' '}
<FormatBalance
currency='SUB'
decimals={10}
value={usedRewardValue}
precision={2}
/>
</span>
</div>
)
})
})()}
</div>
</div>
)
}
34 changes: 19 additions & 15 deletions src/components/creators/TopUsersCard.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { Skeleton } from 'antd'
import { Button, Skeleton } from 'antd'
import clsx from 'clsx'
import { ComponentProps, CSSProperties, useMemo } from 'react'
import { IoChevronForward } from 'react-icons/io5'
import { useFetchProfileSpaces, useSelectProfileSpace, useSelectSpace } from 'src/rtk/app/hooks'
import { useFetchTopUsers } from 'src/rtk/features/activeStaking/hooks'
import { useFetchTopUsers } from 'src/rtk/features/leaderboard/hooks'
import { useMyAddress } from '../auth/MyAccountsContext'
import { useIsMobileWidthOrDevice } from '../responsive'
import { SpaceAvatar } from '../spaces/helpers'
import ViewSpaceLink from '../spaces/ViewSpaceLink'
Expand All @@ -12,6 +14,7 @@ import Segment from '../utils/Segment'
export type TopUsersCardProps = ComponentProps<'div'>

export default function TopUsersCard({ ...props }: TopUsersCardProps) {
const myAddress = useMyAddress()
const { data, loading } = useFetchTopUsers()
const isMobile = useIsMobileWidthOrDevice()

Expand All @@ -25,17 +28,18 @@ export default function TopUsersCard({ ...props }: TopUsersCardProps) {

const isLoading = loading || !data || loadingSpaces

// const seeMoreButton = (
// <Button
// type='primary'
// ghost
// className='p-0 GapMini d-flex align-items-center'
// style={{ height: 'auto', border: 'none', boxShadow: 'none' }}
// >
// <span>See more</span>
// <IoChevronForward />
// </Button>
// )
const seeMoreButton = (
<Button
type='primary'
ghost
className='p-0 GapMini d-flex align-items-center'
href={myAddress ? `/leaderboard/${myAddress}` : '/leaderboard'}
style={{ height: 'auto', border: 'none', boxShadow: 'none' }}
>
<span>See more</span>
<IoChevronForward />
</Button>
)

const content = isLoading ? (
<Skeleton />
Expand All @@ -45,7 +49,7 @@ export default function TopUsersCard({ ...props }: TopUsersCardProps) {
<div className='d-flex align-items-center FontWeightSemibold GapMini'>
<span className='FontSemilarge'>Top users (last 24h)</span>
</div>
{/* {isMobile && seeMoreButton} */}
{isMobile && seeMoreButton}
</div>
<div
className={clsx('mt-2', isMobile && 'GapNormal')}
Expand All @@ -71,7 +75,7 @@ export default function TopUsersCard({ ...props }: TopUsersCardProps) {
</div>
</div>
</div>
{/* {!isMobile && <div className='d-flex justify-content-center mt-2'>{seeMoreButton}</div>} */}
{!isMobile && <div className='d-flex justify-content-center mt-2'>{seeMoreButton}</div>}
</>
)

Expand Down
18 changes: 2 additions & 16 deletions src/components/creators/common/NumberSkeleton.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,5 @@
import { Skeleton } from 'antd'
import SpanSkeleton from 'src/components/utils/SpanSkeleton'

export default function NumberSkeleton() {
return (
<div className='d-flex align-items-center'>
<Skeleton.Input
style={{
height: '1em',
width: '3ch',
marginRight: '4px',
borderRadius: '20px',
position: 'relative',
top: '1px',
display: 'block',
}}
/>
</div>
)
return <SpanSkeleton style={{ width: '3ch' }} />
}
50 changes: 39 additions & 11 deletions src/components/creators/creator-rewards/CreatorRewardInfoCard.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { LineChartOutlined } from '@ant-design/icons'
import { Tooltip } from 'antd'
import clsx from 'clsx'
import Link from 'next/link'
Expand All @@ -17,7 +18,7 @@ import { useFetchTotalStake } from 'src/rtk/features/creators/totalStakeHooks'
import { getAmountRange } from 'src/utils/analytics'
import { activeStakingLinks } from 'src/utils/links'
import NumberSkeleton from '../common/NumberSkeleton'
import StakerRewardHistoryModal from '../staker-rewards/StakerRewardHistoryModal'
import RewardHistoryModal from '../RewardHistoryModal'
import styles from './CreatorRewardInfoCard.module.sass'

export default function CreatorRewardInfoCard() {
Expand Down Expand Up @@ -100,23 +101,50 @@ export default function CreatorRewardInfoCard() {
</span>
</div>
<div
className='pt-2 px-3 d-flex justify-content-center align-items-center ColorPrimary FontWeightMedium GapMini'
onClick={() => {
sendEvent('astake_reward_history_opened', {
amountRange: getAmountRange(totalStake?.amount),
})
setIsOpenRewardHistoryModal(true)
className='mt-2'
style={{
display: 'grid',
gridTemplateColumns: '1fr 1fr',
borderTop: '1px solid #dddddd',
marginLeft: '-1rem',
marginBottom: '-1rem',
width: 'calc(100% + 2rem)',
}}
style={{ cursor: 'pointer' }}
>
<RiHistoryFill />
<span className='FontSmall'>Rewards History</span>
<div
className='py-2.5 px-3 d-flex justify-content-center align-items-center ColorPrimary FontWeightMedium GapTiny'
onClick={() => {
sendEvent('astake_reward_history_opened', {
amountRange: getAmountRange(totalStake?.amount),
})
setIsOpenRewardHistoryModal(true)
}}
style={{ cursor: 'pointer', flex: 1, borderRight: '1px solid #dddddd' }}
>
<RiHistoryFill />
<span className='FontSmall'>History</span>
</div>

<Link href={`/leaderboard/${myAddress}?tab=creator`}>
<a
className='py-2.5 px-3 d-flex justify-content-center align-items-center ColorPrimary FontWeightMedium GapTiny'
onClick={() => {
sendEvent('astake_my_stats_clicked', {
amountRange: getAmountRange(totalStake?.amount),
})
}}
style={{ cursor: 'pointer', flex: 1 }}
>
<LineChartOutlined />
<span className='FontSmall'>My Stats</span>
</a>
</Link>
</div>
</div>
</div>
</Segment>

<StakerRewardHistoryModal
<RewardHistoryModal
visible={isOpenRewardHistoryModal}
onCancel={() => setIsOpenRewardHistoryModal(false)}
/>
Expand Down
Loading

0 comments on commit d6ac0ef

Please sign in to comment.