frontend: stacked-area NW history chart on the dashboard
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
First end-to-end view: ECharts stacked area of net worth by account over the last 365 days, fed from GET /networth/history. - NetWorthChart component with empty-state fallback - Mocked ReactECharts in tests so they run without a DOM canvas - Dashboard now: headline NW + history chart + per-account cards Bundle grew to 467 KB gzipped — ECharts is heavy by design. Will tree-shake via echarts/core imports once the chart surface stabilises. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
f4539f9e6d
commit
5d2b9e931a
3 changed files with 141 additions and 2 deletions
|
|
@ -1,14 +1,23 @@
|
|||
/**
|
||||
* Dashboard — landing page. Wire up gets fleshed out in Phase 1a.
|
||||
* For now: confirm we can reach /networth and render today's NW.
|
||||
* Dashboard — net worth at a glance.
|
||||
*
|
||||
* Three sections, top to bottom:
|
||||
* 1. Headline NW total (latest snapshot)
|
||||
* 2. Stacked-area history chart (per-account, /networth/history)
|
||||
* 3. Per-account cards (latest values, /networth)
|
||||
*/
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { api } from '@/api/client';
|
||||
import { NetWorthChart } from '@/components/NetWorthChart';
|
||||
import { gbp } from '@/lib/format';
|
||||
|
||||
export function Dashboard() {
|
||||
const nw = useQuery({ queryKey: ['networth', 'current'], queryFn: api.networth.current });
|
||||
const history = useQuery({
|
||||
queryKey: ['networth', 'history', 365],
|
||||
queryFn: () => api.networth.history(365),
|
||||
});
|
||||
|
||||
if (nw.isLoading) {
|
||||
return <p className="text-slate-500">Loading net worth…</p>;
|
||||
|
|
@ -45,10 +54,23 @@ export function Dashboard() {
|
|||
<h1 className="text-3xl font-semibold tracking-tight">Net worth</h1>
|
||||
<p className="text-sm text-slate-500">As of {data.snapshot_date}</p>
|
||||
</header>
|
||||
|
||||
<div className="rounded-lg border border-slate-200 bg-white p-6">
|
||||
<div className="text-4xl font-semibold tabular-nums">{gbp(data.total_gbp)}</div>
|
||||
<p className="text-sm text-slate-500 mt-1">{data.accounts.length} accounts</p>
|
||||
</div>
|
||||
|
||||
<div className="rounded-lg border border-slate-200 bg-white p-6">
|
||||
<h2 className="text-lg font-semibold mb-4">Last 12 months</h2>
|
||||
{history.isLoading ? (
|
||||
<p className="text-sm text-slate-500">Loading…</p>
|
||||
) : history.isError || !history.data ? (
|
||||
<p className="text-sm text-slate-500">History unavailable.</p>
|
||||
) : (
|
||||
<NetWorthChart history={history.data} />
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
{data.accounts.map((a) => (
|
||||
<div
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue