`;
}
function downloadPDF() {
const { jsPDF } = window.jspdf;
const doc = new jsPDF();
const data = getFormData();
const pageHeight = doc.internal.pageSize.height;
const pageWidth = doc.internal.pageSize.width;
const margin = 20;
const maxWidth = pageWidth - (margin * 2);
let currentY = margin;
const checkPageBreak = (spaceNeeded) => {
if (currentY + spaceNeeded > pageHeight - margin) {
doc.addPage();
currentY = margin;
}
};
const addSection = (title, text, isSubSection = false) => {
checkPageBreak(isSubSection ? 8 : 16); // Space for title
doc.setFontSize(isSubSection ? 12 : 14);
doc.setFont(undefined, 'bold');
doc.text(title, margin + (isSubSection ? 5 : 0), currentY);
currentY += isSubSection ? 6 : 8;
if (!isSubSection) {
doc.setLineWidth(0.5);
doc.line(margin, currentY, maxWidth + margin, currentY);
currentY += 8;
}
doc.setFontSize(11);
doc.setFont(undefined, 'normal');
const lines = doc.splitTextToSize(text || 'Not provided.', maxWidth - (isSubSection ? 5 : 0));
checkPageBreak(lines.length * 5 + 10); // Space for text + padding
doc.text(lines, margin + (isSubSection ? 5 : 0), currentY);
currentY += (lines.length * 5) + (isSubSection ? 5 : 10); // Add padding after section
};
// --- PDF Content ---
doc.setFontSize(20);
doc.setFont(undefined, 'bold');
doc.text("Project Charter", pageWidth / 2, currentY, { align: 'center' });
currentY += 10;
doc.setFontSize(16);
doc.setTextColor(100);
doc.text(data['charter-title'], pageWidth / 2, currentY, { align: 'center' });
currentY += 15;
doc.setTextColor(0);
addSection("Project Overview", `Project Manager: ${data['charter-pm']}\nProject Sponsor: ${data['charter-sponsor']}\nDate Prepared: ${data['charter-date']}`);
addSection("Business Case", data['charter-business-case']);
addSection("Project Objectives", data['charter-objectives']);
// Scope Section
checkPageBreak(20);
doc.setFontSize(14);
doc.setFont(undefined, 'bold');
doc.text("Project Scope", margin, currentY);
currentY += 8;
doc.setLineWidth(0.5);
doc.line(margin, currentY, maxWidth + margin, currentY);
currentY += 8;
addSection("In-Scope", data['charter-scope-in'], true);
addSection("Out-of-Scope", data['charter-scope-out'], true);
currentY += 5; // Extra padding after the section
addSection("Key Stakeholders", data['charter-stakeholders']);
addSection("Key Milestones & Timeline", data['charter-milestones']);
addSection("Budget Summary", data['charter-budget']);
// Risks & Assumptions Section
checkPageBreak(20);
doc.setFontSize(14);
doc.setFont(undefined, 'bold');
doc.text("Risks & Assumptions", margin, currentY);
currentY += 8;
doc.setLineWidth(0.5);
doc.line(margin, currentY, maxWidth + margin, currentY);
currentY += 8;
addSection("Initial High-Level Risks", data['charter-risks'], true);
addSection("Project Assumptions", data['charter-assumptions'], true);
currentY += 5;
// Approvals
addSection("Approvals", "");
checkPageBreak(40);
doc.text("__________________________________", margin, currentY + 15);
doc.text(data['charter-pm'] || 'Project Manager', margin, currentY + 22);
doc.text("__________________________________", margin + 100, currentY + 15);
doc.text(data['charter-sponsor'] || 'Project Sponsor', margin + 100, currentY + 22);
doc.save('project-charter.pdf');
}
// --- Tab Navigation ---
function switchTab(tabIndex) {
tabs.forEach((tab, index) => {
tab.classList.toggle('active', index === tabIndex);
contents[index].classList.toggle('active', index === tabIndex);
});
currentTab = tabIndex;
updateNavButtons();
}
function updateNavButtons() {
prevBtn.disabled = currentTab === 0;
nextBtn.disabled = currentTab === tabs.length - 1;
}
tabs.forEach((tab, index) => {
tab.addEventListener('click', () => switchTab(index));
});
nextBtn.addEventListener('click', () => { if (currentTab < tabs.length - 1) switchTab(currentTab + 1); });
prevBtn.addEventListener('click', () => { if (currentTab > 0) switchTab(currentTab - 1); });
// --- Event Listeners ---
generateBtn.addEventListener('click', () => {
// IV.D.1: This is type="button"
renderReviewSheet();
switchTab(1); // Switch to review tab
});
pdfDownloadBtn.addEventListener('click', downloadPDF);
// --- Initial Setup ---
setInitialDate();
updateNavButtons();
// Pre-fill review sheet with default data for first load
renderReviewSheet();
});
