No QC checks defined yet. Go to the 'Data Configuration' tab.
`;
qc_planSummary.innerHTML = '';
return;
}
// 1. Group items by Phase (ensure standard order)
const phasesInPlan = qc_getUnique(qc_data.items, 'phase');
const sortedPhases = PHASE_OPTIONS.filter(phase => phasesInPlan.includes(phase));
// 2. Render Summary
qc_planSummary.innerHTML = `
Total Checks: ${qc_data.items.length}
Phases Covered: ${sortedPhases.join(', ')}
`;
// 3. Render Schedule
sortedPhases.forEach(phase => {
const phaseItems = qc_data.items.filter(item => item.phase === phase);
if (phaseItems.length === 0) return;
const sectionDiv = document.createElement('div');
sectionDiv.className = 'qc-table-section pl-4 bg-white rounded-r-lg shadow-md';
const h3Class = "text-xl font-bold text-emerald-700 border-b border-gray-300 pb-2 mb-3";
const tableClass = "w-full text-left border-collapse";
const thClass = "p-3 bg-gray-100 text-sm font-semibold text-gray-600 border-b border-gray-300";
const tdClass = "p-3 border-b border-gray-200 text-sm";
let itemsHTML = phaseItems.map(item => `
| ${qc_escapeHTML(item.check)} |
${qc_escapeHTML(item.frequency)} |
${qc_escapeHTML(item.standard)} |
${qc_escapeHTML(item.owner)} |
`).join('');
sectionDiv.innerHTML = `
${phase} Checks
| QC Check / Task |
Frequency |
Standard |
Responsible Owner |
${itemsHTML}
`;
targetDiv.appendChild(sectionDiv);
});
}
function qc_renderPdfClone() {
// Clone the essential structure for PDF
qc_pdfRenderClone.innerHTML = document.getElementById('qc-dashboard-output').outerHTML;
// Remove the ID to avoid conflicts, add a distinct class for targeting
const cloneOutput = qc_pdfRenderClone.querySelector('#qc-dashboard-output');
if(cloneOutput) {
cloneOutput.removeAttribute('id');
cloneOutput.classList.add('pdf-clone-output');
}
// Re-render the content inside the clone to ensure clean styles/no interaction listeners
const cloneScheduleOutput = qc_pdfRenderClone.querySelector('#qc-schedule-output');
if(cloneScheduleOutput) qc_renderDashboard(cloneScheduleOutput, true);
}
/**
* Generates and downloads a PDF of the schedule
*/
async function qc_downloadPDF() {
if (qc_data.items.length === 0) {
alert("Please add some QC checks before downloading.");
return;
}
if (typeof jspdf === 'undefined' || typeof html2canvas === 'undefined') {
alert("Error: PDF libraries failed to load.");
return;
}
qc_renderPdfClone();
const { jsPDF } = window.jspdf;
try {
// Target the clone div
const canvas = await html2canvas(qc_pdfRenderClone.querySelector('.pdf-clone-output'), {
scale: 1.5,
useCORS: true,
windowWidth: qc_pdfRenderClone.scrollWidth,
windowHeight: qc_pdfRenderClone.scrollHeight
});
const imgData = canvas.toDataURL('image/png');
const imgProps = { width: canvas.width, height: canvas.height };
const pdf = new jsPDF({ orientation: 'l', unit: 'pt', format: 'a4' });
const pdfWidth = pdf.internal.pageSize.getWidth();
const pdfHeight = pdf.internal.pageSize.getHeight();
const margin = 40;
const contentWidth = pdfWidth - (margin * 2);
const contentHeight = (contentWidth * imgProps.height) / imgProps.width;
let heightLeft = contentHeight;
let position = 0;
pdf.addImage(imgData, 'PNG', margin, position + margin, contentWidth, contentHeight);
heightLeft -= (pdfHeight - margin * 2);
while (heightLeft > 0) {
position -= (pdfHeight - margin * 2);
pdf.addPage();
pdf.addImage(imgData, 'PNG', margin, position + margin, contentWidth, contentHeight);
heightLeft -= (pdfHeight - margin * 2);
}
const safeName = (qc_data.projectName || 'qc_plan').replace(/[^a-z0-9]/gi, '_').toLowerCase();
pdf.save(`${safeName}_QC_Plan.pdf`);
} catch (error) {
console.error("PDF generation failed:", error);
alert("An error occurred while generating the PDF.");
}
}
// --- EVENT LISTENERS ---
// Tab link clicks
qc_tabLinks.forEach((link, index) => {
link.addEventListener('click', () => qc_switchTab(index));
});
// Next/Prev button clicks
if (qc_prevButton) {
qc_prevButton.addEventListener('click', () => {
if (qc_currentTab > 0) qc_switchTab(qc_currentTab - 1);
});
}
if (qc_nextButton) {
qc_nextButton.addEventListener('click', () => {
if (qc_currentTab === qc_tabLinks.length - 1) {
qc_updateDataFromConfig();
qc_switchTab(0);
} else {
if (qc_currentTab < qc_tabLinks.length - 1) qc_switchTab(qc_currentTab + 1);
}
});
}
// PDF download
if (qc_downloadPdfButton) {
qc_downloadPdfButton.addEventListener('click', qc_downloadPDF);
}
// --- Config Tab Listeners ---
if (qc_addCheckButton) {
qc_addCheckButton.addEventListener('click', () => {
qc_checksContainer.appendChild(qc_createCheckInput());
});
}
if (qc_configTab) {
// Handle remove
qc_configTab.addEventListener('click', (e) => {
const removeButton = e.target.closest('.qc-remove-item');
if (removeButton) {
removeButton.closest('.border[data-id]').remove();
if(qc_checksContainer.children.length === 0){
qc_checksContainer.appendChild(qc_createCheckInput());
}
}
});
}
// --- INITIALIZATION ---
qc_renderConfig();
qc_renderDashboard();
// Set initial tab state
qc_tabPanes.forEach((pane, index) => {
pane.classList.toggle('hidden', index !== 0);
pane.classList.toggle('qc-active', index === 0);
});
qc_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));
}
});
});