diff --git a/src/features/home/DashboardView.tsx b/src/features/home/DashboardView.tsx index 6ae8c3c..28b8b96 100644 --- a/src/features/home/DashboardView.tsx +++ b/src/features/home/DashboardView.tsx @@ -3,10 +3,10 @@ import * as React from "react"; import Link from "next/link"; import { Skeleton, ProgressCircleRoot, ProgressCircleTrack, ProgressCircleRange } from "@seed-design/react"; -import { Card, AmountToggle, HideAmountsToggle } from "../../ds"; +import { Card, AmountToggle, HideAmountsToggle, IconChip, SectionHeader, EmptyState, categoryStyle } from "../../ds"; import { tugrikShortRaw } from "../../ds/money"; import { useNetWorth, useAnalyzeMonth, useAnalyzeToday, useBudget } from "../../api/hooks/reads"; -import { buildHome, type HomeData } from "./buildHome"; +import { buildHome, type HomeData, type LedgerRow as LedgerRowData } from "./buildHome"; import { sample } from "./sample"; import { homeStrings as s } from "./strings"; @@ -42,6 +42,56 @@ function TugrikCircle({ bg, fg }: { bg: string; fg: string }) { ); } +/** One Орлого/Зарлага row: an IconChip (income → the wallet/green "income" + * style; expense → the payee's category style, falling back to a neutral + * receipt when unknown) + the payee name + a trailing colored amount. + * Mirrors TransactionList's TxnRow pattern. */ +function LedgerEntryRow({ row, income }: { row: LedgerRowData; income: boolean }) { + const cat = categoryStyle(income ? undefined : row.date, income); + return ( +
+
+ + + {row.date} + +
+ + {income ? "+" : "−"} + {row.title} + +
+ ); +} + +/** Skeleton placeholder for a ledger row, shaped like `LedgerEntryRow` so the + * layout doesn't jump once real data (or the sample fallback) arrives — + * avoids flashing the sample payee/amount as if it were a real loaded row. */ +function LedgerRowSkeleton() { + return ( +
+ + +
+ ); +} + /** The Нүүр (home) dashboard: header, safe-to-spend hero, daily-limit + * top budgets, this-month spend, and recent income/expense. Figures come * from `buildHome` (real where the backend has them, `sample` otherwise). @@ -66,6 +116,14 @@ export function DashboardView() { const fraction = budgetDenominator > 0 ? Math.min(1, data.monthlyExpense / budgetDenominator) : 0; const dailyFraction = data.dailyLimitTotal > 0 ? Math.min(1, data.dailyLimitUsed / data.dailyLimitTotal) : 0; + // Genuinely sparse month: real backend data loaded (`built` succeeded, so + // this isn't the full pre-connection sample), but no discretionary spend + // and no real income/expense payees this month — show a designed empty + // state instead of the sample ledger placeholders standing in as if real. + const noRealPayees = + (monthQ.data?.incomePayees?.length ?? 0) === 0 && (monthQ.data?.expensePayees?.length ?? 0) === 0; + const sparseMonth = built !== null && data.monthlyExpense === 0 && noRealPayees; + return (
@@ -84,21 +142,21 @@ export function DashboardView() { color: "var(--mercury-on-brand)", background: "var(--mercury-balance-card)", borderRadius: "var(--seed-radius-r5, 20px)", - padding: "14px 20px", + padding: "18px 20px", }} > -
+
-
- {data.overspent ? s.overspent : s.safeToSpend} - +
+ {data.overspent ? s.overspent : s.safeToSpend} +
-
- {s.spent} +
+ {s.spent} - / {tugrikShortRaw(budgetDenominator)} + / {tugrikShortRaw(budgetDenominator)}
@@ -132,30 +190,30 @@ export function DashboardView() { color: "#fff", background: "var(--mercury-limit-card)", borderRadius: "var(--seed-radius-r5, 20px)", - padding: "14px 20px", + padding: "18px 20px", }} > -
+
-
- {s.dailyLimit} - +
+ {s.dailyLimit} + {" / "}
-
+
{s.todaySpent}:
-
+
{data.budgets.map((b) => ( -
- {b.name} +
+ {b.name} @@ -200,24 +258,37 @@ export function DashboardView() { {/* Recent income / expense ledgers. */}
- - {s.income} - {data.income.map((row, i) => ( -
- {row.title} - {row.date} -
- ))} -
- - {s.expense} - {data.expense.map((row, i) => ( -
- {row.title} - {row.date} -
- ))} -
+ {loading ? ( + <> + + + + + + + + + + ) : sparseMonth ? ( + + + + ) : ( + <> + + + {data.income.map((row, i) => ( + + ))} + + + + {data.expense.map((row, i) => ( + + ))} + + + )}
diff --git a/src/features/home/sample.ts b/src/features/home/sample.ts index a0fa349..f129a1d 100644 --- a/src/features/home/sample.ts +++ b/src/features/home/sample.ts @@ -18,8 +18,8 @@ export const sample: HomeData = { ], monthlyExpense, availableBudget, - income: [{ title: "1,345,634₮", date: "04.01" }], - expense: [{ title: "худалдан авалт", date: "04.01" }], + income: [{ title: "1,345,634₮", date: "Цалин" }], + expense: [{ title: "52,000₮", date: "Худалдан авалт" }], safeToSpend: Math.max(0, availableBudget - monthlyExpense), overspent: monthlyExpense > availableBudget, }; diff --git a/src/features/home/strings.ts b/src/features/home/strings.ts index f9e398e..3e95cd4 100644 --- a/src/features/home/strings.ts +++ b/src/features/home/strings.ts @@ -13,4 +13,6 @@ export const homeStrings = { income: "Орлого", expense: "Зарлага", todaySpent: "Өнөөдөр зарцуулсан", + noSpendTitle: "Энэ сар хараахан зарлага алга", + noSpendHint: "Гүйлгээ хийгдмэгц энд харагдана.", } as const;