Files
finance/src/stores/transactionStore.ts
GitHub Copilot 07fbb82385 Fix: Update button remaining disabled in transaction edit mode
This commit resolves an issue where the Update button in the transaction form
would remain disabled when attempting to edit a transaction. The problem was
in how the transactionStore was managing state updates during transaction editing.

Key changes:
- Enhanced startEditingTransaction function in transactionStore.ts to ensure proper reactivity
- Added clean copy creation of transaction objects to avoid reference issues
- Implemented a state update cycle with null value first to force reactivity
- Added a small timeout to ensure state changes are properly detected by components

The Transaction form now correctly enables the Update button when in edit mode,
regardless of account selection state.
2025-05-05 21:29:36 +00:00

183 lines
6.0 KiB
TypeScript

import { atom } from 'nanostores';
import type { Transaction } from '../types';
// Atom to hold the ID of the currently selected account
export const currentAccountId = atom<string | null>(null);
// Atom to hold the current transactions
export const currentTransactions = atom<Transaction[]>([]);
// Atom to hold the transaction object when editing, or null otherwise
export const transactionToEdit = atom<Transaction | null>(null);
// Atom to trigger refreshes in components that depend on external changes
export const refreshKey = atom<number>(0);
// Action to set the current transactions
export function setTransactions(transactions: Transaction[]) {
console.log('Setting transactions in store:', transactions.length, transactions);
currentTransactions.set(transactions);
}
// Action to increment the refresh key, forcing dependent effects to re-run
export function triggerRefresh() {
console.log('Triggering transaction refresh');
refreshKey.set(refreshKey.get() + 1);
}
// Action to set the transaction to be edited
export function startEditingTransaction(transaction: Transaction) {
console.log('Setting transaction to edit:', transaction);
// Create a clean copy of the transaction to avoid reference issues
const transactionCopy = { ...transaction };
// Force update to ensure subscribers get notified
transactionToEdit.set(null);
// Set after a small delay to ensure state change is detected
setTimeout(() => {
transactionToEdit.set(transactionCopy);
console.log('Transaction edit state updated:', transactionToEdit.get());
}, 0);
}
// Action to clear the edit state
export function cancelEditingTransaction() {
console.log('Canceling transaction edit');
transactionToEdit.set(null);
}
// Action triggered after a transaction is saved (created or updated)
export function transactionSaved(transaction: Transaction) {
console.log('Transaction saved:', transaction);
// Clear edit state if the saved transaction was the one being edited
if (transactionToEdit.get()?.id === transaction.id) {
transactionToEdit.set(null);
}
// Add/update the transaction in the current list
const currentList = currentTransactions.get();
const existingIndex = currentList.findIndex((t) => t.id === transaction.id);
if (existingIndex >= 0) {
// Update existing transaction
const updatedList = [...currentList];
updatedList[existingIndex] = transaction;
currentTransactions.set(updatedList);
} else {
// Add new transaction
currentTransactions.set([transaction, ...currentList]);
}
// Trigger a general refresh after saving
triggerRefresh();
}
// Helper function to load transactions for an account
export async function loadTransactionsForAccount(accountId: string) {
console.log('loadTransactionsForAccount called with ID:', accountId);
try {
if (!accountId) {
console.warn('No account ID provided, clearing transactions');
currentTransactions.set([]);
return [];
}
console.log(`Fetching transactions from API for account: ${accountId}`);
const response = await fetch(`/api/accounts/${accountId}/transactions`);
if (!response.ok) {
console.error('API error:', response.status, response.statusText);
const errorText = await response.text();
console.error('Error response:', errorText);
throw new Error(`Failed to fetch transactions: ${response.statusText}`);
}
const transactions: Transaction[] = await response.json();
console.log(
`Loaded ${transactions.length} transactions for account ${accountId}:`,
transactions,
);
// Set transactions in the store
currentTransactions.set(transactions);
return transactions;
} catch (error) {
console.error('Error loading transactions:', error);
// Don't clear transactions on error, to avoid flickering UI
throw error;
}
}
// Helper to create a new transaction
export async function createTransaction(transaction: Omit<Transaction, 'id'>) {
try {
console.log('Creating new transaction:', transaction);
const response = await fetch('/api/transactions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(transaction),
});
if (!response.ok) {
const errorData = await response.json().catch(() => ({ error: 'Unknown error' }));
throw new Error(errorData.error || `Failed to create transaction: ${response.statusText}`);
}
const newTransaction = await response.json();
console.log('Transaction created successfully:', newTransaction);
// Add the new transaction to the existing list
const currentList = currentTransactions.get();
currentTransactions.set([newTransaction, ...currentList]);
// Trigger refresh to update other components
triggerRefresh();
return newTransaction;
} catch (error) {
console.error('Error creating transaction:', error);
throw error;
}
}
// Helper to update an existing transaction
export async function updateTransaction(id: string, transaction: Partial<Transaction>) {
try {
console.log(`Updating transaction ${id}:`, transaction);
const response = await fetch(`/api/transactions/${id}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(transaction),
});
if (!response.ok) {
const errorData = await response.json().catch(() => ({ error: 'Unknown error' }));
throw new Error(errorData.error || `Failed to update transaction: ${response.statusText}`);
}
const updatedTransaction = await response.json();
console.log('Transaction updated successfully:', updatedTransaction);
// Update the transaction in the existing list
const currentList = currentTransactions.get();
const updatedList = currentList.map((t) =>
t.id === updatedTransaction.id ? updatedTransaction : t,
);
currentTransactions.set(updatedList);
// Trigger refresh to update other components
triggerRefresh();
return updatedTransaction;
} catch (error) {
console.error('Error updating transaction:', error);
throw error;
}
}