From 0e139553e657d2350236cc383c99b46156bdee32 Mon Sep 17 00:00:00 2001 From: Keith Avery Date: Sun, 26 Apr 2026 10:00:06 -0400 Subject: [PATCH] fix(lobby): MP mode Start button reads "Start or Join Adventure" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Playtest 2026-04-26 S4-UX bug: P2 (different host, no shared local Past Journey state) hit "Start Adventure" in Multiplayer mode and was routed to a fresh ``-2`` slug instead of joining P1's existing table. The companion server fix (sidequest-server fix/s4-mp-lobby-join-existing-server) makes POST /api/games join the existing same-slug MP game by default — this UI change signals that intent in the affordance label so users on a second host understand that clicking Start joins rather than splits. Cosmetic-only: the button still calls handleStart unchanged. The heavy lifting is server-side; this is the QoL signal the architect specified as the minimum-viable UI affordance. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/screens/ConnectScreen.tsx | 6 ++- src/screens/__tests__/ConnectScreen.test.tsx | 49 ++++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/src/screens/ConnectScreen.tsx b/src/screens/ConnectScreen.tsx index 058235d..4b81083 100644 --- a/src/screens/ConnectScreen.tsx +++ b/src/screens/ConnectScreen.tsx @@ -518,7 +518,11 @@ export function ConnectScreen({ rounded-md px-10 py-3.5 cursor-pointer shadow-[0_0_16px_rgba(0,0,0,0.3)]" > - {isStarting ? "Starting..." : "Start Adventure"} + {isStarting + ? "Starting..." + : mode === "multiplayer" + ? "Start or Join Adventure" + : "Start Adventure"} diff --git a/src/screens/__tests__/ConnectScreen.test.tsx b/src/screens/__tests__/ConnectScreen.test.tsx index 075ed0b..5b62376 100644 --- a/src/screens/__tests__/ConnectScreen.test.tsx +++ b/src/screens/__tests__/ConnectScreen.test.tsx @@ -785,4 +785,53 @@ describe("ConnectScreen", () => { expect(slugCalls).toHaveLength(0); }); }); + + // -- MP join affordance (playtest 2026-04-26 S4-UX) ----------------------- + // Server fix (sidequest-server fix/s4-mp-lobby-join-existing-server) + // makes POST /api/games join an existing same-slug MP game by default. + // The lobby must signal that intent in MP mode so users on a second + // host (no shared local Past Journey state) understand that clicking + // Start will JOIN the existing table instead of opening a new one. + describe("MP mode Start button copy", () => { + it("renders 'Start Adventure' in solo mode", async () => { + const user = userEvent.setup(); + renderConnect({ genres: GENRES }); + + // Default mode is solo; pick a world so the button is enabled. + await user.click(screen.getByRole("radio", { name: /road warrior/i })); + + // Wasteland auto-selects in single-world genres. + const btn = screen.getByTestId("lobby-start-button"); + expect(btn).toHaveTextContent(/^Start Adventure$/); + }); + + it("renders 'Start or Join Adventure' in multiplayer mode", async () => { + const user = userEvent.setup(); + renderConnect({ genres: GENRES }); + + await user.click(screen.getByRole("radio", { name: /low fantasy/i })); + await user.click(screen.getByRole("radio", { name: /greyhawk/i })); + await user.click(screen.getByRole("radio", { name: /multiplayer/i })); + + const btn = screen.getByTestId("lobby-start-button"); + expect(btn).toHaveTextContent(/^Start or Join Adventure$/); + }); + + it("toggles button copy when switching mode after world is picked", async () => { + const user = userEvent.setup(); + renderConnect({ genres: GENRES }); + + await user.click(screen.getByRole("radio", { name: /low fantasy/i })); + await user.click(screen.getByRole("radio", { name: /greyhawk/i })); + + const btn = screen.getByTestId("lobby-start-button"); + expect(btn).toHaveTextContent(/^Start Adventure$/); + + await user.click(screen.getByRole("radio", { name: /multiplayer/i })); + expect(btn).toHaveTextContent(/^Start or Join Adventure$/); + + await user.click(screen.getByRole("radio", { name: /solo/i })); + expect(btn).toHaveTextContent(/^Start Adventure$/); + }); + }); });