import { useEffect, useRef, useState } from "react" import { Link } from "wouter" import { motion } from "framer-motion" import { Check, ClipboardList, Crown, Music } from "lucide-react" import { SiSpotify, SiYoutube } from "@icons-pack/react-simple-icons" import type { BlindtestTrackInfo, PlayerScore, RoomSnapshot } from "@nerdware/shared" import { Button } from "@workspace/ui/components/button" import { useRoomStore } from "@/store/room" import { Avatar } from "@/components/avatar" import { celebrate } from "@/lib/confetti" import { playVictory } from "@/lib/sound" /** Lien de recherche Spotify (le titre vidéo contient en général artiste + chanson). */ function spotifySearch(track: BlindtestTrackInfo): string { const query = `${track.title} ${track.artist}`.trim() return `https://open.spotify.com/search/${encodeURIComponent(query)}` } type Place = 1 | 2 | 3 // Hauteur de marche, couleurs (or / argent / bronze) et taille d'avatar par place. const PODIUM: Record = { 1: { bar: "h-24", pedestal: "border-amber-400 bg-gradient-to-b from-amber-400/30 to-amber-400/5", text: "text-amber-400", ring: "ring-amber-400", avatar: "size-20", }, 2: { bar: "h-16", pedestal: "border-zinc-300/70 bg-gradient-to-b from-zinc-300/20 to-zinc-300/5", text: "text-zinc-300", ring: "ring-zinc-300", avatar: "size-16", }, 3: { bar: "h-12", pedestal: "border-amber-700/70 bg-gradient-to-b from-amber-700/25 to-amber-700/5", text: "text-amber-600", ring: "ring-amber-700", avatar: "size-16", }, } function PodiumColumn({ entry, place, name, isMe, delay, }: { entry: PlayerScore place: Place name: string isMe: boolean delay: number }) { const cfg = PODIUM[place] return (
{place === 1 && ( )}
{name} {isMe && (toi)} {entry.score}
{place}
) } export function GameEndView({ snapshot }: { snapshot: RoomSnapshot }) { const playerId = useRoomStore((s) => s.playerId) const finalScores = useRoomStore((s) => s.finalScores) const gameTracks = useRoomStore((s) => s.gameTracks) const reset = useRoomStore((s) => s.reset) const returnToLobby = useRoomStore((s) => s.returnToLobby) const isHost = snapshot.hostId === playerId // Confettis de victoire (une fois à l'arrivée sur l'écran de fin). const celebrated = useRef(false) useEffect(() => { if (!celebrated.current) { celebrated.current = true celebrate() playVictory() } }, []) const scores: PlayerScore[] = finalScores ?? snapshot.scores const ranked = [...scores].sort((a, b) => b.score - a.score) const nameOf = (id: string) => snapshot.players.find((p) => p.id === id)?.name ?? "?" const isMe = (id: string) => id === playerId const [first, second, third] = ranked const rest = ranked.slice(3) return (

Partie terminée

🏆 {first ? nameOf(first.playerId) : "?"} l'emporte !

{/* Podium : 2e à gauche, champion au centre, 3e à droite. */}
{second && ( )} {first && ( )} {third && ( )}
{rest.length > 0 && (
    {rest.map((s, i) => (
  1. {i + 4} {nameOf(s.playerId)} {isMe(s.playerId) && ( (toi) )} {s.score}
  2. ))}
)} {gameTracks && gameTracks.length > 0 && ( )}
{isHost ? ( ) : (

En attente que l'hôte relance une partie…

)}
) } function TracksRecap({ tracks }: { tracks: BlindtestTrackInfo[] }) { const [copied, setCopied] = useState(false) async function copyPlaylist() { const text = tracks.map((t) => `${t.title} — ${t.artist}`).join("\n") try { await navigator.clipboard.writeText(text) setCopied(true) setTimeout(() => setCopied(false), 1500) } catch { // presse-papier indisponible : on ignore } } return (

Les musiques de la partie

) }