Overdue Filings
${overdueFilings}
`;
};
const renderPaymentHistoryChart = () => {
const ctx = document.getElementById('paymentHistoryChart').getContext('2d');
const today = new Date('2025-07-26T19:40:00+06:00');
const last12Months = Array.from({ length: 12 }, (_, i) => {
const d = new Date(today);
d.setMonth(d.getMonth() - i);
return { year: d.getFullYear(), month: d.getMonth() };
}).reverse();
const labels = last12Months.map(d => new Date(d.year, d.month).toLocaleString('default', { month: 'short', year: 'numeric' }));
const data = last12Months.map(d => {
return taxRecords
.filter(r => r.filingDate && new Date(r.filingDate).getFullYear() === d.year && new Date(r.filingDate).getMonth() === d.month)
.reduce((sum, r) => sum + r.amount, 0);
});
if (paymentHistoryChart) paymentHistoryChart.destroy();
paymentHistoryChart = new Chart(ctx, {
type: 'bar',
data: {
labels,
datasets: [{
label: 'Amount Paid ($)',
data,
backgroundColor: 'rgba(5, 150, 105, 0.6)',
borderColor: 'rgba(5, 150, 105, 1)',
borderWidth: 1
}]
},
options: {
responsive: true, maintainAspectRatio: false,
scales: { y: { beginAtZero: true, ticks: { callback: value => '$' + value.toLocaleString() } } }
}
});
};
const renderFilingStatusChart = () => {
const ctx = document.getElementById('filingStatusChart').getContext('2d');
const statusCounts = statuses.map(s => taxRecords.filter(t => t.status === s).length);
if (filingStatusChart) filingStatusChart.destroy();
filingStatusChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: statuses,
datasets: [{
data: statusCounts,
backgroundColor: ['#fbbf24', '#10b981', '#ef4444'], // Amber, Emerald, Red
}]
},
options: { responsive: true, maintainAspectRatio: false }
});
};
const renderDeadlinesTable = () => {
const container = document.getElementById('deadlines-table-container');
const sortedRecords = [...taxRecords].sort((a, b) => new Date(a.dueDate) - new Date(b.dueDate));
let tableHtml = `
| Form Name |
Period |
Due Date |
Status |
Amount Paid |
`;
sortedRecords.forEach(r => {
let statusClass = '';
if (r.status === 'Filed') statusClass = 'bg-emerald-100 text-emerald-800';
else if (r.status === 'Pending') statusClass = 'bg-amber-100 text-amber-800';
else if (r.status === 'Overdue') statusClass = 'bg-red-100 text-red-800';
tableHtml += `
| ${r.formName} |
${r.period} |
${r.dueDate} |
${r.status} |
$${(r.amount || 0).toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })} |
`;
});
tableHtml += `
`;
container.innerHTML = tableHtml;
};
const renderRecordListEditor = () => {
const container = recordListEditor.querySelector('.space-y-2');
container.innerHTML = '';
taxRecords.forEach(r => {
const el = document.createElement('div');
el.className = 'flex items-center justify-between p-3 bg-gray-50 rounded-md';
el.innerHTML = `
${r.formName} - ${r.period}
Status: ${r.status} | Due: ${r.dueDate}
`;
container.appendChild(el);
});
};
// --- EVENT HANDLERS ---
taxForm.addEventListener('submit', (e) => {
e.preventDefault();
const id = document.getElementById('record-id').value;
const newRecord = {
formName: document.getElementById('record-form-name').value,
period: document.getElementById('record-period').value,
dueDate: document.getElementById('record-due-date').value,
filingDate: document.getElementById('record-filing-date').value,
amount: parseFloat(document.getElementById('record-amount').value) || 0,
status: document.getElementById('record-status').value,
};
if (id) {
const index = taxRecords.findIndex(r => r.id == id);
taxRecords[index] = { ...taxRecords[index], ...newRecord };
} else {
newRecord.id = taxRecords.length > 0 ? Math.max(...taxRecords.map(r => r.id)) + 1 : 1;
taxRecords.push(newRecord);
}
resetForm();
renderAll();
});
recordListEditor.addEventListener('click', (e) => {
if (e.target.classList.contains('edit-btn')) {
const id = e.target.dataset.recordId;
const record = taxRecords.find(r => r.id == id);
if (record) populateFormForEdit(record);
}
if (e.target.classList.contains('delete-btn')) {
const id = e.target.dataset.recordId;
if (confirm('Are you sure you want to delete this record?')) {
taxRecords = taxRecords.filter(r => r.id != id);
renderAll();
}
}
});
cancelEditBtn.addEventListener('click', resetForm);
downloadPdfBtn.addEventListener('click', () => {
const exportArea = document.getElementById('dashboard-export-area');
const mainTitleEl = document.querySelector('#tax-tool-container h1');
if (!exportArea || !mainTitleEl) return;
const originalBtnText = downloadPdfBtn.innerHTML;
downloadPdfBtn.disabled = true;
downloadPdfBtn.innerHTML = `
Processing...`;
html2canvas(exportArea, { scale: 2, useCORS: true, windowWidth: exportArea.scrollWidth, windowHeight: exportArea.scrollHeight })
.then(canvas => {
const { jsPDF } = window.jspdf;
const imgData = canvas.toDataURL('image/png');
const pdf = new jsPDF({ orientation: 'landscape', unit: 'mm', format: 'a4' });
const pageMargin = 15;
const pdfPageWidth = pdf.internal.pageSize.getWidth();
const pdfPageHeight = pdf.internal.pageSize.getHeight();
const pdfContentWidth = pdfPageWidth - (2 * pageMargin);
const canvasAspectRatio = canvas.width / canvas.height;
const pdfImgHeight = pdfContentWidth / canvasAspectRatio;
let yPos = pageMargin;
pdf.setFontSize(18).setFont('helvetica', 'bold');
pdf.text(mainTitleEl.innerText, pdfPageWidth / 2, yPos, { align: 'center' });
yPos += 12;
let heightLeft = pdfImgHeight;
let positionOnCanvas = 0;
pdf.addImage(imgData, 'PNG', pageMargin, yPos, pdfContentWidth, pdfImgHeight);
heightLeft -= (pdfPageHeight - yPos - pageMargin);
while (heightLeft > 0) {
positionOnCanvas -= (pdfPageHeight - (2 * pageMargin));
pdf.addPage();
pdf.addImage(imgData, 'PNG', pageMargin, positionOnCanvas + pageMargin, pdfContentWidth, pdfImgHeight);
heightLeft -= (pdfPageHeight - (2 * pageMargin));
}
pdf.save(`tax-compliance-dashboard-${new Date().toISOString().slice(0,10)}.pdf`);
})
.catch(err => { console.error("PDF generation failed:", err); alert("Error generating PDF."); })
.finally(() => {
downloadPdfBtn.disabled = false;
downloadPdfBtn.innerHTML = originalBtnText;
});
});
// --- HELPER FUNCTIONS ---
function populateFormForEdit(record) {
document.getElementById('record-id').value = record.id;
document.getElementById('record-form-name').value = record.formName;
document.getElementById('record-period').value = record.period;
document.getElementById('record-due-date').value = record.dueDate;
document.getElementById('record-filing-date').value = record.filingDate;
document.getElementById('record-amount').value = record.amount;
document.getElementById('record-status').value = record.status;
taxForm.querySelector('button[type="submit"]').textContent = 'Update Record';
cancelEditBtn.classList.remove('hidden');
taxForm.scrollIntoView({ behavior: 'smooth' });
}
function resetForm() {
taxForm.reset();
document.getElementById('record-id').value = '';
taxForm.querySelector('button[type="submit"]').textContent = 'Add Record';
cancelEditBtn.classList.add('hidden');
}
// --- INITIALIZATION ---
const switchTab = (tabName) => {
if (tabName === 'dashboard') {
tabDashboardBtn.classList.add('active');
tabConfigBtn.classList.remove('active');
tabDashboardContent.classList.remove('hidden');
tabConfigContent.classList.add('hidden');
prevTabBtn.disabled = true;
nextTabBtn.disabled = false;
} else {
tabDashboardBtn.classList.remove('active');
tabConfigBtn.classList.add('active');
tabDashboardContent.classList.add('hidden');
tabConfigContent.classList.remove('hidden');
prevTabBtn.disabled = false;
nextTabBtn.disabled = true;
}
};
tabDashboardBtn.addEventListener('click', () => switchTab('dashboard'));
tabConfigBtn.addEventListener('click', () => switchTab('config'));
prevTabBtn.addEventListener('click', () => switchTab('dashboard'));
nextTabBtn.addEventListener('click', () => switchTab('config'));
switchTab('dashboard');
renderAll();
});