diff --git a/src/app/statements/page.tsx b/src/app/statements/page.tsx index 50a222f..9d0cfae 100644 --- a/src/app/statements/page.tsx +++ b/src/app/statements/page.tsx @@ -4,7 +4,7 @@ import Link from "next/link"; import { useStatements } from "@/lib/hooks"; function formatDate(d: string | null) { - if (!d) return "-"; + if (!d) return "—"; return new Date(d).toLocaleDateString("en-AU", { day: "2-digit", month: "short", @@ -12,12 +12,22 @@ function formatDate(d: string | null) { }); } -function formatCurrency(amount: number | null, currency = "AUD") { - if (amount === null || amount === undefined) return "-"; +function formatPeriod(start: string | null, end: string | null) { + if (!start && !end) return "—"; + const fmt = (d: string) => + new Date(d).toLocaleDateString("en-AU", { day: "2-digit", month: "short", year: "2-digit" }); + if (!start) return `until ${fmt(end!)}`; + if (!end) return `from ${fmt(start)}`; + return `${fmt(start)} – ${fmt(end)}`; +} + +function formatAmount(n: number | null): string { + if (n === null || n === undefined) return "—"; return new Intl.NumberFormat("en-AU", { style: "currency", - currency, - }).format(amount); + currency: "AUD", + minimumFractionDigits: 2, + }).format(Number(n)); } export default function StatementsPage() { @@ -28,48 +38,80 @@ export default function StatementsPage() {

Statements

{isLoading ? ( -

Loading...

+

Loading...

) : !statements?.length ? ( -

No statements found

+

No statements found

) : ( -
- {statements.map((s) => ( -
-
-

{s.bank_name}

- {s.currency} -
- {s.card_name && ( -

{s.card_name}

- )} -
-

Account: {s.account_number}

-

- Period: {formatDate(s.billing_start_date)} - {formatDate(s.billing_end_date)} -

-

Due: {formatDate(s.payment_due_date)}

-
-
-
-

- {formatCurrency(s.total_amount_due, s.currency)} -

-

- {s.transaction_count} transactions -

-
- - View - -
-
- ))} +
+ + + + + + + + + + + + + + + {statements.map((s) => { + const isCreditCard = Number(s.credit_limit) > 0 || s.payment_due_date != null; + const displayAmount = isCreditCard ? s.total_amount_due : s.closing_balance; + const amountLabel = isCreditCard ? "due" : "balance"; + + return ( + + + + + + + + + + + ); + })} + +
BankAccountPeriodDue / UpdatedCcyAmountTxns
+
+ {s.bank_name} +
+ {s.card_name && ( +
{s.card_name}
+ )} +
+ {s.account_number} + + {formatPeriod(s.billing_start_date, s.billing_end_date)} + + {isCreditCard + ? formatDate(s.payment_due_date) + : formatDate(s.billing_end_date)} + + {s.currency} + + {displayAmount !== null && displayAmount !== undefined ? ( + + {formatAmount(displayAmount)} + + ) : ( + + )} +
{amountLabel}
+
+ {s.transaction_count} + + + View → + +
)}
diff --git a/src/app/transactions/page.tsx b/src/app/transactions/page.tsx index b56cb09..7c3fba4 100644 --- a/src/app/transactions/page.tsx +++ b/src/app/transactions/page.tsx @@ -1,7 +1,8 @@ "use client"; -import { useState, useCallback } from "react"; -import { useTransactions, useBanks, useUpdateTransaction, useBulkAction, useTags } from "@/lib/hooks"; +import { useState, useCallback, Suspense } from "react"; +import { useSearchParams } from "next/navigation"; +import { useTransactions, useBanks, useUpdateTransaction, useBulkAction, useTags, useStatement } from "@/lib/hooks"; import { CATEGORIES, formatCategory } from "@/lib/categories"; import { SplitModal } from "@/components/split-modal"; import { TagPicker } from "@/components/tag-picker"; @@ -98,12 +99,24 @@ function InlineEdit({ } export default function TransactionsPage() { + return ( + Loading...

}> + +
+ ); +} + +function TransactionsContent() { + const searchParams = useSearchParams(); + const initialStatementId = searchParams.get("statement_id") || ""; + const [filters, setFilters] = useState({ from: "", to: "", category: "", bank_name: "", search: "", + statement_id: initialStatementId, tag_id: "", sort_by: "transaction_date", sort_dir: "desc", @@ -118,6 +131,7 @@ export default function TransactionsPage() { const { data, isLoading } = useTransactions(filters); const { data: banks } = useBanks(); const { data: tags } = useTags(); + const { data: statementInfo } = useStatement(parseInt(filters.statement_id) || 0); const updateTxn = useUpdateTransaction(); const bulkAction = useBulkAction(); @@ -161,6 +175,27 @@ export default function TransactionsPage() {

Transactions

+ {/* Statement context banner */} + {filters.statement_id && statementInfo && ( +
+ {statementInfo.bank_name} + {statementInfo.billing_start_date && statementInfo.billing_end_date && ( + + {new Date(statementInfo.billing_start_date).toLocaleDateString("en-AU", { day: "2-digit", month: "short" })} + {" – "} + {new Date(statementInfo.billing_end_date).toLocaleDateString("en-AU", { day: "2-digit", month: "short", year: "numeric" })} + + )} + {statementInfo.transaction_count} transactions + +
+ )} + {/* Filter bar */}