Add pickup game lobbies#272
Draft
mwickett wants to merge 4 commits into
Draft
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
Adds “pickup game” lobbies that allow a signed-in host to create a game without a Circle, share a QR/link or short code, have other signed-in users join, then start into the existing scoring flow with roster-based scoring authorization.
Changes:
- Introduces pickup-lobby server actions + queries (create/join/start + lobby reads) with DB row locking and join token/code.
- Extends game authorization to support pickup scoring via exact roster membership (and keeps Circle semantics).
- Adds UI routes for creating pickup games, joining by code/token, and a lobby page with QR + roster.
Reviewed changes
Copilot reviewed 25 out of 26 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/server/queries/lobbies.ts | New query helpers to fetch pickup lobby by token / for a participant. |
| src/server/queries/games.ts | Expands games list queries to include pickup games and redefines legacy filtering via kind. |
| src/server/mutations/rounds.ts | Switches scoring auth to requireGameScoringAccess and enforces roster-match on score writes. |
| src/server/mutations/lobbies.ts | New server actions for creating/joining/starting pickup lobbies with locks + join credentials. |
| src/server/mutations/index.ts | Re-exports new lobby server actions. |
| src/server/mutations/games.ts | Updates finish/finalization auth to allow pickup players to finalize via scorer access. |
| src/server/mutations/common.ts | Adds local-user provisioning helper and shared pickup/circle scoring authorization + roster assertion. |
| src/server/db/schema.prisma | Adds GameKind, lobby fields, host relation, and supporting indexes. |
| src/server/db/migrations/20260710120000_add_pickup_games/migration.sql | Prisma migration to add enum + new game columns + indexes and backfill legacy kind. |
| src/server/tests/queries.test.ts | Updates getGames tests for OR logic and pickup-without-circle behavior. |
| src/server/tests/mutations.test.ts | Updates scoring mutation tests for round ownership checks and roster enforcement. |
| src/proxy.ts | Allows /games, /games/new, and /games/[id]/lobby without an active Circle while still requiring auth. |
| src/lib/tests/gameLogic.test.ts | Updates game fixtures to include new game fields (kind, startedAt, etc.). |
| src/components/GamesList.tsx | Adjusts UI copy and status badges to include pickup/lobby states. |
| src/app/join/page.tsx | New join-by-code entry page with sign-in gate. |
| src/app/join/JoinByCodeForm.tsx | Client form to join a pickup lobby via short code. |
| src/app/join/[token]/page.tsx | Token-based join confirmation page (with sign-in/sign-up redirects). |
| src/app/join/[token]/JoinLobbyButton.tsx | Client button to execute join action and route to lobby. |
| src/app/games/new/PickupGameSetup.tsx | Client UI to create a pickup lobby with threshold + optional guests. |
| src/app/games/new/page.tsx | Adds game-type chooser routing (circle vs pickup) for New Game. |
| src/app/games/new/GameTypeChooser.tsx | UI for selecting pickup vs circle game creation. |
| src/app/games/[id]/page.tsx | Redirects pickup players to lobby pre-start; allows pickup players to edit after start. |
| src/app/games/[id]/lobby/page.tsx | New lobby page rendering QR/link, lobby code, roster, and controls. |
| src/app/games/[id]/lobby/LobbyControls.tsx | Client controls for polling/refresh, copy link, and host start action. |
| package.json | Adds qrcode runtime dependency and @types/qrcode dev dependency. |
| package-lock.json | Lockfile updates for added dependencies. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+22
to
+30
| }; | ||
|
|
||
| export async function getPickupLobbyByToken(joinToken: string) { | ||
| return prisma.game.findUnique({ | ||
| where: { joinToken }, | ||
| include: lobbyInclude, | ||
| }); | ||
| } | ||
|
|
Comment on lines
+153
to
+167
| } catch (error) { | ||
| if ( | ||
| error && | ||
| typeof error === "object" && | ||
| "code" in error && | ||
| error.code === "P2002" | ||
| ) { | ||
| const racedUser = await prisma.user.findUnique({ | ||
| where: { clerk_user_id: userId }, | ||
| }); | ||
| if (racedUser) return racedUser; | ||
| } | ||
| throw error; | ||
| } | ||
| } |
Comment on lines
+165
to
+177
| export async function joinPickupGameByCode(rawCode: string) { | ||
| await requireAuthContext("user"); | ||
| const code = rawCode | ||
| .trim() | ||
| .toUpperCase() | ||
| .replace(/[^A-Z0-9]/g, ""); | ||
| const game = await prisma.game.findUnique({ | ||
| where: { joinCode: code }, | ||
| select: { joinToken: true }, | ||
| }); | ||
| if (!game?.joinToken) throw new Error("We couldn't find that lobby code"); | ||
| return joinPickupGame(game.joinToken); | ||
| } |
Comment on lines
+40
to
+44
| const copy = async () => { | ||
| await navigator.clipboard.writeText(joinUrl); | ||
| setCopied(true); | ||
| window.setTimeout(() => setCopied(false), 1_800); | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this enables
A signed-in host can create a pickup game without a Circle, show a QR code or lobby code, and let other signed-in Blitzer users confirm that they want to join. The host can also add accountless guests at setup. Once the host starts, every registered participant lands in the existing scoring experience and can enter scores together.
Flow
Gamewith the host and optional guests.Data and authorization
GameKind,startedAt, host, join token, and join code fields through an additive Prisma migration. Existing no-Circle games are markedLEGACY; existing Circle games retain current behavior.GamePlayers; Circle scoring remains authorized by active Circle membership.Validation
npm run typechecknpm run lintnpm test -- --runInBand(167 tests)npx next buildwith the local development environment