Skip to content

Conversation

@Skigim
Copy link
Contributor

@Skigim Skigim commented Feb 5, 2026

Description:

Adds a "Play Again" requeue button to the victory/defeat modal for Ranked 1v1 games. When clicked, it navigates the player back to the homepage and automatically opens the matchmaking modal to queue for another ranked match.

Changes:

  • WinModal.ts: Added isRankedGame state, purple "Play Again" button (only shown for ranked 1v1), and _handleRequeue() method
  • Main.ts: Added ?requeue URL parameter handling to trigger matchmaking modal on page load
  • en.json: Added "requeue": "Play Again" translation string
  • added tests to WinModal.test.ts

Note: temporarily set isRanked flag to true to get the modal to pop in a solo match on dev server and confirmed that ?requeue URL parameter called _handleRequeue() correctly, which opened the sign in process since actually signing in and queuing for a ranked match isn't possible on dev server.

play-again

Please complete the following:

  • I have added screenshots for all UI updates
  • I process any text displayed to the user through translateText() and I've added it to the en.json file
  • I have added relevant tests to the test directory
  • 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:

skigim

@Skigim Skigim requested a review from a team as a code owner February 5, 2026 00:08
Copilot AI review requested due to automatic review settings February 5, 2026 00:08
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 5, 2026

Walkthrough

Win modal gains a ranked "Play Again" (requeue) button for 1v1 ranked games; clicking it navigates to "/?requeue". App startup detects requeue on load, strips it, waits for the matchmaking element, and invokes its open() to start matchmaking.

Changes

Cohort / File(s) Summary
Translations
resources/lang/en.json
Add win_modal.requeue = "Play Again".
Startup flow
src/client/Main.ts
On load detect requeue query param, remove it from URL, wait for the matchmaking-button custom element, and trigger its open()/click to start matchmaking.
Win modal UI & logic
src/client/graphics/layers/WinModal.ts
Add isRankedGame state, detect RankedType.OneVOne when showing modal, render conditional Requeue button, add _handleRequeue() to navigate to /?requeue and hide modal.
Matchmaking API
src/client/Matchmaking.ts
Change MatchmakingButton.open() visibility from private to public so external callers can invoke it.
Tests
tests/client/graphics/layers/WinModal.test.ts
New Vitest suite: mocks utilities and SDK, tests ranked detection, requeue navigation (window.location.href), and requeue query handling; resets mocks between tests.

Sequence Diagram

sequenceDiagram
    participant Player
    participant WinModal
    participant Main
    participant Matchmaking

    Player->>WinModal: Win game (1v1 ranked)
    WinModal->>WinModal: detect RankedType.OneVOne\nset isRankedGame = true
    WinModal->>Player: render "Play Again" button

    Player->>WinModal: click "Play Again"
    WinModal->>WinModal: navigate browser to "/?requeue" and hide modal

    Main->>Main: on load detect "?requeue"\nstrip param from URL
    Main->>Matchmaking: wait for `matchmaking-button` defined\ncall its `open()`
    Matchmaking->>Player: open matchmaking UI
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🏆 A ranked win, a joyful cheer,
Click "Play Again" and shift the gear,
A tiny query leads the way,
From victory back to queue today. 🎮

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: adding a requeue button to the ranked victory/defeat modal, matching the changeset precisely.
Description check ✅ Passed The description is directly related to the changeset, providing clear context about the feature, listing all modified files, and explaining the implementation approach and testing.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request adds a "Play Again" requeue button to the victory/defeat modal for Ranked 1v1 games, allowing players to quickly queue for another ranked match after their game ends.

