Skip to content

Commit

Permalink
Merge pull request #229 from dappforce/deploy/topusers-like
Browse files Browse the repository at this point in the history
Change top users staker data
  • Loading branch information
teodorus-nathaniel authored Feb 2, 2024
2 parents 82399d8 + d110fc3 commit 3bbae66
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 53 deletions.
Binary file added public/images/medals.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
87 changes: 56 additions & 31 deletions src/components/creators/TopUsersCard.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Button, Skeleton } from 'antd'
import clsx from 'clsx'
import Link from 'next/link'
import { ComponentProps, CSSProperties, useMemo } from 'react'
import { IoChevronForward } from 'react-icons/io5'
import { useSendEvent } from 'src/providers/AnalyticContext'
Expand All @@ -11,10 +12,10 @@ import { truncateAddress } from 'src/utils/storage'
import { useMyAddress } from '../auth/MyAccountsContext'
import { FormatBalance } from '../common/balances'
import Avatar from '../profiles/address-views/Avatar'
import ViewProfileLink from '../profiles/ViewProfileLink'
import { useIsMobileWidthOrDevice } from '../responsive'
import ViewSpaceLink from '../spaces/ViewSpaceLink'
import { DfImage } from '../utils/DfImage'
import { MutedSpan } from '../utils/MutedText'
import { Pluralize } from '../utils/Plularize'
import Segment from '../utils/Segment'

export type TopUsersCardProps = ComponentProps<'div'>
Expand Down Expand Up @@ -79,23 +80,31 @@ export default function TopUsersCard({ ...props }: TopUsersCardProps) {
style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr 1fr' : '1fr' }}
>
<div className='d-flex flex-column FontSmall' style={{ minWidth: 0 }}>
<MutedSpan className='FontWeightMedium mb-1'>Stakers</MutedSpan>
<div className='d-flex flex-column GapTiny'>
{data.stakers.map((staker, i) => (
<UserInfo rank={i + 1} key={i} user={staker} />
))}
</div>
<MutedSpan className='FontWeightMedium mb-1'>Likers</MutedSpan>
{data.stakers.length < 3 ? (
<NoUsersContent text='Like the most posts to reach the top!' />
) : (
<div className='d-flex flex-column GapTiny'>
{data.stakers.map((staker, i) => (
<UserInfo type='staker' rank={i + 1} key={i} user={staker} />
))}
</div>
)}
</div>
<div
className={clsx('d-flex flex-column FontSmall', !isMobile && 'mt-3 pt-2')}
style={{ borderTop: !isMobile ? '1px solid #E2E8F0' : 'none', minWidth: 0 }}
>
<MutedSpan className='FontWeightMedium mb-1'>Creators</MutedSpan>
<div className='d-flex flex-column GapTiny'>
{data?.creators.map((creator, i) => (
<UserInfo rank={i + 1} key={i} user={creator} />
))}
</div>
{data.creators.length < 3 ? (
<NoUsersContent text='Create great content and get the most likes to show up here!' />
) : (
<div className='d-flex flex-column GapTiny'>
{data.creators.map((creator, i) => (
<UserInfo type='creator' rank={i + 1} key={i} user={creator} />
))}
</div>
)}
</div>
</div>
{!isMobile && <div className='d-flex justify-content-center mt-2'>{seeMoreButton}</div>}
Expand All @@ -121,7 +130,15 @@ export default function TopUsersCard({ ...props }: TopUsersCardProps) {
)
}

