Skip to content

Commit

Permalink
Merge pull request #11 from session-foundation/feat/testnet_points_le…
Browse files Browse the repository at this point in the history
…aderboard

Feat: Testnet points leaderboard
  • Loading branch information
Aerilym authored Dec 4, 2024
2 parents c1dc489 + 6cfe59a commit cf3492a
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 5 deletions.
14 changes: 14 additions & 0 deletions apps/staking/app/leaderboard/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { ReactNode } from 'react';
import { siteMetadata } from '@/lib/metadata';

export function generateMetadata() {
return siteMetadata({
title: 'Testnet Leaderboard',
description:
'Track the top-performing wallets in the Session Testnet Incentive Program. Rankings are based on total points earned through running and staking to nodes.',
});
}

export default async function RootLayout({ children }: { children: ReactNode }) {
return children;
}
111 changes: 111 additions & 0 deletions apps/staking/app/leaderboard/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
'use client';
import { useQuery } from '@tanstack/react-query';
import { toast } from '@session/ui/lib/toast';
import { PubKey } from '@session/ui/components/PubKey';
import { formatNumber, formatPercentage } from '@/lib/locale-client';
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@session/ui/ui/table';
import Typography from '@session/ui/components/Typography';
import { useWallet } from '@session/wallet/hooks/wallet-hooks';
import { areHexesEqual } from '@session/util-crypto/string';
import Link from 'next/link';
import { Loading } from '@session/ui/components/loading';
import { cn } from '@session/ui/lib/utils';

// TODO: Delete route after testnet incentive program is over

function smartFormatPercentage(decimalPercent: number) {
const maximumFractionDigits = decimalPercent > 0.0001 ? 4 : 6;
return formatPercentage(decimalPercent, { maximumFractionDigits });
}

export default function PointsPage() {
const { address } = useWallet();
const { data, isLoading, isError } = useQuery({
queryKey: ['points'],
queryFn: async () => {
const res = await fetch(process.env.NEXT_PUBLIC_POINTS_PROGRAM_API!);

if (!res.ok) {
toast.error('Failed to fetch points');
}

const data = await res.json();

return (
Object.entries(data.wallets) as Array<
[
string,
{
score: number;
percent: number;
},
]
>
).sort((a, b) => b[1].score - a[1].score);
},
});

return (
<div className="mt-10 flex flex-col items-center gap-6">
<div className="flex max-w-xl flex-col items-center gap-4 text-center">
<Typography variant="h1">Testnet Leaderboard</Typography>
<Typography variant="p">
Track the top-performing wallets in the{' '}
<Link
target="_blank"
href="https://token.getsession.org/testnet-incentive-program"
className="text-session-green underline"
>
Session Testnet Incentive Program
</Link>
. Rankings are based on total points earned through running and staking to nodes.
</Typography>
</div>
{isLoading ? (
<Loading />
) : isError ? (
<span>Something went wrong</span>
) : (
<Table className="w-max max-w-[90vw]">
<TableHeader>
<TableRow className="text-sm md:text-lg">
<TableHead className="hidden md:table-cell">Rank</TableHead>
<TableHead>Wallet Address</TableHead>
<TableHead>Points</TableHead>
<TableHead className="text-right">Percent</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{data?.map(([wallet, { score, percent }], i) => (
<TableRow
key={wallet}
className={cn(
'text-sm md:text-base',
areHexesEqual(wallet, address)
? 'bg-session-green text-session-black hover:bg-session-green-dark'
: 'hover:bg-session-green hover:text-session-black hover:selection:bg-session-black hover:selection:text-session-green'
)}
>
<TableCell className="hidden font-bold md:block">{i + 1}</TableCell>
<TableCell className="w-max">
<PubKey pubKey={wallet} />
</TableCell>
<TableCell>{formatNumber(score)}</TableCell>
<TableCell className="p-0 py-4 pr-1 text-right md:pe-1">
{smartFormatPercentage(percent / 10000)}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
)}
</div>
);
}
9 changes: 6 additions & 3 deletions apps/staking/app/mystakes/modules/TestnetPointsModule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { Address } from 'viem';
import { useQuery } from '@tanstack/react-query';
import { toast } from '@session/ui/lib/toast';
import { areHexesEqual } from '@session/util-crypto/string';
import { formatNumber } from '@/lib/locale-client';
import { formatNumber, formatPercentage } from '@/lib/locale-client';

const noPointsObject = {
score: 0,
Expand Down Expand Up @@ -56,7 +56,7 @@ export default function TestnetPointsModule(params?: { addressOverride?: Address
},
});

const points = data?.score ? `${formatNumber(data.score)} points` : null;
const points = `${formatNumber(data?.score ?? 0)} points`;

return (
<Module>
Expand All @@ -65,7 +65,10 @@ export default function TestnetPointsModule(params?: { addressOverride?: Address
link: externalLink(URL.SESSION_TOKEN_COMMUNITY_SNAPSHOT),
})}
</ModuleTooltip>
<ModuleTitle>{titleFormat('format', { title })}</ModuleTitle>
<ModuleTitle>
{titleFormat('format', { title })}
{` (${formatPercentage((data?.percent ?? 0) / 10000)})`}
</ModuleTitle>
<ModuleDynamicQueryText
status={status as QUERY_STATUS}
fallback={0}
Expand Down
4 changes: 2 additions & 2 deletions packages/ui/components/ui/table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { cn } from '../../lib/utils';

const Table = React.forwardRef<HTMLTableElement, React.HTMLAttributes<HTMLTableElement>>(
({ className, ...props }, ref) => (
<div className="relative w-full overflow-auto">
<div className="relative overflow-auto">
<table ref={ref} className={cn('w-full caption-bottom text-sm', className)} {...props} />
</div>
)
Expand Down Expand Up @@ -44,7 +44,7 @@ const TableRow = React.forwardRef<HTMLTableRowElement, React.HTMLAttributes<HTML
<tr
ref={ref}
className={cn(
'hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors',
'hover:bg-muted/50 data-[state=selected]:bg-muted border-session-white border-b transition-colors',
className
)}
{...props}
Expand Down

0 comments on commit cf3492a

Please sign in to comment.