Guild bank: in-game commands, guild market listings and purchases, shop sales to the bank, guild payments

This commit is contained in:
Claude committed 2026-09-30 17:57:58 +00:00
1 parent 5defda1128
commit e6c6073eae
14 files changed
+680 -82

No files matched your search

+14 -9
View File
@@ -8,7 +8,7 @@
import { toast } from '../lib/store.svelte';
import type { Guild, GuildMember } from '../lib/types';
type Tx = { id: number; actor_uuid: string; kind: 'deposit' | 'withdraw'; amount: number; created_at: string };
type Tx = { id: number; actor_uuid: string; kind: string; amount: number; created_at: string; note?: string };
type WalletData = { balance: number; my_balance?: number; role?: string; currency_symbol?: string; transactions: Tx[] };
let { guild, members, servers, instanceId }: {
@@ -36,9 +36,14 @@
const overLimit = $derived(validAmount && limit != null && value > limit + 1e-9);
const afterGuild = $derived(wallet && validAmount ? wallet.balance + (mode === 'deposit' ? value : -value) : null);
const afterMine = $derived(wallet?.my_balance != null && validAmount ? wallet.my_balance + (mode === 'deposit' ? -value : value) : null);
// Money the guild receives (deposits, shop and market sales, payments from guilds) vs. spends.
const isOut = (kind: string) => kind === 'withdraw' || kind === 'purchase' || kind === 'transfer_out';
const verbs: Record<string, string> = {
deposit: 'deposited', withdraw: 'withdrew', sale: 'sold items', purchase: 'bought', transfer_in: 'received a payment', transfer_out: 'paid a guild'
};
const totals = $derived({
in: wallet?.transactions.filter((t) => t.kind === 'deposit').reduce((n, t) => n + t.amount, 0) ?? 0,
out: wallet?.transactions.filter((t) => t.kind === 'withdraw').reduce((n, t) => n + t.amount, 0) ?? 0
in: wallet?.transactions.filter((t) => !isOut(t.kind)).reduce((n, t) => n + t.amount, 0) ?? 0,
out: wallet?.transactions.filter((t) => isOut(t.kind)).reduce((n, t) => n + t.amount, 0) ?? 0
});
const quick = [10, 50, 100, 500, 1000];
@@ -136,8 +141,8 @@
</div>
<div class="amount">{money(shown)}</div>
<div class="t-stats">
<div><span class="k"><TrendingUp size={12} /> Deposited</span><strong class="in">{money(totals.in)}</strong></div>
<div><span class="k"><ArrowUpFromLine size={12} /> Withdrawn</span><strong class="out">{money(totals.out)}</strong></div>
<div><span class="k"><TrendingUp size={12} /> Money in</span><strong class="in">{money(totals.in)}</strong></div>
<div><span class="k"><ArrowUpFromLine size={12} /> Money out</span><strong class="out">{money(totals.out)}</strong></div>
<div><span class="k"><Wallet size={12} /> Your wallet</span><strong>{wallet.my_balance != null ? money(wallet.my_balance) : '—'}</strong></div>
</div>
<p class="t-note tiny">Totals cover the last {wallet.transactions.length} transfers.</p>
@@ -203,15 +208,15 @@
{#each wallet.transactions as tx (tx.id)}
{@const m = who(tx.actor_uuid)}
<li>
<span class="ic" class:out={tx.kind === 'withdraw'}>
{#if tx.kind === 'withdraw'}<ArrowUpFromLine size={14} />{:else}<ArrowDownToLine size={14} />{/if}
<span class="ic" class:out={isOut(tx.kind)}>
{#if isOut(tx.kind)}<ArrowUpFromLine size={14} />{:else}<ArrowDownToLine size={14} />{/if}
</span>
<Avatar uuid={tx.actor_uuid} name={m?.name ?? '?'} size={1.7} />
<div class="who">
<strong>{m?.name ?? 'Former member'}</strong>
<span class="tiny muted">{tx.kind === 'withdraw' ? 'withdrew' : 'deposited'} · {ago(tx.created_at)}</span>
<span class="tiny muted" title={tx.note}>{verbs[tx.kind] ?? tx.kind}{tx.note ? ` · ${tx.note}` : ''} · {ago(tx.created_at)}</span>
</div>
<span class="amt" class:out={tx.kind === 'withdraw'}>{tx.kind === 'withdraw' ? '−' : '+'}{money(tx.amount)}</span>
<span class="amt" class:out={isOut(tx.kind)}>{isOut(tx.kind) ? '−' : '+'}{money(tx.amount)}</span>
</li>
{/each}
</ul>