restructure play routes: layout with nested game, bingo, board children
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
15
packages/client/src/routes/play.$roomCode.bingo.tsx
Normal file
15
packages/client/src/routes/play.$roomCode.bingo.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import { createFileRoute } from "@tanstack/react-router"
|
||||
import { useRoomStore } from "@/stores/room-store"
|
||||
import { BingoTab } from "@/components/bingo-tab"
|
||||
|
||||
export const Route = createFileRoute("/play/$roomCode/bingo")({
|
||||
component: PlayBingo,
|
||||
})
|
||||
|
||||
function PlayBingo() {
|
||||
const { room, gameState, send } = useRoomStore()
|
||||
|
||||
if (!room || !gameState) return null
|
||||
|
||||
return <BingoTab currentAct={room.currentAct} gameState={gameState} send={send} />
|
||||
}
|
||||
15
packages/client/src/routes/play.$roomCode.board.tsx
Normal file
15
packages/client/src/routes/play.$roomCode.board.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import { createFileRoute } from "@tanstack/react-router"
|
||||
import { useRoomStore } from "@/stores/room-store"
|
||||
import { BoardTab } from "@/components/board-tab"
|
||||
|
||||
export const Route = createFileRoute("/play/$roomCode/board")({
|
||||
component: PlayBoard,
|
||||
})
|
||||
|
||||
function PlayBoard() {
|
||||
const { room, gameState } = useRoomStore()
|
||||
|
||||
if (!room || !gameState) return null
|
||||
|
||||
return <BoardTab currentAct={room.currentAct} gameState={gameState} />
|
||||
}
|
||||
15
packages/client/src/routes/play.$roomCode.game.tsx
Normal file
15
packages/client/src/routes/play.$roomCode.game.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import { createFileRoute } from "@tanstack/react-router"
|
||||
import { useRoomStore } from "@/stores/room-store"
|
||||
import { GameTab } from "@/components/game-tab"
|
||||
|
||||
export const Route = createFileRoute("/play/$roomCode/game")({
|
||||
component: PlayGame,
|
||||
})
|
||||
|
||||
function PlayGame() {
|
||||
const { room, gameState, send } = useRoomStore()
|
||||
|
||||
if (!room || !gameState) return null
|
||||
|
||||
return <GameTab currentAct={room.currentAct} gameState={gameState} send={send} />
|
||||
}
|
||||
7
packages/client/src/routes/play.$roomCode.index.tsx
Normal file
7
packages/client/src/routes/play.$roomCode.index.tsx
Normal file
@@ -0,0 +1,7 @@
|
||||
import { createFileRoute, redirect } from "@tanstack/react-router"
|
||||
|
||||
export const Route = createFileRoute("/play/$roomCode/")({
|
||||
beforeLoad: ({ params }) => {
|
||||
throw redirect({ to: "/play/$roomCode/game", params })
|
||||
},
|
||||
})
|
||||
@@ -2,25 +2,19 @@ import { useEffect, useRef, useState } from "react"
|
||||
import { createFileRoute } from "@tanstack/react-router"
|
||||
import { useWebSocket } from "@/hooks/use-websocket"
|
||||
import { useRoomStore } from "@/stores/room-store"
|
||||
import { PlayerList } from "@/components/player-list"
|
||||
import { PredictionsForm } from "@/components/predictions-form"
|
||||
import { JuryVoting } from "@/components/jury-voting"
|
||||
import { BingoCard } from "@/components/bingo-card"
|
||||
import { Leaderboard } from "@/components/leaderboard"
|
||||
import { QuizBuzzer } from "@/components/quiz-buzzer"
|
||||
import { RoomHeader } from "@/components/room-header"
|
||||
import { RoomLayout } from "@/components/room-layout"
|
||||
import { BottomNav } from "@/components/bottom-nav"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
||||
|
||||
export const Route = createFileRoute("/play/$roomCode")({
|
||||
component: PlayerView,
|
||||
component: PlayLayout,
|
||||
})
|
||||
|
||||
function PlayerView() {
|
||||
function PlayLayout() {
|
||||
const { roomCode } = Route.useParams()
|
||||
const { send } = useWebSocket(roomCode)
|
||||
const { room, mySessionId, connectionStatus, gameState } = useRoomStore()
|
||||
const { room, mySessionId, connectionStatus } = useRoomStore()
|
||||
const joinSentRef = useRef(false)
|
||||
const [manualName, setManualName] = useState("")
|
||||
|
||||
@@ -85,91 +79,9 @@ function PlayerView() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex min-h-screen flex-col">
|
||||
<RoomHeader roomCode={roomCode} currentAct={room.currentAct} connectionStatus={connectionStatus} />
|
||||
<div className="flex-1 p-4">
|
||||
{gameState && (room.currentAct === "lobby" || room.currentAct === "pre-show") && (
|
||||
<div className="flex flex-col gap-4">
|
||||
<PredictionsForm
|
||||
entries={gameState.lineup.entries}
|
||||
existingPrediction={gameState.myPrediction}
|
||||
locked={gameState.predictionsLocked}
|
||||
onSubmit={(prediction) =>
|
||||
send({ type: "submit_prediction", ...prediction })
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{gameState && room.currentAct === "live-event" && (
|
||||
<Tabs defaultValue="jury" className="flex-1">
|
||||
<TabsList className="w-full">
|
||||
<TabsTrigger value="jury" className="flex-1">Jury</TabsTrigger>
|
||||
<TabsTrigger value="bingo" className="flex-1">Bingo</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="jury" className="mt-4">
|
||||
{gameState.currentJuryRound ? (
|
||||
<JuryVoting
|
||||
round={gameState.currentJuryRound}
|
||||
myVote={gameState.myJuryVote}
|
||||
onVote={(rating) => send({ type: "submit_jury_vote", rating })}
|
||||
/>
|
||||
) : (
|
||||
<div className="py-8 text-center text-muted-foreground">
|
||||
Waiting for host to open voting...
|
||||
</div>
|
||||
)}
|
||||
</TabsContent>
|
||||
<TabsContent value="bingo" className="mt-4">
|
||||
{gameState.myBingoCard ? (
|
||||
<BingoCard
|
||||
card={gameState.myBingoCard}
|
||||
onTap={(tropeId) => send({ type: "tap_bingo_square", tropeId })}
|
||||
/>
|
||||
) : (
|
||||
<div className="py-8 text-center text-muted-foreground">
|
||||
No bingo card yet
|
||||
</div>
|
||||
)}
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
)}
|
||||
|
||||
{gameState && (room.currentAct === "scoring" || room.currentAct === "ended") && gameState.myPrediction && (
|
||||
<PredictionsForm
|
||||
entries={gameState.lineup.entries}
|
||||
existingPrediction={gameState.myPrediction}
|
||||
locked={true}
|
||||
actualResults={gameState.actualResults}
|
||||
onSubmit={() => {}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{gameState && room.currentAct === "scoring" && gameState.currentQuizQuestion && (
|
||||
<QuizBuzzer
|
||||
question={gameState.currentQuizQuestion}
|
||||
buzzStatus={gameState.myQuizBuzzStatus}
|
||||
onBuzz={() => send({ type: "buzz" })}
|
||||
/>
|
||||
)}
|
||||
|
||||
{gameState && room.currentAct === "scoring" && (
|
||||
<Leaderboard entries={gameState.leaderboard} resultsEntered={!!gameState?.actualResults} />
|
||||
)}
|
||||
|
||||
{room.currentAct === "ended" && (
|
||||
<div className="flex flex-col items-center gap-4 py-8">
|
||||
<p className="text-lg text-muted-foreground">The party has ended. Thanks for playing!</p>
|
||||
{gameState && <Leaderboard entries={gameState.leaderboard} resultsEntered={!!gameState?.actualResults} />}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<PlayerList
|
||||
players={room.players}
|
||||
mySessionId={mySessionId}
|
||||
predictionSubmitted={gameState?.predictionSubmitted}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<>
|
||||
<RoomLayout roomCode={roomCode} connectionStatus={connectionStatus} />
|
||||
<BottomNav basePath="/play/$roomCode" roomCode={roomCode} isHost={false} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user