Files
firefly-ui/src/lib/components/accounts/MerchantsTop.svelte
T
hh fffb770cac feat(accounts): merchants and payers as a league table
Expense and revenue accounts list this month per currency, share,
visits, average, twelve months, typical and the change against it, last
visit and category; quiet ones fold into one line behind i. 1 to 5 sort,
; groups by category with subtotals, x and s c set the category on all
of a merchant's transactions in the period.
2026-10-16 15:35:38 +00:00

73 lines
2.2 KiB
Svelte

<script lang="ts">
import type { Kind } from "#lib/accounts/merchants.js";
import { useMerchants } from "#lib/accounts/merchants.svelte.js";
import Box from "#lib/components/Box.svelte";
import { indexUrl } from "./links.js";
import MerchantCell, { type Column } from "./MerchantCell.svelte";
const COLUMNS: Column[] = ["name", "month", "share", "change"];
let { kind, limit = 8 }: { kind: Kind; limit?: number } = $props();
const data = useMerchants(() => kind);
const all = $derived(data.board?.merchants ?? []);
const top = $derived(all.filter((m) => !m.quiet).slice(0, limit));
const href = $derived(indexUrl(kind));
</script>
<Box
body="p-0"
{href}
title={kind === "expense" ? "Where it went" : "Where it came from"}
>
{#if data.error}
<p class="p-3 text-expense">{data.error.message}</p>
{:else if data.board && top.length > 0}
<table class="w-full border-collapse text-[13px]">
<thead class="sr-only">
<tr>
<th scope="col">{kind === "expense" ? "Merchant" : "Payer"}</th>
<th scope="col">This period</th>
<th scope="col">Share</th>
<th scope="col">vs typical</th>
</tr>
</thead>
<tbody>
{#each top as m (m.id)}
<tr
class="border-cladd-outline/60 border-t align-top first:border-t-0"
>
{#each COLUMNS as col (col)}
<td
class="h-7 whitespace-nowrap px-2 py-1 sm:px-3 {col === "name"
? ""
: "text-right"} {col === "share"
? "hidden sm:table-cell"
: ""}"
>
<MerchantCell
{col}
compare={data.day !== null}
{kind}
max={top[0]?.share ?? 0}
merchant={m}
past={data.board.past}
/>
</td>
{/each}
</tr>
{/each}
</tbody>
</table>
{:else if data.board}
<p class="p-3 text-cladd-fg-soft">Nothing in this period.</p>
{:else}
<div class="h-40"></div>
{/if}
{#snippet footer()}
<a class="text-brand dark:text-(--ff-series-1) hover:underline" {href}
>See all {all.length}</a
>
{/snippet}
</Box>