From 1e94333d8f0275542ae7fd6e49fb8b7f03ad3d11 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 11 Sep 2025 22:46:41 +0000 Subject: [PATCH] feat(frontend): Improve transactions table mobile UX with responsive card layout Co-authored-by: elisiariocouto <818914+elisiariocouto@users.noreply.github.com> --- frontend/src/components/TransactionsTable.tsx | 300 +++++++++++++----- 1 file changed, 213 insertions(+), 87 deletions(-) diff --git a/frontend/src/components/TransactionsTable.tsx b/frontend/src/components/TransactionsTable.tsx index e60fd73..e495555 100644 --- a/frontend/src/components/TransactionsTable.tsx +++ b/frontend/src/components/TransactionsTable.tsx @@ -412,9 +412,9 @@ export default function TransactionsTable() { -
+
{/* Search */} -
+
@@ -448,8 +448,7 @@ export default function TransactionsTable() { {accounts?.map((account) => ( ))} @@ -489,7 +488,7 @@ export default function TransactionsTable() {
{/* Amount Range Filters */} -
+
- {/* Table */} + {/* Responsive Table/Cards */}
-
- - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => ( - - ))} - - ))} - - - {table.getRowModel().rows.length === 0 ? ( - - - - ) : ( - table.getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - + {/* Desktop Table View (hidden on mobile) */} +
+
+
-
- - {header.isPlaceholder - ? null - : flexRender( - header.column.columnDef.header, - header.getContext(), - )} - - {header.column.getCanSort() && ( -
- - -
- )} -
-
-
- -
-

- No transactions found -

-

- {hasActiveFilters - ? "Try adjusting your filters to see more results." - : "No transactions are available for the selected criteria."} -

-
- {flexRender( - cell.column.columnDef.cell, - cell.getContext(), - )} -
+ + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => ( + ))} - )) - )} - -
+
+ + {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef.header, + header.getContext(), + )} + + {header.column.getCanSort() && ( +
+ + +
+ )} +
+
+ ))} + + + {table.getRowModel().rows.length === 0 ? ( + + +
+ +
+

+ No transactions found +

+

+ {hasActiveFilters + ? "Try adjusting your filters to see more results." + : "No transactions are available for the selected criteria."} +

+ + + ) : ( + table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender( + cell.column.columnDef.cell, + cell.getContext(), + )} + + ))} + + )) + )} + + +
+
+ + {/* Mobile Card View (visible only on mobile) */} +
+ {table.getRowModel().rows.length === 0 ? ( +
+
+ +
+

+ No transactions found +

+

+ {hasActiveFilters + ? "Try adjusting your filters to see more results." + : "No transactions are available for the selected criteria."} +

+
+ ) : ( +
+ {table.getRowModel().rows.map((row) => { + const transaction = row.original; + const account = accounts?.find( + (acc) => acc.id === transaction.account_id, + ); + const isPositive = transaction.transaction_value > 0; + + return ( +
+
+
+
+
+ {isPositive ? ( + + ) : ( + + )} +
+
+

+ {transaction.description} +

+
+ {account && ( +

+ {account.name || "Unnamed Account"} •{" "} + {account.institution_id} +

+ )} + {(transaction.creditor_name || transaction.debtor_name) && ( +

+ {isPositive ? "From: " : "To: "} + {transaction.creditor_name || transaction.debtor_name} +

+ )} + {transaction.reference && ( +

Ref: {transaction.reference}

+ )} +

+ {transaction.transaction_date + ? formatDate(transaction.transaction_date) + : "No date"} + {transaction.booking_date && + transaction.booking_date !== transaction.transaction_date && ( + + (Booked: {formatDate(transaction.booking_date)}) + + )} +

+
+
+
+
+
+

+ {isPositive ? "+" : ""} + {formatCurrency( + transaction.transaction_value, + transaction.transaction_currency, + )} +

+ +
+
+
+ ); + })} +
+ )}
{/* Pagination */} {pagination && ( -
-
+
+ {/* Mobile pagination controls */} +
-
+ + {/* Mobile pagination info */} +
+

+ Page {pagination.page} of{" "} + {pagination.total_pages} +
+ + Showing {(pagination.page - 1) * pagination.per_page + 1}- + {Math.min(pagination.page * pagination.per_page, pagination.total)} of {pagination.total} + +

+
+ + {/* Desktop pagination */} +

Showing{" "}