From af3fffae4310bd1aa1efef7ad074b314ffd979c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dawid=20Wysoki=C5=84ski?= Date: Tue, 2 Apr 2024 08:24:02 +0200 Subject: [PATCH] refactor: extended village profile - use /api/v2 --- postbuild.js | 2 +- src/common/dialog-table-v2.ts | 132 +++++++++++++++++++++++++++ src/extended-map-popup.user.ts | 2 +- src/extended-village-profile.user.ts | 59 +++++++----- 4 files changed, 169 insertions(+), 26 deletions(-) create mode 100644 src/common/dialog-table-v2.ts diff --git a/postbuild.js b/postbuild.js index 2097491..4cf9f2d 100644 --- a/postbuild.js +++ b/postbuild.js @@ -31,7 +31,7 @@ const metadata = { // ==/UserScript==`, 'extended-village-profile': `// ==UserScript== // @name Extended village profile -// @version 1.0.4 +// @version 1.1.0 // @description Adds additional info and actions on a village overview. // @author Dawid Wysokiński - Kichiyaki - contact@twhelp.app // @match https://*/game.php?*screen=info_village* diff --git a/src/common/dialog-table-v2.ts b/src/common/dialog-table-v2.ts new file mode 100644 index 0000000..2cee4d3 --- /dev/null +++ b/src/common/dialog-table-v2.ts @@ -0,0 +1,132 @@ +import { createTranslationFunc } from '../utils'; + +const t = createTranslationFunc({ + pl_PL: { + Loading: 'Wczytywanie', + 'Previous page': 'Poprzednia strona', + 'Next page': 'Następna strona', + 'Something went wrong while loading the data': + 'Coś poszło nie tak podczas wczytywania danych', + }, +}); + +export type DialogTableColumn = { + header: string; + accessor: (row: T, index: number, rows: T[]) => string; +}; + +export type Cursor = { + next?: string; + self?: string; +}; + +export type LoadDataResult = { + cursor?: Cursor; + data: T[]; +}; + +export class DialogTableV2 { + private readonly prevPageId: string; + private readonly nextPageId: string; + + private readonly prevCursors: Cursor[] = []; + + constructor( + private readonly id: string, + private readonly columns: DialogTableColumn[], + private readonly limit: number, + private readonly loadData: ( + cursor: string | undefined, + limit: number + ) => Promise> + ) { + this.prevPageId = `${this.id}_page_prev`; + this.nextPageId = `${this.id}_page_next`; + } + + public async render() { + await this.renderPage(); + } + + private async renderPage(pageCursor?: string) { + window.Dialog.show(this.id, `

${t('Loading')}...

`); + + try { + const { data, cursor } = await this.loadData(pageCursor, this.limit); + + window.Dialog.show( + this.id, + ` + ${this.buildPagination(cursor)} + ${this.buildTable(data)} + ` + ); + + this.addEventListeners(cursor); + } catch (err) { + console.error(err); + window.Dialog.close(); + window.UI.ErrorMessage(t('Something went wrong while loading the data')); + } + } + + private buildPagination(cursor?: Cursor): string { + return ` +
+ + +
+ `; + } + + private buildTable(data: T[]) { + return ` + + + + ${this.columns.map((col) => ``).join('')} + + ${data + .map( + (r, index) => ` + + ${this.columns + .map((col) => ``) + .join('')} + + ` + ) + .join('')} + +
${col.header}
${col.accessor(r, index, data)}
+ `; + } + + private addEventListeners(cursor?: Cursor) { + document + .querySelector('#' + this.prevPageId) + ?.addEventListener('click', () => { + const prev = this.prevCursors.pop(); + if (!prev) { + return; + } + this.renderPage(prev.self); + }); + + document + .querySelector('#' + this.nextPageId) + ?.addEventListener('click', () => { + if (!cursor) { + return; + } + this.prevCursors.push(cursor); + this.renderPage(cursor.next); + }); + } +} diff --git a/src/extended-map-popup.user.ts b/src/extended-map-popup.user.ts index 74d875e..c85e8b6 100644 --- a/src/extended-map-popup.user.ts +++ b/src/extended-map-popup.user.ts @@ -55,7 +55,7 @@ class TWHelpConnector { private readonly client: TWHelpV2Client; constructor( - private readonly baseUrl: string, + readonly baseUrl: string, private readonly version: string, private readonly server: string ) { diff --git a/src/extended-village-profile.user.ts b/src/extended-village-profile.user.ts index 50e33a2..ada0e4f 100644 --- a/src/extended-village-profile.user.ts +++ b/src/extended-village-profile.user.ts @@ -1,8 +1,8 @@ -import { Ennoblement, ServerConfig, TWHelpClient } from './lib/twhelp'; import { createTranslationFunc } from './utils'; -import { DialogTable } from './common/dialog-table'; import { calcLoyalty } from './lib/tw'; import { Cache } from './lib/cache'; +import { TWHelpV2Client, Ennoblement, ServerConfig } from './lib/twhelpv2'; +import { DialogTableV2 } from './common/dialog-table-v2'; const t = createTranslationFunc({ pl_PL: { @@ -22,32 +22,42 @@ const t = createTranslationFunc({ class TWHelpConnector { private static SERVER_CONFIG_CACHE_KEY = - 'extended_village_profile_server_config'; + 'extended_village_profile_server_config_v2'; private cache = new Cache(localStorage); + + private client: TWHelpV2Client; + constructor( - private readonly client: TWHelpClient, + readonly baseUrl: string, private readonly version: string, private readonly server: string, private readonly id: number - ) {} + ) { + this.client = new TWHelpV2Client({ BASE: baseUrl }); + } serverConfig() { return this.cache.load( TWHelpConnector.SERVER_CONFIG_CACHE_KEY, 3600, - () => { - return this.client.serverConfig(this.version, this.server); + async () => { + return ( + await this.client.servers.getServerConfig({ + versionCode: this.version, + serverKey: this.server, + }) + ).data; } ); } async latestEnnoblement() { - const ennoblements = await this.client.villageEnnoblements( - this.version, - this.server, - this.id, + const ennoblements = await this.client.ennoblements.listVillageEnnoblements( { + versionCode: this.version, + serverKey: this.server, + villageId: this.id, limit: 1, sort: ['createdAt:DESC'], } @@ -55,11 +65,14 @@ class TWHelpConnector { return ennoblements.data.length > 0 ? ennoblements.data[0] : null; } - villageEnnoblements(page: number, limit: number) { - return this.client.villageEnnoblements(this.version, this.server, this.id, { - offset: (page - 1) * limit, - limit, - sort: ['createdAt:desc'], + villageEnnoblements(cursor: string | undefined, limit: number) { + return this.client.ennoblements.listVillageEnnoblements({ + cursor, + versionCode: this.version, + serverKey: this.server, + villageId: this.id, + limit: limit, + sort: ['createdAt:DESC'], }); } } @@ -138,7 +151,7 @@ class UI { private async showEnnoblements(e: Event) { e.preventDefault(); - await new DialogTable( + await new DialogTableV2( DialogId.ENNOBLEMENTS, [ { @@ -182,8 +195,8 @@ class UI { }, ], 30, - (page: number, limit: number) => { - return this.connector.villageEnnoblements(page, limit); + async (cursor, limit) => { + return this.connector.villageEnnoblements(cursor, limit); } ).render(); } @@ -191,9 +204,9 @@ class UI { class ExtendedVillageProfile { connector: TWHelpConnector; - constructor(client: TWHelpClient) { + constructor(apiBaseUrl: string) { this.connector = new TWHelpConnector( - client, + apiBaseUrl, window.game_data.market, window.game_data.world, this.getVillageId() @@ -226,9 +239,7 @@ class ExtendedVillageProfile { return; } - await new ExtendedVillageProfile( - new TWHelpClient(process.env.TWHELP_API_BASE_URL ?? '') - ) + await new ExtendedVillageProfile(process.env.TWHELP_API_BASE_URL ?? '') .run() .catch((err) => { console.log(err);