Changes:

  • Added requeue button to WinModal that navigates to homepage with a ?requeue parameter
  • Implemented URL parameter handler in Main.ts to automatically open matchmaking modal on page load
  • Added translation key for the button text
  • Added basic tests for the requeue functionality

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
src/client/graphics/layers/WinModal.ts Adds isRankedGame state to detect ranked 1v1 games, renders purple "Play Again" button when applicable, and implements _handleRequeue method to navigate with requeue parameter
src/client/Main.ts Adds URL parameter handler to detect ?requeue parameter and automatically open matchmaking modal with 500ms delay and fallback to button click
resources/lang/en.json Adds "requeue": "Play Again" translation string to win_modal section
tests/client/graphics/layers/WinModal.test.ts Adds tests for ranked game detection, navigation behavior, and URL parameter parsing (though tests don't actually test the WinModal component itself)

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@tests/client/graphics/layers/WinModal.test.ts`:
- Around line 1-3: Prettier formatting in the test file
tests/client/graphics/layers/WinModal.test.ts is failing CI; run the formatter
to fix whitespace and import ordering issues by executing npx prettier --write
tests/client/graphics/layers/WinModal.test.ts, then review the imports (e.g.,
the top-level imports of describe/expect/it/vi/beforeEach/afterEach and
RankedType) for any remaining style problems, stage the formatted file, and
commit the changes.
- Around line 29-34: The mock for crazyGamesSDK used in the test is missing the
gameplayStop function which WinModal.show() invokes; update the vi.mock export
for crazyGamesSDK to include gameplayStop: vi.fn() (matching the same shape as
happytime and requestAd) so tests calling WinModal.show() won't fail due to a
missing function.
🧹 Nitpick comments (2)
src/client/Main.ts (1)

758-777: Consider making the timeout delay configurable or adding a comment explaining the choice.

The 500ms delay is a magic number. A brief comment explaining why this value was chosen (e.g., waiting for DOM/components to be ready) would help future maintainers.

Also, the fallback selector "matchmaking-button button" assumes the internal DOM structure of the matchmaking button component. If that component changes, this fallback could silently fail.

💡 Suggested improvements
     // Handle requeue parameter for ranked matchmaking
     const searchParams = new URLSearchParams(window.location.search);
     if (searchParams.has("requeue")) {
       // Remove the requeue parameter from URL
       history.replaceState(null, "", "/");
-      // Open matchmaking modal after a short delay to ensure page is ready
+      // Open matchmaking modal after a short delay to ensure components are rendered.
+      // 500ms chosen empirically to allow Lit components to complete their update cycle.
       setTimeout(() => {
         // Try to open the matchmaking modal directly first
         if (this.matchmakingModal) {
           this.matchmakingModal.open();
         } else {
-          // Fallback: simulate a click on the matchmaking button
-          const matchmakingButton = document.querySelector(
-            "matchmaking-button button",
-          ) as HTMLButtonElement;
-          matchmakingButton?.click();
+          // Fallback: find and click the matchmaking button element
+          const matchmakingButtonEl = document.querySelector(
+            "matchmaking-button",
+          ) as HTMLElement & { click?: () => void };
+          if (matchmakingButtonEl) {
+            const innerButton = matchmakingButtonEl.querySelector("button") as HTMLButtonElement;
+            innerButton?.click();
+          }
         }
       }, 500);
     }
tests/client/graphics/layers/WinModal.test.ts (1)

61-103: Tests verify logic patterns but don't test actual component behavior.

These tests re-implement the handler logic instead of invoking the actual WinModal methods. While they document the expected behavior, they won't catch bugs if the component implementation changes.

Consider adding tests that:

  1. Instantiate WinModal
  2. Set game mock with different rankedType values
  3. Call show() and verify isRankedGame state
  4. Verify button visibility based on state
💡 Example of a more integrated test approach
describe("WinModal component", () => {
  it("should set isRankedGame to true for ranked 1v1", async () => {
    const modal = new WinModal();
    modal.game = {
      config: () => ({
        gameConfig: () => ({ rankedType: RankedType.OneVOne }),
      }),
      // ... other required mocks
    } as any;
    
    await modal.show();
    
    expect(modal["isRankedGame"]).toBe(true);
  });
});

@github-project-automation github-project-automation bot moved this from Triage to Development in OpenFront Release Management Feb 5, 2026
- Replace 500ms setTimeout with customElements.whenDefined()
- Add console.warn when matchmaking button not found
- Remove dead matchmakingModal code path (always null)
- Add gameplayStop to CrazyGamesSDK mock
- Fix Prettier formatting in test file
@Skigim Skigim marked this pull request as draft February 5, 2026 00:43
coderabbitai[bot]
coderabbitai bot previously approved these changes Feb 5, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/client/Main.ts`:
- Around line 759-776: The requeue path bypasses the button's username
validation and clobbers other URL params/hash; instead of calling
MatchmakingButton.open() directly and history.replaceState(null, "", "/"),
remove only the "requeue" key from the URLSearchParams and reconstruct the URL
as location.pathname + (params.toString() ? "?" + params.toString() : "") +
location.hash then call history.replaceState(null, "", newUrl); and, to reuse
the button's validation, trigger the existing button handler (e.g., dispatch a
click or call the same validation method on the MatchmakingButton) rather than
invoking open() directly so invalid usernames are blocked the same way as the
normal button.

@Skigim Skigim marked this pull request as ready for review February 5, 2026 03:00
- Changed open() from private to public in MatchmakingButton
- Requeue triggers button click to go through username validation
- Only removes 'requeue' param, preserves other URL params and hash
- Addresses PR review about fragile selector and validation bypass
@Skigim Skigim force-pushed the feature/ranked-requeue-button branch from 7775b1a to 60c34f1 Compare February 5, 2026 03:52
@github-project-automation github-project-automation bot moved this from Triage to Final Review in OpenFront Release Management Feb 7, 2026
@evanpelle evanpelle merged commit 32adfa2 into openfrontio:main Feb 7, 2026
8 of 9 checks passed
@github-project-automation github-project-automation bot moved this from Final Review to Complete in OpenFront Release Management Feb 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: Complete

Development

Successfully merging this pull request may close these issues.

3 participants