Personal Finance Dashboard

Personal Finance Dashboard
Note: All financial data is stored locally in your browser. Clearing browser data will remove your saved information.

Financial Snapshot

Net Worth

$0.00

Total Assets

$0.00

Total Liabilities

$0.00

Budget Period

N/A

Total Budgeted

$0.00

Total Spent

$0.00

Budget Difference

$0.00

Savings Goals Overview

No active savings goals.

Net Worth Calculation

Total Assets

$0.00

Total Liabilities

$0.00

Calculated Net Worth

$0.00

Assets

No assets added yet.

Liabilities

No liabilities added yet.

Budget & Actual Expenses

Budget Categories

No budget categories defined yet.

Expense Breakdown Chart

No expense data to display chart.

Savings Goals

No savings goals added yet.

    No assets added yet.

    '; return; } const table = document.createElement('table'); table.className = 'pfd-table'; table.innerHTML = ` Asset NameValueAction ${assets.map(asset => ` ${escapeHtml(asset.name)} ${formatCurrency(asset.value)} `).join('')} `; assetsTableContainer.appendChild(table); console.log('Assets table rendered'); } catch (e) { console.error('Error in renderAssetsTable:', e); } } function renderLiabilitiesTable() { console.log('Rendering liabilities table'); try { if (!liabilitiesTableContainer) { console.error('Liabilities table container not found'); return; } liabilitiesTableContainer.innerHTML = ''; if (liabilities.length === 0) { liabilitiesTableContainer.innerHTML = '

    No liabilities added yet.

    '; return; } const table = document.createElement('table'); table.className = 'pfd-table'; table.innerHTML = ` Liability NameAmount OwedAction ${liabilities.map(lib => ` ${escapeHtml(lib.name)} ${formatCurrency(lib.amount)} `).join('')} `; liabilitiesTableContainer.appendChild(table); console.log('Liabilities table rendered'); } catch (e) { console.error('Error in renderLiabilitiesTable:', e); } } function handleAddAsset(e) { e.preventDefault(); console.log('Adding asset'); try { const name = assetNameInput.value.trim(); const value = parseFloat(assetValueInput.value); if (name && !isNaN(value) && value >= 0) { assets.push({ id: Date.now(), name: name, value: value }); saveData('pfd_assets', assets); renderNetWorth(); addAssetForm.reset(); console.log('Asset added successfully'); } else { alert('Please enter a valid asset name and non-negative value.'); } } catch (e) { console.error('Error in handleAddAsset:', e); } } function handleRemoveAsset(e) { console.log('Handling remove asset'); try { if (e.target.classList.contains('pfd-remove-asset')) { const idToRemove = parseInt(e.target.getAttribute('data-id'), 10); assets = assets.filter(asset => asset.id !== idToRemove); saveData('pfd_assets', assets); renderNetWorth(); console.log('Asset removed successfully'); } } catch (e) { console.error('Error in handleRemoveAsset:', e); } } function handleAddLiability(e) { e.preventDefault(); console.log('Adding liability'); try { const name = liabilityNameInput.value.trim(); const amount = parseFloat(liabilityAmountInput.value); if (name && !isNaN(amount) && amount >= 0) { liabilities.push({ id: Date.now(), name: name, amount: amount }); saveData('pfd_liabilities', liabilities); renderNetWorth(); addLiabilityForm.reset(); console.log('Liability added successfully'); } else { alert('Please enter a valid liability name and non-negative amount.'); } } catch (e) { console.error('Error in handleAddLiability:', e); } } function handleRemoveLiability(e) { console.log('Handling remove liability'); try { if (e.target.classList.contains('pfd-remove-liability')) { const idToRemove = parseInt(e.target.getAttribute('data-id'), 10); liabilities = liabilities.filter(lib => lib.id !== idToRemove); saveData('pfd_liabilities', liabilities); renderNetWorth(); console.log('Liability removed successfully'); } } catch (e) { console.error('Error in handleRemoveLiability:', e); } } // Budget & Expenses Functionality function handleBudgetPeriodChange(e) { console.log('Handling budget period change'); try { budget.period = e.target.value.trim(); saveData('pfd_budget', budget); updateOverview(); console.log('Budget period updated'); } catch (e) { console.error('Error in handleBudgetPeriodChange:', e); } } function calculateBudgetTotals() { console.log('Calculating budget totals'); try { const totalBudgeted = budget.categories.reduce((sum, cat) => sum + (cat.budgeted || 0), 0); const totalActual = budget.categories.reduce((sum, cat) => sum + (cat.actual || 0), 0); const difference = totalBudgeted - totalActual; console.log('Budget totals:', { totalBudgeted, totalActual, difference }); return { totalBudgeted, totalActual, difference }; } catch (e) { console.error('Error in calculateBudgetTotals:', e); return { totalBudgeted: 0, totalActual: 0, difference: 0 }; } } function renderBudget() { console.log('Rendering budget'); try { renderBudgetTable(); renderExpenseChart(); updateOverview(); console.log('Budget rendered successfully'); } catch (e) { console.error('Error in renderBudget:', e); } } function renderBudgetTable() { console.log('Rendering budget table'); try { if (!budgetTableContainer) { console.error('Budget table container not found'); return; } budgetTableContainer.innerHTML = ''; if (budget.categories.length === 0) { budgetTableContainer.innerHTML = '

    No budget categories defined yet.

    '; return; } const table = document.createElement('table'); table.className = 'pfd-table pfd-budget-table'; table.innerHTML = ` Category Budgeted ($) Actual ($) Difference ($) Action ${budget.categories.map(cat => ` ${escapeHtml(cat.name)} ${formatCurrency(cat.budgeted)} ${formatCurrency(cat.budgeted - cat.actual)} `).join('')} ${renderBudgetTotalRow()} `; budgetTableContainer.appendChild(table); console.log('Budget table rendered'); } catch (e) { console.error('Error in renderBudgetTable:', e); } } function renderBudgetTotalRow() { console.log('Rendering budget total row'); try { const { totalBudgeted, totalActual, difference } = calculateBudgetTotals(); return ` Total ${formatCurrency(totalBudgeted)} ${formatCurrency(totalActual)} ${formatCurrency(difference)} `; } catch (e) { console.error('Error in renderBudgetTotalRow:', e); return ''; } } function handleAddBudgetCategory(e) { e.preventDefault(); console.log('Adding budget category'); try { const name = budgetCatNameInput.value.trim(); const budgeted = parseFloat(budgetCatAmountInput.value); if (name && !isNaN(budgeted) && budgeted >= 0) { const exists = budget.categories.some(cat => cat.name.toLowerCase() === name.toLowerCase()); if (exists) { alert(`Budget category "${name}" already exists.`); return; } budget.categories.push({ id: Date.now(), name: name, budgeted: budgeted, actual: 0 }); saveData('pfd_budget', budget); renderBudget(); addBudgetCategoryForm.reset(); console.log('Budget category added successfully'); } else { alert('Please enter a valid category name and non-negative budgeted amount.'); } } catch (e) { console.error('Error in handleAddBudgetCategory:', e); } } function handleRemoveBudgetCategory(e) { console.log('Handling remove budget category'); try { if (e.target.classList.contains('pfd-remove-budget-cat')) { const idToRemove = parseInt(e.target.getAttribute('data-id'), 10); budget.categories = budget.categories.filter(cat => cat.id !== idToRemove); saveData('pfd_budget', budget); renderBudget(); console.log('Budget category removed successfully'); } } catch (e) { console.error('Error in handleRemoveBudgetCategory:', e); } } function handleActualBudgetChange(e) { console.log('Handling actual budget change'); try { if (e.target.classList.contains('pfd-budget-actual-input')) { const idToUpdate = parseInt(e.target.getAttribute('data-id'), 10); const newActual = parseFloat(e.target.value); const category = budget.categories.find(cat => cat.id === idToUpdate); if (category && !isNaN(newActual) && newActual >= 0) { category.actual = newActual; saveData('pfd_budget', budget); renderBudget(); console.log('Budget actual updated'); } else if (category) { e.target.value = category.actual.toFixed(2); alert("Please enter a valid non-negative amount."); } } } catch (e) { console.error('Error in handleActualBudgetChange:', e); } } // Chart.js Integration function renderExpenseChart() { console.log('Rendering expense chart'); try { if (!window.Chart) { console.error('Chart.js not loaded, skipping chart rendering'); return; } const ctx = expenseChartCanvas.getContext('2d'); const categoriesWithSpending = budget.categories.filter(cat => cat.actual > 0); if (categoriesWithSpending.length === 0) { if (expenseChartInstance) { expenseChartInstance.destroy(); expenseChartInstance = null; } expenseChartCanvas.style.display = 'none'; chartNoDataMsg.style.display = 'block'; console.log('No spending data, chart hidden'); return; } expenseChartCanvas.style.display = 'block'; chartNoDataMsg.style.display = 'none'; const labels = categoriesWithSpending.map(cat => cat.name); const data = categoriesWithSpending.map(cat => cat.actual); const backgroundColors = [ '#2a9d8f', '#e9c46a', '#f4a261', '#e76f51', '#457b9d', '#264653', '#a8dadc', '#e63946', '#f1faee', '#1d3557' ]; const chartData = { labels: labels, datasets: [{ label: 'Actual Spending ($)', data: data, backgroundColor: backgroundColors.slice(0, data.length), borderColor: getComputedStyle(document.documentElement).getPropertyValue('--pfd-white-color').trim(), borderWidth: 1 }] }; const chartOptions = { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'bottom', labels: { padding: 15 } }, tooltip: { callbacks: { label: function(context) { let label = context.dataset.label || ''; if (label) { label += ': '; } if (context.parsed !== null) { label += formatCurrency(context.parsed); } return label; } } }, customCanvasBackgroundColor: { color: getComputedStyle(document.documentElement).getPropertyValue('--pfd-white-color').trim() || 'white', } } }; if (expenseChartInstance) { expenseChartInstance.destroy(); } expenseChartInstance = new Chart(ctx, { type: 'pie', data: chartData, options: chartOptions, plugins: [{ id: 'customCanvasBackgroundColor', beforeDraw: (chart, args, options) => { const {ctx} = chart; ctx.save(); ctx.globalCompositeOperation = 'destination-over'; ctx.fillStyle = options.color || '#ffffff'; ctx.fillRect(0, 0, chart.width, chart.height); ctx.restore(); } }] }); console.log('Expense chart rendered successfully'); } catch (e) { console.error('Error in renderExpenseChart:', e); } } // Savings Goals Functionality function renderSavingsGoals() { console.log('Rendering savings goals'); try { if (!goalsListContainer || !goalsListUl) { console.error('Goals list container or ul not found'); return; } goalsListUl.innerHTML = ''; goalsListContainer.querySelector('.pfd-no-data')?.remove(); if (savingsGoals.length === 0) { if (!goalsListContainer.querySelector('.pfd-no-data')) { goalsListContainer.insertAdjacentHTML('afterbegin', '

    No savings goals added yet.

    '); } console.log('No savings goals, showing no-data message'); return; } savingsGoals.sort((a, b) => a.name.localeCompare(b.name)); savingsGoals.forEach(goal => { const progress = goal.target > 0 ? Math.min((goal.current / goal.target) * 100, 100) : 0; const li = document.createElement('li'); li.setAttribute('data-id', goal.id); li.innerHTML = `

    ${escapeHtml(goal.name)}

    Saved: ${formatCurrency(goal.current)} of ${formatCurrency(goal.target)} Target
    ${progress.toFixed(1)}%
    `; goalsListUl.appendChild(li); }); updateOverview(); console.log('Savings goals rendered successfully'); } catch (e) { console.error('Error in renderSavingsGoals:', e); } } function handleAddGoal(e) { e.preventDefault(); console.log('Adding savings goal'); try { const name = goalNameInput.value.trim(); const target = parseFloat(goalTargetInput.value); const current = parseFloat(goalCurrentInput.value); if (name && !isNaN(target) && target > 0 && !isNaN(current) && current >= 0) { const exists = savingsGoals.some(g => g.name.toLowerCase() === name.toLowerCase()); if (exists) { alert(`Savings goal "${name}" already exists.`); return; } savingsGoals.push({ id: Date.now(), name: name, target: target, current: Math.min(current, target) }); saveData('pfd_savingsGoals', savingsGoals); renderSavingsGoals(); addGoalForm.reset(); console.log('Savings goal added successfully'); } else { alert('Please enter a valid goal name, positive target amount, and non-negative current amount.'); } } catch (e) { console.error('Error in handleAddGoal:', e); } } function handleRemoveGoal(e) { console.log('Handling remove goal'); try { if (e.target.classList.contains('pfd-remove-goal')) { const idToRemove = parseInt(e.target.getAttribute('data-id'), 10); savingsGoals = savingsGoals.filter(goal => goal.id !== idToRemove); saveData('pfd_savingsGoals', savingsGoals); renderSavingsGoals(); console.log('Savings goal removed successfully'); } } catch (e) { console.error('Error in handleRemoveGoal:', e); } } function handleGoalCurrentChange(e) { console.log('Handling goal current change'); try { if (e.target.classList.contains('pfd-update-goal-btn')) { const idToUpdate = parseInt(e.target.getAttribute('data-id'), 10); const inputElement = e.target.closest('li').querySelector('.pfd-goal-current-input'); const newCurrent = parseFloat(inputElement.value); const goal = savingsGoals.find(g => g.id === idToUpdate); if (goal && !isNaN(newCurrent) && newCurrent >= 0) { goal.current = Math.min(newCurrent, goal.target); saveData('pfd_savingsGoals', savingsGoals); renderSavingsGoals(); console.log('Goal current amount updated'); } else if (goal) { inputElement.value = goal.current.toFixed(2); alert("Please enter a valid non-negative amount."); } } } catch (e) { console.error('Error in handleGoalCurrentChange:', e); } } // Overview Tab Update function updateOverview() { console.log('Updating overview'); try { const { totalAssets, totalLiabilities, netWorth } = calculateNetWorth(); if (overviewNetworth) { overviewNetworth.textContent = formatCurrency(netWorth); overviewNetworth.className = netWorth >= 0 ? 'pfd-amount positive' : 'pfd-amount negative'; } if (overviewAssets) overviewAssets.textContent = formatCurrency(totalAssets); if (overviewLiabilities) overviewLiabilities.textContent = formatCurrency(totalLiabilities); const { totalBudgeted, totalActual, difference } = calculateBudgetTotals(); if (overviewBudgetPeriod) overviewBudgetPeriod.textContent = budget.period || 'N/A'; if (overviewBudgeted) overviewBudgeted.textContent = formatCurrency(totalBudgeted); if (overviewSpent) overviewSpent.textContent = formatCurrency(totalActual); if (overviewBudgetDiff) { overviewBudgetDiff.textContent = formatCurrency(difference); overviewBudgetDiff.className = difference >= 0 ? 'pfd-amount positive' : 'pfd-amount negative'; } if (overviewGoalsSummary) { overviewGoalsSummary.innerHTML = ''; if (savingsGoals.length === 0) { overviewGoalsSummary.innerHTML = '

    No active savings goals.

    '; console.log('No savings goals in overview'); return; } const goalsGrid = document.createElement('div'); goalsGrid.className = 'pfd-grid'; savingsGoals.slice(0, 4).forEach(goal => { const progress = goal.target > 0 ? Math.min((goal.current / goal.target) * 100, 100) : 0; const card = document.createElement('div'); card.className = 'pfd-summary-card'; card.innerHTML = `

    ${escapeHtml(goal.name)}

    ${progress.toFixed(1)}%

    ${formatCurrency(goal.current)} / ${formatCurrency(goal.target)}

    `; goalsGrid.appendChild(card); }); overviewGoalsSummary.appendChild(goalsGrid); if (savingsGoals.length > 4) { overviewGoalsSummary.innerHTML += `

    View all ${savingsGoals.length} goals...

    `; overviewGoalsSummary.querySelector('.pfd-switch-tab-link').addEventListener('click', (e) => { e.preventDefault(); console.log('Goals link clicked'); const targetTab = e.target.getAttribute('data-tab-target'); tabs.forEach(t => t.classList.remove('active')); tabContents.forEach(c => c.classList.remove('active')); const targetButton = dashboardContainer.querySelector(`.pfd-tab-button[data-tab="${targetTab}"]`); const targetContent = document.getElementById(`tab-${targetTab}`); if (targetButton && targetContent) { targetButton.classList.add('active'); targetContent.classList.add('active'); console.log(`Switched to goals tab via link`); } else { console.error(`Failed to switch to goals tab: button or content not found`); } }); } } console.log('Overview updated successfully'); } catch (e) { console.error('Error in updateOverview:', e); } } // PDF Export function handleDownloadPdf() { console.log('Handling PDF download'); try { if (!window.jspdf) { console.error('jsPDF not loaded, cannot generate PDF'); alert('PDF generation is unavailable due to a loading issue.'); return; } const { jsPDF } = window.jspdf; const doc = new jsPDF(); const styles = getComputedStyle(document.documentElement); const primaryColor = styles.getPropertyValue('--pfd-primary-color').trim() || '#2a9d8f'; const infoColor = styles.getPropertyValue('--pfd-info-color').trim() || '#457b9d'; const textColor = styles.getPropertyValue('--pfd-text-color').trim() || '#343a40'; const whiteColor = styles.getPropertyValue('--pfd-white-color').trim() || '#fff'; const successColor = styles.getPropertyValue('--pfd-success-color').trim() || '#2a9d8f'; const dangerColor = styles.getPropertyValue('--pfd-danger-color').trim() || '#e76f51'; let currentY = 20; const leftMargin = 15; const rightMargin = doc.internal.pageSize.width - 15; const centerPage = doc.internal.pageSize.width / 2; doc.setFontSize(18); doc.setTextColor(primaryColor); doc.text('Personal Finance Summary', centerPage, currentY, { align: 'center' }); currentY += 15; doc.setFontSize(14); doc.setTextColor(infoColor); doc.text('Net Worth Summary', leftMargin, currentY); currentY += 8; doc.setDrawColor(styles.getPropertyValue('--pfd-border-color').trim()); doc.line(leftMargin, currentY - 2, rightMargin, currentY - 2); currentY += 8; const { totalAssets, totalLiabilities, netWorth } = calculateNetWorth(); doc.setFontSize(11); doc.setTextColor(textColor); doc.text(`Total Assets: ${formatCurrency(totalAssets)}`, leftMargin, currentY); currentY += 7; doc.text(`Total Liabilities: ${formatCurrency(totalLiabilities)}`, leftMargin, currentY); currentY += 7; doc.setFont('helvetica', 'bold'); doc.setTextColor(netWorth >= 0 ? successColor : dangerColor); doc.text(`Net Worth: ${formatCurrency(netWorth)}`, leftMargin, currentY); doc.setFont('helvetica', 'normal'); currentY += 15; doc.setFontSize(14); doc.setTextColor(infoColor); doc.text(`Budget Summary (${budget.period || 'N/A'})`, leftMargin, currentY); currentY += 8; doc.line(leftMargin, currentY - 2, rightMargin, currentY - 2); currentY += 8; const { totalBudgeted, totalActual, difference } = calculateBudgetTotals(); doc.setFontSize(11); doc.setTextColor(textColor); doc.text(`Total Budgeted: ${formatCurrency(totalBudgeted)}`, leftMargin, currentY); currentY += 7; doc.text(`Total Spent: ${formatCurrency(totalActual)}`, leftMargin, currentY); currentY += 7; doc.setFont('helvetica', 'bold'); doc.setTextColor(difference >= 0 ? successColor : dangerColor); doc.text(`Difference: ${formatCurrency(difference)}`, leftMargin, currentY); doc.setFont('helvetica', 'normal'); currentY += 10; if (budget.categories.length > 0) { const budgetTableData = budget.categories.map(cat => [ cat.name, formatCurrency(cat.budgeted), formatCurrency(cat.actual), formatCurrency(cat.budgeted - cat.actual) ]); budgetTableData.push([ { content: 'Total', styles: { fontStyle: 'bold' } }, { content: formatCurrency(totalBudgeted), styles: { fontStyle: 'bold', halign: 'right' } }, { content: formatCurrency(totalActual), styles: { fontStyle: 'bold', halign: 'right' } }, { content: formatCurrency(difference), styles: { fontStyle: 'bold', halign: 'right', textColor: difference >= 0 ? successColor : dangerColor } } ]); doc.autoTable({ head: [['Category', 'Budgeted', 'Actual', 'Difference']], body: budgetTableData, startY: currentY, theme: 'grid', headStyles: { fillColor: infoColor, textColor: whiteColor, fontStyle: 'bold' }, styles: { fontSize: 9, cellPadding: 2, textColor: textColor }, columnStyles: { 1: { halign: 'right' }, 2: { halign: 'right' }, 3: { halign: 'right' } }, didParseCell: function (data) { if (data.section === 'body' && data.column.index === 3) { const rawValue = budget.categories[data.row.index]?.budgeted - budget.categories[data.row.index]?.actual; if (rawValue !== undefined && rawValue < 0) { data.cell.styles.textColor = dangerColor; } else if (rawValue !== undefined && rawValue >= 0) { data.cell.styles.textColor = successColor; } } } }); currentY = doc.lastAutoTable.finalY + 10; } if (expenseChartInstance && budget.categories.filter(cat => cat.actual > 0).length > 0) { try { const chartImage = expenseChartCanvas.toDataURL('image/png', 1.0); const chartHeight = 80; const chartWidth = 100; if (currentY + chartHeight > doc.internal.pageSize.height - 20) { doc.addPage(); currentY = 20; } doc.setFontSize(14); doc.setTextColor(infoColor); doc.text('Expense Breakdown Chart', leftMargin, currentY); currentY += 8; doc.line(leftMargin, currentY - 2, rightMargin, currentY - 2); currentY += 5; const imgX = centerPage - chartWidth / 2; doc.addImage(chartImage, 'PNG', imgX, currentY, chartWidth, chartHeight); currentY += chartHeight + 10; } catch (error) { console.error("Error adding chart to PDF:", error); doc.setTextColor(dangerColor); doc.text('Error rendering chart image.', leftMargin, currentY); currentY += 10; } } if (savingsGoals.length > 0) { if (currentY + 20 > doc.internal.pageSize.height - 20) { doc.addPage(); currentY = 20; } doc.setFontSize(14); doc.setTextColor(infoColor); doc.text('Savings Goals Progress', leftMargin, currentY); currentY += 8; doc.line(leftMargin, currentY - 2, rightMargin, currentY - 2); currentY += 8; const goalTableData = savingsGoals.map(goal => { const progress = goal.target > 0 ? Math.min((goal.current / goal.target) * 100, 100) : 0; return [ goal.name, formatCurrency(goal.target), formatCurrency(goal.current), `${progress.toFixed(1)}%` ]; }); doc.autoTable({ head: [['Goal Name', 'Target ($)', 'Current ($)', 'Progress']], body: goalTableData, startY: currentY, theme: 'grid', headStyles: { fillColor: infoColor, textColor: whiteColor, fontStyle: 'bold' }, styles: { fontSize: 9, cellPadding: 2, textColor: textColor }, columnStyles: { 1: { halign: 'right' }, 2: { halign: 'right' }, 3: { halign: 'right' } } }); } doc.save('personal-finance-summary.pdf'); console.log('PDF generated successfully'); } catch (e) { console.error('Error in handleDownloadPdf:', e); } } // Event Listeners Setup function setupEventListeners() { console.log('Setting up event listeners'); try { if (addAssetForm) addAssetForm.addEventListener('submit', handleAddAsset); if (assetsTableContainer) assetsTableContainer.addEventListener('click', handleRemoveAsset); if (addLiabilityForm) addLiabilityForm.addEventListener('submit', handleAddLiability); if (liabilitiesTableContainer) liabilitiesTableContainer.addEventListener('click', handleRemoveLiability); if (budgetPeriodInput) budgetPeriodInput.addEventListener('change', handleBudgetPeriodChange); if (addBudgetCategoryForm) addBudgetCategoryForm.addEventListener('submit', handleAddBudgetCategory); if (budgetTableContainer) { budgetTableContainer.addEventListener('click', handleRemoveBudgetCategory); budgetTableContainer.addEventListener('change', handleActualBudgetChange); } if (addGoalForm) addGoalForm.addEventListener('submit', handleAddGoal); if (goalsListUl) { goalsListUl.addEventListener('click', handleRemoveGoal); goalsListUl.addEventListener('click', handleGoalCurrentChange); } if (downloadPdfButton) downloadPdfButton.addEventListener('click', handleDownloadPdf); console.log('Event listeners attached successfully'); } catch (e) { console.error('Error in setupEventListeners:', e); } } // Initialization function init() { console.log('init called'); try { console.log('Loading assets'); assets = loadData('pfd_assets', []); console.log('Loading liabilities'); liabilities = loadData('pfd_liabilities', []); console.log('Loading budget'); budget = loadData('pfd_budget', { period: "", categories: [] }); console.log('Loading savings goals'); savingsGoals = loadData('pfd_savingsGoals', []); console.log('Rendering net worth'); renderNetWorth(); console.log('Rendering budget'); renderBudget(); console.log('Rendering savings goals'); renderSavingsGoals(); console.log('Updating overview'); updateOverview(); console.log('Setting up event listeners'); setupEventListeners(); console.log('Setting budget period input'); if (budgetPeriodInput) { budgetPeriodInput.value = budget.period; } else { console.error('budgetPeriodInput not found'); } console.log('Initialization completed'); } catch (e) { console.error('Error during initialization:', e.message, e.stack); throw e; // Rethrow to catch in outer try-catch } } // Start the application try { console.log('Starting initialization'); setupTabs(); // Call setupTabs first to ensure tabs work init(); } catch (e) { console.error('Failed to initialize dashboard:', e.message, e.stack); } });

    Take control of your financial future with WorkToolz.com’s intuitive Personal Finance Dashboard. Designed for everyday users, this powerful tool simplifies the complexities of managing your money, helping you achieve your financial goals with ease. Forget about confusing jargon and complicated spreadsheets; our dashboard presents your financial snapshot in a clear, natural, and easy-to-understand format.

    The Personal Finance Dashboard provides a comprehensive overview of your financial health, allowing you to track your net worth, total assets, and total liabilities at a glance. Understand exactly where your money is going with our detailed budget and expenses section. You can set up budget periods, monitor your total budgeted amounts against your actual spending, and quickly identify any budget differences. This clear visualization empowers you to make informed decisions about your expenditures and adjust your habits to align with your financial objectives.

    Beyond tracking, our dashboard helps you plan for the future by enabling you to set and monitor savings goals. Whether you’re saving for a down payment on a house, a dream vacation, or simply building an emergency fund, the Personal Finance Dashboard keeps your goals in sight and motivates you to stay on track. The tool is designed to be user-friendly, ensuring that even those new to financial management can navigate its features effortlessly. We believe that managing your money should be straightforward and stress-free, and our dashboard is built to reflect that philosophy.

    Your financial data is stored locally in your browser, providing you with peace of mind regarding your privacy. There’s no need to worry about sensitive information being stored on external servers. However, remember that clearing your browser data will remove your saved information, so always keep that in mind when managing your financial records. The Personal Finance Dashboard is your personal guide to financial clarity, helping you understand your current situation, plan for what’s ahead, and ultimately achieve financial freedom. Start your journey towards better money management today with WorkToolz.com.

    Scroll to Top