import { html, LitElement } from "lit"; import { customElement, property, query, state } from "lit/decorators.js"; import { GameEndInfo } from "../core/Schemas"; import { GameMapType } from "../core/game/Game"; import { fetchGameById } from "./Api"; import { terrainMapFileLoader } from "./TerrainMapFileLoader"; import { UsernameInput } from "./UsernameInput"; import { renderDuration, translateText } from "./Utils"; import { PlayerInfo, Ranking, RankType, } from "./components/baseComponents/ranking/GameInfoRanking"; import "./components/baseComponents/ranking/PlayerRow"; import "./components/baseComponents/ranking/RankingControls"; import "./components/baseComponents/ranking/RankingHeader"; @customElement("game-info-modal") export class GameInfoModal extends LitElement { @query("o-modal") private modalEl!: HTMLElement & { open: () => void; close: () => void; }; @state() private mapImage: string | null = null; @state() private gameInfo: GameEndInfo | null = null; @state() private rankedPlayers: Array = []; @property({ type: String }) gameId: string | null = null; @property({ type: String }) rankType = RankType.Lifetime; @state() private username: string | null = null; @state() private isLoadingGame: boolean = true; private ranking: Ranking | null = null; connectedCallback() { super.connectedCallback(); this.updateRanking(); } createRenderRoot() { return this; } render() { return html`
${this.isLoadingGame ? this.renderLoadingAnimation() : this.renderRanking()}
`; } private renderRanking() { if (this.rankedPlayers.length === 0) { return html`

❌ ${translateText("game_info_modal.no_winner")}

`; } return html` ${this.renderGameInfo()} ${this.renderSummaryTable()} `; } private renderLoadingAnimation() { return html`

${translateText("game_info_modal.loading_game_info")}

`; } private sort(e: CustomEvent) { this.rankType = e.detail; this.updateRanking(); } private updateRanking() { if (this.ranking) { this.rankedPlayers = this.ranking.sortedBy(this.rankType); } } private renderGameInfo() { const info = this.gameInfo; if (!info) { return html``; } return html`
${this.mapImage ? html`` : html`
`}
${info.config.gameMode} ${info.config.gameMap}
${renderDuration(info.duration)}
${info.players.length} ${translateText("game_info_modal.players")}
`; } private renderSummaryTable() { const bestScore = this.rankedPlayers.length > 0 ? this.score(this.rankedPlayers[0]) : 0; return html` `; } public open() { this.modalEl?.open(); } public close() { this.modalEl?.close(); } private score(player: PlayerInfo): number { if (!this.ranking) return 0; return this.ranking.score(player, this.rankType); } private async loadMapImage(gameMap: string) { try { const mapType = gameMap as GameMapType; const data = terrainMapFileLoader.getMapData(mapType); this.mapImage = data.webpPath; } catch (error) { console.error("Failed to load map image:", error); } } public loadUserName() { const usernameInput = document.querySelector( "username-input", ) as UsernameInput; if (usernameInput) { this.username = usernameInput.getCurrentUsername(); } } public async loadGame(gameId: string) { try { this.isLoadingGame = true; this.loadUserName(); const session = await fetchGameById(gameId); if (!session) return; this.gameInfo = session.info; this.ranking = new Ranking(session); this.updateRanking(); this.isLoadingGame = false; await this.loadMapImage(session.info.config.gameMap); } catch (err) { console.error("Failed to load game:", err); } finally { this.isLoadingGame = false; } } }