Affiche le n°1 d'Icare et de la Corne d'Abondance sur /leaderboard
Build and deploy / deploy (push) Successful in 36s

Nouvelle section (game-highlights.tsx) juste sous les raccourcis : avatar, pseudo et score du meneur actuel de chaque mini-jeu, cliquable vers le jeu correspondant. Même règle que les podiums existants : rien affiché tant que le meneur est à 0. Score en text-sea (pas gold-bright, peu lisible sur fond marbre — même choix déjà fait pour Icare/Corne/l'Urne).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Valentin ROBIN
2026-08-25 19:39:38 +02:00
parent 3aa2ea451c
commit 187cdec0e2
3 changed files with 88 additions and 13 deletions
+30 -12
View File
@@ -2,6 +2,7 @@ import { redirect } from "next/navigation";
import { createClient } from "@/lib/supabase/server";
import { LeaderboardView } from "./leaderboard-view";
import { QuickLinks } from "./quick-links";
import { GameHighlights, type GameLeader } from "./game-highlights";
import { AgoraLogo } from "@/components/agora-logo";
import { formatCountdown, formatTribunalDateTime } from "@/lib/tribunal-date";
@@ -15,22 +16,37 @@ export default async function LeaderboardPage() {
redirect("/login");
}
const [{ data: profiles, error }, { data: settings }, { data: wallNotesToday }] = await Promise.all([
supabase
.from("profiles")
.select("id, pseudo, avatar_url, points, previous_rank, role")
.order("points", { ascending: false }),
supabase.from("settings").select("tribunal_date").eq("id", true).single(),
// wall_notes_for_date() (jamais une lecture directe de wall_notes, dont
// la RLS ne laisserait voir que ses propres notes) : seul moyen de
// connaître le nombre total de publications du jour sans exposer qui a
// publié quoi — sert juste de compteur pour la pastille du raccourci.
supabase.rpc("wall_notes_for_date"),
]);
const [{ data: profiles, error }, { data: settings }, { data: wallNotesToday }, { data: icarusTop }, { data: melonTop }] =
await Promise.all([
supabase
.from("profiles")
.select("id, pseudo, avatar_url, points, previous_rank, role")
.order("points", { ascending: false }),
supabase.from("settings").select("tribunal_date").eq("id", true).single(),
// wall_notes_for_date() (jamais une lecture directe de wall_notes, dont
// la RLS ne laisserait voir que ses propres notes) : seul moyen de
// connaître le nombre total de publications du jour sans exposer qui a
// publié quoi — sert juste de compteur pour la pastille du raccourci.
supabase.rpc("wall_notes_for_date"),
supabase.from("icarus_scores").select("user_id, best_score").order("best_score", { ascending: false }).limit(1),
supabase.from("melon_scores").select("user_id, best_score").order("best_score", { ascending: false }).limit(1),
]);
const isJudge = profiles?.find((p) => p.id === user.id)?.role === "judge";
const tribunalDate = settings?.tribunal_date ?? null;
const profileById = new Map((profiles ?? []).map((p) => [p.id, p]));
// Comme les podiums d'Icare/Corne : un meneur à 0 (personne n'a encore
// joué) n'est pas un champion, pas de couronne pour un score par défaut.
function buildLeader(rows: { user_id: string; best_score: number }[] | null): GameLeader {
const top = rows?.[0];
if (!top || top.best_score <= 0) return null;
const profile = profileById.get(top.user_id);
return { pseudo: profile?.pseudo ?? "Un Citoyen", avatarUrl: profile?.avatar_url ?? null, score: top.best_score };
}
const icarusLeader = buildLeader(icarusTop);
const melonLeader = buildLeader(melonTop);
return (
<div className="mx-auto w-full max-w-2xl px-4 py-8">
<div className="mb-6 flex flex-col items-center text-center">
@@ -44,6 +60,8 @@ export default async function LeaderboardPage() {
<QuickLinks wallNoteCount={wallNotesToday?.length ?? 0} />
<GameHighlights icarusLeader={icarusLeader} melonLeader={melonLeader} />
{error && (
<p role="alert" className="text-sm text-oxblood">
Impossible de charger le classement pour le moment.