`;
}).join('');
}
function renderConfigTable() {
configTableBody.innerHTML = complianceItems.map(item => `
`).join('');
}
function updateDashboard() {
const statusCounts = { compliant: 0, in_progress: 0, non_compliant: 0, not_assessed: 0 };
const lawStats = {};
complianceItems.forEach(item => {
statusCounts[item.status]++;
if (!lawStats[item.law]) {
lawStats[item.law] = { compliant: 0, in_progress: 0, non_compliant: 0, not_assessed: 0, total: 0 };
}
lawStats[item.law][item.status]++;
lawStats[item.law].total++;
});
// Overall Chart
const overallCtx = document.getElementById('overall-chart').getContext('2d');
if (charts.overall) charts.overall.destroy();
charts.overall = new Chart(overallCtx, {
type: 'doughnut',
data: {
labels: Object.values(statusMap).map(s => s.label),
datasets: [{
data: Object.values(statusCounts),
backgroundColor: Object.values(statusMap).map(s => s.color),
borderColor: '#fff',
}]
},
options: { responsive: true, plugins: { legend: { position: 'bottom' } } }
});
// Legislation Chart
const legislationCtx = document.getElementById('legislation-chart').getContext('2d');
if (charts.legislation) charts.legislation.destroy();
charts.legislation = new Chart(legislationCtx, {
type: 'bar',
data: {
labels: Object.keys(lawStats),
datasets: Object.keys(statusMap).map(status => ({
label: statusMap[status].label,
data: Object.values(lawStats).map(law => (law[status] / law.total) * 100),
backgroundColor: statusMap[status].color,
}))
},
options: {
responsive: true, maintainAspectRatio: false,
scales: { x: { stacked: true }, y: { stacked: true, beginAtZero: true, max: 100, ticks: { callback: value => value + '%' } } },
plugins: { legend: { display: false }, tooltip: { callbacks: { label: (c) => `${c.dataset.label}: ${c.raw.toFixed(1)}%` } } }
}
});
}
// --- PDF GENERATION ---
function generatePDF() {
const { jsPDF } = window.jspdf;
const doc = new jsPDF();
doc.setFontSize(20);
doc.text("Financial Fraud Compliance Report", 105, 22, { align: 'center' });
doc.setFontSize(12);
doc.text(`Generated on: ${new Date().toLocaleDateString()}`, 105, 30, { align: 'center' });
doc.setFontSize(16);
doc.text("Compliance Summary", 14, 45);
const summaryData = Object.keys(statusMap).map(key => [
statusMap[key].label,
complianceItems.filter(i => i.status === key).length.toString()
]);
doc.autoTable({
startY: 50,
head: [['Status', 'Number of Items']],
body: summaryData,
theme: 'striped',
headStyles: { fillColor: [79, 70, 229] },
});
doc.setFontSize(16);
doc.text("Detailed Checklist Status", 14, doc.autoTable.previous.finalY + 15);
const detailedData = complianceItems.map(item => [
item.law,
item.section,
item.description,
statusMap[item.status].label
]);
doc.autoTable({
startY: doc.autoTable.previous.finalY + 20,
head: [['Legislation', 'Section', 'Description', 'Status']],
body: detailedData,
theme: 'grid',
headStyles: { fillColor: [79, 70, 229] },
columnStyles: { 2: { cellWidth: 80 } }
});
doc.save('Financial-Fraud-Compliance-Report.pdf');
}
// --- EVENT LISTENERS ---
tabButtons.forEach(btn => btn.addEventListener('click', () => switchTab(btn.dataset.tab)));
prevBtn.addEventListener('click', () => handleNav(-1));
nextBtn.addEventListener('click', () => handleNav(1));
downloadPdfBtn.addEventListener('click', generatePDF);
checklistContainer.addEventListener('change', e => {
if (e.target.type === 'radio') {
const id = parseInt(e.target.closest('[data-item-id]').dataset.itemId);
const item = complianceItems.find(i => i.id === id);
if (item) {
item.status = e.target.value;
updateDashboard();
}
}
});
configTableBody.addEventListener('input', e => {
const input = e.target.closest('.config-input');
if (input) {
const id = parseInt(input.closest('[data-item-id]').dataset.itemId);
const item = complianceItems.find(i => i.id === id);
if (item) {
item[input.dataset.field] = input.value;
}
}
});
configTableBody.addEventListener('focusout', () => {
renderAll(); // Re-render everything if config changes to update headers etc.
});
configTableBody.addEventListener('click', e => {
const btn = e.target.closest('.delete-item-btn');
if (btn) {
const id = parseInt(btn.closest('[data-item-id]').dataset.itemId);
complianceItems = complianceItems.filter(i => i.id !== id);
renderAll();
}
});
addItemBtn.addEventListener('click', () => {
const newId = complianceItems.length ? Math.max(...complianceItems.map(i => i.id)) + 1 : 1;
complianceItems.push({
id: newId, law: "New Law", section: "New Section", description: "Enter description here.", status: "not_assessed"
});
renderAll();
});
// --- INITIALIZATION ---
function init() {
switchTab('dashboard');
renderAll();
}
init();
});
