Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 78 additions & 14 deletions src/app/(app)/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,13 +112,36 @@ export default async function DashboardPage() {
.in('source', ['review', 'help_review']);
const mentorPoints = mentorEvents?.reduce((acc, e) => acc + (e.xp_delta || 0), 0) || 0;

// Leaderboard
// Leaderboard
const { data: leaders } = await service
.from('profiles')
.select('github_handle, xp')
.order('xp', { ascending: false })
.limit(4);

// Get all profiles to calculate current user's rank
const { data: allProfiles } = await service
.from('profiles')
.select('github_handle, xp')
.order('xp', { ascending: false });

const currentUserRank =
allProfiles?.findIndex((p: any) => p.github_handle === profile?.github_handle) ?? -1;

const myLeaderboardEntry =
currentUserRank >= 0
? {
github_handle: profile?.github_handle ?? 'You',
xp,
rank: currentUserRank + 1,
}
: null;

const isUserVisible = leaders?.some(
(leader: any) => leader.github_handle === profile?.github_handle,
);

// Mentees
const { data: menteesData } = await service
.from('help_requests')
Expand Down Expand Up @@ -238,23 +261,64 @@ export default async function DashboardPage() {
<section>
<div className="mb-6 flex items-center justify-between border-b border-[#2d333b] pb-4">
<h2 className="text-[11px] uppercase tracking-widest text-zinc-500">
ACTIVE ISSUES
LEADERBOARD SNAPSHOT
</h2>
<Link
href="/issues"
className="flex items-center gap-2 text-[11px] uppercase tracking-widest text-zinc-400 hover:text-white"
>
BROWSE MORE <ArrowRight className="h-3 w-3" />
</Link>

<span className="text-[11px] uppercase tracking-widest text-zinc-500">GLOBAL</span>
</div>

{recs.length > 0 ? (
<RecCards recs={recs} />
) : (
<div className="py-4 text-sm text-zinc-500">
No recommendations yet. Check back soon.
</div>
)}
<div className="text-xs uppercase tracking-widest">
{leaders && leaders.length > 0 ? (
<>
{leaders.map((leader: any, index: number) => {
const isMe = leader.github_handle === profile?.github_handle;

return (
<div
key={leader.github_handle}
className={`flex justify-between border-b border-[#2d333b] py-3.5 ${
isMe ? '-mx-3 bg-[#3b0764]/40 px-3 text-purple-300' : 'text-zinc-400'
}`}
>
<div className="flex gap-5">
<span className={`w-6 ${isMe ? 'opacity-50' : 'text-zinc-600'}`}>
{(index + 1).toString().padStart(2, '0')}
</span>
{leader.github_handle} {isMe && '(YOU)'}
</div>

<span>{leader.xp.toLocaleString()} XP</span>
</div>
);
})}

{!isUserVisible && myLeaderboardEntry && (
<>
<div className="border-t border-[#3f3f46] pb-2 pt-5">
<span className="text-[10px] tracking-[0.3em] text-zinc-500">
YOUR RANK
</span>
</div>

<div className="-mx-3 flex justify-between bg-[#3b0764]/30 px-3 py-3.5 text-purple-300">
<div className="flex gap-5">
<span className="w-6 opacity-50">
{myLeaderboardEntry.rank.toString().padStart(2, '0')}
</span>
{myLeaderboardEntry.github_handle} (YOU)
</div>

<span>{myLeaderboardEntry.xp.toLocaleString()} XP</span>
</div>
</>
)}
</>
) : (
<div className="py-4 text-[11px] uppercase tracking-widest text-zinc-500">
Leaderboard is empty.
</div>
)}
</div>
</section>

<section>
Expand Down
99 changes: 73 additions & 26 deletions src/app/(app)/leaderboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,33 +27,80 @@ export default async function LeaderboardPage({
</nav>

<ul className="mt-6 divide-y divide-zinc-800 rounded-2xl border border-zinc-800 bg-zinc-900">
{isOk(result) && result.data.length === 0 ? (
<li className="p-6 text-[11px] uppercase tracking-widest text-zinc-500">
BE THE FIRST ON THE BOARD — MERGE A PR TO EARN XP{' '}
</li>
{isOk(result) && result.data.entries.length === 0 ? (
<li className="p-6 text-zinc-400">No entries yet.</li>
) : isOk(result) ? (
result.data.map((entry) => (
<li key={entry.userId} className="flex items-center gap-4 p-4">
<span className="w-8 text-zinc-500">#{entry.rank}</span>
{entry.avatarUrl && (
// eslint-disable-next-line @next/next/no-img-element
<img
src={entry.avatarUrl}
alt=""
className="h-8 w-8 rounded-full"
referrerPolicy="no-referrer"
/>
)}
<Link href={`/@${entry.githubHandle}`} className="flex-1 hover:underline">
<span className="font-medium">@{entry.githubHandle}</span>
{entry.displayName && (
<span className="ml-2 text-sm text-zinc-500">{entry.displayName}</span>
)}
</Link>
<span className="text-sm tabular-nums">L{entry.level}</span>
<span className="w-20 text-right tabular-nums">{entry.xp.toLocaleString()} XP</span>
</li>
))
<>
{(() => {
// Current logged-in user handle from visible list
const currentGithubHandle = result.data.entries.find((e: any) => e.rank)?.githubHandle;

const isUserVisible = result.data.entries.some(
(entry: any) => entry.githubHandle === currentGithubHandle,
);

return (
<>
{result.data.entries.map((entry: any) => {
const isMe = entry.githubHandle === currentGithubHandle;

return (
<li
key={entry.userId}
className={`flex items-center gap-4 p-4 ${
isMe ? 'bg-purple-950/30 text-purple-300' : ''
}`}
>
<span className="w-8 text-zinc-500">#{entry.rank}</span>

{entry.avatarUrl && (
// eslint-disable-next-line @next/next/no-img-element
<img
src={entry.avatarUrl}
alt=""
className="h-8 w-8 rounded-full"
referrerPolicy="no-referrer"
/>
)}

<Link href={`/@${entry.githubHandle}`} className="flex-1 hover:underline">
<span className="font-medium">@{entry.githubHandle}</span>

{entry.displayName && (
<span className="ml-2 text-sm text-zinc-500">
{entry.displayName}
</span>
)}

{isMe && <span className="ml-2 text-xs text-purple-400">(YOU)</span>}
</Link>

<span className="text-sm tabular-nums">L{entry.level}</span>

<span className="w-20 text-right tabular-nums">
{entry.xp.toLocaleString()} XP
</span>
</li>
);
})}

{!isUserVisible && (
<>
<li className="border-t border-zinc-700 px-4 pb-2 pt-4">
<span className="text-xs font-semibold tracking-wide text-zinc-500">
YOUR RANK
</span>
</li>

<li className="flex items-center gap-4 bg-purple-950/20 p-4 text-purple-300">
<span className="text-sm">Your rank is outside visible leaderboard.</span>
</li>
</>
)}
</>
);
})()}
</>
) : (
<li className="p-6 text-rose-400">Couldn&apos;t load: {result.error.message}</li>
)}
Expand Down
Loading
Loading