stats button on clan games history (#4628)

## Description:

adds stats button to clan games tab 

<img width="1011" height="660" alt="image"
src="https://github.com/user-attachments/assets/fe39f000-6da9-4f1b-9a20-62e8177e6fdb"
/>


## 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

## Please put your Discord username so you can be contacted if a bug or
regression is found:

w.o.n
This commit is contained in:
Ryan
2026-07-17 10:20:32 -07:00
committed by GitHub
parent f070d4843d
commit c4447cd434
5 changed files with 348 additions and 16 deletions
+49
View File
@@ -75,6 +75,12 @@ export class ClanModal extends BaseModal {
// selection and accumulated scroll on the previous clan. Keyed-by-tag
// would persist across hops if that becomes desired.
private gameHistoryCache: ClanGameHistoryCache | null = null;
private gameHistoryScrollTop = 0;
// Moving to the dedicated stats page closes this inline modal. These
// one-shot flags keep that close/open pair from clearing or reloading the
// clan detail that the stats Back button returns to.
private preserveStateForGameStats = false;
private returningFromGameStats = false;
private previousListTab: ListTab = "my-clans";
private get onListView(): boolean {
@@ -206,6 +212,10 @@ export class ClanModal extends BaseModal {
}
protected onOpen(args?: Record<string, unknown>): void {
if (this.returningFromGameStats) {
this.returningFromGameStats = false;
return;
}
const targetTag =
typeof args?.clan === "string"
? args.clan.trim()
@@ -219,6 +229,7 @@ export class ClanModal extends BaseModal {
}
protected onClose(): void {
if (this.preserveStateForGameStats) return;
this.activeTab = "my-clans";
this.previousListTab = "my-clans";
this.view = "list";
@@ -228,6 +239,8 @@ export class ClanModal extends BaseModal {
this.browseCache = null;
this.detailCache = null;
this.gameHistoryCache = null;
this.gameHistoryScrollTop = 0;
this.returningFromGameStats = false;
}
private async loadMyClans(opts: { allowGuest?: boolean } = {}) {
@@ -370,6 +383,8 @@ export class ClanModal extends BaseModal {
@history-updated=${(e: CustomEvent<ClanGameHistoryCache>) => {
this.gameHistoryCache = e.detail;
}}
@view-stats=${(e: CustomEvent<{ gameId: string }>) =>
this.openGameStats(e.detail.gameId)}
@close-clan-modal=${() => this.close()}
></clan-game-history-view>`;
}
@@ -502,6 +517,40 @@ export class ClanModal extends BaseModal {
this.setActiveTab("overview");
}
private openGameStats(gameId: string): void {
const statsModal = document.querySelector<
HTMLElement & { openFromClan(gameId: string): void }
>("game-stats-modal");
if (!statsModal) return;
this.gameHistoryScrollTop = this.modalEl?.getScrollTop() ?? 0;
this.preserveStateForGameStats = true;
try {
statsModal.openFromClan(gameId);
} finally {
this.preserveStateForGameStats = false;
}
}
public returnToGameHistory(): void {
const tag = this.selectedClanTag;
if (!tag) return;
this.returningFromGameStats = true;
this.open({ clan: tag, tab: "game-history" });
void this.restoreGameHistoryScroll();
}
private async restoreGameHistoryScroll(): Promise<void> {
await this.updateComplete;
await this.modalEl?.updateComplete;
const historyView = this.querySelector<
HTMLElement & { updateComplete?: Promise<boolean> }
>("clan-game-history-view");
await historyView?.updateComplete;
this.modalEl?.setScrollTop(this.gameHistoryScrollTop);
}
private renderMyClans() {
const hasClans = this.myClans.length > 0;
const hasRequests = this.myPendingRequests.length > 0;
+20 -9
View File
@@ -10,7 +10,7 @@ export class GameStatsModal extends BaseModal {
protected routerName = "stats";
@state() private gameId: string | null = null;
private openedFromAccount = false;
private openedFrom: "account" | "clan" | null = null;
protected renderHeaderSlot() {
return modalHeader({
@@ -39,21 +39,32 @@ export class GameStatsModal extends BaseModal {
protected onClose(): void {
this.gameId = null;
this.openedFromAccount = false;
this.openedFrom = null;
}
public openFromAccount(gameId: string): void {
this.openedFromAccount = true;
this.openedFrom = "account";
this.open({ gameID: gameId });
}
public openFromClan(gameId: string): void {
this.openedFrom = "clan";
this.open({ gameID: gameId });
}
private back(): void {
const returnToAccount = this.openedFromAccount;
const openedFrom = this.openedFrom;
this.close();
if (!returnToAccount) return;
document
.querySelector<HTMLElement & { returnToGames(): void }>("account-modal")
?.returnToGames();
if (openedFrom === "account") {
document
.querySelector<HTMLElement & { returnToGames(): void }>("account-modal")
?.returnToGames();
} else if (openedFrom === "clan") {
document
.querySelector<
HTMLElement & { returnToGameHistory(): void }
>("clan-modal")
?.returnToGameHistory();
}
}
}
@@ -197,6 +197,16 @@ export class ClanGameHistoryView extends LitElement {
}
}
private showStats(gameId: string) {
this.dispatchEvent(
new CustomEvent<{ gameId: string }>("view-stats", {
detail: { gameId },
bubbles: true,
composed: true,
}),
);
}
render() {
if (this.loadState === "forbidden") {
return html`
@@ -423,13 +433,22 @@ export class ClanGameHistoryView extends LitElement {
.showVisibilityToggle=${false}
></copy-button>
</div>
<button
type="button"
@click=${() => this.watchReplay(game.gameId)}
class="shrink-0 px-3 py-1.5 text-xs font-bold text-white uppercase tracking-wider bg-malibu-blue hover:bg-aquarius active:bg-malibu-blue/80 rounded-lg transition-all"
>
${translateText("clan_modal.history_watch_replay")}
</button>
<div class="flex items-center gap-2 shrink-0">
<button
type="button"
@click=${() => this.showStats(game.gameId)}
class="px-3 py-1.5 text-xs font-bold text-white/80 uppercase tracking-wider bg-white/10 hover:bg-white/20 border border-white/10 rounded-lg transition-colors"
>
${translateText("game_list.stats")}
</button>
<button
type="button"
@click=${() => this.watchReplay(game.gameId)}
class="px-3 py-1.5 text-xs font-bold text-white uppercase tracking-wider bg-malibu-blue hover:bg-aquarius active:bg-malibu-blue/80 rounded-lg transition-all"
>
${translateText("clan_modal.history_watch_replay")}
</button>
</div>
</div>
<div
class="px-4 py-3 grid grid-cols-2 sm:grid-cols-3 gap-x-4 gap-y-2 justify-items-center text-center"