diff options
author | Ilion Beyst <ilion.beyst@gmail.com> | 2022-10-30 16:23:18 +0100 |
---|---|---|
committer | Ilion Beyst <ilion.beyst@gmail.com> | 2022-10-30 16:23:35 +0100 |
commit | 8d556bbff1bd716c2c42c8002706038f28b55b91 (patch) | |
tree | 4d0ae186430d3c927faeb8919cbddaebbf532541 | |
parent | f429adb4f8607ef9b8b8e2c9fa3634c5f39a5602 (diff) | |
download | planetwars.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.svelte | 73 | ||||
-rw-r--r-- | web/pw-server/src/routes/bots/[bot_name]/matches.svelte | 53 |
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> |