"use client"; 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 { tugrikShortRaw } from "../../ds/money"; import { useNetWorth, useAnalyzeMonth, useAnalyzeToday, useBudget } from "../../api/hooks/reads"; import { buildHome, type HomeData } from "./buildHome"; import { sample } from "./sample"; import { homeStrings as s } from "./strings"; /** A number that's redacted with a Seed skeleton block while loading, and a * tap-to-reveal `AmountToggle` once real data has arrived. Mirrors iOS's * `.skeleton(loading)` view modifier, which redacts the finished layout in * place rather than swapping in a separate spinner. */ function Amount({ value, loading, width = "72px" }: { value: number; loading: boolean; width?: string }) { if (loading) return ; return ; } /** The circular "₮" badge used on every card (togrogCircle in DashboardView.swift). */ function TugrikCircle({ bg, fg }: { bg: string; fg: string }) { 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). * Ported from ios/Mercury/Features/Home/DashboardView.swift. */ export function DashboardView() { const netWorthQ = useNetWorth(); const monthQ = useAnalyzeMonth(); const todayQ = useAnalyzeToday(); const budgetQ = useBudget(); const loading = netWorthQ.isLoading || monthQ.isLoading || todayQ.isLoading || budgetQ.isLoading; const built = buildHome({ netWorth: netWorthQ.data, month: monthQ.data, today: todayQ.data, budget: budgetQ.data, }); const data: HomeData = built ?? sample; const budgetDenominator = data.availableBudget; const fraction = budgetDenominator > 0 ? Math.min(1, data.monthlyExpense / budgetDenominator) : 0; const dailyFraction = data.dailyLimitTotal > 0 ? Math.min(1, data.dailyLimitUsed / data.dailyLimitTotal) : 0; return (
{s.wordmark}
{/* Safe-to-spend hero (green): how much is left to spend this month after committed obligations and what's already been spent. */}
{data.overspent ? s.overspent : s.safeToSpend}
{s.spent} / {tugrikShortRaw(budgetDenominator)}
{/* Daily limit + top budgets (blue). */}
{s.dailyLimit} {" / "}
{s.todaySpent}:

{data.budgets.map((b) => (
{b.name} / {b.range}
))} {/* This month's spend (white). */} {s.thisMonth}
{loading ? ( ) : ( {tugrikShortRaw(data.monthlyExpense)} )} {s.expenseLabel}
{s.viewAll} ›
{/* 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}
))}
); }