diff --git a/app/about/page.tsx b/app/about/page.tsx index f460e21..5541b14 100644 --- a/app/about/page.tsx +++ b/app/about/page.tsx @@ -137,31 +137,91 @@ export default function AboutPage() { - {/* Paliers */} + {/* Badges */}

- Paliers du compteur total + Badges

{[ - { emoji: "🌱", label: "Moins de 10 parties", range: "< 10" }, - { emoji: "👾", label: "10 parties et plus", range: "10+" }, - { emoji: "🎮", label: "100 parties et plus", range: "100+" }, - { emoji: "🎯", label: "500 parties et plus", range: "500+" }, - { emoji: "⚡", label: "1 000 parties et plus", range: "1 000+" }, - { emoji: "🔥", label: "5 000 parties et plus", range: "5 000+" }, { - emoji: "🚀", - label: "10 000 parties et plus", + file: "novice", + name: "Novice", + label: "Moins de 5 victoires", + range: "< 5", + }, + { + file: "apprenti", + name: "Apprenti", + label: "5 victoires et plus", + range: "5+", + }, + { + file: "initié", + name: "Initié", + label: "20 victoires et plus", + range: "20+", + }, + { + file: "adepte", + name: "Adepte", + label: "50 victoires et plus", + range: "50+", + }, + { + file: "expert", + name: "Expert", + label: "150 victoires et plus", + range: "150+", + }, + { + file: "maître", + name: "Maître", + label: "500 victoires et plus", + range: "500+", + }, + { + file: "légende", + name: "Légende", + label: "1 000 victoires et plus", + range: "1 000+", + }, + { + file: "mythique", + name: "Mythique", + label: "2 500 victoires et plus", + range: "2 500+", + }, + { + file: "transcendant", + name: "Transcendant", + label: "5 000 victoires et plus", + range: "5 000+", + }, + { + file: "omniscient", + name: "Omniscient", + label: "10 000 victoires et plus", range: "10 000+", }, - ].map(({ emoji, label, range }) => ( -
- - {emoji} + ].map(({ file, name, label, range }) => ( +
+ {name} + + {name} + + + {label} + + + {range} - {label} - {range}
))}
diff --git a/app/components/HomeScreen.tsx b/app/components/HomeScreen.tsx index f29bab4..2a1673e 100644 --- a/app/components/HomeScreen.tsx +++ b/app/components/HomeScreen.tsx @@ -3,19 +3,10 @@ import Image from "next/image"; import { useEffect, useState } from "react"; import type { Session } from "next-auth"; - -function totalEmoji(n: number): string { - if (n >= 10000) return "🚀"; - if (n >= 5000) return "🔥"; - if (n >= 1000) return "⚡"; - if (n >= 500) return "🎯"; - if (n >= 100) return "🎮"; - if (n >= 10) return "👾"; - return "🌱"; -} +import { getBadge } from "../../lib/badges"; function useDailyStats() { - const [today, setToday] = useState(null); // renommé plus bas en total + const [today, setToday] = useState(null); useEffect(() => { fetch("/api/stats") .then((r) => r.json()) @@ -25,6 +16,24 @@ function useDailyStats() { return today; } +function useUserWins(enabled: boolean) { + const [wins, setWins] = useState(0); + useEffect(() => { + if (!enabled) return; + fetch("/api/games") + .then((r) => (r.ok ? r.json() : [])) + .then((games: unknown) => { + if (Array.isArray(games)) { + setWins((games as { won: boolean }[]).filter((g) => g.won).length); + } else { + setWins(0); + } + }) + .catch(() => setWins(0)); + }, [enabled]); + return wins; +} + type HomeScreenProps = { playerName: string; setPlayerName: (v: string) => void; @@ -65,6 +74,8 @@ export function HomeScreen({ const btnGhost = "min-h-9 px-3 rounded-lg text-xs sm:text-sm font-semibold bg-[#242424] border border-[#2e2e2e] text-[#f0f0f0] hover:bg-[#1a1a1a] cursor-pointer whitespace-nowrap"; const today = useDailyStats(); + const wins = useUserWins(!!session?.user); + const badge = session?.user ? getBadge(wins) : null; return (
@@ -78,9 +89,20 @@ export function HomeScreen({ className="flex items-center gap-1.5 sm:gap-2 bg-[#242424] border border-[#2e2e2e] rounded-full pl-1 pr-2.5 sm:pr-3 py-1 cursor-pointer hover:bg-[#1a1a1a]" onClick={onShowProfile} > - - {session.user.name?.[0]?.toUpperCase() ?? "?"} - + {badge ? ( + // eslint-disable-next-line @next/next/no-img-element + {badge.name} + ) : ( + + {session.user.name?.[0]?.toUpperCase() ?? "?"} + + )} {session.user.name} @@ -109,13 +131,19 @@ export function HomeScreen({

{today !== null && (

- {totalEmoji(today)}{" "} {today.toLocaleString("fr-FR")} {" "} partie{today > 1 ? "s" : ""} jouée{today > 1 ? "s" : ""} au total

)} + {badge && ( +
+ {/* eslint-disable-next-line @next/next/no-img-element */} + {badge.name} + {badge.name} +
+ )}
{/* Form */} diff --git a/app/components/ProfileScreen.tsx b/app/components/ProfileScreen.tsx index 8d15513..4635002 100644 --- a/app/components/ProfileScreen.tsx +++ b/app/components/ProfileScreen.tsx @@ -1,7 +1,9 @@ "use client"; +import Image from "next/image"; import { useEffect, useState } from "react"; import { signOut } from "next-auth/react"; +import { getBadge, getNextBadge } from "../../lib/badges"; type Game = { id: string; @@ -77,6 +79,10 @@ export function ProfileScreen({ filter === "all" ? games : games.filter((g) => g.mode === filter); const stats = computeStats(filtered); + const allStats = computeStats(games); + const badge = getBadge(allStats.won); + const next = getNextBadge(allStats.won); + const statCard = "bg-[#1a1a1a] border border-[#2e2e2e] rounded-xl p-3 sm:p-3.5 text-center flex flex-col gap-1"; const btnGhost = @@ -105,6 +111,25 @@ export function ProfileScreen({
+ {/* Badge */} + {!loading && ( +
+ {badge.name} + {badge.name} + {next && ( + + {next.threshold - allStats.won} victoire{next.threshold - allStats.won > 1 ? "s" : ""} avant {next.name} + + )} +
+ )} + {/* Stats grid */}
diff --git a/lib/badges.ts b/lib/badges.ts new file mode 100644 index 0000000..ce65fdc --- /dev/null +++ b/lib/badges.ts @@ -0,0 +1,23 @@ +export type Badge = { name: string; file: string; threshold: number }; + +export const BADGES: Badge[] = [ + { name: "Omniscient", file: "omniscient", threshold: 10000 }, + { name: "Transcendant", file: "transcendant", threshold: 5000 }, + { name: "Mythique", file: "mythique", threshold: 2500 }, + { name: "Légende", file: "légende", threshold: 1000 }, + { name: "Maître", file: "maître", threshold: 500 }, + { name: "Expert", file: "expert", threshold: 150 }, + { name: "Adepte", file: "adepte", threshold: 50 }, + { name: "Initié", file: "initié", threshold: 20 }, + { name: "Apprenti", file: "apprenti", threshold: 5 }, + { name: "Novice", file: "novice", threshold: 0 }, +]; + +export function getBadge(wins: number): Badge { + return BADGES.find((b) => wins >= b.threshold) ?? BADGES[BADGES.length - 1]; +} + +export function getNextBadge(wins: number): Badge | null { + const idx = BADGES.findIndex((b) => wins >= b.threshold); + return idx > 0 ? BADGES[idx - 1] : null; +} diff --git a/public/badges/adepte.Png b/public/badges/adepte.Png new file mode 100755 index 0000000..e5edccb Binary files /dev/null and b/public/badges/adepte.Png differ diff --git a/public/badges/apprenti.Png b/public/badges/apprenti.Png new file mode 100755 index 0000000..a5ce7fa Binary files /dev/null and b/public/badges/apprenti.Png differ diff --git a/public/badges/expert.Png b/public/badges/expert.Png new file mode 100755 index 0000000..05d1b84 Binary files /dev/null and b/public/badges/expert.Png differ diff --git a/public/badges/initié.Png b/public/badges/initié.Png new file mode 100755 index 0000000..07a3468 Binary files /dev/null and b/public/badges/initié.Png differ diff --git a/public/badges/légende.Png b/public/badges/légende.Png new file mode 100755 index 0000000..c6babb2 Binary files /dev/null and b/public/badges/légende.Png differ diff --git a/public/badges/maître.Png b/public/badges/maître.Png new file mode 100755 index 0000000..1a3158e Binary files /dev/null and b/public/badges/maître.Png differ diff --git a/public/badges/mythique.Png b/public/badges/mythique.Png new file mode 100755 index 0000000..c02062b Binary files /dev/null and b/public/badges/mythique.Png differ diff --git a/public/badges/novice.Png b/public/badges/novice.Png new file mode 100755 index 0000000..7e1d804 Binary files /dev/null and b/public/badges/novice.Png differ diff --git a/public/badges/omniscient.Png b/public/badges/omniscient.Png new file mode 100755 index 0000000..90063c4 Binary files /dev/null and b/public/badges/omniscient.Png differ diff --git a/public/badges/transcendant.Png b/public/badges/transcendant.Png new file mode 100755 index 0000000..8b2f3d2 Binary files /dev/null and b/public/badges/transcendant.Png differ