diff options
Diffstat (limited to 'web/pw-server/src/routes/matches/index.svelte')
-rw-r--r-- | web/pw-server/src/routes/matches/index.svelte | 129 |
1 files changed, 107 insertions, 22 deletions
diff --git a/web/pw-server/src/routes/matches/index.svelte b/web/pw-server/src/routes/matches/index.svelte index 448048b..8c106fa 100644 --- a/web/pw-server/src/routes/matches/index.svelte +++ b/web/pw-server/src/routes/matches/index.svelte @@ -1,36 +1,121 @@ <script lang="ts" context="module"> - export async function load() { - const res = await fetch("/api/matches", { - headers: { - "Content-Type": "application/json", - }, - }); + import { ApiClient } from "$lib/api_client"; + + const PAGE_SIZE = "50"; + + export async function load({ url, fetch }) { + try { + const apiClient = new ApiClient(fetch); + const botName = url.searchParams.get("bot"); + + let query = { + count: PAGE_SIZE, + before: url.searchParams.get("before"), + after: url.searchParams.get("after"), + bot: botName, + }; + + let { matches, has_next } = await apiClient.get("/api/matches", removeUndefined(query)); + + // TODO: should this be done client-side? + if (query["after"]) { + matches = matches.reverse(); + } - if (res.ok) { return { props: { - matches: await res.json(), + matches, + botName, + hasNext: has_next, + query, }, }; + } catch (error) { + return { + status: error.status, + error: new Error("failed to load matches"), + }; } + } - return { - status: res.status, - error: new Error("failed to load matches"), - }; + function removeUndefined(obj: Record<string, string>): Record<string, string> { + Object.keys(obj).forEach((key) => { + if (obj[key] === undefined || obj[key] === null) { + delete obj[key]; + } + }); + return obj; } </script> <script lang="ts"> - import dayjs from "dayjs"; - export let matches; + import LinkButton from "$lib/components/LinkButton.svelte"; + import MatchList from "$lib/components/matches/MatchList.svelte"; + + export let matches: object[]; + export let botName: string | null; + // whether a next page exists in the current iteration direction (before/after) + export let hasNext: boolean; + export let query: object; + + type Cursor = { + before?: string; + after?: string; + }; + + function pageLink(cursor: Cursor) { + let paramsObj = { + ...cursor, + }; + if (botName) { + paramsObj["bot"] = botName; + } + const params = new URLSearchParams(paramsObj); + return `?${params}`; + } + + function olderMatchesLink(matches: object[]): string { + if (matches.length == 0 || (query["before"] && !hasNext)) { + return null; + } + const lastTimestamp = matches[matches.length - 1]["timestamp"]; + return pageLink({ before: lastTimestamp }); + } + + function newerMatchesLink(matches: object[]): string { + if ( + matches.length == 0 || + (query["after"] && !hasNext) || + // we are viewing the first page, so there should be no newer matches. + // alternatively, we could show a "refresh" here. + (!query["before"] && !query["after"]) + ) { + return null; + } + const firstTimestamp = matches[0]["timestamp"]; + return pageLink({ after: firstTimestamp }); + } </script> -<a href="/matches/new">new match</a> -<ul> - {#each matches as match} - <li> - <a href="/matches/{match['id']}">{dayjs(match["created_at"]).format("YYYY-MM-DD HH:mm")}</a> - </li> - {/each} -</ul> +<div class="container"> + <MatchList {matches} /> + <div class="page-controls"> + <div class="btn-group"> + <LinkButton href={newerMatchesLink(matches)}>Newer</LinkButton> + <LinkButton href={olderMatchesLink(matches)}>Older</LinkButton> + </div> + </div> +</div> + +<style lang="scss"> + .container { + width: 800px; + margin: 0 auto; + } + + .page-controls { + display: flex; + justify-content: center; + margin: 24px 0; + } +</style> |