aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIlion Beyst <ilion.beyst@gmail.com>2022-10-30 16:23:18 +0100
committerIlion Beyst <ilion.beyst@gmail.com>2022-10-30 16:23:35 +0100
commit8d556bbff1bd716c2c42c8002706038f28b55b91 (patch)
tree4d0ae186430d3c927faeb8919cbddaebbf532541
parentf429adb4f8607ef9b8b8e2c9fa3634c5f39a5602 (diff)
downloadplanetwars.dev-8d556bbff1bd716c2c42c8002706038f28b55b91.tar.xz
planetwars.dev-8d556bbff1bd716c2c42c8002706038f28b55b91.zip
add filtering and infinite scroll to BotMatches
-rw-r--r--web/pw-server/src/lib/components/matches/BotMatchList.svelte73
-rw-r--r--web/pw-server/src/routes/bots/[bot_name]/matches.svelte53
2 files changed, 100 insertions, 26 deletions
diff --git a/web/pw-server/src/lib/components/matches/BotMatchList.svelte b/web/pw-server/src/lib/components/matches/BotMatchList.svelte
index 959cd07..4a00909 100644
--- a/web/pw-server/src/lib/components/matches/BotMatchList.svelte
+++ b/web/pw-server/src/lib/components/matches/BotMatchList.svelte
@@ -1,19 +1,84 @@
<script lang="ts">
- import type { BotMatch } from "$lib/matches";
+ import { ApiClient } from "$lib/api_client";
+ import { apiMatchtoBotMatch, BotMatch } from "$lib/matches";
+ import { onDestroy, onMount } from "svelte";
import BotMatchCard from "./BotMatchCard.svelte";
- export let botMatches: BotMatch[];
+ export let botName: string;
+ export let opponentName: string | undefined;
+ export let mapName: string | undefined;
- function match_url(match: object) {
- return `/matches/${match["id"]}`;
+ let botMatches: BotMatch[] = [];
+ let nextCursor = undefined;
+ let loading = false;
+ let hasMore = true;
+
+ onMount(async () => {
+ window.addEventListener("scroll", onScroll);
+ window.addEventListener("resize", onScroll);
+ });
+
+ onDestroy(() => {
+ window.removeEventListener("scroll", onScroll);
+ window.removeEventListener("resize", onScroll);
+ });
+
+ function onScroll(e: Event) {
+ // const element = e.target as HTMLElement;
+ const element = window.document.body;
+ if (hasMore && element.scrollHeight - window.scrollY - element.clientHeight <= 300) {
+ fetchNextPage();
+ }
+ }
+
+ async function fetchNextPage() {
+ if (loading) {
+ return;
+ }
+ loading = true;
+ const params = { bot: botName, count: "50" };
+ if (opponentName) {
+ params["opponent"] = opponentName;
+ }
+ if (mapName) {
+ params["map"] = mapName;
+ }
+ if (nextCursor) {
+ params["before"] = nextCursor;
+ }
+ const apiClient = new ApiClient();
+ let { matches, has_next } = await apiClient.get("/api/matches", params);
+ if (has_next) {
+ nextCursor = matches[matches.length - 1]["timestamp"];
+ } else {
+ hasMore = false;
+ }
+ botMatches = botMatches.concat(matches.map((m) => apiMatchtoBotMatch(botName, m)));
+ loading = false;
}
+
+ async function resetList(..._params: any[]) {
+ botMatches = [];
+ nextCursor = undefined;
+ hasMore = true;
+ await fetchNextPage();
+ }
+
+ $: resetList(botName, opponentName, mapName);
</script>
<div>
{#each botMatches as botMatch}
<BotMatchCard {botMatch} />
{/each}
+ {#if loading}
+ <div class="loading-container">Loading...</div>
+ {/if}
</div>
<style lang="scss">
+ .loading-container {
+ text-align: center;
+ padding: 16px;
+ }
</style>
diff --git a/web/pw-server/src/routes/bots/[bot_name]/matches.svelte b/web/pw-server/src/routes/bots/[bot_name]/matches.svelte
index a3c97cb..979054c 100644
--- a/web/pw-server/src/routes/bots/[bot_name]/matches.svelte
+++ b/web/pw-server/src/routes/bots/[bot_name]/matches.svelte
@@ -1,26 +1,21 @@
<script lang="ts" context="module">
import { ApiClient } from "$lib/api_client";
- import type { Match } from "$lib/api_types";
-
- const PAGE_SIZE = "50";
export async function load({ params, fetch }) {
try {
const apiClient = new ApiClient(fetch);
const botName = params["bot_name"];
- let { matches, has_next } = await apiClient.get("/api/matches", { bot: botName });
-
- // TODO: should this be done client-side?
- // if (query["after"]) {
- // matches = matches.reverse();
- // }
+ const [allBots, allMaps] = await Promise.all([
+ apiClient.get("/api/bots"),
+ apiClient.get("/api/maps"),
+ ]);
return {
props: {
- matches,
botName,
- hasNext: has_next,
+ allBots,
+ allMaps,
},
};
} catch (error) {
@@ -33,20 +28,35 @@
</script>
<script lang="ts">
- import LinkButton from "$lib/components/LinkButton.svelte";
import BotMatchList from "$lib/components/matches/BotMatchList.svelte";
- import { apiMatchtoBotMatch } from "$lib/matches";
+ import Select from "svelte-select";
- export let matches: Match[];
- export let botName: string | null;
- // whether a next page exists in the current iteration direction (before/after)
- // export let hasNext: boolean;
+ export let botName: string;
+ export let allBots: object[];
+ export let allMaps: object[];
- $: botMatches = matches.map((match) => apiMatchtoBotMatch(botName, match));
+ let opponentName: string | undefined;
+ let mapName: string | undefined;
</script>
<div class="container">
- <BotMatchList {botMatches} />
+ <div class="selections">
+ <Select
+ items={allBots}
+ placeholder="Select opponent"
+ label="name"
+ itemId="name"
+ bind:justValue={opponentName}
+ />
+ <Select
+ items={allMaps}
+ placeholder="Select map"
+ label="name"
+ itemId="name"
+ bind:justValue={mapName}
+ />
+ </div>
+ <BotMatchList {botName} {opponentName} {mapName} />
</div>
<style lang="scss">
@@ -56,9 +66,8 @@
width: 100%;
}
- .page-controls {
+ .selections {
display: flex;
- justify-content: center;
- margin: 24px 0;
+ padding: 16px 4px;
}
</style>