Skip to content

Commit

Permalink
Add referral leaderboard
Browse files Browse the repository at this point in the history
  • Loading branch information
samchuk-vlad committed Jul 23, 2024
1 parent de6be39 commit 1d9b80f
Show file tree
Hide file tree
Showing 6 changed files with 369 additions and 17 deletions.
6 changes: 3 additions & 3 deletions src/modules/points/PointsWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -309,8 +309,8 @@ const UserStatsSection = ({
</LinkText> */}
</Card>
)}
<div className='flex w-full items-center gap-4 p-4'>
<div className='flex w-full flex-col gap-1'>
<div className='flex w-full items-center gap-4 px-4'>
<div className='flex w-full flex-col gap-1 border-r border-slate-700 py-4'>
<span className='text-text-muted'>LIKES LEFT TODAY:</span>
<div className='flex items-center gap-3'>
<Image src={Thumbsup} alt='' className='h-8 w-8' />
Expand All @@ -325,7 +325,7 @@ const UserStatsSection = ({
</LinkText>
</div>
</div>
<div className='flex w-full flex-col gap-1'>
<div className='flex w-full flex-col gap-1 py-4'>
<span className='text-text-muted'>POINTS EARNED:</span>
<div
className='mr-1 flex items-center gap-3'
Expand Down
156 changes: 156 additions & 0 deletions src/modules/telegram/FriendsPage/LeaderboardModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import BlueGradient from '@/assets/graphics/landing/gradients/blue.png'
import MedalsImage from '@/assets/graphics/medals.png'
import Button from '@/components/Button'
import Loading from '@/components/Loading'
import { Column, TableRow } from '@/components/Table'
import { getReferralLeaderboardQuery } from '@/services/datahub/referral/query'
import { useMyMainAddress } from '@/stores/my-account'
import { cx, mutedTextColorStyles } from '@/utils/class-names'
import { Transition } from '@headlessui/react'
import Image from 'next/image'
import { useMemo } from 'react'
import { createPortal } from 'react-dom'
import { HiXMark } from 'react-icons/hi2'
import { UserPreview } from '../StatsPage/LeaderboardTable'

type LeaderboardModalProps = {
isOpen: boolean
close: () => void
}

const LeaderboardModal = ({ isOpen, close }: LeaderboardModalProps) => {
const myAddress = useMyMainAddress()

return createPortal(
<>
<Transition
appear
show={isOpen}
className='fixed inset-0 z-10 h-full w-full bg-background transition duration-300'
enterFrom={cx('opacity-0')}
enterTo='opacity-100'
leaveFrom='h-auto'
leaveTo='opacity-0 !duration-150'
/>
<Transition
appear
show={isOpen}
className='fixed inset-0 z-10 flex h-full w-full flex-col bg-background pb-20 transition duration-300'
enterFrom={cx('opacity-0 -translate-y-48')}
enterTo='opacity-100 translate-y-0'
leaveFrom='h-auto'
leaveTo='opacity-0 -translate-y-24 !duration-150'
>
<div className='mx-auto flex w-full max-w-screen-md flex-1 flex-col overflow-auto'>
<Image
src={BlueGradient}
priority
alt=''
className='absolute -top-56 left-1/2 w-full -translate-x-1/2'
/>
<div className='flex flex-col gap-2'>
<div className='relative mx-auto flex w-full items-center justify-between px-4 py-4'>
<span className='text-xl font-bold'>
Referrers Leaderboard 🏆
</span>
<Button
className='-mr-2'
variant='transparent'
size='circleSm'
onClick={close}
>
<HiXMark className='text-3xl' />
</Button>
</div>
<span></span>
</div>
<div className='relative mx-auto flex h-full w-full flex-col items-center px-4'>
<LeaderboardTable />
</div>
</div>
</Transition>
</>,
document.body
)
}

export const tableColumns = (): Column[] => [
{
index: 'user',
align: 'left',
className: cx('p-0 py-2 pr-2'),
},
{
index: 'id',
align: 'right',
className: cx('p-0 py-2 pl-2 w-[15%] text-slate-400 '),
},
]

const LeaderboardTable = () => {
const myAddress = useMyMainAddress()
const { data: referrersData, isLoading } =
getReferralLeaderboardQuery.useQuery(myAddress || '')

const data = useMemo(() => {
return (
referrersData?.map((item, i) => ({
id: i + 1,
user: (
<UserPreview
address={item.address}
nameClassName='[&>span]:overflow-hidden [&>span]:whitespace-nowrap [&>span]:text-ellipsis'
desc={
<span className='text-sm text-slate-400'>
👋 {item.count} frens
</span>
}
/>
),
})) || []
)
}, [referrersData])

return (
<>
{data.length === 0 &&
(isLoading ? (
<Loading title='Loading table data' className='p-7' />
) : (
<div
className='flex flex-col items-center justify-center p-4 text-center'
style={{ gridColumn: '1/4' }}
>
<Image
src={MedalsImage}
alt=''
className='relative w-[70px] max-w-sm'
/>
<span className={cx(mutedTextColorStyles)}>
Invite your frens to show up here!
</span>
</div>
))}
{!!data.length && (
<div className='flex w-full flex-col'>
<table className='w-full table-fixed text-left'>
<tbody>
{data.map((item, i) => {
return (
<TableRow
key={i}
columns={tableColumns()}
item={item}
withDivider={false}
/>
)
})}
</tbody>
</table>
</div>
)}
</>
)
}

export default LeaderboardModal
21 changes: 8 additions & 13 deletions src/modules/telegram/FriendsPage/ReferralTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,15 @@ import { useMemo } from 'react'
import { UserPreview } from '../StatsPage/LeaderboardTable'

export const tableColumns = (): Column[] => [
{
index: 'id',
align: 'left',
className: cx('p-0 py-2 pl-2 w-[10%] text-slate-400 '),
},
{
index: 'user',
align: 'left',
className: cx('p-0 py-2 pr-2 w-[55%]'),
className: cx('p-0 py-2 pr-2'),
},
{
index: 'date',
index: 'id',
align: 'right',
className: cx('p-0 py-2 pr-2'),
className: cx('p-0 py-2 pl-2 w-[15%] text-slate-400 '),
},
]

Expand All @@ -47,13 +42,13 @@ const ReferralTable = ({
<UserPreview
address={item.socialProfileId}
nameClassName='[&>span]:overflow-hidden [&>span]:whitespace-nowrap [&>span]:text-ellipsis'
desc={
<span className='text-sm text-slate-400'>
{dayjs(item.timestamp).format('DD MMM')}
</span>
}
/>
),
date: (
<span className='text-slate-400'>
{dayjs(item.timestamp).format('DD MMM, YYYY')}
</span>
),
})) || []
)
}, [referrals])
Expand Down
120 changes: 120 additions & 0 deletions src/modules/telegram/FriendsPage/ReferrerStats.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import Diamond from '@/assets/emojis/diamond.png'
import AddressAvatar from '@/components/AddressAvatar'
import Button from '@/components/Button'
import LinkText from '@/components/LinkText'
import Name from '@/components/Name'
import SkeletonFallback from '@/components/SkeletonFallback'
import SubsocialProfileModal from '@/components/subsocial-profile/SubsocialProfileModal'
import { useSendEvent } from '@/stores/analytics'
import { useMyMainAddress } from '@/stores/my-account'
import { cx } from '@/utils/class-names'
import { formatNumber } from '@/utils/strings'
import Image from 'next/image'
import { useState } from 'react'
import { IoIosArrowForward, IoIosStats } from 'react-icons/io'
import { RiPencilFill } from 'react-icons/ri'
import LeaderboardModal from './LeaderboardModal'

