From e8e36e6674ddc27aaede1c2c5b9df09770528615 Mon Sep 17 00:00:00 2001 From: pixii Date: Thu, 6 Mar 2025 10:24:44 +0100 Subject: [PATCH] feat: implement room joining by link and add dedicated room-utils store --- frontend/src/components/ConnectRoom.svelte | 270 +++------------------ frontend/src/components/Game/Lobby.svelte | 13 +- frontend/src/routes/Game.svelte | 12 +- frontend/src/routes/Join.svelte | 0 frontend/src/stores/roomStore.ts | 146 +++++++++++ frontend/src/stores/sessionStore.ts | 1 + 6 files changed, 202 insertions(+), 240 deletions(-) delete mode 100644 frontend/src/routes/Join.svelte create mode 100644 frontend/src/stores/roomStore.ts diff --git a/frontend/src/components/ConnectRoom.svelte b/frontend/src/components/ConnectRoom.svelte index a13c784..f7590c6 100644 --- a/frontend/src/components/ConnectRoom.svelte +++ b/frontend/src/components/ConnectRoom.svelte @@ -8,22 +8,14 @@ Helper, } from "flowbite-svelte"; import { _ } from "svelte-i18n"; - import { sessionStore } from "/stores/sessionStore"; + import { loading, join_error, create_error, rejoinRoomCode, rejoinRoomSessionData, requestJoinRoom, requestCreateRoom, joinSession, checkSessionData } from "../stores/roomStore"; - let loading: "join" | "create" | false = false; - let rejoinRoomCode = ""; - let rejoinRoomSessionData = { - sessionToken: "", - userId: "", - }; let joinRoomId = ""; - let join_error: string | false = false; - let create_error: string | false = false; let inputRef: HTMLInputElement | null = null; function formatInput(event: any) { let rawValue = event.target.value.replace(/\D/g, ""); - join_error = false; + join_error.set(false); if (rawValue.length > 6) { rawValue = rawValue.slice(0, 6); @@ -36,217 +28,27 @@ joinRoomId = formattedValue; if (joinRoomId.length > 6) { - requestJoinRoom(); + requestJoinRoom(joinRoomId); } } function handleKeyDown(event: any) { if (event.key === "Backspace") { - join_error = false; + join_error.set(false); let cursorPosition = event.target.selectionStart; if (cursorPosition === 4) { - // If cursor is at "-" position, delete the number before it joinRoomId = joinRoomId.slice(0, 2); event.preventDefault(); } } } - async function requestJoinRoom(joinCode = joinRoomId) { - if (loading) return; - loading = "join"; - join_error = false; - - try { - const controller = new AbortController(); - // 5s timeout - const timeout = setTimeout(() => controller.abort(), 5000); - - const response = await fetch(`/api/room/join`, { - method: "POST", - body: JSON.stringify({ - JoinCode: joinCode.replaceAll("-", ""), - UsernameProposal: "UsernameProposal", - }), - headers: { - "Content-Type": "application/json", - }, - signal: controller.signal, - }); - - clearTimeout(timeout); - - if (!response.ok) { - const data: { StatusCode: string; Message: string } = - await response.json(); - // TODO i18n here on StatusCode if not use Message - if (["invalid_join_code"].includes(data?.StatusCode)) { - join_error = "no_room_found"; - } else if (data?.Message) { - join_error = data?.Message; - } else { - throw new Error("Server error"); - } - return; - } - - const data: { - SessionToken: string; - PlayerId: string; - Username: string; - Permissions: any; - } = await response.json(); - const SessionToken = data.SessionToken; - const UserId = data.PlayerId; - joinSession(SessionToken, UserId); - } catch (error: any) { - if (error.name === "AbortError") { - join_error = "timeout"; - } else { - join_error = "request_failed"; - } - console.error("Error joining room: ", error); - } finally { - loading = false; - setTimeout(() => { - focusInput(); - }, 50); - } - } - - async function requestCreateRoom() { - if (loading) return; - loading = "create"; - create_error = false; - - try { - const controller = new AbortController(); - // 5s timeout - const timeout = setTimeout(() => controller.abort(), 5000); - - const response = await fetch(`/api/room/create`, { - method: "POST", - body: JSON.stringify({ - UsernameProposal: "UsernameProposal", - }), - headers: { - "Content-Type": "application/json", - }, - signal: controller.signal, - }); - - clearTimeout(timeout); - - if (!response.ok) { - throw new Error("Server error"); - } - - const data: - | { - SessionToken: string; - PlayerId: string; - Username: string; - Permissions: any; - } - | { error: string } = await response.json(); - - if (response.ok) { - const SessionToken = data.SessionToken; - const UserId = data.PlayerId; - sessionStore.connect(SessionToken, UserId); - } else { - create_error = data.error || "room_creation_failed"; - } - } catch (error: any) { - if (error.name === "AbortError") { - create_error = "timeout"; - } else { - create_error = String(error); - } - console.error("Error creating room:", error); - } finally { - loading = false; - } - } - function focusInput() { inputRef?.focus(); } - function joinSession(sessionToken: string, userId: string) { - try { - sessionStore.connect(sessionToken, userId); - } catch (error: any) { - join_error = "request_failed"; - console.error("Error joining room session: ", error); - } finally { - loading = false; - setTimeout(() => { - focusInput(); - }, 50); - } - } - - async function checkSessionToken( - sessionToken: string | undefined, - ): Promise { - if (!sessionToken) return false; - const params = new URLSearchParams({ - sessionToken: sessionToken, - }); - const res = await fetch(`/api/check/session?${params}`); - return res.status == 200; - } - - async function checkJoinCode( - joinCode: string | undefined, - ): Promise { - if (!joinCode) return false; - const params = new URLSearchParams({ - JoinCode: joinCode, - }); - const res = await fetch(`/api/check/joinCode?${params}`); - return res.status == 200; - } - - async function checkSessionData() { - const currentSessionData: { - sessionToken?: string; - userId?: string; - joinCode?: string; - } = JSON.parse(localStorage.getItem("currentSessionIds") || "{}"); - if (await checkSessionToken(currentSessionData.sessionToken)) { - // Session is still valid - rejoinRoomSessionData = currentSessionData as any; - return; - } - if (await checkJoinCode(currentSessionData.joinCode)) { - // joinCode is still valid - rejoinRoomCode = currentSessionData.joinCode as string; - return; - } - - const lastSessionData: { - sessionToken?: string; - userId?: string; - joinCode?: string; - } = JSON.parse(localStorage.getItem("lastSessionIds") || "{}"); - - if (await checkSessionToken(lastSessionData.sessionToken)) { - // Session is still valid - rejoinRoomSessionData = lastSessionData as any; - return; - } - if (await checkJoinCode(lastSessionData.joinCode)) { - // joinCode is still valid - rejoinRoomCode = lastSessionData.joinCode as string; - return; - } - } - - // focus room code input on mount onMount(() => { focusInput(); checkSessionData(); @@ -254,19 +56,19 @@
- {#if rejoinRoomSessionData?.sessionToken} + {#if $rejoinRoomSessionData?.sessionToken}
{/if} - {#if rejoinRoomCode} + {#if $rejoinRoomCode}
+
{#if sessionStore.isConnected()} @@ -235,11 +240,11 @@ - {#if sessionStore.getPlayerPermissions().isHost} + {#if sessionStore.getPlayerPermissions().isHost && sessionStore.getState().gameState === GameState.Lobby}