`;
riskRegisterList.appendChild(card);
});
};
const renderConfigList = () => {
configRiskList.innerHTML = '';
if (risks.length === 0) {
configRiskList.innerHTML = `
`;
configRiskList.appendChild(item);
});
};
// --- UI & TAB LOGIC ---
const updateTabUI = () => {
tabs.forEach(tab => tab.classList.toggle('active', tab.dataset.tab === currentTab));
tabContents.forEach(content => {
if (content.id === `tab-${currentTab}`) {
content.classList.add('active', 'fade-in');
} else {
content.classList.remove('active', 'fade-in');
}
});
const currentIndex = tabOrder.indexOf(currentTab);
prevBtn.disabled = currentIndex === 0;
nextBtn.disabled = currentIndex === tabOrder.length - 1;
// Render content when tab is shown
if (currentTab === 'dashboard') renderRiskMatrix();
if (currentTab === 'register') renderRiskRegister();
if (currentTab === 'config') renderConfigList();
};
const changeTab = (direction) => {
const currentIndex = tabOrder.indexOf(currentTab);
const newIndex = currentIndex + direction;
if (newIndex >= 0 && newIndex < tabOrder.length) {
currentTab = tabOrder[newIndex];
updateTabUI();
}
};
// --- EVENT LISTENERS ---
tabs.forEach(tab => tab.addEventListener('click', () => {
currentTab = tab.dataset.tab;
updateTabUI();
}));
prevBtn.addEventListener('click', () => changeTab(-1));
nextBtn.addEventListener('click', () => changeTab(1));
riskForm.addEventListener('submit', (e) => {
e.preventDefault();
const id = document.getElementById('risk-id').value;
const newRisk = {
id: id ? parseInt(id) : Date.now(),
description: document.getElementById('risk-description').value,
category: document.getElementById('risk-category').value,
likelihood: parseInt(document.getElementById('risk-likelihood').value),
impact: parseInt(document.getElementById('risk-impact').value),
mitigation: document.getElementById('risk-mitigation').value,
};
if (id) { // Editing
risks = risks.map(r => r.id === newRisk.id ? newRisk : r);
} else { // Adding
risks.push(newRisk);
}
resetForm();
renderConfigList();
});
cancelEditBtn.addEventListener('click', resetForm);
configRiskList.addEventListener('click', (e) => {
const target = e.target;
const id = parseInt(target.dataset.id);
if (target.classList.contains('edit-btn')) {
const riskToEdit = risks.find(r => r.id === id);
if (riskToEdit) populateForm(riskToEdit);
}
if (target.classList.contains('delete-btn')) {
risks = risks.filter(r => r.id !== id);
renderConfigList();
}
});
// --- FORM & DATA HANDLING ---
function populateForm(risk) {
formTitle.textContent = 'Edit Risk';
document.getElementById('risk-id').value = risk.id;
document.getElementById('risk-description').value = risk.description;
document.getElementById('risk-category').value = risk.category;
document.getElementById('risk-likelihood').value = risk.likelihood;
document.getElementById('risk-impact').value = risk.impact;
document.getElementById('risk-mitigation').value = risk.mitigation;
cancelEditBtn.classList.remove('hidden');
}
function resetForm() {
formTitle.textContent = 'Add New Risk';
riskForm.reset();
document.getElementById('risk-id').value = '';
cancelEditBtn.classList.add('hidden');
}
// --- PDF DOWNLOAD ---
downloadPdfBtn.addEventListener('click', () => {
if (typeof window.jspdf === 'undefined') {
console.error('PDF generation library (jsPDF) is not available.');
return;
}
const { jsPDF } = window.jspdf;
const doc = new jsPDF({ unit: 'pt', format: 'a4' });
if (typeof doc.autoTable === 'undefined') {
console.error('The PDF autotable plugin is not available. PDF cannot be generated.');
return;
}
// Header
doc.setFont('helvetica', 'bold');
doc.setFontSize(22);
doc.setTextColor('#1e293b');
doc.text('Legal Risk Assessment Report', doc.internal.pageSize.getWidth() / 2, 60, { align: 'center' });
// Risk Matrix Drawing
doc.setFont('helvetica', 'bold');
doc.setFontSize(16);
doc.text('Risk Matrix', 40, 120);
const matrixX = 40, matrixY = 140, matrixSize = 250, cellSize = matrixSize / 5;
// Draw cells and colors
for (let row = 0; row < 5; row++) {
for (let col = 0; col < 5; col++) {
const likelihood = 5 - row;
const impact = col + 1;
doc.setFillColor(getRiskColorHex(likelihood, impact).substring(1)); // Remove #
doc.rect(matrixX + col * cellSize, matrixY + row * cellSize, cellSize, cellSize, 'F');
}
}
// Draw risk dots
doc.setFont('helvetica', 'bold');
doc.setFontSize(8);
risks.forEach((risk, index) => {
const x = matrixX + (risk.impact - 0.5) * cellSize;
const y = matrixY + (5.5 - risk.likelihood) * cellSize;
doc.setFillColor(255, 255, 255);
doc.circle(x, y, 7, 'F');
doc.setFillColor(0, 0, 0);
doc.circle(x, y, 6, 'F');
doc.setTextColor(255, 255, 255);
doc.text(String(index + 1), x, y, { align: 'center', baseline: 'middle' });
});
// Risk Register Table
const tableData = risks.map((risk, index) => [
`#${index + 1}`,
risk.description,
risk.category,
`${risk.likelihood} (L) x ${risk.impact} (I) = ${risk.likelihood * risk.impact}`,
risk.mitigation
]);
doc.autoTable({
head: [['ID', 'Description', 'Category', 'Score', 'Mitigation']],
body: tableData,
startY: matrixY + matrixSize + 40,
theme: 'grid',
headStyles: { fillColor: '#f1f5f9', textColor: '#334155', fontStyle: 'bold' },
styles: { cellPadding: 5, fontSize: 9, font: 'helvetica' },
columnStyles: {
0: { cellWidth: 30 },
1: { cellWidth: 150 },
2: { cellWidth: 80 },
3: { cellWidth: 80 },
4: { cellWidth: 'auto' }
}
});
doc.save('Legal-Risk-Assessment-Report.pdf');
});
// --- INITIALIZATION ---
updateTabUI();
});
No risks to configure.
`;
return;
}
risks.forEach(risk => {
const item = document.createElement('div');
item.className = 'p-3 border rounded-md bg-white flex justify-between items-center';
item.innerHTML = `
${risk.description}
L: ${risk.likelihood}, I: ${risk.impact}
