// Extended player profile import { Ennoblement, ListResult, Player, TribeChange, TWHelpClient, } from './lib/client'; import { DialogTable } from './common/DialogTable'; const SCREEN = 'info_player'; const MODE = null; const translations: Record> = { pl_PL: { 'Joined at': 'Dołączył o', 'Last activity at': 'Ostatnio aktywny o', 'Best rank': 'Najlepszy ranking', 'Most points': 'Najwięcej punktów', 'Most villages': 'Najwięcej wiosek', 'Show tribe changes': 'Pokaż zmiany plemion', 'Show history': 'Pokaż historię', 'Show ennoblements': 'Pokaż przejęcia', 'Old tribe': 'Stare plemię', 'New tribe': 'Nowe plemię', 'Date/time': 'Data/czas', Village: 'Wioska', 'Old owner': 'Stary właściciel', 'New owner': 'Nowy właściciel', Points: 'Punkty', Barbarian: 'Barbarzyńska', Unknown: 'Nieznany', }, }; const t = (s: string) => { return translations[window.game_data.locale]?.[s] ?? s; }; class TWHelpConnector { constructor( private readonly client: TWHelpClient, private readonly version: string, private readonly server: string, private readonly id: number ) {} player() { return this.client.player(this.version, this.server, this.id); } playerTribeChanges(page: number, limit: number) { return this.client.playerTribeChanges(this.version, this.server, this.id, { offset: (page - 1) * limit, limit: limit, sort: ['createdAt:desc', 'id:asc'], }); } playerEnnoblements(page: number, limit: number) { return this.client.playerEnnoblements(this.version, this.server, this.id, { offset: (page - 1) * limit, limit: limit, sort: ['createdAt:desc'], }); } } enum DialogId { TRIBE_CHANGES = 'kichiyaki_tribe_changes', ENNOBLEMENTS = 'kichiyaki_ennoblements', } interface UIConnector { playerTribeChanges( page: number, limit: number ): Promise>; playerEnnoblements( page: number, limit: number ): Promise>; } class UI { constructor( private readonly player: Player, private readonly connector: UIConnector ) {} public render() { this.renderAdditionalInfo(); this.renderActions(); } private renderAdditionalInfo() { const tbody = document.querySelector('#player_info tbody'); if (!(tbody instanceof HTMLTableSectionElement)) { return; } tbody.insertAdjacentHTML( 'beforeend', ` ${t('Joined at')}: ${new Date(this.player.createdAt).toLocaleString()} ${t('Last activity at')}: ${new Date(this.player.lastActivityAt).toLocaleString()} ${t('Best rank')}: ${this.player.bestRank} (${new Date( this.player.bestRankAt ).toLocaleString()}) ${t('Most points')}: ${this.player.mostPoints.toLocaleString()} (${new Date( this.player.mostPointsAt ).toLocaleString()}) ${t('Most villages')}: ${this.player.mostVillages.toLocaleString()} (${new Date( this.player.mostVillagesAt ).toLocaleString()}) ` ); } private renderActions() { const tbody = document .querySelector('#content_value a[href*="twstats"]') ?.closest('tbody'); if (!(tbody instanceof HTMLTableSectionElement)) { return; } [ { name: t('Show tribe changes'), handler: this.showTribeChanges.bind(this), }, { name: t('Show history'), handler: this.showHistory.bind(this) }, { name: t('Show ennoblements'), handler: this.showEnnoblements.bind(this), }, ].forEach(({ name, handler }) => { const tr = document.createElement('tr'); const td = document.createElement('td'); td.colSpan = 2; const a = document.createElement('a'); a.innerText = name; a.href = '#'; a.addEventListener('click', handler); a.setAttribute('data-player-id', this.player.id.toString()); td.appendChild(a); tr.appendChild(td); tbody.appendChild(tr); }); } private async showTribeChanges(e: Event) { e.preventDefault(); await new DialogTable( DialogId.TRIBE_CHANGES, [ { header: t('Old tribe'), accessor: (tc) => tc.player.tribe ? `${tc.player.tribe.tag}` : '-', }, { header: t('New tribe'), accessor: (tc) => tc.newTribe ? `${tc.newTribe.tag}` : '-', }, { header: t('Date/time'), accessor: (tc) => new Date(tc.createdAt).toLocaleString(), }, ], 30, (page: number, limit: number) => { return this.connector.playerTribeChanges(page, limit); } ).render(); } private showHistory(e: Event) { e.preventDefault(); } private async showEnnoblements(e: Event) { e.preventDefault(); await new DialogTable( DialogId.ENNOBLEMENTS, [ { header: t('Village'), accessor: (e) => `${e.village.fullName}`, }, { header: t('Points'), accessor: (e) => e.points.toLocaleString(), }, { header: t('Old owner'), accessor: (e) => e.oldOwner ? `${e.oldOwner.name}${ e.oldOwner.tribe ? ` (${e.oldOwner.tribe.tag})` : '' }` : t('Barbarian'), }, { header: t('New owner'), accessor: (e) => e.newOwner ? `${e.newOwner.name}${ e.newOwner.tribe ? ` (${e.newOwner.tribe.tag})` : '' }` : t('Unknown'), }, { header: t('Date/time'), accessor: (e) => new Date(e.createdAt).toLocaleString(), }, ], 30, (page: number, limit: number) => { return this.connector.playerEnnoblements(page, limit); } ).render(); } } class ExtendedPlayerProfile { connector: TWHelpConnector; constructor(client: TWHelpClient) { this.connector = new TWHelpConnector( client, window.game_data.market, window.game_data.world, this.getPlayerId() ); } async render() { const player = await this.connector.player(); new UI(player, this.connector).render(); } private getPlayerId() { const str = new URLSearchParams(window.location.search).get('id'); if (!str) { return window.game_data.player.id; } return parseInt(str); } } (async () => { if (window.game_data.screen !== SCREEN || window.game_data.mode !== MODE) { return; } await new ExtendedPlayerProfile( new TWHelpClient(process.env.TWHELP_API_BASE_URL ?? '') ).render(); })();