Refactor index.astro to improve type safety, enhance UI update functions, and streamline event handling for transactions

This commit is contained in:
GitHub Copilot
2025-04-24 08:37:33 -04:00
parent b76a24edba
commit bb6bd75434
2 changed files with 57 additions and 38 deletions

View File

@@ -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
View 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>;
}
}