function UserInfo({ rank, user }: { rank: number; user: { address: string; reward: string } }) {
function UserInfo({
rank,
user,
type,
}: {
rank: number
user: { address: string; reward?: string; count?: number }
type: 'staker' | 'creator'
}) {
const profile = useSelectProfile(user.address)

const avatar = (
Expand All @@ -145,7 +162,7 @@ function UserInfo({ rank, user }: { rank: number; user: { address: string; rewar
return (
<div className='d-flex align-items-center'>
<div className='position-relative'>
{profile ? <ViewSpaceLink space={profile.struct} title={avatar} /> : avatar}
<Link href={`/leaderboard/${user.address}`}>{avatar}</Link>
{[1, 2, 3].includes(rank) && (
<Medal
className='position-absolute FontTiny'
Expand All @@ -155,29 +172,37 @@ function UserInfo({ rank, user }: { rank: number; user: { address: string; rewar
)}
</div>
<div className='d-flex flex-column' style={{ minWidth: 0 }}>
{profile ? (
<ViewSpaceLink
containerClassName='d-flex'
className='d-flex'
style={{ minWidth: 0 }}
title={name}
space={profile?.struct}
/>
) : (
<ViewProfileLink
className='ColorNormal'
title={name}
account={{ address: user.address }}
/>
)}
<Link href={`/leaderboard/${user.address}`} passHref>
<a className='ColorNormal'>{name}</a>
</Link>
<div className='d-flex align-items-center ColorMuted GapMini'>
<FormatBalance value={user.reward} currency='SUB' decimals={10} precision={2} />
{type === 'creator' ? (
<FormatBalance value={user.reward} currency='SUB' decimals={10} precision={2} />
) : (
<span>
<Pluralize count={user.count ?? 0} singularText='like' pluralText='likes' />
</span>
)}
</div>
</div>
</div>
)
}

function NoUsersContent({ text }: { text: string }) {
return (
<div
className='d-flex flex-column justify-content-center align-items-center RoundedBig text-center'
style={{ background: '#F8FAFC', height: '158px', boxShadow: '0px 2px 14.5px 0px #ECF1F7' }}
>
<DfImage src='/images/medals.png' preview={false} size={70} />
<span className='FontSmall' style={{ color: '#64748B' }}>
{text}
</span>
</div>
)
}

function Medal({ rank, ...props }: ComponentProps<'div'> & { rank: 1 | 2 | 3 }) {
const rankStyles: Record<number, CSSProperties> = {
1: {
Expand Down
44 changes: 23 additions & 21 deletions src/components/utils/datahub/leaderboard.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import dayjs from 'dayjs'
import gql from 'graphql-tag'
import { GeneralStatistics } from 'src/rtk/features/leaderboard/generalStatisticsSlice'
import { LeaderboardData } from 'src/rtk/features/leaderboard/leaderboardSlice'
Expand All @@ -6,19 +7,12 @@ import { UserStatistics } from 'src/rtk/features/leaderboard/userStatisticsSlice
import { datahubQueryRequest, getDayAndWeekTimestamp } from './utils'

const GET_TOP_USERS = gql`
query GetTopUsers($from: String!) {
staker: activeStakingAddressesRankedByRewardsForPeriod(
args: {
filter: { period: WEEK, role: STAKER, timestamp: $from }
limit: 3
offset: 0
order: DESC
}
query GetTopUsers($from: String!, $fromTimestamp: String!) {
staker: activeStakingStakersRankedBySuperLikesForPeriod(
args: { fromTime: $fromTimestamp, limit: 3 }
) {
data {
address
reward
}
address
count
}
creator: activeStakingAddressesRankedByRewardsForPeriod(
args: {
Expand All @@ -37,35 +31,43 @@ const GET_TOP_USERS = gql`
`
export async function getTopUsers(): Promise<TopUsers> {
const { week } = getDayAndWeekTimestamp()
let startOfWeekTimestamp = dayjs.utc().startOf('day')
let daysToMonday = startOfWeekTimestamp.day() - 1
if (daysToMonday < 0) {
daysToMonday += 7
}
startOfWeekTimestamp = startOfWeekTimestamp.subtract(daysToMonday, 'day')

const res = await datahubQueryRequest<
{
staker: {
data: {
address: string
reward: string
}[]
}
address: string
count: number
}[]
creator: {
data: {
address: string
reward: string
}[]
}
},
{ from: string }
{ from: string; fromTimestamp: string }
>({
query: GET_TOP_USERS,
variables: { from: week.toString() },
variables: {
from: week.toString(),
fromTimestamp: startOfWeekTimestamp.valueOf().toString(),
},
})

return {
creators: res.data.creator.data.map(({ address, reward }) => ({
address,
reward,
})),
stakers: res.data.staker.data.map(({ address, reward }) => ({
stakers: res.data.staker.map(({ address, count }) => ({
address,
reward,
count,
})),
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/rtk/features/leaderboard/topUsersSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import { createSimpleFetchWrapper } from 'src/rtk/app/wrappers'
import { fetchProfileSpaces } from '../profiles/profilesSlice'

type User = { address: string; reward: string }
type UserByLike = { address: string; count: number }
export type TopUsers = {
creators: User[]
stakers: User[]
stakers: UserByLike[]
}

const sliceName = 'topUsers'
Expand Down

0 comments on commit 3bbae66

Please sign in to comment.