feat(reports): live firefly reports with drill-down, money flow and spending calendar
This commit is contained in:
1 parent
60caee10dc
commit
62cd17ecde
39 files changed
+6596
No files matched your search
@@ -0,0 +1,73 @@
|
||||
<script lang="ts">
|
||||
import { createQuery } from "@tanstack/svelte-query";
|
||||
import Box from "#lib/components/Box.svelte";
|
||||
import {
|
||||
AUDIT_COLUMNS,
|
||||
type AuditColumn,
|
||||
DEFAULT_AUDIT,
|
||||
} from "#lib/reports/audit.js";
|
||||
import { reportQueries } from "#lib/reports/queries.js";
|
||||
import { navigate, useReport } from "#lib/reports/report.svelte.js";
|
||||
import { page } from "$app/state";
|
||||
import AuditAccount from "./AuditAccount.svelte";
|
||||
|
||||
const report = useReport();
|
||||
const p = $derived(report.params);
|
||||
const balances = createQuery(() => reportQueries.balances(p.start, p.end));
|
||||
|
||||
const columns = $derived.by(() => {
|
||||
const raw = page.url.searchParams.get("cols");
|
||||
if (raw === null) {
|
||||
return DEFAULT_AUDIT;
|
||||
}
|
||||
const keys = new Set(raw.split(","));
|
||||
return AUDIT_COLUMNS.map((c) => c.key).filter((key) => keys.has(key));
|
||||
});
|
||||
const accounts = $derived(
|
||||
report.selected
|
||||
.map((id) => ({ account: report.byId().get(id), id }))
|
||||
.filter((a) => a.account)
|
||||
.sort((a, b) =>
|
||||
(a.account?.name ?? "").localeCompare(b.account?.name ?? "")
|
||||
)
|
||||
);
|
||||
|
||||
function toggle(key: AuditColumn, on: boolean) {
|
||||
const next = AUDIT_COLUMNS.map((c) => c.key).filter((k) =>
|
||||
k === key ? on : columns.includes(k)
|
||||
);
|
||||
navigate({ cols: next.join(",") });
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col gap-4">
|
||||
<Box body="px-3 py-2" title="Options">
|
||||
<fieldset class="flex flex-wrap gap-x-4 gap-y-1">
|
||||
<legend class="sr-only">Visible columns</legend>
|
||||
{#each AUDIT_COLUMNS as column (column.key)}
|
||||
<label class="flex h-7 items-center gap-1.5 text-[13px]">
|
||||
<input
|
||||
checked={columns.includes(column.key)}
|
||||
class="size-3.5 accent-[var(--ff-brand)]"
|
||||
onchange={(event) =>
|
||||
toggle(column.key, event.currentTarget.checked)}
|
||||
type="checkbox"
|
||||
>
|
||||
{column.label}
|
||||
</label>
|
||||
{/each}
|
||||
</fieldset>
|
||||
</Box>
|
||||
{#if !report.accountsReady}
|
||||
<p class="text-cladd-fg-soft">Loading</p>
|
||||
{/if}
|
||||
{#each accounts as item (item.id)}
|
||||
<AuditAccount
|
||||
account={item.account}
|
||||
after={balances.data?.after.get(item.id)}
|
||||
before={balances.data?.before.get(item.id)}
|
||||
{columns}
|
||||
id={item.id}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
Reference in new issue
Block a user