feat(accounts): debts in general words, actions named by what they record
Cards are titled by the account name with the position on its own line: owes you, you owe, settled, and paid back more than borrowed when a debt crossed zero against its direction, so one account per person covers both directions. Actions read Record repayment, Lend more, Pay back, Borrow more and Offset against another debt, which says what it moves. No more friends in the copy; the dashboard box is Debts.
This commit is contained in:
1 parent
4936258f32
commit
54895b9305
11 files changed
+352
-336
No files matched your search
@@ -1,14 +1,11 @@
|
||||
<script lang="ts">
|
||||
import { createQuery, keepPreviousData } from "@tanstack/svelte-query";
|
||||
import { isDebt, owed, stance } from "#lib/accounts/ledger.js";
|
||||
import { editUrl, showUrl } from "#lib/components/accounts/links.js";
|
||||
import Box from "#lib/components/Box.svelte";
|
||||
import { useColumn } from "#lib/dashboard/column.svelte.js";
|
||||
import {
|
||||
formatPrimary,
|
||||
inPrimaryTotal,
|
||||
ratesQuery,
|
||||
} from "#lib/dashboard/primary.svelte.js";
|
||||
import { formatMoney, toNumber } from "#lib/format.js";
|
||||
import { formatMoney } from "#lib/format.js";
|
||||
import { display } from "#lib/money/display.svelte.js";
|
||||
import { period } from "#lib/period.svelte.js";
|
||||
import { goto } from "$app/navigation";
|
||||
import { accountsQuery, byCurrency } from "./data.js";
|
||||
@@ -18,14 +15,10 @@
|
||||
placeholderData: keepPreviousData,
|
||||
}));
|
||||
|
||||
const rates = createQuery(() => ratesQuery());
|
||||
|
||||
const groups = $derived(
|
||||
byCurrency(
|
||||
(liabilities.data ?? []).filter(
|
||||
(a) =>
|
||||
a.attributes.liability_type === "debt" &&
|
||||
toNumber(a.attributes.debt_amount) !== 0
|
||||
(a) => isDebt(a) && stance(a.attributes) !== "settled"
|
||||
),
|
||||
(a) => a.attributes.currency_code ?? ""
|
||||
).map(([code, list]) => {
|
||||
@@ -36,15 +29,12 @@
|
||||
symbol: first.currency_symbol ?? code,
|
||||
};
|
||||
const rows = list
|
||||
.map((a) => {
|
||||
const due = Math.abs(toNumber(a.attributes.debt_amount));
|
||||
return {
|
||||
id: a.id,
|
||||
key: `debt-${a.id}`,
|
||||
name: a.attributes.name,
|
||||
value: a.attributes.liability_direction === "credit" ? due : -due,
|
||||
};
|
||||
})
|
||||
.map((a) => ({
|
||||
id: a.id,
|
||||
key: `debt-${a.id}`,
|
||||
name: a.attributes.name,
|
||||
value: owed(a.attributes),
|
||||
}))
|
||||
.sort((x, y) => y.value - x.value);
|
||||
return {
|
||||
code,
|
||||
@@ -57,18 +47,24 @@
|
||||
);
|
||||
|
||||
const nets = $derived.by(() => {
|
||||
const total = inPrimaryTotal(
|
||||
groups.map((g) => ({ amount: g.net, code: g.code })),
|
||||
rates.data
|
||||
const total = display.total(
|
||||
groups.map((g) => ({ ...g.cur, amount: g.net }))
|
||||
);
|
||||
if (total === null) {
|
||||
return groups.map((g) => ({
|
||||
code: g.code,
|
||||
net: g.net,
|
||||
text: formatMoney({ amount: Math.abs(g.net), ...g.cur }),
|
||||
text: formatMoney({ ...g.cur, amount: Math.abs(g.net) }),
|
||||
}));
|
||||
}
|
||||
return [{ code: "all", net: total, text: formatPrimary(Math.abs(total)) }];
|
||||
const text = formatMoney({ ...total, amount: Math.abs(total.amount) });
|
||||
return [
|
||||
{
|
||||
code: "all",
|
||||
net: total.amount,
|
||||
text: total.converted ? `≈${text}` : text,
|
||||
},
|
||||
];
|
||||
});
|
||||
|
||||
const column = useColumn(4, () =>
|
||||
@@ -91,12 +87,7 @@
|
||||
{/snippet}
|
||||
|
||||
{#if groups.length > 0}
|
||||
<Box
|
||||
body="p-0"
|
||||
footer={more}
|
||||
href="/accounts/liabilities"
|
||||
title="Debts with friends"
|
||||
>
|
||||
<Box body="p-0" footer={more} href="/accounts/liabilities" title="Debts">
|
||||
<div
|
||||
class="flex flex-wrap gap-x-4 gap-y-1 px-3 py-2 transition-opacity {liabilities.isPlaceholderData
|
||||
? "opacity-60"
|
||||
@@ -111,7 +102,7 @@
|
||||
: "text-expense"}"
|
||||
>{g.text}</span
|
||||
>
|
||||
{g.net > 0 ? "owed to me" : "I owe"}</span
|
||||
{g.net > 0 ? "owed to you" : "owed by you"}</span
|
||||
>
|
||||
{/if}
|
||||
{/each}
|
||||
|
||||
Reference in new issue
Block a user