Expense Categorization Tool

Expense Categorization Tool

Automatically sort your expenses and generate a professional report.

Add Your Expenses

Paste your expenses below (one per line, e.g., "Starbucks Coffee, 5.75") or add them manually.

Review Your Expenses

Expense Report

Spending by Category

No expenses entered yet.

'; return; } const categoryOptions = categories.map(c => ``).join(''); const tableRows = expenseData.expenses.map(exp => ` ${exp.description} $${exp.amount.toFixed(2)} `).join(''); container.innerHTML = ` ${tableRows}
Description Amount Category
`; document.querySelectorAll('.category-select').forEach(select => { select.addEventListener('change', (e) => { const expenseId = parseInt(e.target.dataset.id); const newCategory = e.target.value; const expense = expenseData.expenses.find(ex => ex.id === expenseId); if (expense) expense.category = newCategory; }); }); } function renderReport() { const summary = {}; categories.forEach(c => summary[c] = 0); let total = 0; expenseData.expenses.forEach(exp => { summary[exp.category] += exp.amount; total += exp.amount; }); // Render Summary Table const summaryTableContainer = document.getElementById('summary-table-container'); const summaryRows = categories.map(cat => { if (summary[cat] > 0) { return ` ${cat} $${summary[cat].toFixed(2)} ${total > 0 ? (summary[cat] / total * 100).toFixed(1) : 0}% `; } return ''; }).join(''); summaryTableContainer.innerHTML = `

Summary

${summaryRows}
CategoryTotal% of Total
Total$${total.toFixed(2)}100%
`; // Render Chart const ctx = document.getElementById('expense-chart').getContext('2d'); const chartData = { labels: [], datasets: [{ data: [], backgroundColor: ['#22c55e', '#3b82f6', '#8b5cf6', '#ec4899', '#f97316', '#eab308', '#64748b', '#ef4444'], }] }; categories.forEach(cat => { if (summary[cat] > 0) { chartData.labels.push(cat); chartData.datasets[0].data.push(summary[cat]); } }); if (expenseChartInstance) expenseChartInstance.destroy(); expenseChartInstance = new Chart(ctx, { type: 'doughnut', data: chartData, options: { responsive: true, maintainAspectRatio: true, plugins: { legend: { position: 'bottom' } } } }); } // --- PDF GENERATION --- async function generatePdfReport() { downloadPdfBtn.disabled = true; downloadPdfBtn.textContent = 'Generating...'; const summary = {}; categories.forEach(c => summary[c] = 0); let total = 0; expenseData.expenses.forEach(exp => { summary[exp.category] += exp.amount; total += exp.amount; }); // Prepare chart data for PDF const pdfChartData = { labels: [], datasets: [{ data: [], backgroundColor: ['#22c55e', '#3b82f6', '#8b5cf6', '#ec4899', '#f97316', '#eab308', '#64748b', '#ef4444'] }]}; categories.forEach(cat => { if (summary[cat] > 0) { pdfChartData.labels.push(cat); pdfChartData.datasets[0].data.push(summary[cat]); } }); // Prepare table data for PDF const summaryTableRows = categories.map(cat => { if (summary[cat] > 0) { return `${cat}$${summary[cat].toFixed(2)}${total > 0 ? (summary[cat] / total * 100).toFixed(1) : 0}%`; } return ''; }).join(''); const detailsHtml = categories.map(cat => { const items = expenseData.expenses.filter(e => e.category === cat); if (items.length === 0) return ''; const itemRows = items.map(item => `${item.description}$${item.amount.toFixed(2)}`).join(''); return `
${cat}
${itemRows}
DescriptionAmount
`; }).join(''); const reportHtml = `

Expense Report

Generated on:
${new Date("2025-09-11").toLocaleDateString()}

${summaryTableRows}
CategoryTotal%
Total$${total.toFixed(2)}100%
${detailsHtml}
`; const pdfTemplate = document.getElementById('pdf-template'); pdfTemplate.innerHTML = reportHtml; pdfTemplate.classList.remove('invisible'); // Render chart on the hidden canvas const pdfCtx = document.getElementById('pdf-chart').getContext('2d'); new Chart(pdfCtx, { type: 'doughnut', data: pdfChartData, options: { animation: { duration: 0 }, plugins: { legend: { display: false } } } }); // A small delay to ensure chart is rendered before html2canvas runs setTimeout(async () => { try { const { jsPDF } = window.jspdf; const canvas = await html2canvas(pdfTemplate.querySelector('.pdf-report-container'), { scale: 2 }); const imgData = canvas.toDataURL('image/png'); const pdf = new jsPDF({ orientation: 'p', unit: 'pt', format: 'a4' }); const pdfWidth = pdf.internal.pageSize.getWidth(); const pdfHeight = (canvas.height * pdfWidth) / canvas.width; pdf.addImage(imgData, 'PNG', 0, 0, pdfWidth, pdfHeight); pdf.save('Expense_Report.pdf'); } catch(e) { console.error('PDF Generation Error:', e); } finally { downloadPdfBtn.disabled = false; downloadPdfBtn.textContent = 'Download Expense Report'; pdfTemplate.classList.add('invisible'); pdfTemplate.innerHTML = ''; } }, 500); } downloadPdfBtn.addEventListener('click', generatePdfReport); // --- INITIALIZATION --- switchTab(0); });
Scroll to Top