Add persistent cross-game player bank (Refs #146)

This commit is contained in:
2026-10-12 20:21:58 -04:00
parent bcd3b99ee4
commit e071e5b574
14 changed files with 866 additions and 1 deletions
@@ -1,3 +1,4 @@
import { bankProfile } from '$lib/server/fleet/bank.js';
import { error } from '@sveltejs/kit';
import { playerReport } from '$lib/server/reports/index.js';
import { isLeaderboardMetric } from '$lib/server/fleet/leaderboard.js';
@@ -38,6 +39,7 @@ export async function load({ params, url }: { params: { guid: string }; url: URL
if (!profile) error(404, 'Player not found');
return {
profile,
bank: bankProfile(params.guid),
returnTo: leaderboardReturnHref(url.searchParams.get('returnTo')),
scope: { game: game ?? '', map: map ?? '', players: players ?? '', metric, entry }
};
@@ -1,4 +1,5 @@
<script lang="ts">
import type { bankProfile } from '$lib/server/fleet/bank.js';
import Select from '$ui/components/primitives/Select.svelte';
import Field from '$ui/components/primitives/Field.svelte';
import RelativeTime from '$ui/components/RelativeTime.svelte';
@@ -43,6 +44,7 @@
}: {
data: {
profile: PlayerProfile;
bank: ReturnType<typeof bankProfile>;
returnTo: string;
scope: {
game: string;
@@ -162,6 +164,45 @@
description="Stats appear after a game's end report arrives, provided this player was observed at round 2 or later. Games without an end report do not contribute."
/>
{/if}
<section aria-labelledby="bank-title">
<h2 id="bank-title">Bank</h2>
<p>
<strong>{number.format(data.bank.balance)} points</strong> shared across Black Ops I and II.
</p>
{#if data.bank.pending}<p>
A transfer is pending. Available: {number.format(data.bank.available)} points.
</p>{/if}
{#if data.bank.entries.length}
<div class="table-scroll">
<table>
<caption>Recent bank transfers</caption>
<thead
><tr
><th scope="col">Time</th><th scope="col">Server</th><th scope="col"
>Transfer</th
><th scope="col">Balance</th><th scope="col">Match</th></tr
></thead
>
<tbody
>{#each data.bank.entries as entry (entry.id)}
<tr
><td>{$timeFormat.dateTime(entry.createdAt)}</td><td
>{serverTitle(entry.server)}</td
><td>{entry.amount > 0 ? '+' : ''}{number.format(entry.amount)}</td
><td>{number.format(entry.balance)}</td><td
>{#if entry.matchAvailable}<a href={`/matches/${entry.matchId}`}
>#{entry.matchId}</a
>{:else}{entry.matchId
? `#${entry.matchId} (history expired)`
: '—'}{/if}</td
></tr
>
{/each}</tbody
>
</table>
</div>
{:else}<p>No bank transfers yet.</p>{/if}
</section>
<nav class="jump-links" aria-label="Player sections">
<a href="#overview">Overview</a><a href="#maps-title">Maps</a><a href="#history-title"
>Matches</a