feat(profiles): add public player profiles with clickable leaderboard entries

- Create /api/users/[id] endpoint for public player stats
- Add PublicProfileScreen component with stats by mode
- Make leaderboard entries clickable to view player profiles
- Fix .gitignore to exclude .claude/ and *.db files
This commit is contained in:
jessy-david-dev
2026-04-11 15:17:56 +02:00
parent 2a382a24eb
commit 7d1b236b46
4 changed files with 208 additions and 2 deletions
+7 -1
View File
@@ -1,6 +1,7 @@
"use client";
import { useEffect, useState } from "react";
import { PublicProfileScreen } from "./PublicProfileScreen";
type LeaderboardRow = {
id: string;
@@ -29,6 +30,7 @@ export function LeaderboardScreen({ onBack }: { onBack: () => void }) {
const [rows, setRows] = useState<LeaderboardRow[]>([]);
const [loading, setLoading] = useState(true);
const [mode, setMode] = useState<Mode>("all");
const [viewingUserId, setViewingUserId] = useState<string | null>(null);
useEffect(() => {
fetch("/api/leaderboard")
@@ -36,6 +38,10 @@ export function LeaderboardScreen({ onBack }: { onBack: () => void }) {
.then((data) => { setRows(data); setLoading(false); });
}, []);
if (viewingUserId) {
return <PublicProfileScreen userId={viewingUserId} onBack={() => setViewingUserId(null)} />;
}
const sorted = [...rows]
.filter((r) => mode === "solo" ? r.soloGames > 0 : mode === "multi" ? r.multiGames > 0 : true)
.sort((a, b) => {
@@ -81,7 +87,7 @@ export function LeaderboardScreen({ onBack }: { onBack: () => void }) {
const wins = mode === "solo" ? row.soloWins : mode === "multi" ? row.multiWins : row.wins;
return (
<div key={row.id} className={`flex items-center gap-2.5 px-3.5 py-3 rounded-xl border ${i < 3 ? "border-[#7c3aed] bg-[#7c3aed]/8" : "border-[#2e2e2e] bg-[#1a1a1a]"}`}>
<div key={row.id} onClick={() => setViewingUserId(row.id)} className={`flex items-center gap-2.5 px-3.5 py-3 rounded-xl border cursor-pointer hover:brightness-110 transition-all ${i < 3 ? "border-[#7c3aed] bg-[#7c3aed]/8" : "border-[#2e2e2e] bg-[#1a1a1a]"}`}>
<span className="text-xl w-8 text-center shrink-0">{MEDALS[i] ?? `#${i + 1}`}</span>
<div className="flex-1 min-w-0 flex flex-col gap-1">
<span className="font-bold text-sm truncate">{row.name}</span>