feat(dashboard): morning page, compact accounts, what the bot entered, next 7 days
The right column drops the box per account for one table per currency with sparklines and the last five transactions on l, a list of what was entered since the last look (x marks reviewed), bills and piggy bank dates in the next seven days, and debts with friends net per currency. The left column opens with spending so far against a typical month, and $ shows totals in UAH.
This commit is contained in:
1 parent
cea51281cd
commit
8c4e72666b
11 files changed
+1452
-312
No files matched your search
+59
-60
@@ -1,93 +1,92 @@
|
||||
<script lang="ts">
|
||||
import { createQuery, keepPreviousData } from "@tanstack/svelte-query";
|
||||
import AccountBox from "#lib/components/dashboard/AccountBox.svelte";
|
||||
import { createQuery } from "@tanstack/svelte-query";
|
||||
import AccountsBlock from "#lib/components/dashboard/AccountsBlock.svelte";
|
||||
import AccountsChart from "#lib/components/dashboard/AccountsChart.svelte";
|
||||
import BudgetsChart from "#lib/components/dashboard/BudgetsChart.svelte";
|
||||
import CategoriesChart from "#lib/components/dashboard/CategoriesChart.svelte";
|
||||
import DebtsBox from "#lib/components/dashboard/DebtsBox.svelte";
|
||||
import {
|
||||
accountsChartQuery,
|
||||
accountsQuery,
|
||||
seriesPoints,
|
||||
} from "#lib/components/dashboard/data.js";
|
||||
import DueBox from "#lib/components/dashboard/DueBox.svelte";
|
||||
import { accountsQuery } from "#lib/components/dashboard/data.js";
|
||||
import InboxBox from "#lib/components/dashboard/InboxBox.svelte";
|
||||
import InfoBoxes from "#lib/components/dashboard/InfoBoxes.svelte";
|
||||
import InsightBox from "#lib/components/dashboard/InsightBox.svelte";
|
||||
import PaceBox from "#lib/components/dashboard/PaceBox.svelte";
|
||||
import PiggyBanksBox from "#lib/components/dashboard/PiggyBanksBox.svelte";
|
||||
import SubscriptionsBox from "#lib/components/dashboard/SubscriptionsBox.svelte";
|
||||
import PageHeader from "#lib/components/shell/PageHeader.svelte";
|
||||
import { today } from "#lib/dates.js";
|
||||
import Checkbox from "#lib/components/ui/checkbox/checkbox.svelte";
|
||||
import { provideColumn } from "#lib/dashboard/column.svelte.js";
|
||||
import { inPrimary, ratesQuery } from "#lib/dashboard/primary.svelte.js";
|
||||
import { useKeys } from "#lib/keys.svelte.js";
|
||||
import { period } from "#lib/period.svelte.js";
|
||||
import { session } from "#lib/session.svelte.js";
|
||||
|
||||
const assets = createQuery(() => ({
|
||||
...accountsQuery("asset", period.start, period.end),
|
||||
placeholderData: keepPreviousData,
|
||||
}));
|
||||
const chart = createQuery(() => ({
|
||||
...accountsChartQuery(period.start, period.end),
|
||||
placeholderData: keepPreviousData,
|
||||
}));
|
||||
provideColumn();
|
||||
|
||||
const frontpage = $derived.by(() => {
|
||||
const list = (assets.data ?? [])
|
||||
.filter((a) => a.attributes.active !== false)
|
||||
.sort((a, b) => (a.attributes.order ?? 0) - (b.attributes.order ?? 0));
|
||||
if (!("frontpageAccounts" in session.prefs)) {
|
||||
return list;
|
||||
}
|
||||
const ids = new Set(session.frontpageAccounts);
|
||||
return list.filter((a) => ids.has(a.id));
|
||||
});
|
||||
const rates = createQuery(() => ratesQuery());
|
||||
const primary = $derived(session.primary?.code ?? "");
|
||||
const ownRates = $derived(
|
||||
inPrimary.on && Object.values(rates.data ?? {}).some((r) => r.own)
|
||||
);
|
||||
|
||||
const trends = $derived(
|
||||
new Map(
|
||||
(chart.data ?? []).map((set) => {
|
||||
const points = seriesPoints(set, false);
|
||||
return [
|
||||
set.label,
|
||||
{
|
||||
marker: points.findIndex((p) => p.x === today()),
|
||||
values: points.map((p) => p.y),
|
||||
},
|
||||
];
|
||||
})
|
||||
)
|
||||
useKeys(() => [
|
||||
{
|
||||
group: "Dashboard",
|
||||
keys: "$",
|
||||
label: `Show totals in ${primary}`,
|
||||
run: () => inPrimary.toggle(),
|
||||
},
|
||||
]);
|
||||
|
||||
const assets = createQuery(() =>
|
||||
accountsQuery("asset", period.start, period.end)
|
||||
);
|
||||
|
||||
$effect(() => {
|
||||
if (
|
||||
assets.isSuccess &&
|
||||
!assets.isPlaceholderData &&
|
||||
assets.data.length === 0
|
||||
) {
|
||||
if (assets.isSuccess && assets.data.length === 0) {
|
||||
location.assign("/new-user");
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<PageHeader subtitle="What's playing?" title="Dashboard" />
|
||||
<PageHeader subtitle="What's playing?" title="Dashboard">
|
||||
{#snippet actions()}
|
||||
<div class="flex items-center gap-1.5 text-[12px] text-cladd-fg-soft">
|
||||
<Checkbox
|
||||
checked={inPrimary.on}
|
||||
id="in-primary"
|
||||
onCheckedChange={() => inPrimary.toggle()}
|
||||
/>
|
||||
<label for="in-primary">Show in {primary}</label>
|
||||
<span class="hidden sm:inline"><span class="kbd">$</span></span>
|
||||
{#if ownRates}
|
||||
<span>≈ from your own exchanges</span>
|
||||
{/if}
|
||||
</div>
|
||||
{/snippet}
|
||||
</PageHeader>
|
||||
|
||||
<InfoBoxes />
|
||||
|
||||
<div class="mt-3 grid gap-3 lg:grid-cols-12">
|
||||
<div class="flex min-w-0 flex-col gap-3 lg:col-span-8">
|
||||
<div
|
||||
class="mt-3 grid gap-3 xl:grid-cols-[minmax(0,1fr)_minmax(25rem,36%)] xl:grid-rows-[auto_1fr]"
|
||||
>
|
||||
<PaceBox class="xl:col-start-1" />
|
||||
<div
|
||||
class="flex min-w-0 flex-col gap-3 xl:col-start-2 xl:row-span-2 xl:row-start-1"
|
||||
>
|
||||
<AccountsBlock />
|
||||
<InboxBox />
|
||||
<DueBox />
|
||||
<DebtsBox />
|
||||
<SubscriptionsBox />
|
||||
<PiggyBanksBox />
|
||||
</div>
|
||||
<div class="flex min-w-0 flex-col gap-3 self-start xl:col-start-1">
|
||||
<AccountsChart />
|
||||
<BudgetsChart />
|
||||
<CategoriesChart />
|
||||
</div>
|
||||
<div class="flex min-w-0 flex-col gap-3 lg:col-span-4">
|
||||
{#each frontpage as account (account.id)}
|
||||
{@const trend = trends.get(account.attributes.name)}
|
||||
<AccountBox
|
||||
{account}
|
||||
marker={trend?.marker ?? -1}
|
||||
trend={trend?.values ?? []}
|
||||
/>
|
||||
{/each}
|
||||
<SubscriptionsBox />
|
||||
<PiggyBanksBox />
|
||||
<DebtsBox />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 flex flex-col gap-3">
|
||||
|
||||
Reference in new issue
Block a user