79 lines
3.9 KiB
Svelte
79 lines
3.9 KiB
Svelte
<script lang="ts">
|
|
import type { AfkSession } from '$lib/afk.js';
|
|
import { contextHref } from '$lib/navigation-context.js';
|
|
import { formatDuration } from '$ui/duration.js';
|
|
import { timeFormat } from '$ui/stores/time-zone.js';
|
|
import ServerIdentity from '../ServerIdentity.svelte';
|
|
|
|
let { entries, source }: { entries: AfkSession[]; source: URL } = $props();
|
|
const duration = (seconds: number) => formatDuration(seconds * 1000);
|
|
const label = (value: string) => value.replaceAll('_', ' ');
|
|
</script>
|
|
|
|
<!-- svelte-ignore a11y_no_noninteractive_tabindex (Keyboard users need to scroll wide tables.) -->
|
|
<div class="afk-table-scroll" role="region" aria-label="AFK sessions" tabindex="0">
|
|
<table class="afk-table">
|
|
<caption class="sr-only">AFK session reservations and outcomes</caption>
|
|
<thead
|
|
><tr
|
|
><th scope="col">Player</th><th scope="col">Session</th><th scope="col">Time</th><th
|
|
scope="col">Outcome</th
|
|
><th scope="col">Server / match</th></tr
|
|
></thead
|
|
>
|
|
<tbody>
|
|
{#each entries as session (session.sessionId)}
|
|
<tr>
|
|
<td
|
|
><a
|
|
class="afk-player"
|
|
href={contextHref(
|
|
`/leaderboard/players/${encodeURIComponent(session.guid)}`,
|
|
source
|
|
)}>{session.name ?? session.guid}</a
|
|
><small class="afk-id">{session.guid}</small></td
|
|
>
|
|
<td
|
|
><time datetime={session.createdAt}
|
|
>{$timeFormat.dateTime(session.createdAt)}</time
|
|
><small
|
|
>{session.startedAt
|
|
? `Started ${$timeFormat.dateTime(session.startedAt)}`
|
|
: 'Start unconfirmed'}</small
|
|
><small class="afk-id">{session.sessionId}</small></td
|
|
>
|
|
<td class="afk-number"
|
|
><strong
|
|
>{session.consumedSeconds === null
|
|
? 'Unconfirmed duration'
|
|
: `${duration(session.consumedSeconds)} used`}</strong
|
|
><small>{duration(session.authorizedSeconds)} authorized</small
|
|
>{#if session.state === 'corrected' && session.chargedSeconds !== null}<small
|
|
>Corrected charge: {duration(session.chargedSeconds)}</small
|
|
>{/if}{#if session.consumedSeconds === null && session.confirmedSeconds > 0}<small
|
|
>Confirmed at least {duration(session.confirmedSeconds)}</small
|
|
>{/if}</td
|
|
>
|
|
<td
|
|
><span class:afk-warning={session.state === 'unresolved'}
|
|
>{label(session.state)}</span
|
|
>{#if session.endReason}<small>{label(session.endReason)}</small
|
|
>{/if}{#if session.endedAt}<small
|
|
>{$timeFormat.dateTime(session.endedAt)}</small
|
|
>{/if}</td
|
|
>
|
|
<td
|
|
><ServerIdentity name={session.server} /><small
|
|
>{#if session.matchAvailable && session.matchId}<a
|
|
href={contextHref(`/matches/${session.matchId}`, source)}
|
|
>Match #{session.matchId}</a
|
|
>{:else if session.matchId}Match #{session.matchId} · History expired{:else}No
|
|
match history{/if}</small
|
|
></td
|
|
>
|
|
</tr>
|
|
{/each}
|
|
</tbody>
|
|
</table>
|
|
</div>
|