mercury-web/src/features/assets/AccountDetail.tsx

104 lines
3.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import * as React from "react";
import { useNetWorth, useTransactions } from "@/api/hooks/reads";
import { Card } from "@/ds";
import { tugrikRaw } from "@/ds/money";
import { assetsStrings as s } from "./strings";
const mutedStyle: React.CSSProperties = { color: "var(--seed-color-fg-neutral-subtle)" };
export interface AccountDetailProps {
accountId: number;
}
/**
* Read-only account detail — no bank-server actions live here (that's iOS's
* `AccountDetailView`, gated behind a live bank connection this web app
* doesn't drive yet). Shows the balance from `/networth` plus this
* account's recent transactions.
*/
export function AccountDetail({ accountId }: AccountDetailProps) {
const netWorth = useNetWorth();
const transactions = useTransactions({ account: accountId, limit: 30 });
const account = (netWorth.data?.accounts ?? []).find((a) => a.accountId === accountId);
return (
<div style={{ display: "flex", flexDirection: "column", gap: 20 }}>
<header style={{ display: "flex", alignItems: "center", gap: 12 }}>
<BackLink />
<h1 style={{ margin: 0, fontSize: 18, fontWeight: 700, flex: 1 }}>{account?.bank ?? s.accountDetail.bank}</h1>
</header>
<Card style={{ textAlign: "center", padding: "24px 20px" }}>
<div style={{ fontSize: 12, ...mutedStyle }}>{account?.accountNumber}</div>
<div style={{ fontSize: 32, fontWeight: 700, marginTop: 8 }}>{tugrikRaw(account?.balance ?? "0")}</div>
</Card>
<Card style={{ padding: "6px 20px" }}>
<DetailRow label={s.accountDetail.bank} value={account?.bank ?? "—"} />
<Divider />
<DetailRow label={s.accountDetail.accountNumber} value={account?.accountNumber ?? "—"} />
<Divider />
<DetailRow label={s.accountDetail.currency} value={account?.currency ?? "—"} />
</Card>
<section>
<h3 style={{ margin: "0 0 10px", fontSize: 14, fontWeight: 700 }}>{s.accountDetail.recentTransactions}</h3>
{transactions.isLoading ? (
<p style={{ fontSize: 13, ...mutedStyle }}></p>
) : (transactions.data ?? []).length === 0 ? (
<p style={{ fontSize: 13, ...mutedStyle }}>{s.accountDetail.noTransactions}</p>
) : (
<Card style={{ padding: 0 }}>
{(transactions.data ?? []).map((txn, i) => {
const income = txn.direction === "income";
return (
<React.Fragment key={i}>
{i > 0 && <Divider />}
<div style={{ display: "flex", justifyContent: "space-between", padding: "14px 16px" }}>
<div>
<div style={{ fontWeight: 600 }}>{txn.title || txn.category}</div>
<div style={{ fontSize: 12, ...mutedStyle }}>{txn.date.slice(0, 10)}</div>
</div>
<div
style={{
fontWeight: 700,
color: income ? "var(--seed-color-fg-positive)" : "var(--seed-color-fg-critical)",
}}
>
{income ? "+" : ""}
{tugrikRaw(txn.amount)}
</div>
</div>
</React.Fragment>
);
})}
</Card>
)}
</section>
</div>
);
}
function BackLink() {
return (
<a href="/assets" style={{ textDecoration: "none", color: "inherit", fontWeight: 600 }}>
{s.common.back}
</a>
);
}
function DetailRow({ label, value }: { label: string; value: string }) {
return (
<div style={{ display: "flex", justifyContent: "space-between", padding: "14px 0" }}>
<span style={mutedStyle}>{label}</span>
<span style={{ fontWeight: 600 }}>{value}</span>
</div>
);
}
function Divider() {
return <div style={{ height: 1, background: "var(--seed-color-border-neutral, #e5e5e5)" }} />;
}