mirror of
https://github.com/acedanger/finance.git
synced 2025-12-05 22:50:12 -08:00
Refactor index.astro to improve type safety, enhance UI update functions, and streamline event handling for transactions
This commit is contained in:
@@ -3,6 +3,7 @@ import BaseLayout from '../layouts/BaseLayout.astro';
|
||||
import Sidebar from '../components/Sidebar.astro';
|
||||
import MainContent from '../components/MainContent.astro';
|
||||
import type { Account, Transaction } from '../types';
|
||||
import type { TransactionEventDetail } from '../types/events';
|
||||
import { formatCurrency, formatDate } from '../utils';
|
||||
|
||||
// Fetch accounts from API
|
||||
@@ -32,23 +33,29 @@ if (initialAccount.id) {
|
||||
</BaseLayout>
|
||||
|
||||
<script>
|
||||
// Import types for client-side script
|
||||
type Transaction = import('../types').Transaction;
|
||||
type Account = import('../types').Account;
|
||||
type TransactionEventDetail = import('../types/events').TransactionEventDetail;
|
||||
|
||||
// --- DOM Elements ---
|
||||
const accountSelect = document.getElementById('account-select');
|
||||
const accountSelect = document.getElementById('account-select') as HTMLSelectElement;
|
||||
const currentAccountNameSpan = document.getElementById('current-account-name');
|
||||
const accountBalanceSpan = document.getElementById('account-balance');
|
||||
const transactionTableBody = document.getElementById('transaction-table-body');
|
||||
const transactionSection = document.getElementById('transaction-section');
|
||||
|
||||
// --- Helper Functions ---
|
||||
function formatCurrency(amount) {
|
||||
function formatCurrency(amount: number): string {
|
||||
return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(amount);
|
||||
}
|
||||
|
||||
function formatDate(dateString) {
|
||||
function formatDate(dateString: string): string {
|
||||
const date = new Date(dateString + 'T00:00:00');
|
||||
return new Intl.DateTimeFormat('en-US', { year: 'numeric', month: 'short', day: 'numeric' }).format(date);
|
||||
}
|
||||
|
||||
async function fetchAccountTransactions(accountId) {
|
||||
async function fetchAccountTransactions(accountId: string): Promise<Transaction[]> {
|
||||
try {
|
||||
const response = await fetch(`/api/accounts/${accountId}/transactions`);
|
||||
if (!response.ok) throw new Error('Failed to fetch transactions');
|
||||
@@ -59,7 +66,7 @@ if (initialAccount.id) {
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchAccountDetails(accountId) {
|
||||
async function fetchAccountDetails(accountId: string): Promise<Account | null> {
|
||||
try {
|
||||
const response = await fetch(`/api/accounts/${accountId}`);
|
||||
if (!response.ok) throw new Error('Failed to fetch account details');
|
||||
@@ -71,10 +78,9 @@ if (initialAccount.id) {
|
||||
}
|
||||
|
||||
// --- Update UI Function ---
|
||||
async function updateUIForAccount(accountId) {
|
||||
async function updateUIForAccount(accountId: string): Promise<void> {
|
||||
console.log("Updating UI for account:", accountId);
|
||||
|
||||
const transactionSection = document.getElementById('transaction-section');
|
||||
if (transactionSection) {
|
||||
transactionSection.classList.add('loading');
|
||||
}
|
||||
@@ -116,7 +122,7 @@ if (initialAccount.id) {
|
||||
}
|
||||
}
|
||||
|
||||
function updateTransactionTable(transactions) {
|
||||
function updateTransactionTable(transactions: Transaction[]): void {
|
||||
if (!transactionTableBody) return;
|
||||
|
||||
const sortedTransactions = [...transactions].sort((a, b) =>
|
||||
@@ -152,17 +158,31 @@ if (initialAccount.id) {
|
||||
transactionTableBody.appendChild(row);
|
||||
});
|
||||
|
||||
// Add event listeners for edit and delete buttons
|
||||
setupTransactionButtons();
|
||||
}
|
||||
|
||||
function setupTransactionButtons(): void {
|
||||
const transactionRows = transactionTableBody?.querySelectorAll('tr[data-txn-id]');
|
||||
transactionRows?.forEach(row => {
|
||||
const txnId = row.getAttribute('data-txn-id');
|
||||
if (!txnId) return;
|
||||
|
||||
// Delete button handler
|
||||
const deleteBtn = row.querySelector('.delete-btn');
|
||||
deleteBtn?.addEventListener('click', () => handleDeleteTransaction(txnId));
|
||||
|
||||
// Edit button handler
|
||||
const editBtn = row.querySelector('.edit-btn');
|
||||
editBtn?.addEventListener('click', () => handleEditTransaction(txnId));
|
||||
});
|
||||
}
|
||||
|
||||
// --- Transaction Actions ---
|
||||
async function handleDeleteTransaction(txnId) {
|
||||
async function handleDeleteTransaction(txnId: string): Promise<void> {
|
||||
if (!confirm('Are you sure you want to delete this transaction?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const transactionSection = document.getElementById('transaction-section');
|
||||
if (transactionSection) {
|
||||
transactionSection.classList.add('loading');
|
||||
}
|
||||
@@ -191,10 +211,12 @@ if (initialAccount.id) {
|
||||
}
|
||||
}
|
||||
|
||||
async function handleEditTransaction(txnId) {
|
||||
async function handleEditTransaction(txnId: string): Promise<void> {
|
||||
try {
|
||||
// Find transaction in current transactions list
|
||||
const currentAccountId = accountSelect?.value;
|
||||
if (!currentAccountId) return;
|
||||
|
||||
const transactions = await fetchAccountTransactions(currentAccountId);
|
||||
const transaction = transactions.find(t => t.id === txnId);
|
||||
|
||||
@@ -203,7 +225,7 @@ if (initialAccount.id) {
|
||||
}
|
||||
|
||||
// Trigger edit mode in form
|
||||
document.dispatchEvent(new CustomEvent('editTransaction', {
|
||||
document.dispatchEvent(new CustomEvent<TransactionEventDetail>('editTransaction', {
|
||||
detail: { transaction }
|
||||
}));
|
||||
|
||||
@@ -212,44 +234,28 @@ if (initialAccount.id) {
|
||||
}
|
||||
}
|
||||
|
||||
function setupTransactionButtons() {
|
||||
const transactionRows = transactionTableBody?.querySelectorAll('tr[data-txn-id]');
|
||||
transactionRows?.forEach(row => {
|
||||
const txnId = row.getAttribute('data-txn-id');
|
||||
if (!txnId) return;
|
||||
|
||||
// Delete button handler
|
||||
const deleteBtn = row.querySelector('.delete-btn');
|
||||
deleteBtn?.addEventListener('click', () => handleDeleteTransaction(txnId));
|
||||
|
||||
// Edit button handler
|
||||
const editBtn = row.querySelector('.edit-btn');
|
||||
editBtn?.addEventListener('click', () => handleEditTransaction(txnId));
|
||||
});
|
||||
}
|
||||
|
||||
// --- Event Listeners ---
|
||||
if (accountSelect) {
|
||||
accountSelect.addEventListener('change', async (event) => {
|
||||
const selectedAccountId = event.target.value;
|
||||
await updateUIForAccount(selectedAccountId);
|
||||
accountSelect.addEventListener('change', (event: Event) => {
|
||||
const target = event.target as HTMLSelectElement;
|
||||
updateUIForAccount(target.value);
|
||||
});
|
||||
}
|
||||
|
||||
// Listen for transaction events
|
||||
document.addEventListener('transactionCreated', async (event) => {
|
||||
document.addEventListener('transactionCreated', ((event: CustomEvent<TransactionEventDetail>) => {
|
||||
const currentAccountId = accountSelect?.value;
|
||||
if (currentAccountId) {
|
||||
await updateUIForAccount(currentAccountId);
|
||||
updateUIForAccount(currentAccountId);
|
||||
}
|
||||
});
|
||||
}) as EventListener);
|
||||
|
||||
document.addEventListener('transactionUpdated', async (event) => {
|
||||
document.addEventListener('transactionUpdated', ((event: CustomEvent<TransactionEventDetail>) => {
|
||||
const currentAccountId = accountSelect?.value;
|
||||
if (currentAccountId) {
|
||||
await updateUIForAccount(currentAccountId);
|
||||
updateUIForAccount(currentAccountId);
|
||||
}
|
||||
});
|
||||
}) as EventListener);
|
||||
|
||||
// Initial load with transactions if available
|
||||
const initialAccountId = accountSelect?.value;
|
||||
|
||||
13
src/types/events.ts
Normal file
13
src/types/events.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import type { Transaction } from "../types";
|
||||
|
||||
export interface TransactionEventDetail {
|
||||
transaction: Transaction;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface WindowEventMap {
|
||||
transactionCreated: CustomEvent<TransactionEventDetail>;
|
||||
transactionUpdated: CustomEvent<TransactionEventDetail>;
|
||||
editTransaction: CustomEvent<TransactionEventDetail>;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user