Files
Epicnabbo-Catalogus-Updated…/src/app/api/leaderboard/route.ts
T
openhands 41be6835bf Add missing admin action files and navigation links
- Add 11 missing server action files: badges, bulk-users, catalog, catalog-bc, catalog-items, import-badges, import-furni, multi-account-detect, permissions, rooms, soundtracks
- Add missing admin navigation links: tickets, sounds, translations, import, radio sub-pages
- Add translation keys for all new navigation items
2026-07-11 12:01:05 +02:00

74 lines
2.3 KiB
TypeScript

import { apiJson } from "@/lib/api";
import { prisma } from "@/lib/prisma";
// Public REST API — leaderboard. Mirrors src/app/leaderboard/page.tsx.
// AtomCMS-faithful currency type ids (see prisma/schema.prisma UsersCurrency):
// Credits = -1 (lives on users.credits), Duckets = 0, Diamonds = 5.
export const dynamic = "force-dynamic";
type LeaderboardType = "credits" | "diamonds" | "duckets";
const CURRENCY_TYPE: Record<Exclude<LeaderboardType, "credits">, number> = {
diamonds: 5,
duckets: 0,
};
type Row = { rank: number; username: string; look: string; value: number };
async function loadCreditsRows(): Promise<Row[]> {
const users = await prisma.user.findMany({
orderBy: { credits: "desc" },
take: 20,
select: { username: true, look: true, credits: true },
});
return users.map((u, i) => ({
rank: i + 1,
username: u.username,
look: u.look,
value: u.credits,
}));
}
async function loadCurrencyRows(type: number): Promise<Row[]> {
const top = await prisma.usersCurrency.findMany({
where: { type },
orderBy: { amount: "desc" },
take: 20,
select: { userId: true, amount: true },
});
if (top.length === 0) return [];
const users = await prisma.user.findMany({
where: { id: { in: top.map((t) => t.userId) } },
select: { id: true, username: true, look: true },
});
const byId = new Map(users.map((u) => [u.id, u]));
return top
.map((t) => {
const u = byId.get(t.userId);
if (!u) return null;
return { username: u.username, look: u.look, value: t.amount };
})
.filter((r): r is Omit<Row, "rank"> => r !== null)
.map((r, i) => ({ rank: i + 1, ...r }));
}
export async function GET(req: Request) {
try {
const sp = new URL(req.url).searchParams;
const requested = sp.get("type");
const type: LeaderboardType = requested === "diamonds" || requested === "duckets" ? requested : "credits";
const rows =
type === "credits"
? await loadCreditsRows()
: // eslint-disable-next-line security/detect-object-injection -- type validated to "diamonds"|"duckets"
await loadCurrencyRows(CURRENCY_TYPE[type]);
return apiJson({ type, data: rows }, { status: 200 });
} catch {
return apiJson({ type: "credits", data: [] }, { status: 200 });
}
}