Budget & Financial Management Dashboard

An overview of your income, expenses, and budget for the current month.

Total Income

$0

Total Expenses

$0

Net Savings

$0

Monthly Cash Flow

Expense Breakdown

Budget vs. Actuals

Recent Transactions

DateDescriptionCategoryAmount

Manage Budgets

CategoryBudgetAction

Add Transaction

DateDescriptionCategoryAmountAction

Error: A required library is missing.

'; return; } // --- DATA MANAGEMENT --- let budgets = JSON.parse(localStorage.getItem('bfm_budgets')) || []; let transactions = JSON.parse(localStorage.getItem('bfm_transactions')) || []; const getSampleData = () => { const sampleBudgets = [ { category: 'Housing', amount: 2200 }, { category: 'Transportation', amount: 500 }, { category: 'Food', amount: 800 }, { category: 'Utilities', amount: 300 }, { category: 'Entertainment', amount: 250 }, { category: 'Savings', amount: 1000 } ]; const sampleTransactions = []; const today = new Date(); const year = today.getFullYear(); const month = today.getMonth(); const createDate = (day) => new Date(year, month, day).toISOString().split('T')[0]; sampleTransactions.push( { id: 't1', date: createDate(1), desc: 'Paycheck', amount: 3500, type: 'Income', category: 'Salary' }, { id: 't2', date: createDate(1), desc: 'Rent', amount: 2200, type: 'Expense', category: 'Housing' }, { id: 't3', date: createDate(2), desc: 'Electricity Bill', amount: 120, type: 'Expense', category: 'Utilities' }, { id: 't4', date: createDate(3), desc: 'Groceries', amount: 180.50, type: 'Expense', category: 'Food' }, { id: 't5', date: createDate(5), desc: 'Gasoline', amount: 55.75, type: 'Expense', category: 'Transportation' }, { id: 't6', date: createDate(6), desc: 'Movie Night', amount: 45, type: 'Expense', category: 'Entertainment' }, { id: 't7', date: createDate(7), desc: 'Internet Bill', amount: 80, type: 'Expense', category: 'Utilities' }, { id: 't8', date: createDate(8), desc: 'Stock Dividend', amount: 150, type: 'Income', category: 'Investments' } ); budgets = sampleBudgets; transactions = sampleTransactions; }; if (budgets.length === 0 && transactions.length === 0) { getSampleData(); } const saveState = () => { localStorage.setItem('bfm_budgets', JSON.stringify(budgets)); localStorage.setItem('bfm_transactions', JSON.stringify(transactions)); }; // --- CHART INSTANCES --- let cashflowChart, expenseChart, budgetChart; // --- ELEMENT REFERENCES & UTILITIES --- const tabButtons = document.querySelectorAll('.bfm-tab-button'); const tabContents = document.querySelectorAll('.bfm-tab-content'); const nextBtn = document.getElementById('bfm-next-btn'); const prevBtn = document.getElementById('bfm-prev-btn'); const formatCurrency = (val) => val.toLocaleString('en-US', { style: 'currency', currency: 'USD' }); const currentMonth = new Date().getMonth(); const currentYear = new Date().getFullYear(); // --- RENDER FUNCTIONS --- const renderAll = () => { try { const currentMonthTransactions = transactions.filter(t => { const d = new Date(t.date + 'T00:00:00'); return d.getMonth() === currentMonth && d.getFullYear() === currentYear; }); renderKPIs(currentMonthTransactions); renderCashflowChart(); renderExpenseChart(currentMonthTransactions); renderBudgetChart(currentMonthTransactions); renderTransactionTables(); updateNavButtons(); } catch(error) { console.error("Dashboard rendering failed:", error); } }; const renderKPIs = (data) => { const totalIncome = data.filter(t=>t.type==='Income').reduce((s,t)=>s+t.amount, 0); const totalExpense = data.filter(t=>t.type==='Expense').reduce((s,t)=>s+t.amount, 0); document.getElementById('bfm-income-kpi').textContent = formatCurrency(totalIncome); document.getElementById('bfm-expense-kpi').textContent = formatCurrency(totalExpense); const netEl = document.getElementById('bfm-net-kpi'); netEl.textContent = formatCurrency(totalIncome - totalExpense); netEl.className = (totalIncome - totalExpense) >= 0 ? 'net positive' : 'net negative'; }; const renderCashflowChart = () => { const monthlyData = transactions.reduce((acc, t) => { const month = t.date.substring(0, 7); if (!acc[month]) acc[month] = { income: 0, expense: 0 }; if (t.type === 'Income') acc[month].income += t.amount; else acc[month].expense += t.amount; return acc; }, {}); const sortedMonths = Object.keys(monthlyData).sort(); const options = { chart: { type: 'bar', height: 350, stacked: false }, series: [ { name: 'Income', data: sortedMonths.map(m => monthlyData[m].income) }, { name: 'Expense', data: sortedMonths.map(m => monthlyData[m].expense) } ], xaxis: { categories: sortedMonths }, yaxis: { labels: { formatter: val => formatCurrency(val) } }, colors: ['var(--bfm-success-color)', 'var(--bfm-danger-color)'], dataLabels: { enabled: false } }; if(cashflowChart) cashflowChart.destroy(); document.querySelector("#bfm-cashflow-chart").innerHTML = ''; cashflowChart = new ApexCharts(document.querySelector("#bfm-cashflow-chart"), options); cashflowChart.render(); }; const renderExpenseChart = (data) => { const expensesByCategory = data.filter(t=>t.type === 'Expense').reduce((acc, t) => { acc[t.category] = (acc[t.category] || 0) + t.amount; return acc; }, {}); const options = { chart: { type: 'donut', height: 350 }, series: Object.values(expensesByCategory), labels: Object.keys(expensesByCategory), legend: { position: 'bottom' } }; if(expenseChart) expenseChart.destroy(); document.querySelector("#bfm-expense-category-chart").innerHTML = ''; expenseChart = new ApexCharts(document.querySelector("#bfm-expense-category-chart"), options); expenseChart.render(); }; const renderBudgetChart = (data) => { const seriesData = []; const categories = []; budgets.forEach(b => { const actual = data.filter(t=>t.category === b.category && t.type === 'Expense').reduce((s,t)=>s+t.amount, 0); seriesData.push({ budget: b.amount, actual }); categories.push(b.category); }); const options = { chart: { type: 'bar', height: 350 }, series: [ { name: 'Actual Spending', data: seriesData.map(d=>d.actual) }, { name: 'Budgeted Amount', data: seriesData.map(d=>d.budget) } ], xaxis: { categories: categories }, yaxis: { labels: { formatter: val => formatCurrency(val) } }, plotOptions: { bar: { horizontal: true } }, colors: ['var(--bfm-secondary-color)', '#bdc3c7'], dataLabels: { enabled: false } }; if(budgetChart) budgetChart.destroy(); document.querySelector("#bfm-budget-chart").innerHTML = ''; budgetChart = new ApexCharts(document.querySelector("#bfm-budget-chart"), options); budgetChart.render(); }; const renderTransactionTables = () => { const recentTbody = document.getElementById('bfm-recent-transactions-tbody'); recentTbody.innerHTML = ''; transactions.sort((a,b) => new Date(b.date) - new Date(a.date)).slice(0,5).forEach(t => { const amountClass = t.type === 'Income' ? 'income' : 'expense'; recentTbody.innerHTML += `${t.date}${t.desc}${t.category}${t.type==='Income' ? '' : '-'}${formatCurrency(t.amount)}`; }); // Manage tab tables const budgetsTbody = document.getElementById('bfm-budgets-tbody'); budgetsTbody.innerHTML = ''; budgets.forEach(b => { budgetsTbody.innerHTML += `${b.category}${formatCurrency(b.amount)}`; }); const allTransTbody = document.getElementById('bfm-transactions-tbody'); allTransTbody.innerHTML = ''; transactions.forEach(t => { const amountClass = t.type === 'Income' ? 'income' : 'expense'; allTransTbody.innerHTML += `${t.date}${t.desc}${t.category}${t.type==='Income' ? '' : '-'}${formatCurrency(t.amount)}`; }); // Datalist const categories = [...new Set(budgets.map(b=>b.category).concat(transactions.map(t=>t.category)))]; document.getElementById('bfm-category-list').innerHTML = categories.map(c=>``).join(''); }; // --- EVENT HANDLING --- const switchTab = (tabId) => { tabContents.forEach(c => c.style.display = 'none'); tabButtons.forEach(b => b.classList.remove('active')); const activeContent = document.getElementById(tabId); const activeButton = document.querySelector(`.bfm-tab-button[data-tab="${tabId}"]`); if (activeContent && activeButton) { activeContent.style.display = 'block'; activeButton.classList.add('active'); } updateNavButtons(); }; const updateNavButtons = () => { const i = [...tabButtons].findIndex(b => b.classList.contains('active')); prevBtn.disabled = i === 0; nextBtn.disabled = i === tabButtons.length - 1; }; tabButtons.forEach(b => b.addEventListener('click', () => switchTab(b.dataset.tab))); nextBtn.addEventListener('click', () => { const i = [...tabButtons].findIndex(b=>b.classList.contains('active')); if (i < tabButtons.length - 1) switchTab(tabButtons[i+1].dataset.tab); }); prevBtn.addEventListener('click', () => { const i = [...tabButtons].findIndex(b=>b.classList.contains('active')); if (i > 0) switchTab(tabButtons[i-1].dataset.tab); }); document.getElementById('bfm-budget-form').addEventListener('submit', e => { e.preventDefault(); const category = document.getElementById('bfm-budget-category').value; const amount = parseFloat(document.getElementById('bfm-budget-amount').value); const existingIndex = budgets.findIndex(b => b.category === category); if (existingIndex > -1) budgets[existingIndex].amount = amount; else budgets.push({ category, amount }); saveState(); renderAll(); e.target.reset(); }); document.getElementById('bfm-transaction-form').addEventListener('submit', e => { e.preventDefault(); transactions.unshift({ id: 't' + Date.now(), date: document.getElementById('bfm-trans-date').value, desc: document.getElementById('bfm-trans-desc').value, amount: parseFloat(document.getElementById('bfm-trans-amount').value), type: document.getElementById('bfm-trans-type').value, category: document.getElementById('bfm-trans-category').value }); saveState(); renderAll(); e.target.reset(); }); document.getElementById('bfm-manage-tab').addEventListener('click', e => { if(e.target.tagName !== 'BUTTON') return; const type = e.target.dataset.type; if(confirm(`Are you sure you want to delete this ${type}?`)) { if(type === 'budget') { budgets = budgets.filter(b => b.category !== e.target.dataset.category); } else if (type === 'transaction') { transactions = transactions.filter(t => t.id !== e.target.dataset.id); } saveState(); renderAll(); } }); // --- PDF EXPORT --- document.getElementById('bfm-download-pdf-btn').addEventListener('click', function() { const btn = this; btn.textContent = 'Generating...'; btn.disabled = true; const content = document.getElementById('bfm-pdf-capture-area'); html2canvas(content, { scale: 2 }).then(canvas => { const doc = new jsPDF({ orientation: 'p', unit: 'mm', format: 'a4' }); const imgData = canvas.toDataURL('image/png'); const pdfWidth = doc.internal.pageSize.getWidth(); const imgHeight = (canvas.height * pdfWidth) / canvas.width; doc.setFontSize(18); doc.text(`Financial Report - ${new Date().toLocaleString('default', { month: 'long', year: 'numeric' })}`, 14, 22); doc.addImage(imgData, 'PNG', 0, 30, pdfWidth, imgHeight); doc.save('Financial_Report.pdf'); }).finally(() => { btn.textContent = 'Download Report'; btn.disabled = false; }); }); // --- INITIALIZATION --- renderAll(); });
Scroll to Top