mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-23 21:16:21 +00:00
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:
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user