type ReferrerStatsProps = {
refCount: number
pointsEarned: string
isLoading?: boolean
}

const pointsPerUser = 200_000

const ReferrerStats = ({
refCount,
pointsEarned,
isLoading,
}: ReferrerStatsProps) => {
const [openProfileModal, setOpenProfileModal] = useState(false)
const [openLeaderboard, setOpenLeaderboard] = useState(false)
const myAddress = useMyMainAddress()
const sendEvent = useSendEvent()

return (
<>
<div className='flex w-full flex-col rounded-xl bg-slate-800 hover:cursor-pointer'>
<div
className={cx('border-b border-slate-700 p-4')}
onClick={() => {
sendEvent('open_leaderboard')
setOpenLeaderboard(true)
}}
>
<div className='flex items-center justify-between gap-2'>
<div className='flex items-center gap-2'>
<AddressAvatar address={myAddress ?? ''} className='h-16 w-16' />
<div className='flex flex-col gap-1'>
<div className='flex items-center gap-3'>
<Name
address={myAddress ?? ''}
clipText
className='text-lg font-medium !text-text'
/>
<Button
size='circleSm'
variant='muted'
className='inline flex-shrink-0'
onClick={(e) => {
e.preventDefault()
e.stopPropagation()

sendEvent('edit_profile_click')
setOpenProfileModal(true)
}}
>
<RiPencilFill />
</Button>
</div>
<LinkText
variant='primary'
className='flex items-center gap-2 hover:no-underline focus:no-underline'
>
<IoIosStats /> See the Leaderboard
</LinkText>
</div>
</div>
<IoIosArrowForward className={cx('fill-slate-400 text-2xl')} />
</div>
</div>
<div className='flex w-full items-center gap-4 px-4'>
<div className='flex w-full flex-col gap-1 border-r border-slate-700 py-4'>
<SkeletonFallback isLoading={isLoading} className='w-8'>
<span className='flex items-center gap-2 text-2xl font-bold'>
<Image src={Diamond} alt='' className='h-8 w-8' />
{formatNumber(refCount * pointsPerUser, { shorten: true })}
</span>
</SkeletonFallback>
<span className='text-sm font-medium text-slate-400'>
Points earned from {refCount} invited friends
</span>
</div>
<div className='flex w-full flex-col gap-1 py-4'>
<SkeletonFallback isLoading={isLoading} className='w-8'>
<span className='flex items-center gap-2 text-2xl font-bold'>
<Image src={Diamond} alt='' className='h-8 w-8' />
{formatNumber(pointsEarned, { shorten: true })}
</span>
</SkeletonFallback>
<span className='text-sm font-medium text-slate-400'>
Points earned from your friends activity
</span>
</div>
</div>
</div>
<SubsocialProfileModal
title='✏️ Edit Profile'
closeModal={() => setOpenProfileModal(false)}
isOpen={openProfileModal}
/>
<LeaderboardModal
isOpen={openLeaderboard}
close={() => setOpenLeaderboard(false)}
/>
</>
)
}

export default ReferrerStats
3 changes: 2 additions & 1 deletion src/modules/telegram/FriendsPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { useState } from 'react'
import { MdCheck, MdOutlineContentCopy } from 'react-icons/md'
import SkeletonFallback from '../../../components/SkeletonFallback'
import ReferralTable from './ReferralTable'
import ReferrerStats from './ReferrerStats'

export default function FriendsPage() {
useTgNoScroll()
Expand Down Expand Up @@ -75,7 +76,7 @@ const FriendsPageContent = () => {
</div>
</div>
<div className='flex flex-col gap-4'>
<ReferralCards
<ReferrerStats
refCount={refCount ?? 0}
pointsEarned={pointsEarned ?? '0'}
isLoading={isLoading}
Expand Down
Loading

0 comments on commit 1d9b80f

Please sign in to comment.