import { html } from "lit"; import { customElement, state } from "lit/decorators.js"; import Countries from "resources/countries.json" with { type: "json" }; import { UserMeResponse } from "src/core/ApiSchemas"; import { assetUrl } from "src/core/AssetUrls"; import { Cosmetics, Flag } from "src/core/CosmeticSchemas"; import { UserSettings } from "src/core/game/UserSettings"; import { getUserMe } from "./Api"; import { fetchCosmetics, flagRelationship, ResolvedCosmetic, } from "./Cosmetics"; import { translateText } from "./Utils"; import { BaseModal } from "./components/BaseModal"; import "./components/CosmeticButton"; import "./components/NotLoggedInWarning"; import { modalHeader } from "./components/ui/ModalHeader"; function countryFlag(name: string, code: string): Flag { return { name, url: assetUrl(`/flags/${code}.svg`), product: null, rarity: "common", affiliateCode: null, }; } @customElement("flag-input-modal") export class FlagInputModal extends BaseModal { @state() private search = ""; @state() private cosmetics: Cosmetics | null = null; @state() private userMe: UserMeResponse | false = false; public returnTo = ""; updated(changedProperties: Map) { super.updated(changedProperties); } private renderFlags() { const userSettings = new UserSettings(); const selectedFlag = userSettings.getFlag() ?? ""; const cosmeticFlags = Object.entries(this.cosmetics?.flags ?? {}) .filter(([, flag]) => { if (!this.includedInSearch({ name: flag.name, code: flag.name })) return false; return flagRelationship(flag, this.userMe, null) === "owned"; }) .map(([key, flag]) => { const r: ResolvedCosmetic = { type: "flag", cosmetic: flag, colorPalette: null, relationship: "owned", key: `flag:${key}`, }; return html` { this.setFlag(`flag:${key}`); this.close(); }} > `; }); const noFlagResolved: ResolvedCosmetic = { type: "flag", cosmetic: countryFlag("None", "xx"), colorPalette: null, relationship: "owned", key: "country:xx", }; const noFlag = this.search ? null : html` { this.setFlag("country:xx"); this.close(); }} > `; const countryFlags = Countries.filter( (country) => country.code !== "xx" && !country.restricted && this.includedInSearch(country), ).map((country) => { const r: ResolvedCosmetic = { type: "flag", cosmetic: countryFlag(country.name, country.code), colorPalette: null, relationship: "owned", key: `country:${country.code}`, }; return html` { this.setFlag(`country:${country.code}`); this.close(); }} > `; }); return html`
${noFlag} ${cosmeticFlags} ${countryFlags}
`; } render() { const content = html`
${modalHeader({ title: translateText("flag_input.title"), onBack: () => this.close(), ariaLabel: translateText("common.back"), rightContent: html``, })}
${this.renderFlags()}
`; if (this.inline) { return content; } return html` ${content} `; } private includedInSearch(country: { name: string; code: string }): boolean { return ( country.name.toLowerCase().includes(this.search.toLowerCase()) || country.code.toLowerCase().includes(this.search.toLowerCase()) ); } private handleSearch(event: Event) { this.search = (event.target as HTMLInputElement).value; } private setFlag(flag: string) { new UserSettings().setFlag(flag); } protected async onOpen(): Promise { [this.cosmetics, this.userMe] = await Promise.all([ fetchCosmetics(), getUserMe().then((r) => r || (false as const)), ]); } protected onClose(): void { this.search = ""; if (this.returnTo) { const returnEl = document.querySelector(this.returnTo) as any; if (returnEl?.open) { returnEl.open(); } this.returnTo = ""; } } }