${pap_escapeHTML(pap_data.summary) || 'Executive Summary/Concept Required.'}
`;
targetDiv.innerHTML += identityHTML;
// 2. Site & Technical Details
let technicalHTML = `
2. Site & Technical Details
Proposed Location: ${pap_escapeHTML(pap_data.location) || 'N/A'}
Medium: ${pap_escapeHTML(pap_data.medium) || 'N/A'}
Dimensions & Structural Requirements:
${pap_escapeHTML(pap_data.specs) || 'Dimensions and technical specifications are required.'}
`;
targetDiv.innerHTML += technicalHTML;
// 3. Budget & Timeline
let budgetTableHTML = '';
let totalSum = 0;
if (pap_data.budgetBreakdown.length > 0) {
budgetTableHTML = pap_data.budgetBreakdown.map(item => {
totalSum += item.amount;
return `
| ${pap_escapeHTML(item.category)} |
${pap_formatCurrency(item.amount)} |
`;
}).join('');
}
let timelineText = pap_data.duration > 0 ? `Estimated duration:
${pap_data.duration} months.` : 'Timeline/Duration not specified.';
let budgetHTML = `
3. Budget & Timeline
Total Project Cost
${pap_formatCurrency(pap_data.totalBudget)}
${timelineText}
Detailed Breakdown
| Category |
Amount (USD) |
${budgetTableHTML || '| No breakdown items added. |
'}
| TOTAL SUM |
${pap_formatCurrency(totalSum)} |
`;
targetDiv.innerHTML += budgetHTML;
// 4. Maintenance Plan
let maintenanceHTML = `
4. Maintenance Plan
Routine Care & Longevity:
${pap_escapeHTML(pap_data.maintenance) || 'Maintenance plan is required.'}
`;
targetDiv.innerHTML += maintenanceHTML;
}
/**
* Renders a clone for PDF generation
*/
function pap_renderPdfClone() {
pap_pdfRenderClone.innerHTML = `
Public Art Proposal
`;
// Render data into the clone's content area
const contentArea = pap_pdfRenderClone.querySelector('.space-y-6');
pap_renderDashboard(contentArea, true);
}
/**
* Generates and downloads a PDF of the proposal
*/
async function pap_downloadPDF() {
if (!pap_data.title || !pap_data.artist || !pap_data.summary) {
alert("Please complete the Project Identity section before downloading.");
return;
}
if (typeof jspdf === 'undefined' || typeof html2canvas === 'undefined') {
console.error("PAP Tool Error: jsPDF or html2canvas library not loaded.");
alert("Error: PDF libraries failed to load. Please check console.");
return;
}
pap_renderPdfClone(); // Create and populate the clone
const { jsPDF } = window.jspdf;
try {
// Target the entire clone div
const canvas = await html2canvas(pap_pdfRenderClone, {
scale: 1.5, // Increase resolution slightly
useCORS: true,
windowWidth: pap_pdfRenderClone.scrollWidth,
windowHeight: pap_pdfRenderClone.scrollHeight // Capture full height
});
const imgData = canvas.toDataURL('image/png');
const imgWidth = canvas.width;
const imgHeight = canvas.height;
const pdf = new jsPDF({ orientation: 'p', unit: 'pt', format: 'a4' });
const pdfWidth = pdf.internal.pageSize.getWidth();
const pdfHeight = pdf.internal.pageSize.getHeight();
// Scale image height to fit pdf width, handle multiple pages
const margin = 40;
const contentWidth = pdfWidth - (margin * 2);
const contentHeight = (contentWidth * imgHeight) / imgWidth;
let heightLeft = contentHeight;
let position = 0; // y-position of the image slice on the page
// Add the first page
pdf.addImage(imgData, 'PNG', margin, position + margin, contentWidth, contentHeight);
heightLeft -= (pdfHeight - margin * 2);
// Add subsequent pages if needed
while (heightLeft > 0) {
position -= (pdfHeight - margin * 2); // Move the image's y-position up
pdf.addPage();
pdf.addImage(imgData, 'PNG', margin, position + margin, contentWidth, contentHeight);
heightLeft -= (pdfHeight - margin * 2);
}
const safeName = (pap_data.title || 'public_art_proposal').replace(/[^a-z0-9]/gi, '_').toLowerCase();
pdf.save(`${safeName}.pdf`);
} catch (error) {
console.error("PAP Tool Error: PDF generation failed.", error);
alert("An error occurred while generating the PDF. Please try again.");
}
}
// --- EVENT LISTENERS ---
// Tab link clicks
pap_tabLinks.forEach((link, index) => {
link.addEventListener('click', () => pap_switchTab(index));
});
// Next/Prev button clicks
if (pap_prevButton) {
pap_prevButton.addEventListener('click', () => {
if (pap_currentTab > 0) pap_switchTab(pap_currentTab - 1);
});
}
if (pap_nextButton) {
pap_nextButton.addEventListener('click', () => {
// If on the last tab (Config tab, index 1)
if (pap_currentTab === pap_tabLinks.length - 1) {
// Act as Submit: Save data and switch to Dashboard (index 0)
pap_updateDataFromConfig();
pap_switchTab(0);
} else {
// Otherwise, just go to the next tab
if (pap_currentTab < pap_tabLinks.length - 1) pap_switchTab(pap_currentTab + 1);
}
});
}
// PDF download
if (pap_downloadPdfButton) {
pap_downloadPdfButton.addEventListener('click', pap_downloadPDF);
}
// --- Config Tab Listeners ---
if (pap_addBudgetItemButton) {
pap_addBudgetItemButton.addEventListener('click', () => {
const newItem = pap_createBudgetItemInput();
const container = pap_budgetBreakdownContainer.querySelector('.space-y-2');
if(container) container.appendChild(newItem);
else pap_budgetBreakdownContainer.appendChild(newItem);
});
}
if (pap_configTab) {
// Handle remove
pap_configTab.addEventListener('click', (e) => {
const removeButton = e.target.closest('.pap-remove-budget-item');
if (removeButton) {
removeButton.closest('.flex[data-id]').remove();
}
});
}
// --- INITIALIZATION ---
pap_renderConfig(); // Populate config tab on load
pap_renderDashboard(); // Show initial state on dashboard
// Set initial tab state
pap_tabPanes.forEach((pane, index) => {
pane.classList.toggle('hidden', index !== 0);
pane.classList.toggle('pap-active', index === 0);
});
pap_tabLinks.forEach((link, index) => {
TAB_CLASSES.active.forEach(cls => link.classList.remove(cls));
TAB_CLASSES.inactive.forEach(cls => link.classList.remove(cls));
if (index === 0) {
TAB_CLASSES.active.forEach(cls => link.classList.add(cls));
} else {
TAB_CLASSES.inactive.forEach(cls => link.classList.add(cls));
}
});
});