Skip to content

Commit

Permalink
Merge pull request #197 from dappforce/deploy/my-leaderboard
Browse files Browse the repository at this point in the history
UI Improvements
  • Loading branch information
teodorus-nathaniel authored Jan 25, 2024
2 parents cb78a9f + bfc1a35 commit 74014ee
Show file tree
Hide file tree
Showing 10 changed files with 239 additions and 85 deletions.
100 changes: 60 additions & 40 deletions src/components/common/balances/Balance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,52 +19,69 @@ const log = newLogger('useCreateBallance')
const M_LENGTH = 6 + 1
const K_LENGTH = 3 + 1

function format(
value: Compact<any> | BN | string,
currency: string,
decimals: number,
withSi?: boolean,
_isShort?: boolean,
precision?: number,
function format({
value,
currency,
decimals,
withSi,
isShort: _isShort,
fixedDecimalsLength,
precision,
withMutedDecimals = true,
alwaysShowDecimals = false,
): React.ReactNode {
}: {
value: Compact<any> | BN | string
currency: string
fixedDecimalsLength?: number
decimals: number
withSi?: boolean
isShort?: boolean
precision?: number
withMutedDecimals?: boolean
alwaysShowDecimals?: boolean
}): React.ReactNode {
// 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 && !alwaysShowDecimals)
try {
const [prefix, postfix] = formatBalance(balanceValue, {
forceUnit: '-',
decimals,
withSi: false,
withZero: true,
}).split('.')
const isShort = _isShort || (withSi && prefix.length >= K_LENGTH && !alwaysShowDecimals)

if (prefix.length > M_LENGTH && !alwaysShowDecimals) {
const balance = formatBalance(balanceValue, { decimals, withUnit: false })
return (
<>
{balance}&nbsp;{currency}
</>
)
}

if (prefix.length > M_LENGTH && !alwaysShowDecimals) {
const balance = formatBalance(balanceValue, { decimals, withUnit: false })
return (
<>
{balance}&nbsp;{currency}
{prefix}
{!isShort && (
<>
.
<span className={clsx(withMutedDecimals && 'DfBalanceDecimals')}>
{fixedDecimalsLength
? postfix.substring(0, fixedDecimalsLength).padEnd(fixedDecimalsLength, '0')
: precision
? parseFloat(`0.${postfix}`).toPrecision(precision).substring(2)
: postfix || '0000'}
</span>
</>
)}
&nbsp;{currency}
</>
)
} catch {
return null
}

return (
<>
{prefix}
{!isShort && (
<>
.
<span className={clsx(withMutedDecimals && 'DfBalanceDecimals')}>
{precision
? parseFloat(`0.${postfix}`).toPrecision(precision).substring(2)
: postfix || '0000'}
</span>
</>
)}
&nbsp;{currency}
</>
)
}

type FormatBalanceProps = BareProps & {
Expand All @@ -75,6 +92,7 @@ type FormatBalanceProps = BareProps & {
precision?: number
withMutedDecimals?: boolean
alwaysShowDecimals?: boolean
fixedDecimalsLength?: number
}

export const FormatBalance = ({
Expand All @@ -84,6 +102,7 @@ export const FormatBalance = ({
isShort,
className,
precision,
fixedDecimalsLength,
withMutedDecimals = true,
alwaysShowDecimals,
...bareProps
Expand All @@ -92,16 +111,17 @@ export const FormatBalance = ({

const { unit: defaultCurrency, decimals: defaultDecimal } = formatBalance.getDefaults()

const balance = format(
const balance = format({
value,
currency || defaultCurrency,
decimals || defaultDecimal,
true,
currency: currency || defaultCurrency,
decimals: decimals || defaultDecimal,
withSi: true,
isShort,
precision,
fixedDecimalsLength,
withMutedDecimals,
alwaysShowDecimals,
)
})

return (
<span className={clsx('DfFormatBalance', className)} {...bareProps}>
Expand Down
9 changes: 8 additions & 1 deletion src/components/leaderboard/UserLeaderboardPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ export default function UserLeaderboardPage({ address }: UserLeaderboardPageProp
{data && (
<div className={clsx(styles.Statistics)}>
<ProfileCard
rank={data[tabState]?.rank}
variant={tabState === 'creator' ? 'pink' : 'blue'}
address={address}
detail={
Expand Down Expand Up @@ -207,7 +208,13 @@ export default function UserLeaderboardPage({ address }: UserLeaderboardPageProp
: 'Creators ranked by the amount of SUB earned with Active Staking this week.'}
</MutedSpan>
</div>
<LeaderboardTable className='mt-3' role={tabState} />
<LeaderboardTable
className='mt-3'
role={tabState}
currentUserRank={
data && { address, rank: data[tabState].rank, reward: data[tabState].earnedByPeriod }
}
/>
</DfCard>
</div>
<DfCard size='small' withShadow={false} className='lg-hidden mt-4'>
Expand Down
69 changes: 52 additions & 17 deletions src/components/leaderboard/common/LeaderboardTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,19 @@ import styles from './LeaderboardTable.module.sass'

export type LeaderboardTableProps = ComponentProps<'div'> & {
role: LeaderboardRole
currentUserRank?: {
rank: number
reward: string
address: string
}
}

const TABLE_LIMIT = 10
export default function LeaderboardTable({ role, ...props }: LeaderboardTableProps) {
export default function LeaderboardTable({
role,
currentUserRank,
...props
}: LeaderboardTableProps) {
const [isOpenModal, setIsOpenModal] = useState(false)
const { page, data } = useGetLeaderboardData(role)
const dispatch = useAppDispatch()
Expand All @@ -42,13 +51,25 @@ export default function LeaderboardTable({ role, ...props }: LeaderboardTablePro
}
}, [dispatch, role])

const { addresses, slicedData } = useMemo(
() => ({
addresses: data.slice(0, TABLE_LIMIT).map(row => row.address),
slicedData: data.slice(0, TABLE_LIMIT),
}),
[data],
)
const { addresses, slicedData } = useMemo<{
addresses: string[]
slicedData: typeof data
}>(() => {
if (!currentUserRank || currentUserRank.rank < TABLE_LIMIT) {
return {
addresses: data.slice(0, TABLE_LIMIT).map(row => row.address),
slicedData: data.slice(0, TABLE_LIMIT),
}
}
return {
addresses: [
...data.slice(0, TABLE_LIMIT - 1).map(row => row.address),
currentUserRank.address,
],
slicedData: [...data.slice(0, TABLE_LIMIT - 1), currentUserRank],
}
}, [data, currentUserRank])

const { loading } = useFetchProfileSpaces({ ids: addresses })

return (
Expand All @@ -65,7 +86,13 @@ export default function LeaderboardTable({ role, ...props }: LeaderboardTablePro
{slicedData.length === 0 &&
Array.from({ length: 3 }).map((_, idx) => <UserRowSkeleton key={idx} />)}
{slicedData.map(row => (
<UserRow role={role} key={row.rank} data={row} loading={!!loading} />
<UserRow
currentAddress={currentUserRank?.address}
role={role}
key={row.rank}
data={row}
loading={!!loading}
/>
))}
<Button onClick={() => setIsOpenModal(true)} type='link' className={styles.ViewMore}>
View more
Expand All @@ -76,6 +103,7 @@ export default function LeaderboardTable({ role, ...props }: LeaderboardTablePro
visible={isOpenModal}
onCancel={() => setIsOpenModal(false)}
role={role}
currentAddress={currentUserRank?.address}
/>
</>
)
Expand All @@ -100,10 +128,12 @@ function UserRow({
data,
loading,
role,
currentAddress,
}: {
data: LeaderboardData['data'][number]
loading: boolean
role: LeaderboardRole
currentAddress?: string
}) {
const myAddress = useMyAddress() ?? ''
const sendEvent = useSendEvent()
Expand All @@ -127,12 +157,12 @@ function UserRow({
className={clsx(
styles.LeaderboardRow,
role === 'creator' && styles.RowPink,
myAddress === data.address && styles.Active,
(isMyAddress || currentAddress === data.address) && styles.Active,
'!ColorNormal',
)}
>
<MutedSpan>{data.rank + 1}</MutedSpan>
<div className='d-flex align-items-center' style={{ minWidth: 0 }}>
<div className='d-flex align-items-center' style={{ minWidth: 0, height: '41px' }}>
{isLoading ? (
<>
<Skeleton.Avatar size={32} className='mr-1' />
Expand All @@ -146,10 +176,7 @@ function UserRow({
avatar={profile?.content?.image}
size={32}
/>
<div
className='d-flex flex-column justify-content-center'
style={{ minWidth: 0, height: '41px' }}
>
<div className='d-flex flex-column justify-content-center' style={{ minWidth: 0 }}>
<span
style={{
overflow: 'hidden',
Expand Down Expand Up @@ -185,7 +212,7 @@ function UserRow({
value={data.reward}
currency='SUB'
decimals={10}
precision={2}
fixedDecimalsLength={2}
/>
</span>
</a>
Expand All @@ -196,10 +223,12 @@ function UserRow({
type LeaderboardTableModalProps = {
role: LeaderboardRole
isLoadingFirstBatchOfData: boolean
currentAddress?: string
} & CustomModalProps
function LeaderboardTableModal({
role,
isLoadingFirstBatchOfData,
currentAddress,
...props
}: LeaderboardTableModalProps) {
const { data, hasMore } = useGetLeaderboardData(role)
Expand Down Expand Up @@ -260,7 +289,13 @@ function LeaderboardTableModal({
loader={<Loading className={styles.Loading} />}
>
{data.map(row => (
<UserRow role={role} data={row} loading={isLoading} key={row.rank} />
<UserRow
currentAddress={currentAddress}
role={role}
data={row}
loading={isLoading}
key={row.rank}
/>
))}
</InfiniteScroll>
</div>
Expand Down
8 changes: 8 additions & 0 deletions src/components/leaderboard/common/ProfileCard.module.sass
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@
align-items: center
gap: $space_normal
grid-row: span 2
position: relative

.Rank
position: absolute
right: $space_normal
top: $space_normal
font-weight: $font_weight_semibold
color: $color_muted

.ProfileContent
display: flex
Expand Down
4 changes: 3 additions & 1 deletion src/components/leaderboard/common/ProfileCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ export type ProfileCardProps = DfCardProps & {
address?: string
title?: string
detail?: ReactNode
rank?: number
}

export default function ProfileCard({ address, title, detail, ...props }: ProfileCardProps) {
export default function ProfileCard({ address, rank, title, detail, ...props }: ProfileCardProps) {
const isMobile = useIsMobileWidthOrDevice()
const profile = useSelectProfile(address)

Expand All @@ -41,6 +42,7 @@ export default function ProfileCard({ address, title, detail, ...props }: Profil
size='small'
withShadow={false}
>
{typeof rank === 'number' && <span className={clsx(styles.Rank)}>#{rank + 1}</span>}
{address ? (
profile?.struct ? (
<ViewSpaceLink space={profile?.struct} title={avatar} />
Expand Down
Loading

0 comments on commit 74014ee

Please sign in to comment.