Skip to content

Conversation

@bbarni2020
Copy link
Collaborator

No description provided.

Copilot AI review requested due to automatic review settings December 23, 2025 17:41
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements leaderboard functionality across three admin dashboard pages (ysws-review, review, and print) to display top contributors based on their review or printing activity.

Key changes:

  • Added server-side queries to aggregate review counts across different review types (t1Review, legionReview, t2Review)
  • Replaced "Coming soon!" placeholders with functional leaderboard tables showing top 10 contributors
  • Added project count display to the review page header

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
src/routes/dashboard/admin/ysws-review/+page.svelte Implemented leaderboard table for YSWS reviewers with user links and review counts
src/routes/dashboard/admin/ysws-review/+page.server.ts Added database query to aggregate t2Review counts and generate top 10 leaderboard
src/routes/dashboard/admin/review/+page.svelte Implemented leaderboard table for all reviewers and added project count to header
src/routes/dashboard/admin/review/+page.server.ts Added database queries to aggregate t1Review, legionReview, and t2Review counts for comprehensive leaderboard
src/routes/dashboard/admin/print/+page.svelte Implemented leaderboard table for printers showing top contributors
src/routes/dashboard/admin/print/+page.server.ts Added database query to aggregate legionReview counts for printing leaderboard

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +136 to +141
{#each data.leaderboard as row}
<tr>
<td class="py-1" align="left">
<a class="underline" href={`/dashboard/users/${row.id}`}>{row.name}</a>
</td>
<td class="py-1" align="right">{row.review_count}</td>
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable name 'review_count' is misleading in this context. Since this leaderboard tracks printing actions (as indicated by the column header "Number of prints" and the empty state message "No printing actions yet."), it should be renamed to something like 'print_count' or 'action_count' for clarity.

Suggested change
{#each data.leaderboard as row}
<tr>
<td class="py-1" align="left">
<a class="underline" href={`/dashboard/users/${row.id}`}>{row.name}</a>
</td>
<td class="py-1" align="right">{row.review_count}</td>
{#each data.leaderboard as { id, name, review_count: print_count }}
<tr>
<td class="py-1" align="left">
<a class="underline" href={`/dashboard/users/${id}`}>{name}</a>
</td>
<td class="py-1" align="right">{print_count}</td>

Copilot uses AI. Check for mistakes.
Comment on lines +33 to +71
const t1Agg = db
.$with('t1Agg')
.as(
db
.select({ userId: t1Review.userId, t1Cnt: sql<number>`COUNT(*)`.as('t1Cnt') })
.from(t1Review)
.groupBy(t1Review.userId)
);

const legionAgg = db
.$with('legionAgg')
.as(
db
.select({ userId: legionReview.userId, legionCnt: sql<number>`COUNT(*)`.as('legionCnt') })
.from(legionReview)
.groupBy(legionReview.userId)
);

const t2Agg = db
.$with('t2Agg')
.as(
db
.select({ userId: t2Review.userId, t2Cnt: sql<number>`COUNT(*)`.as('t2Cnt') })
.from(t2Review)
.groupBy(t2Review.userId)
);

const totalExpr = sql<number>`COALESCE(${t1Agg.t1Cnt}, 0) + COALESCE(${legionAgg.legionCnt}, 0) + COALESCE(${t2Agg.t2Cnt}, 0)`;

const leaderboard = await db
.with(t1Agg, legionAgg, t2Agg)
.select({ id: user.id, name: user.name, review_count: totalExpr })
.from(user)
.leftJoin(t1Agg, eq(t1Agg.userId, user.id))
.leftJoin(legionAgg, eq(legionAgg.userId, user.id))
.leftJoin(t2Agg, eq(t2Agg.userId, user.id))
.where(and(ne(user.trust, 'red'), ne(user.hackatimeTrust, 'red'), gt(totalExpr, 0)))
.orderBy(desc(totalExpr))
.limit(10);
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The leaderboard query pattern is duplicated across three files (ysws-review, review, and print +page.server.ts). Consider extracting this into a shared utility function that accepts the review tables and optional filters as parameters to improve maintainability and reduce code duplication.

Copilot uses AI. Check for mistakes.
Comment on lines +34 to +52
const legionAgg = db
.$with('legionAgg')
.as(
db
.select({ userId: legionReview.userId, legionCnt: sql<number>`COUNT(*)`.as('legionCnt') })
.from(legionReview)
.groupBy(legionReview.userId)
);

const totalExpr = sql<number>`COALESCE(${legionAgg.legionCnt}, 0)`;

const leaderboard = await db
.with(legionAgg)
.select({ id: user.id, name: user.name, review_count: totalExpr })
.from(user)
.leftJoin(legionAgg, eq(legionAgg.userId, user.id))
.where(and(ne(user.trust, 'red'), ne(user.hackatimeTrust, 'red'), gt(totalExpr, 0)))
.orderBy(desc(totalExpr))
.limit(10);
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The leaderboard query pattern is duplicated across three files (ysws-review, review, and print +page.server.ts). Consider extracting this into a shared utility function that accepts the review tables and optional filters as parameters to improve maintainability and reduce code duplication.

Copilot uses AI. Check for mistakes.
Comment on lines +126 to +148
<div class="w-full overflow-x-auto">
{#if data.leaderboard?.length > 0}
<table class="w-full text-sm">
<thead>
<tr class="text-primary-300">
<th class="py-1" align="left">Printer</th>
<th class="py-1" align="right">Number of prints</th>
</tr>
</thead>
<tbody>
{#each data.leaderboard as row}
<tr>
<td class="py-1" align="left">
<a class="underline" href={`/dashboard/users/${row.id}`}>{row.name}</a>
</td>
<td class="py-1" align="right">{row.review_count}</td>
</tr>
{/each}
</tbody>
</table>
{:else}
<p class="text-sm text-primary-300">No printing actions yet.</p>
{/if}
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The leaderboard table markup is duplicated across all three admin pages (ysws-review, review, and print). Consider extracting this into a reusable Svelte component that accepts the leaderboard data, column headers, and user type label as props to reduce duplication and improve maintainability.

Copilot uses AI. Check for mistakes.
{#each data.leaderboard as row}
<tr>
<td class="py-1" align="left">
<a class="underline" href={`../users/${row.id}`}>{row.name}</a>
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The URL path uses a relative path '../users/' which may cause navigation issues depending on the current route. Consider using an absolute path '/dashboard/users/' for consistency with the review page implementation (line 127 in review/+page.svelte).

Suggested change
<a class="underline" href={`../users/${row.id}`}>{row.name}</a>
<a class="underline" href={`/dashboard/users/${row.id}`}>{row.name}</a>

Copilot uses AI. Check for mistakes.
Comment on lines +45 to +53
const leaderboard = await db
.with(legionAgg)
.select({ id: user.id, name: user.name, review_count: totalExpr })
.from(user)
.leftJoin(legionAgg, eq(legionAgg.userId, user.id))
.where(and(ne(user.trust, 'red'), ne(user.hackatimeTrust, 'red'), gt(totalExpr, 0)))
.orderBy(desc(totalExpr))
.limit(10);

Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable name 'review_count' is misleading in this context. Since this leaderboard tracks printing actions (as indicated by the query using legionReview table), it should be renamed to something like 'print_count' or 'action_count' to accurately reflect what's being counted.

Suggested change
const leaderboard = await db
.with(legionAgg)
.select({ id: user.id, name: user.name, review_count: totalExpr })
.from(user)
.leftJoin(legionAgg, eq(legionAgg.userId, user.id))
.where(and(ne(user.trust, 'red'), ne(user.hackatimeTrust, 'red'), gt(totalExpr, 0)))
.orderBy(desc(totalExpr))
.limit(10);
const leaderboardRaw = await db
.with(legionAgg)
.select({ id: user.id, name: user.name, print_count: totalExpr })
.from(user)
.leftJoin(legionAgg, eq(legionAgg.userId, user.id))
.where(and(ne(user.trust, 'red'), ne(user.hackatimeTrust, 'red'), gt(totalExpr, 0)))
.orderBy(desc(totalExpr))
.limit(10);
const leaderboard = leaderboardRaw.map((entry) => ({
...entry,
review_count: entry.print_count
}));

Copilot uses AI. Check for mistakes.
Comment on lines +33 to +51
const t2Agg = db
.$with('t2Agg')
.as(
db
.select({ userId: t2Review.userId, t2Cnt: sql<number>`COUNT(*)`.as('t2Cnt') })
.from(t2Review)
.groupBy(t2Review.userId)
);

const totalExpr = sql<number>`COALESCE(${t2Agg.t2Cnt}, 0)`;

const leaderboard = await db
.with(t2Agg)
.select({ id: user.id, name: user.name, review_count: totalExpr })
.from(user)
.leftJoin(t2Agg, eq(t2Agg.userId, user.id))
.where(and(ne(user.trust, 'red'), ne(user.hackatimeTrust, 'red'), gt(totalExpr, 0)))
.orderBy(desc(totalExpr))
.limit(10);
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The leaderboard query pattern is duplicated across three files (ysws-review, review, and print +page.server.ts). Consider extracting this into a shared utility function that accepts the review tables and optional filters as parameters to improve maintainability and reduce code duplication.

Copilot uses AI. Check for mistakes.
Comment on lines +114 to +136
<div class="w-full overflow-x-auto">
{#if data.leaderboard?.length > 0}
<table class="w-full text-sm">
<thead>
<tr class="text-primary-300">
<th class="py-1" align="left">Reviewer</th>
<th class="py-1" align="right">Reviews</th>
</tr>
</thead>
<tbody>
{#each data.leaderboard as row}
<tr>
<td class="py-1" align="left">
<a class="underline" href={`../users/${row.id}`}>{row.name}</a>
</td>
<td class="py-1" align="right">{row.review_count}</td>
</tr>
{/each}
</tbody>
</table>
{:else}
<p class="text-sm text-primary-300">No reviews yet.</p>
{/if}
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The leaderboard table markup is duplicated across all three admin pages (ysws-review, review, and print). Consider extracting this into a reusable Svelte component that accepts the leaderboard data, column headers, and user type label as props to reduce duplication and improve maintainability.

Copilot uses AI. Check for mistakes.
Comment on lines +114 to +136
<div class="w-full overflow-x-auto">
{#if data.leaderboard?.length > 0}
<table class="w-full text-sm">
<thead>
<tr class="text-primary-300">
<th class="py-1" align="left">Reviewer</th>
<th class="py-1" align="right">Reviews</th>
</tr>
</thead>
<tbody>
{#each data.leaderboard as row}
<tr>
<td class="py-1" align="left">
<a class="underline" href={`/dashboard/users/${row.id}`}>{row.name}</a>
</td>
<td class="py-1" align="right">{row.review_count}</td>
</tr>
{/each}
</tbody>
</table>
{:else}
<p class="text-sm text-primary-300">No reviews yet.</p>
{/if}
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The leaderboard table markup is duplicated across all three admin pages (ysws-review, review, and print). Consider extracting this into a reusable Svelte component that accepts the leaderboard data, column headers, and user type label as props to reduce duplication and improve maintainability.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant