Critical-Risk Clauses
${criticalRiskClauses}
`;
};
const renderClauseList = () => {
const container = document.getElementById('clause-list-container');
const listDiv = container.querySelector('#clause-list') || document.createElement('div');
listDiv.id = 'clause-list';
listDiv.className = 'space-y-3 mt-4';
listDiv.innerHTML = '';
if (clauses.length === 0) {
listDiv.innerHTML = '
No clauses added yet.
';
} else {
clauses.forEach(clause => {
listDiv.innerHTML += `
${clause.title}
${clause.text}
`;
});
}
container.appendChild(listDiv);
};
const renderRiskAssessment = () => {
const container = document.getElementById('risk-assessment-container');
if (!container) return;
container.innerHTML = '';
if (clauses.length === 0) {
container.innerHTML = '
Add clauses in the "Contract & Clause Input" tab to assess risks.
';
}
const likelihoodOptions = Object.keys(riskMatrix.likelihood).map(k => `
`).join('');
const impactOptions = Object.keys(riskMatrix.impact).map(k => `
`).join('');
clauses.forEach(clause => {
const risksHtml = clause.risks.map((risk, index) => `
`).join('');
container.innerHTML += `
${clause.title}
${risksHtml}
`;
});
};
const renderAll = () => {
renderDashboard();
renderClauseList();
renderRiskAssessment();
};
// --- EVENT HANDLERS & FORM LOGIC ---
function handleClauseSave(e) {
e.preventDefault();
const id = document.getElementById('clause-id').value;
const title = document.getElementById('clause-title').value;
const text = document.getElementById('clause-text').value;
if (id) {
const index = clauses.findIndex(c => c.id == id);
if (index !== -1) clauses[index] = { ...clauses[index], title, text };
} else {
clauses.push({ id: getNextId(clauses), title, text, risks: [] });
}
clauseForm.reset();
document.getElementById('clause-id').value = '';
renderAll();
}
window.editClause = (id) => {
const clause = clauses.find(c => c.id === id);
if(clause) {
document.getElementById('clause-id').value = clause.id;
document.getElementById('clause-title').value = clause.title;
document.getElementById('clause-text').value = clause.text;
document.getElementById('clause-title').focus();
}
};
window.deleteClause = (id) => {
clauses = clauses.filter(c => c.id !== id);
renderAll();
};
window.addRisk = (clauseId) => {
const clause = clauses.find(c => c.id === clauseId);
if (clause) {
clause.risks.push({ riskType: 'New Risk', likelihood: 'Low', impact: 'Low', mitigation: '' });
renderRiskAssessment();
}
};
window.updateRisk = (clauseId, riskIndex, field, value) => {
const clause = clauses.find(c => c.id === clauseId);
if(clause && clause.risks[riskIndex]) {
clause.risks[riskIndex][field] = value;
renderDashboard(); // Update dashboard scores in real-time
}
};
window.deleteRisk = (clauseId, riskIndex) => {
const clause = clauses.find(c => c.id === clauseId);
if (clause) {
clause.risks.splice(riskIndex, 1);
renderAll();
}
};
// --- TAB NAVIGATION ---
window.changeTab = (tabIndex) => {
// When changing tabs, re-render everything to ensure data consistency
renderAll();
currentTab = tabIndex;
const tabs = document.querySelectorAll('.tab');
const tabContents = document.querySelectorAll('.tab-content');
tabs.forEach((tab, index) => {
tab.classList.toggle('tab-active', index === tabIndex);
tab.classList.toggle('tab-inactive', index !== tabIndex);
});
tabContents.forEach((content, index) => {
content.style.display = index === tabIndex ? 'block' : 'none';
});
};
window.navigateTab = (direction) => {
const numTabs = document.querySelectorAll('.tab').length;
let newTab = currentTab + direction;
if (newTab < 0) newTab = 0;
if (newTab >= numTabs) newTab = numTabs - 1;
changeTab(newTab);
};
// --- PDF DOWNLOAD FUNCTIONALITY ---
window.downloadPDF = () => {
const { jsPDF } = window.jspdf;
const doc = new jsPDF({ orientation: 'p', unit: 'mm', format: 'a4' });
// Header
doc.setFontSize(18);
doc.text('Contract Risk Analysis Report', 14, 22);
doc.setFontSize(11);
doc.setTextColor(100);
doc.text(`Contract: ${document.getElementById('contract-name').value || 'N/A'}`, 14, 30);
doc.text(`Counterparty: ${document.getElementById('counterparty-name').value || 'N/A'}`, 14, 36);
doc.text(`Value: ${formatCurrency(document.getElementById('contract-value').value || 0)}`, 120, 30);
// Summary Table
const totalRiskScore = clauses.reduce((total, clause) => total + clause.risks.reduce((clauseSum, risk) => clauseSum + getRiskScore(risk.likelihood, risk.impact), 0), 0);
const overallRiskLevel = getRiskLevel(totalRiskScore);
doc.autoTable({
startY: 45,
head: [['Overall Risk Score', 'Risk Level', 'Analyzed Clauses']],
body: [[totalRiskScore, overallRiskLevel.text, clauses.length]],
theme: 'striped',
headStyles: { fillColor: [44, 62, 80] },
});
// Detailed Clauses Table
const head = [['Clause', 'Risk Type', 'Likelihood', 'Impact', 'Score', 'Mitigation Strategy']];
const body = [];
clauses.forEach(clause => {
if (clause.risks.length > 0) {
clause.risks.forEach((risk, index) => {
const score = getRiskScore(risk.likelihood, risk.impact);
body.push([
index === 0 ? clause.title : '', // Show clause title only for the first risk
risk.riskType,
risk.likelihood,
risk.impact,
score,
risk.mitigation
]);
});
} else {
body.push([clause.title, 'No risks assigned', '-', '-', '-', 'N/A']);
}
});
doc.autoTable({
startY: doc.autoTable.previous.finalY + 10,
head: head,
body: body,
theme: 'grid',
headStyles: { fillColor: [22, 160, 133] },
didParseCell: function (data) {
// Merge cells for clause titles
if (data.body) {
let i = 0;
while (i < data.body.length) {
let row = data.body[i];
if (row.cells[0].raw) {
let rowspan = 1;
for (let j = i + 1; j < data.body.length; j++) {
if (data.body[j].cells[0].raw === '') {
rowspan++;
} else {
break;
}
}
if (rowspan > 1) {
row.cells[0].rowSpan = rowspan;
}
}
i++;
}
}
}
});
doc.save('Contract_Risk_Report.pdf');
};
// --- INITIAL RENDER ---
renderAll();
});