Budget Tracking Dashboard
Monthly Overview
Total Budget
$0
Total Spent
$0
Remaining
$0
Overall Budget Usage
Spending by Category
Transactions for Selected Month
| Date | Description | Category | Amount |
|---|
Manage Monthly Budgets
| Category | Monthly Budget | Action |
|---|
Log an Expense
| Date | Description | Category | Amount | Action |
|---|
Error: A required library is missing.
'; return; } // --- DATA MANAGEMENT --- let budgets = JSON.parse(localStorage.getItem('btd_budgets')) || []; let expenses = JSON.parse(localStorage.getItem('btd_expenses')) || []; const getSampleData = () => { budgets = [ { category: 'Rent/Mortgage', amount: 2200 }, { category: 'Utilities', amount: 350 }, { category: 'Groceries', amount: 700 }, { category: 'Transportation', amount: 400 }, { category: 'Entertainment', amount: 250 }, { category: 'Health Insurance', amount: 450 } ]; const today = new Date('2025-07-08'); const year = today.getFullYear(); const month = today.getMonth(); const createDate = (day) => new Date(year, month, day).toISOString().split('T')[0]; expenses = [ { id: 'e1', date: createDate(1), desc: 'Apartment Rent', category: 'Rent/Mortgage', amount: 2200 }, { id: 'e2', date: createDate(2), desc: 'Electricity Bill', category: 'Utilities', amount: 110.45 }, { id: 'e3', date: createDate(3), desc: 'Whole Foods', category: 'Groceries', amount: 175.20 }, { id: 'e4', date: createDate(5), desc: 'Gasoline', category: 'Transportation', amount: 52.80 }, { id: 'e5', date: createDate(6), desc: 'Movie Tickets', category: 'Entertainment', amount: 35.00 }, { id: 'e6', date: createDate(7), desc: 'Health Premium', category: 'Health Insurance', amount: 450.00 } ]; }; if (budgets.length === 0) getSampleData(); const saveState = () => { localStorage.setItem('btd_budgets', JSON.stringify(budgets)); localStorage.setItem('btd_expenses', JSON.stringify(expenses)); }; // --- CHART INSTANCES & UTILITIES --- let gaugeChart, varianceChart; const tabButtons = document.querySelectorAll('.btd-tab-button'); const tabContents = document.querySelectorAll('.btd-tab-content'); const nextBtn = document.getElementById('btd-next-btn'); const prevBtn = document.getElementById('btd-prev-btn'); const monthFilter = document.getElementById('btd-month-filter'); const formatCurrency = (val) => val.toLocaleString('en-US', { style: 'currency', currency: 'USD' }); // --- RENDER FUNCTIONS --- const renderAll = () => { try { const selectedMonth = monthFilter.value; // YYYY-MM format const [year, month] = selectedMonth.split('-').map(Number); const filteredExpenses = expenses.filter(e => { const d = new Date(e.date + 'T00:00:00'); return d.getFullYear() === year && d.getMonth() === month - 1; }); renderKPIs(filteredExpenses); renderGaugeChart(filteredExpenses); renderVarianceChart(filteredExpenses); renderTransactionTables(filteredExpenses); updateNavButtons(); } catch(error) { console.error("Dashboard rendering failed:", error); } }; const renderKPIs = (data) => { const totalBudget = budgets.reduce((sum, b) => sum + b.amount, 0); const totalSpent = data.reduce((sum, e) => sum + e.amount, 0); const remaining = totalBudget - totalSpent; document.getElementById('btd-budget-kpi').textContent = formatCurrency(totalBudget); document.getElementById('btd-spent-kpi').textContent = formatCurrency(totalSpent); const remainingEl = document.getElementById('btd-remaining-kpi'); remainingEl.textContent = formatCurrency(remaining); remainingEl.className = remaining >= 0 ? 'remaining positive' : 'remaining negative'; }; const renderGaugeChart = (data) => { const totalBudget = budgets.reduce((sum, b) => sum + b.amount, 0); const totalSpent = data.reduce((sum, e) => sum + e.amount, 0); const percentageSpent = totalBudget > 0 ? Math.round((totalSpent / totalBudget) * 100) : 0; const options = { chart: { type: 'radialBar', height: 350 }, series: [percentageSpent], plotOptions: { radialBar: { hollow: { size: '70%' }, dataLabels: { name: { show: true, offsetY: -10, fontSize: '16px', color: '#6c757d', formatter: () => 'Budget Used' }, value: { show: true, fontSize: '36px', formatter: (val) => `${val}%` } } } }, stroke: { lineCap: 'round' }, colors: [percentageSpent > 100 ? 'var(--btd-danger-color)' : percentageSpent > 80 ? 'var(--btd-warning-color)' : 'var(--btd-success-color)'] }; if(gaugeChart) gaugeChart.destroy(); document.querySelector("#btd-gauge-chart").innerHTML = ''; gaugeChart = new ApexCharts(document.querySelector("#btd-gauge-chart"), options); gaugeChart.render(); }; const renderVarianceChart = (data) => { const seriesData = budgets.map(b => { const actual = data.filter(e => e.category === b.category).reduce((sum, e) => sum + e.amount, 0); return { category: b.category, budget: b.amount, actual }; }); const options = { chart: { type: 'bar', height: 350, stacked: true }, series: [ { name: 'Spent', data: seriesData.map(d => d.actual) }, { name: 'Remaining', data: seriesData.map(d => Math.max(0, d.budget - d.actual)) } ], xaxis: { categories: seriesData.map(d => d.category) }, plotOptions: { bar: { horizontal: false } }, colors: ['var(--btd-secondary-color)', '#e0e0e0'], dataLabels: { enabled: false } }; if(varianceChart) varianceChart.destroy(); document.querySelector("#btd-variance-chart").innerHTML = ''; varianceChart = new ApexCharts(document.querySelector("#btd-variance-chart"), options); varianceChart.render(); }; const renderTransactionTables = (filteredData) => { const recentTbody = document.getElementById('btd-transactions-tbody'); recentTbody.innerHTML = ''; filteredData.forEach(e => { recentTbody.innerHTML += `