`;
};
const renderBudgetTable = () => {
budgetTableBody.innerHTML = '';
if (expenses.length === 0) {
budgetTableBody.innerHTML = `
No expense items found. Add one in the 'Manage Expenses' tab. `;
return;
}
expenses.forEach(item => {
const variance = item.budgeted - item.spent;
let varianceColor = 'text-slate-700';
if (variance > 0) varianceColor = 'text-green-600 font-semibold';
if (variance < 0) varianceColor = 'text-red-600 font-semibold';
const row = document.createElement('tr');
row.className = 'border-b border-slate-200 hover:bg-slate-50';
row.innerHTML = `
${item.category}
$${formatCurrency(item.budgeted)}
$${formatCurrency(item.spent)}
$${formatCurrency(variance)}
Edit
Delete
`;
budgetTableBody.appendChild(row);
});
};
// --- FORM & DATA LOGIC ---
const clearForm = () => {
form.reset();
expenseIdInput.value = '';
saveExpenseBtn.textContent = 'Save Item';
};
const saveExpense = () => {
const expenseData = {
category: expenseCategoryInput.value.trim(),
budgeted: parseFloat(budgetedAmountInput.value) || 0,
spent: parseFloat(actualAmountInput.value) || 0,
};
if (!expenseData.category) {
alert('Expense Category is required.'); return;
}
const id = expenseIdInput.value;
if (id) { // Update
const index = expenses.findIndex(e => e.id == id);
expenses[index] = { ...expenses[index], ...expenseData };
} else { // Add new
expenseData.id = nextExpenseId++;
expenses.push(expenseData);
}
clearForm();
renderAll();
showTab(0);
};
const editExpense = (id) => {
const item = expenses.find(e => e.id == id);
if (item) {
expenseIdInput.value = item.id;
expenseCategoryInput.value = item.category;
budgetedAmountInput.value = item.budgeted;
actualAmountInput.value = item.spent;
saveExpenseBtn.textContent = 'Update Item';
showTab(1);
}
};
const deleteExpense = (id) => {
if (confirm('Are you sure you want to delete this expense item?')) {
const row = budgetTableBody.querySelector(`.delete-btn[data-id='${id}']`).closest('tr');
row.classList.add('deleting');
setTimeout(() => {
expenses = expenses.filter(e => e.id != id);
renderAll();
}, 300);
}
};
// --- UI & NAVIGATION LOGIC ---
const showTab = (tabIndex) => {
tabContents.forEach(c => c.classList.add('hidden'));
tabButtons.forEach(b => b.classList.replace('active', 'inactive'));
document.getElementById(`tab-content-${tabIndex}`).classList.remove('hidden');
document.querySelector(`.tab-button[data-tab='${tabIndex}']`).classList.replace('inactive', 'active');
updateNavButtons();
currentTab = tabIndex;
};
const updateNavButtons = () => {
prevBtn.style.visibility = currentTab === 0 ? 'hidden' : 'visible';
nextBtn.style.visibility = currentTab === totalTabs - 1 ? 'hidden' : 'visible';
};
const navigateTabs = (direction) => {
const nextTabIndex = currentTab + direction;
if (nextTabIndex >= 0 && nextTabIndex < totalTabs) showTab(nextTabIndex);
};
// --- PDF GENERATION ---
const downloadPDF = () => {
const { jsPDF } = window.jspdf;
const pdfContentArea = document.getElementById('pdf-content-area');
const totalBudgeted = expenses.reduce((sum, item) => sum + item.budgeted, 0);
const totalSpent = expenses.reduce((sum, item) => sum + item.spent, 0);
const totalVariance = totalBudgeted - totalSpent;
let pdfHtml = `
Legal Expense Budget Report
Expense Category
Budgeted ($)
Actual Spent ($)
Variance ($)
${expenses.map(e => `
${e.category || ''}
${formatCurrency(e.budgeted)}
${formatCurrency(e.spent)}
${formatCurrency(e.budgeted - e.spent)}
`).join('')}
Total
$${formatCurrency(totalBudgeted)}
$${formatCurrency(totalSpent)}
$${formatCurrency(totalVariance)}
`;
pdfContentArea.innerHTML = pdfHtml;
pdfContentArea.classList.remove('hidden');
html2canvas(pdfContentArea, { scale: 2 }).then(canvas => {
const imgData = canvas.toDataURL('image/png');
const pdf = new jsPDF({ orientation: 'p', unit: 'pt', format: 'a4' });
const pdfWidth = pdf.internal.pageSize.getWidth();
const imgProps = pdf.getImageProperties(imgData);
const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width;
pdf.addImage(imgData, 'PNG', 0, 0, pdfWidth, pdfHeight);
pdf.save('Legal_Expense_Budget_Report.pdf');
pdfContentArea.innerHTML = '';
pdfContentArea.classList.add('hidden');
});
};
// --- EVENT LISTENERS ---
prevBtn.addEventListener('click', () => navigateTabs(-1));
nextBtn.addEventListener('click', () => navigateTabs(1));
tabButtons.forEach(button => button.addEventListener('click', () => showTab(parseInt(button.dataset.tab))));
saveExpenseBtn.addEventListener('click', saveExpense);
clearFormBtn.addEventListener('click', clearForm);
downloadPdfBtn.addEventListener('click', downloadPDF);
budgetTableBody.addEventListener('click', (e) => {
const target = e.target;
if (target.classList.contains('edit-btn')) {
editExpense(target.dataset.id);
}
if (target.classList.contains('delete-btn')) {
deleteExpense(target.dataset.id);
}
});
// --- INITIALIZATION ---
renderAll();
showTab(0);
});