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 Sidebar from '../components/Sidebar.astro';
|
||||||
import MainContent from '../components/MainContent.astro';
|
import MainContent from '../components/MainContent.astro';
|
||||||
import type { Account, Transaction } from '../types';
|
import type { Account, Transaction } from '../types';
|
||||||
|
import type { TransactionEventDetail } from '../types/events';
|
||||||
import { formatCurrency, formatDate } from '../utils';
|
import { formatCurrency, formatDate } from '../utils';
|
||||||
|
|
||||||
// Fetch accounts from API
|
// Fetch accounts from API
|
||||||
@@ -32,23 +33,29 @@ if (initialAccount.id) {
|
|||||||
</BaseLayout>
|
</BaseLayout>
|
||||||
|
|
||||||
<script>
|
<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 ---
|
// --- DOM Elements ---
|
||||||
const accountSelect = document.getElementById('account-select');
|
const accountSelect = document.getElementById('account-select') as HTMLSelectElement;
|
||||||
const currentAccountNameSpan = document.getElementById('current-account-name');
|
const currentAccountNameSpan = document.getElementById('current-account-name');
|
||||||
const accountBalanceSpan = document.getElementById('account-balance');
|
const accountBalanceSpan = document.getElementById('account-balance');
|
||||||
const transactionTableBody = document.getElementById('transaction-table-body');
|
const transactionTableBody = document.getElementById('transaction-table-body');
|
||||||
|
const transactionSection = document.getElementById('transaction-section');
|
||||||
|
|
||||||
// --- Helper Functions ---
|
// --- Helper Functions ---
|
||||||
function formatCurrency(amount) {
|
function formatCurrency(amount: number): string {
|
||||||
return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(amount);
|
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');
|
const date = new Date(dateString + 'T00:00:00');
|
||||||
return new Intl.DateTimeFormat('en-US', { year: 'numeric', month: 'short', day: 'numeric' }).format(date);
|
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 {
|
try {
|
||||||
const response = await fetch(`/api/accounts/${accountId}/transactions`);
|
const response = await fetch(`/api/accounts/${accountId}/transactions`);
|
||||||
if (!response.ok) throw new Error('Failed to fetch 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 {
|
try {
|
||||||
const response = await fetch(`/api/accounts/${accountId}`);
|
const response = await fetch(`/api/accounts/${accountId}`);
|
||||||
if (!response.ok) throw new Error('Failed to fetch account details');
|
if (!response.ok) throw new Error('Failed to fetch account details');
|
||||||
@@ -71,10 +78,9 @@ if (initialAccount.id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// --- Update UI Function ---
|
// --- Update UI Function ---
|
||||||
async function updateUIForAccount(accountId) {
|
async function updateUIForAccount(accountId: string): Promise<void> {
|
||||||
console.log("Updating UI for account:", accountId);
|
console.log("Updating UI for account:", accountId);
|
||||||
|
|
||||||
const transactionSection = document.getElementById('transaction-section');
|
|
||||||
if (transactionSection) {
|
if (transactionSection) {
|
||||||
transactionSection.classList.add('loading');
|
transactionSection.classList.add('loading');
|
||||||
}
|
}
|
||||||
@@ -116,7 +122,7 @@ if (initialAccount.id) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateTransactionTable(transactions) {
|
function updateTransactionTable(transactions: Transaction[]): void {
|
||||||
if (!transactionTableBody) return;
|
if (!transactionTableBody) return;
|
||||||
|
|
||||||
const sortedTransactions = [...transactions].sort((a, b) =>
|
const sortedTransactions = [...transactions].sort((a, b) =>
|
||||||
@@ -152,17 +158,31 @@ if (initialAccount.id) {
|
|||||||
transactionTableBody.appendChild(row);
|
transactionTableBody.appendChild(row);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add event listeners for edit and delete buttons
|
|
||||||
setupTransactionButtons();
|
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 ---
|
// --- Transaction Actions ---
|
||||||
async function handleDeleteTransaction(txnId) {
|
async function handleDeleteTransaction(txnId: string): Promise<void> {
|
||||||
if (!confirm('Are you sure you want to delete this transaction?')) {
|
if (!confirm('Are you sure you want to delete this transaction?')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const transactionSection = document.getElementById('transaction-section');
|
|
||||||
if (transactionSection) {
|
if (transactionSection) {
|
||||||
transactionSection.classList.add('loading');
|
transactionSection.classList.add('loading');
|
||||||
}
|
}
|
||||||
@@ -191,10 +211,12 @@ if (initialAccount.id) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleEditTransaction(txnId) {
|
async function handleEditTransaction(txnId: string): Promise<void> {
|
||||||
try {
|
try {
|
||||||
// Find transaction in current transactions list
|
// Find transaction in current transactions list
|
||||||
const currentAccountId = accountSelect?.value;
|
const currentAccountId = accountSelect?.value;
|
||||||
|
if (!currentAccountId) return;
|
||||||
|
|
||||||
const transactions = await fetchAccountTransactions(currentAccountId);
|
const transactions = await fetchAccountTransactions(currentAccountId);
|
||||||
const transaction = transactions.find(t => t.id === txnId);
|
const transaction = transactions.find(t => t.id === txnId);
|
||||||
|
|
||||||
@@ -203,7 +225,7 @@ if (initialAccount.id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Trigger edit mode in form
|
// Trigger edit mode in form
|
||||||
document.dispatchEvent(new CustomEvent('editTransaction', {
|
document.dispatchEvent(new CustomEvent<TransactionEventDetail>('editTransaction', {
|
||||||
detail: { transaction }
|
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 ---
|
// --- Event Listeners ---
|
||||||
if (accountSelect) {
|
if (accountSelect) {
|
||||||
accountSelect.addEventListener('change', async (event) => {
|
accountSelect.addEventListener('change', (event: Event) => {
|
||||||
const selectedAccountId = event.target.value;
|
const target = event.target as HTMLSelectElement;
|
||||||
await updateUIForAccount(selectedAccountId);
|
updateUIForAccount(target.value);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Listen for transaction events
|
// Listen for transaction events
|
||||||
document.addEventListener('transactionCreated', async (event) => {
|
document.addEventListener('transactionCreated', ((event: CustomEvent<TransactionEventDetail>) => {
|
||||||
const currentAccountId = accountSelect?.value;
|
const currentAccountId = accountSelect?.value;
|
||||||
if (currentAccountId) {
|
if (currentAccountId) {
|
||||||
await updateUIForAccount(currentAccountId);
|
updateUIForAccount(currentAccountId);
|
||||||
}
|
}
|
||||||
});
|
}) as EventListener);
|
||||||
|
|
||||||
document.addEventListener('transactionUpdated', async (event) => {
|
document.addEventListener('transactionUpdated', ((event: CustomEvent<TransactionEventDetail>) => {
|
||||||
const currentAccountId = accountSelect?.value;
|
const currentAccountId = accountSelect?.value;
|
||||||
if (currentAccountId) {
|
if (currentAccountId) {
|
||||||
await updateUIForAccount(currentAccountId);
|
updateUIForAccount(currentAccountId);
|
||||||
}
|
}
|
||||||
});
|
}) as EventListener);
|
||||||
|
|
||||||
// Initial load with transactions if available
|
// Initial load with transactions if available
|
||||||
const initialAccountId = accountSelect?.value;
|
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