From 1dadb5bc73974b583e42662f02d62954b59959b1 Mon Sep 17 00:00:00 2001 From: Mattia Migliorini Date: Wed, 21 Jan 2026 05:32:59 +0100 Subject: [PATCH] Change join-changed event listener to fix Game Replay functionality (#2968) Resolves #2967 ## Description: The "Replay" action on recent games doesn't work anymore after the release of v29. The problem arises because `AccountModal.viewGame()` correctly calls `history.pushState()` with the game URL and then dispatches the `join-changed` event. The `join-changed` event listener in `Main.ts` calls `onHashUpdate()`, which first calls `JoinPrivateLobbyModal.close()` and then handles the new URL. The problem is that `JoinPrivateLobbyModal.onClose()` resets the modal UI, but also replaces the history state with `/`, therefore `handleUrl()` receives the homepage URL instead of the game URL. This PR fixes the above by creating a dedicated callback for the `join-changed` event (which is dispatched only by `AccountModal` ATM), skipping the `JoinPrivateLobbyModal.close()` call. ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced ## Please put your Discord username so you can be contacted if a bug or regression is found: deshack_82603 --- src/client/Main.ts | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/client/Main.ts b/src/client/Main.ts index baa592bab..8858b2f43 100644 --- a/src/client/Main.ts +++ b/src/client/Main.ts @@ -588,12 +588,8 @@ class Client { const onHashUpdate = () => { // Reset the UI to its initial state this.joinModal?.close(); - if (this.gameStop !== null) { - this.handleLeaveLobby(); - } - // Attempt to join lobby - this.handleUrl(); + onJoinChanged(); }; const onPopState = () => { @@ -627,10 +623,19 @@ class Client { } }; + const onJoinChanged = () => { + if (this.gameStop !== null) { + this.handleLeaveLobby(); + } + + // Attempt to join lobby + this.handleUrl(); + }; + // Handle browser navigation & manual hash edits window.addEventListener("popstate", onPopState); window.addEventListener("hashchange", onHashUpdate); - window.addEventListener("join-changed", onHashUpdate); + window.addEventListener("join-changed", onJoinChanged); function updateSliderProgress(slider: HTMLInputElement) { const percent =