150 lines
6.4 KiB
JavaScript
150 lines
6.4 KiB
JavaScript
document.addEventListener('DOMContentLoaded', () => {
|
|
const initialBalanceEl = document.getElementById('initialBalance');
|
|
const currentBalanceEl = document.getElementById('currentBalance');
|
|
const transactionHistoryEl = document.getElementById('transactionHistory');
|
|
const incomeForm = document.getElementById('incomeForm');
|
|
const expenseForm = document.getElementById('expenseForm');
|
|
const incomeModal = new bootstrap.Modal(document.getElementById('incomeModal'));
|
|
const expenseModal = new bootstrap.Modal(document.getElementById('expenseModal'));
|
|
const toastEl = document.getElementById('liveToast');
|
|
const toast = new bootstrap.Toast(toastEl);
|
|
|
|
// Search elements
|
|
const startDateEl = document.getElementById('startDate');
|
|
const endDateEl = document.getElementById('endDate');
|
|
const searchBtn = document.getElementById('searchBtn');
|
|
const clearBtn = document.getElementById('clearBtn');
|
|
|
|
let transactions = JSON.parse(localStorage.getItem('transactions')) || [];
|
|
let initialBalance = parseFloat(localStorage.getItem('initialBalance')) || 0;
|
|
|
|
initialBalanceEl.value = initialBalance;
|
|
|
|
const formatCurrency = (amount) => {
|
|
return new Intl.NumberFormat('en-IN', { style: 'currency', currency: 'INR' }).format(amount);
|
|
};
|
|
|
|
const showToast = (message, type) => {
|
|
const toastBody = toastEl.querySelector('.toast-body');
|
|
const toastHeader = toastEl.querySelector('.toast-header');
|
|
toastBody.textContent = message;
|
|
toastHeader.classList.remove('bg-success', 'bg-danger');
|
|
toastHeader.classList.add(type === 'success' ? 'bg-success' : 'bg-danger');
|
|
toast.show();
|
|
};
|
|
|
|
const renderTransactions = (transactionsToRender) => {
|
|
transactionHistoryEl.innerHTML = '';
|
|
let balance = initialBalance;
|
|
transactions.forEach(t => balance += t.amount);
|
|
|
|
if (transactionsToRender.length === 0) {
|
|
transactionHistoryEl.innerHTML = '<tr><td colspan="5" class="text-center text-muted">No transactions found for this period.</td></tr>';
|
|
} else {
|
|
transactionsToRender.slice().reverse().forEach(transaction => {
|
|
const row = document.createElement('tr');
|
|
const typeClass = transaction.amount > 0 ? 'text-success' : 'text-danger';
|
|
row.innerHTML = `
|
|
<td>${new Date(transaction.date).toLocaleDateString()}</td>
|
|
<td><span class="badge bg-${transaction.amount > 0 ? 'success' : 'danger'}">${transaction.amount > 0 ? 'Income' : 'Expense'}</span></td>
|
|
<td>${transaction.description}</td>
|
|
<td class="text-end fw-bold ${typeClass}">${formatCurrency(transaction.amount)}</td>
|
|
<td><button class="btn btn-sm btn-outline-danger delete-btn" data-id="${transaction.id}"><i class="bi bi-trash"></i></button></td>
|
|
`;
|
|
transactionHistoryEl.appendChild(row);
|
|
});
|
|
}
|
|
|
|
currentBalanceEl.textContent = formatCurrency(balance);
|
|
};
|
|
|
|
const addTransaction = (amount, description, date) => {
|
|
const transaction = {
|
|
id: Date.now(),
|
|
date: date || new Date().toISOString().split('T')[0],
|
|
amount: amount,
|
|
description: description
|
|
};
|
|
transactions.push(transaction);
|
|
localStorage.setItem('transactions', JSON.stringify(transactions));
|
|
renderTransactions(transactions);
|
|
};
|
|
|
|
const deleteTransaction = (id) => {
|
|
transactions = transactions.filter(t => t.id !== id);
|
|
localStorage.setItem('transactions', JSON.stringify(transactions));
|
|
renderTransactions(transactions);
|
|
showToast('Transaction deleted successfully!', 'success');
|
|
};
|
|
|
|
transactionHistoryEl.addEventListener('click', (e) => {
|
|
if (e.target.closest('.delete-btn')) {
|
|
const id = parseInt(e.target.closest('.delete-btn').dataset.id);
|
|
deleteTransaction(id);
|
|
}
|
|
});
|
|
|
|
initialBalanceEl.addEventListener('input', (e) => {
|
|
initialBalance = parseFloat(e.target.value) || 0;
|
|
localStorage.setItem('initialBalance', initialBalance);
|
|
renderTransactions(transactions);
|
|
});
|
|
|
|
incomeForm.addEventListener('submit', (e) => {
|
|
e.preventDefault();
|
|
const amount = parseFloat(document.getElementById('incomeAmount').value);
|
|
const description = document.getElementById('incomeDescription').value;
|
|
const date = document.getElementById('incomeDate').value;
|
|
if (amount > 0 && description && date) {
|
|
addTransaction(amount, description, date);
|
|
showToast('Income added successfully!', 'success');
|
|
incomeForm.reset();
|
|
document.getElementById('incomeDate').valueAsDate = new Date();
|
|
incomeModal.hide();
|
|
} else {
|
|
showToast('Please enter a valid amount, description, and date.', 'danger');
|
|
}
|
|
});
|
|
|
|
expenseForm.addEventListener('submit', (e) => {
|
|
e.preventDefault();
|
|
const amount = parseFloat(document.getElementById('expenseAmount').value);
|
|
const description = document.getElementById('expenseDescription').value;
|
|
const date = document.getElementById('expenseDate').value;
|
|
if (amount > 0 && description && date) {
|
|
addTransaction(-amount, description, date);
|
|
showToast('Expense added successfully!', 'success');
|
|
expenseForm.reset();
|
|
document.getElementById('expenseDate').valueAsDate = new Date();
|
|
expenseModal.hide();
|
|
} else {
|
|
showToast('Please enter a valid amount, description, and date.', 'danger');
|
|
}
|
|
});
|
|
|
|
searchBtn.addEventListener('click', () => {
|
|
const startDate = startDateEl.value;
|
|
const endDate = endDateEl.value;
|
|
|
|
if (!startDate || !endDate) {
|
|
showToast('Please select both a start and end date.', 'danger');
|
|
return;
|
|
}
|
|
|
|
const filteredTransactions = transactions.filter(t => {
|
|
const transactionDate = t.date;
|
|
return transactionDate >= startDate && transactionDate <= endDate;
|
|
});
|
|
|
|
renderTransactions(filteredTransactions);
|
|
});
|
|
|
|
clearBtn.addEventListener('click', () => {
|
|
startDateEl.value = '';
|
|
endDateEl.value = '';
|
|
renderTransactions(transactions);
|
|
});
|
|
|
|
renderTransactions(transactions);
|
|
});
|