Overall Compliance Score
${overallScore.toFixed(0)}%
`;
// Populate category scores
const scoresContainer = document.getElementById('category-scores-container');
categoryScores.forEach(cat => {
const scoreEl = document.createElement('div');
scoreEl.innerHTML = `
${cat.name}
${cat.score.toFixed(0)}%
`;
scoresContainer.appendChild(scoreEl);
});
// Render Chart
const chartCanvas = document.getElementById('complianceRadarChart').getContext('2d');
new Chart(chartCanvas, {
type: 'radar',
data: {
labels: categoryScores.map(cs => cs.name),
datasets: [{
label: 'Compliance Score',
data: categoryScores.map(cs => cs.score),
backgroundColor: 'rgba(59, 130, 246, 0.2)',
borderColor: 'rgba(59, 130, 246, 1)',
borderWidth: 2,
pointBackgroundColor: 'rgba(59, 130, 246, 1)',
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
r: {
angleLines: { color: '#e5e7eb' },
grid: { color: '#e5e7eb' },
pointLabels: { font: { size: 12 } },
suggestedMin: 0,
suggestedMax: 100
}
},
plugins: { legend: { display: false } }
}
});
// Add PDF download listener
document.getElementById('download-pdf-btn').addEventListener('click', generatePdf);
};
const renderChecklist = (category, index) => {
const checklistContent = document.getElementById(`content-${tabIdentifiers[index]}`);
if (!checklistContent) return;
let itemsHtml = category.items.map((item, itemIndex) => `
`).join('');
checklistContent.innerHTML = `
${category.name}
${itemsHtml}
`;
};
const renderConfig = () => {
const configContent = document.getElementById('content-config');
if (!configContent) return;
let categoriesHtml = appData.categories.map((cat, catIndex) => `
`).join('');
configContent.innerHTML = `
Customize Compliance Checklist
`;
document.getElementById('data-config-form').addEventListener('submit', handleConfigUpdate);
};
const switchTab = (tabIndex) => {
activeTabIndex = tabIndex;
// Update tab buttons
document.querySelectorAll('.tab-btn').forEach((btn, index) => {
btn.classList.toggle('active', index === tabIndex);
});
// Update content visibility
document.querySelectorAll('.tab-content').forEach((content, index) => {
content.classList.toggle('hidden', index !== tabIndex);
});
updateNavButtons();
};
const updateNavButtons = () => {
prevTabBtn.disabled = activeTabIndex === 0;
nextTabBtn.disabled = activeTabIndex === tabIdentifiers.length - 1;
};
const handleConfigUpdate = (e) => {
e.preventDefault();
const newCategories = [];
appData.categories.forEach((_, catIndex) => {
const catName = document.getElementById(`cat-name-${catIndex}`).value;
const items = [];
document.querySelectorAll(`#items-container-${catIndex} .item-input`).forEach(input => {
const originalItem = appData.categories[catIndex].items[input.dataset.itemIndex];
items.push({ text: input.value, compliant: originalItem.compliant });
});
newCategories.push({ name: catName, items: items });
});
appData.categories = newCategories;
// Re-initialize the entire UI with new data
initializeUI();
alert('Checklist updated successfully!');
};
const handleCheckboxChange = (e) => {
const catIndex = e.target.dataset.catIndex;
const itemIndex = e.target.dataset.itemIndex;
appData.categories[catIndex].items[itemIndex].compliant = e.target.checked;
renderDashboard(); // Update score dynamically
};
const generatePdf = () => {
loadingOverlay.style.display = 'flex';
const { jsPDF } = window.jspdf;
const pdfContent = document.getElementById('pdf-content-area');
const pdfHeader = document.getElementById('pdf-header');
document.getElementById('pdf-generated-date').textContent = new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' });
pdfHeader.classList.remove('hidden');
html2canvas(pdfContent, { scale: 2, useCORS: true, logging: false })
.then(canvas => {
pdfHeader.classList.add('hidden');
const imgData = canvas.toDataURL('image/jpeg', 0.95);
const pdf = new jsPDF({
orientation: 'p',
unit: 'px',
format: 'a4'
});
const pdfWidth = pdf.internal.pageSize.getWidth();
const pdfHeight = pdf.internal.pageSize.getHeight();
const canvasWidth = canvas.width;
const canvasHeight = canvas.height;
const ratio = canvasWidth / canvasHeight;
const height = pdfWidth / ratio;
pdf.addImage(imgData, 'JPEG', 0, 0, pdfWidth, height > pdfHeight ? pdfHeight : height);
pdf.save('Banking-Compliance-Report.pdf');
loadingOverlay.style.display = 'none';
}).catch(err => {
console.error("PDF generation failed:", err);
pdfHeader.classList.add('hidden');
loadingOverlay.style.display = 'none';
alert('An error occurred generating the PDF.');
});
};
// --- INITIALIZATION ---
const initializeUI = () => {
// Clear existing UI elements
tabsContainer.innerHTML = '';
mainContent.innerHTML = '';
// Define tabs structure
const tabs = [
{ name: 'Compliance Dashboard', id: 'dashboard' },
...appData.categories.map(cat => ({ name: cat.name, id: cat.name.toLowerCase().replace(/\s+/g, '-') })),
{ name: 'Data Configuration', id: 'config' }
];
tabIdentifiers = tabs.map(t => t.id);
// Create tab buttons and content divs
tabs.forEach((tab, index) => {
// Button
const button = document.createElement('button');
button.type = 'button';
button.id = `tab-${tab.id}`;
button.className = `tab-btn py-3 px-4 border-b-2 font-medium text-sm sm:text-base`;
button.textContent = tab.name;
button.addEventListener('click', () => switchTab(index));
tabsContainer.appendChild(button);
// Content
const contentDiv = document.createElement('div');
contentDiv.id = `content-${tab.id}`;
contentDiv.className = 'tab-content';
mainContent.appendChild(contentDiv);
});
// Populate content for each tab
renderDashboard();
appData.categories.forEach((cat, index) => {
renderChecklist(cat, index + 1); // +1 to offset dashboard
});
renderConfig();
// Set initial active tab
switchTab(0);
// Attach checkbox listeners
mainContent.querySelectorAll('.compliance-checkbox').forEach(cb => {
cb.addEventListener('change', handleCheckboxChange);
});
};
initializeUI(); // Initial call to build the UI
lucide.createIcons();
prevTabBtn.addEventListener('click', () => {
if (activeTabIndex > 0) switchTab(activeTabIndex - 1);
});
nextTabBtn.addEventListener('click', () => {
if (activeTabIndex < tabIdentifiers.length - 1) switchTab(activeTabIndex + 1);
});
});