diff --git a/src/common/components/TransactionList.tsx b/src/common/components/TransactionList.tsx
index d62bf0d..fc4eccd 100644
--- a/src/common/components/TransactionList.tsx
+++ b/src/common/components/TransactionList.tsx
@@ -14,7 +14,7 @@ import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown";
import { formatCurrency } from "../../../react-openapi";
import type { ExpenseItem, TxnFieldConfigs } from "../types";
-import { groupByMonth } from "../utils/transactions";
+import { groupByDate, groupByMonth } from "../utils/transactions";
import { monthLabel } from "../utils/dates";
import { TransactionRow } from "./TransactionRow";
@@ -160,13 +160,48 @@ export function TransactionList({ items, fields }: TransactionListProps) {
- {group.items.map((item) => (
-
+ {groupByDate(group.items).map((dateGroup) => (
+
+
+
+ {dateGroup.label}
+
+
+
+ {dateGroup.items.length} transaction{dateGroup.items.length === 1 ? "" : "s"}
+
+
+
+ {dateGroup.items.map((item) => (
+
+ ))}
+
+
))}
diff --git a/src/common/utils/dates.ts b/src/common/utils/dates.ts
index d6b5e83..5758b3d 100644
--- a/src/common/utils/dates.ts
+++ b/src/common/utils/dates.ts
@@ -63,4 +63,9 @@ export function monthLabel(key: string): string {
if (!y || !m) return key;
const d = new Date(y, m - 1, 1);
return d.toLocaleDateString("en-IN", { month: "long", year: "numeric" });
+}
+
+export function dateLabel(value: string): string {
+ const d = parseOccurredAt(value);
+ return d.toLocaleDateString("en-IN", { day: "numeric", month: "short", year: "numeric" });
}
\ No newline at end of file
diff --git a/src/common/utils/transactions.ts b/src/common/utils/transactions.ts
index 9538088..6da2894 100644
--- a/src/common/utils/transactions.ts
+++ b/src/common/utils/transactions.ts
@@ -1,10 +1,34 @@
import type { ExpenseItem, GroupedMonth } from "../types";
-import { monthKey, parseOccurredAt } from "./dates";
+import { dateLabel, monthKey, parseOccurredAt } from "./dates";
export function isExpense(item: ExpenseItem): boolean {
return (item.amount ?? 0) < 0;
}
+export interface DateGroup {
+ date: string;
+ label: string;
+ items: ExpenseItem[];
+}
+
+export function groupByDate(items: ExpenseItem[]): DateGroup[] {
+ const sorted = [...items].sort(
+ (a, b) => parseOccurredAt(b.occurred_at).getTime() - parseOccurredAt(a.occurred_at).getTime(),
+ );
+ const map = new Map();
+ for (const item of sorted) {
+ const key = item.occurred_at ?? "";
+ const list = map.get(key) ?? [];
+ list.push(item);
+ map.set(key, list);
+ }
+ return [...map.entries()].map(([date, list]) => ({
+ date,
+ label: dateLabel(date),
+ items: list,
+ }));
+}
+
export function groupByMonth(items: ExpenseItem[]): GroupedMonth[] {
const map = new Map();
for (const item of items) {