mirror of
https://github.com/acedanger/finance.git
synced 2025-12-05 22:50:12 -08:00
feat: Enhance AccountSummary and TransactionTable components with refresh functionality and improve loading/empty states
This commit is contained in:
@@ -2,7 +2,10 @@ import React, { useState, useEffect } from "react";
|
||||
import { useStore } from "@nanostores/react";
|
||||
import type { Account } from "../types";
|
||||
import { formatCurrency } from "../utils";
|
||||
import { currentAccountId as currentAccountIdStore } from "../stores/transactionStore";
|
||||
import {
|
||||
currentAccountId as currentAccountIdStore,
|
||||
refreshKey,
|
||||
} from "../stores/transactionStore";
|
||||
|
||||
interface AccountSummaryProps {
|
||||
// No props needed, data comes from store and fetch
|
||||
@@ -10,6 +13,7 @@ interface AccountSummaryProps {
|
||||
|
||||
export default function AccountSummary({}: AccountSummaryProps) {
|
||||
const currentAccountId = useStore(currentAccountIdStore);
|
||||
const refreshCounter = useStore(refreshKey);
|
||||
const [account, setAccount] = useState<Account | null>(null);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
@@ -43,7 +47,7 @@ export default function AccountSummary({}: AccountSummaryProps) {
|
||||
};
|
||||
|
||||
fetchDetails();
|
||||
}, [currentAccountId]);
|
||||
}, [currentAccountId, refreshCounter]);
|
||||
|
||||
// Determine content based on state
|
||||
let balanceContent: React.ReactNode;
|
||||
|
||||
@@ -45,10 +45,10 @@ export default function AddTransactionForm({}: AddTransactionFormProps) {
|
||||
const dateObj = new Date(transactionToEdit.date);
|
||||
// Check if date is valid before formatting
|
||||
if (!isNaN(dateObj.getTime())) {
|
||||
// Adjust for timezone offset to prevent date shifting
|
||||
const timezoneOffset = dateObj.getTimezoneOffset() * 60000; //offset in milliseconds
|
||||
const adjustedDate = new Date(dateObj.getTime() - timezoneOffset);
|
||||
setDate(adjustedDate.toISOString().split("T")[0]);
|
||||
// Directly format the date object (usually interpreted as UTC midnight)
|
||||
// into the YYYY-MM-DD format required by the input.
|
||||
// No timezone adjustment needed here.
|
||||
setDate(dateObj.toISOString().split("T")[0]);
|
||||
} else {
|
||||
console.warn(
|
||||
"Invalid date received for editing:",
|
||||
|
||||
@@ -6,12 +6,14 @@ import {
|
||||
startEditingTransaction,
|
||||
currentAccountId as currentAccountIdStore,
|
||||
triggerRefresh,
|
||||
refreshKey,
|
||||
} from "../stores/transactionStore";
|
||||
|
||||
interface TransactionTableProps {}
|
||||
|
||||
export default function TransactionTable({}: TransactionTableProps) {
|
||||
const currentAccountId = useStore(currentAccountIdStore);
|
||||
const refreshCounter = useStore(refreshKey);
|
||||
|
||||
const [transactions, setTransactions] = useState<Transaction[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
@@ -46,7 +48,7 @@ export default function TransactionTable({}: TransactionTableProps) {
|
||||
};
|
||||
|
||||
fetchTransactions();
|
||||
}, [currentAccountId]);
|
||||
}, [currentAccountId, refreshCounter]);
|
||||
|
||||
const sortedTransactions = [...transactions].sort(
|
||||
(a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()
|
||||
@@ -109,30 +111,17 @@ export default function TransactionTable({}: TransactionTableProps) {
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div id="transaction-section" className={isLoading ? "loading" : ""}>
|
||||
{error && (
|
||||
<div className="error-message" style={{ padding: "1rem" }}>
|
||||
Error loading transactions: {error}
|
||||
</div>
|
||||
)}
|
||||
<table className="transaction-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Description</th>
|
||||
<th className="amount-col">Amount</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="transaction-table-body">
|
||||
{isLoading ? (
|
||||
// Helper function to render loading state
|
||||
const renderLoading = () => (
|
||||
<tr>
|
||||
<td colSpan={4} style={{ textAlign: "center", padding: "2rem" }}>
|
||||
Loading transactions...
|
||||
</td>
|
||||
</tr>
|
||||
) : sortedTransactions.length === 0 && !error ? (
|
||||
);
|
||||
|
||||
// Helper function to render empty state
|
||||
const renderEmpty = () => (
|
||||
<tr>
|
||||
<td
|
||||
colSpan={4}
|
||||
@@ -145,8 +134,10 @@ export default function TransactionTable({}: TransactionTableProps) {
|
||||
No transactions found for this account.
|
||||
</td>
|
||||
</tr>
|
||||
) : (
|
||||
!error &&
|
||||
);
|
||||
|
||||
// Helper function to render transaction rows
|
||||
const renderRows = () =>
|
||||
sortedTransactions.map((txn) => (
|
||||
<tr key={txn.id} data-txn-id={txn.id}>
|
||||
<td>{formatDate(txn.date)}</td>
|
||||
@@ -175,8 +166,32 @@ export default function TransactionTable({}: TransactionTableProps) {
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
))
|
||||
));
|
||||
|
||||
return (
|
||||
<div id="transaction-section" className={isLoading ? "loading" : ""}>
|
||||
{error && (
|
||||
<div className="error-message" style={{ padding: "1rem" }}>
|
||||
Error loading transactions: {error}
|
||||
</div>
|
||||
)}
|
||||
<table className="transaction-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Description</th>
|
||||
<th className="amount-col">Amount</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="transaction-table-body">
|
||||
{isLoading
|
||||
? renderLoading()
|
||||
: error
|
||||
? null // Error message is shown above the table
|
||||
: sortedTransactions.length === 0
|
||||
? renderEmpty()
|
||||
: renderRows()}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
{
|
||||
"$schema": "node_modules/wrangler/config-schema.json",
|
||||
"name": "finance",
|
||||
// Update to today's date
|
||||
"observability": {
|
||||
"logs": {
|
||||
"enabled": true
|
||||
}
|
||||
},
|
||||
"compatibility_date": "2025-04-24",
|
||||
"assets": {
|
||||
"directory": "./dist"
|
||||
|
||||
Reference in New Issue
Block a user