Compliance Summary
| Regulation |
Required |
Proposed |
Status |
`;
Object.keys(appData.checklist).forEach(key => {
const item = appData.checklist[key];
let status = 'N/A';
let statusClass = '';
const requiredVal = item.required;
const proposedVal = item.proposed;
if (isNaN(parseFloat(requiredVal)) || isNaN(parseFloat(proposedVal))) {
// Text comparison
status = (requiredVal.toLowerCase() === proposedVal.toLowerCase()) ? 'Compliant' : 'Needs Review';
statusClass = (status === 'Compliant') ? 'compliant' : 'non-compliant';
} else {
// Number comparison
const req = parseFloat(requiredVal);
const prop = parseFloat(proposedVal);
// Handle max vs min requirements based on keywords
if (item.label.toLowerCase().includes('max')) {
status = (prop <= req) ? 'Compliant' : 'Non-Compliant';
} else { // Assume minimum
status = (prop >= req) ? 'Compliant' : 'Non-Compliant';
}
statusClass = (status === 'Compliant') ? 'compliant' : 'non-compliant';
}
appData.results.push({ label: item.label, required: requiredVal, proposed: proposedVal, status: status });
html += `
| ${item.label} |
${requiredVal} |
${proposedVal} |
${status} |
`;
});
html += `
`;
reportOutput.innerHTML = html;
showTab(4);
};
const handlePdfDownload = () => {
if (!appData.results) {
alert('Please generate a report first.');
return;
}
const { jsPDF } = window.jspdf;
const doc = new jsPDF();
doc.setFontSize(20);
doc.text("Land Use & Zoning Compliance Report", 105, 20, { align: 'center' });
doc.setFontSize(10);
doc.text(`Report Date: ${new Date().toLocaleDateString()}`, 105, 28, { align: 'center' });
const propInfo = `Address: ${appData.propertyAddress}, ${appData.propertyCity}, ${appData.propertyState}\nZoning: ${appData.zoningDistrict}\nProposed Use: ${appData.useDescription}`;
doc.setFontSize(12);
doc.text("Property Information", 14, 45);
doc.setFontSize(10);
doc.text(propInfo, 14, 52);
const tableBody = appData.results.map(r => [r.label, r.required, r.proposed, r.status]);
doc.autoTable({
startY: 75,
head: [['Regulation', 'Required', 'Proposed', 'Status']],
body: tableBody,
theme: 'grid',
headStyles: { fillColor: [41, 128, 185] },
didParseCell: function(data) {
if (data.section === 'body' && data.column.index === 3) {
if (data.cell.raw === 'Non-Compliant' || data.cell.raw === 'Needs Review') {
data.cell.styles.textColor = [220, 53, 69];
}
if (data.cell.raw === 'Compliant') {
data.cell.styles.textColor = [25, 135, 84];
}
}
}
});
const finalY = doc.autoTable.previous.finalY;
doc.setFontSize(8);
doc.setTextColor(150);
doc.text("Disclaimer: This report is for informational purposes only. Verify all information with your local planning department.", 105, doc.internal.pageSize.height - 10, { align: 'center' });
doc.save(`Zoning-Report-${appData.propertyAddress.replace(/\s/g, '_') || 'General'}.pdf`);
};
// Event Listeners
nextBtn.addEventListener('click', () => {
if (!validateTab(currentTab)) return;
saveTabData();
if (currentTab < totalTabs - 1) {
showTab(currentTab + 1);
} else if (currentTab === totalTabs - 1) {
generateReport();
}
});
prevBtn.addEventListener('click', () => {
if (currentTab > 1) {
saveTabData();
showTab(currentTab - 1);
}
});
useCategorySelect.addEventListener('change', populateChecklist);
downloadPdfBtn.addEventListener('click', handlePdfDownload);
// Initial Setup
updateNavigation();
});