import { useState } from "react" import type { BlindtestMode, GameType, RoomSnapshot, RoundConfig, } from "@nerdware/shared" import { Button } from "@workspace/ui/components/button" import { useRoomStore } from "@/store/room" import { Avatar } from "@/components/avatar" const QUESTION_OPTIONS = [3, 5, 10] const TRACKS_OPTIONS = [1, 2, 3] const GAME_TYPES: { value: GameType; label: string }[] = [ { value: "mixed", label: "Mixte" }, { value: "quiz", label: "Quiz" }, { value: "blindtest", label: "Blindtest" }, ] const MODE_LABELS: Record = { title_artist: "Titre & artiste", who_added: "Qui l'a ajouté ?", mixed: "Mixte", } const inputClass = "border-input bg-background h-10 w-full rounded-md border px-3 py-2 text-sm focus-visible:ring-ring focus-visible:ring-2 focus-visible:outline-none disabled:opacity-50" /** Construit la séquence de manches selon le type de partie. */ function buildRounds( gameType: GameType, quizCount: number, totalTracks: number ): RoundConfig[] { if (gameType === "quiz") { return Array.from({ length: quizCount }, () => ({ type: "quiz" })) } if (gameType === "blindtest") { return Array.from({ length: totalTracks }, () => ({ type: "blindtest" })) } // Mixte : on alterne quiz / blindtest pour multiplier les changements de mode. const rounds: RoundConfig[] = [] let q = quizCount let b = totalTracks while (q > 0 || b > 0) { if (q > 0) { rounds.push({ type: "quiz" }) q-- } if (b > 0) { rounds.push({ type: "blindtest" }) b-- } } return rounds } export function LobbyView({ snapshot }: { snapshot: RoomSnapshot }) { const playerId = useRoomStore((s) => s.playerId) const updateSettings = useRoomStore((s) => s.updateSettings) const startGame = useRoomStore((s) => s.startGame) const isHost = snapshot.hostId === playerId const { gameType, blindtestMode, tracksPerPlayer } = snapshot.settings const [count, setCount] = useState(5) const [busy, setBusy] = useState(false) const [error, setError] = useState(null) const totalTracks = snapshot.submissions.reduce((n, s) => n + s.count, 0) const myCount = snapshot.submissions.find((s) => s.playerId === playerId)?.count ?? 0 const showQuiz = gameType === "quiz" || gameType === "mixed" const showBlindtest = gameType === "blindtest" || gameType === "mixed" const rounds = buildRounds(gameType, showQuiz ? count : 0, totalTracks) const canStart = rounds.length > 0 async function start() { setError(null) setBusy(true) try { await startGame(rounds) } catch (err) { setError((err as { message?: string }).message ?? "Erreur") } finally { setBusy(false) } } return (

Joueurs ({snapshot.players.length})

    {snapshot.players.map((p) => (
  • {p.name} {p.id === playerId && ( (toi) )} {p.id === snapshot.hostId ? "Hôte" : ""} {!p.connected && " · hors ligne"}
  • ))}
{isHost && (
{GAME_TYPES.map((t) => ( ))}
)} {isHost && showQuiz && (
Questions de quiz
{QUESTION_OPTIONS.map((n) => ( ))}
)} {isHost && showBlindtest && (
Mode blindtest
{(["title_artist", "who_added", "mixed"] as const).map((m) => ( ))}
Titres par joueur
{TRACKS_OPTIONS.map((n) => ( ))}
)} {showBlindtest && ( )} {isHost ? ( ) : (

En attente du lancement par l'hôte… {showBlindtest && ` (${totalTracks} titres soumis)`}

)} {error &&

{error}

}
) } function TrackSubmission({ tracksPerPlayer, myCount, }: { tracksPerPlayer: number myCount: number }) { const submitTrack = useRoomStore((s) => s.submitTrack) const [url, setUrl] = useState("") const [submitting, setSubmitting] = useState(false) const [feedback, setFeedback] = useState(null) const [accepted, setAccepted] = useState([]) const quotaReached = myCount >= tracksPerPlayer async function submit() { if (!url.trim()) { return } setSubmitting(true) setFeedback(null) const res = await submitTrack(url.trim()) if (res.accepted) { setAccepted((a) => [...a, res.title ?? url.trim()]) setUrl("") } else { setFeedback(res.reason ?? "Refusé") } setSubmitting(false) } return (
Tes titres ({myCount}/{tracksPerPlayer})
setUrl(e.target.value)} onKeyDown={(e) => e.key === "Enter" && submit()} />
{feedback &&

{feedback}

} {accepted.length > 0 && (
    {accepted.map((t, i) => (
  • ✓ {t}
  • ))}
)}
) }