diff --git a/apps/web/src/components/multiplayer/MultiplayerScoreScreen.tsx b/apps/web/src/components/multiplayer/MultiplayerScoreScreen.tsx new file mode 100644 index 0000000..5e95588 --- /dev/null +++ b/apps/web/src/components/multiplayer/MultiplayerScoreScreen.tsx @@ -0,0 +1,114 @@ +import { useNavigate } from "@tanstack/react-router"; +import type { LobbyPlayer } from "@lila/shared"; + +type MultiplayerScoreScreenProps = { + players: LobbyPlayer[]; + winnerIds: string[]; + currentUserId: string; + lobbyCode: string; +}; + +export const MultiplayerScoreScreen = ({ + players, + winnerIds, + currentUserId, + lobbyCode, +}: MultiplayerScoreScreenProps) => { + const navigate = useNavigate(); + + const sortedPlayers = [...players].sort((a, b) => b.score - a.score); + + const isWinner = winnerIds.includes(currentUserId); + const isTie = winnerIds.length > 1; + + const winnerNames = winnerIds + .map((id) => players.find((p) => p.userId === id)?.user.name ?? id) + .join(" and "); + + return ( +
+
+ {/* Result header */} +
+

+ {isTie ? "It's a tie!" : isWinner ? "You win! 🎉" : "Game over"} +

+

+ {isTie ? `${winnerNames} tied` : `${winnerNames} wins!`} +

+
+ +
+ + {/* Score list */} +
+ {sortedPlayers.map((player, index) => { + const isCurrentUser = player.userId === currentUserId; + const isPlayerWinner = winnerIds.includes(player.userId); + return ( +
+
+ + {index + 1}. + + + {player.user.name} + {isCurrentUser && ( + + (you) + + )} + + {isPlayerWinner && ( + + 👑 + + )} +
+ + {player.score} pts + +
+ ); + })} +
+ +
+ + {/* Actions */} +
+ + +
+
+
+ ); +}; diff --git a/apps/web/src/routes/__root.tsx b/apps/web/src/routes/__root.tsx index e7fe4b0..0add685 100644 --- a/apps/web/src/routes/__root.tsx +++ b/apps/web/src/routes/__root.tsx @@ -17,20 +17,24 @@ const RootLayout = () => { Home - - About + + Play + + + Multiplayer
{session ? ( +

Click to copy

+
+ +
+ + {/* Player list */} +
+

+ Players ({lobby.players.length}) +

+
    + {lobby.players.map((player) => ( +
  • + + {player.user.name} + {player.userId === lobby.hostUserId && ( + + host + + )} +
  • + ))} +
+
+ + {/* Error */} + {error &&

{error}

} + + {/* Start button — host only */} + {isHost && ( + + )} + + {/* Non-host waiting message */} + {!isHost && ( +

+ Waiting for host to start the game... +

+ )} +
+
+ ); } diff --git a/packages/shared/src/schemas/lobby.ts b/packages/shared/src/schemas/lobby.ts index 7b7b7d5..c9687c4 100644 --- a/packages/shared/src/schemas/lobby.ts +++ b/packages/shared/src/schemas/lobby.ts @@ -27,6 +27,9 @@ export const JoinLobbyResponseSchema = LobbySchema; export type JoinLobbyResponse = z.infer; +export const GameRouteSearchSchema = z.object({ lobbyId: z.uuid() }); +export type GameRouteSearch = z.infer; + // ---------------------------------------------------------------------------- // WebSocket: Client → Server // ----------------------------------------------------------------------------