Select a meeting to view its feedback summary.
`;
downloadPdfBtn.disabled = true;
return;
}
const meetingFeedback = feedback[meetingId] || [];
if (meetingFeedback.length === 0) {
resultsSummary.innerHTML = `
No feedback has been submitted for this meeting yet.
`;
downloadPdfBtn.disabled = true;
return;
}
// Calculate averages
const avgScores = {};
criteria.forEach(c => {
const total = meetingFeedback.reduce((sum, f) => sum + (f.ratings[c.id] || 0), 0);
const count = meetingFeedback.filter(f => f.ratings[c.id]).length;
avgScores[c.id] = count > 0 ? (total / count).toFixed(1) : 'N/A';
});
const scoresHTML = criteria.map(c => `
${c.name}
${avgScores[c.id]} / 5.0
`).join('');
const commentsHTML = meetingFeedback
.filter(f => f.comments.trim() !== '')
.map(f => `
"${f.comments}"`)
.join('');
resultsSummary.innerHTML = `
Average Scores (${meetingFeedback.length} responses)
Comments
${commentsHTML || '- No comments submitted.
'}
`;
downloadPdfBtn.disabled = false;
}
// --- EVENT HANDLERS ---
function handleFeedbackSubmit(e) {
e.preventDefault();
const meetingId = meetingSelect.value;
if (!meetingId) {
alert('Please select a meeting first.');
return;
}
const formData = new FormData(feedbackForm);
const newFeedback = { ratings: {}, comments: formData.get('feedback-comments') || '' };
for (const [key, value] of formData.entries()) {
if (key.startsWith('rating-')) {
const criterionId = key.split('-')[1];
newFeedback.ratings[criterionId] = parseInt(value);
}
}
if (!feedback[meetingId]) {
feedback[meetingId] = [];
}
feedback[meetingId].push(newFeedback);
alert('Thank you for your feedback!');
feedbackForm.reset();
updateDashboard();
}
function handleAdd(e, type) {
e.preventDefault();
const input = e.target.querySelector('input[type="text"]');
const name = input.value.trim();
if (name) {
if (type === 'meeting') {
meetings.push({ id: Date.now(), name });
} else {
criteria.push({ id: Date.now(), name });
}
input.value = '';
renderAll();
}
}
function handleDelete(e) {
if (e.target.classList.contains('delete-btn')) {
const { type, id } = e.target.dataset;
if (type === 'meeting') {
meetings = meetings.filter(m => m.id != id);
} else {
criteria = criteria.filter(c => c.id != id);
}
renderAll();
}
}
function generatePdf() {
const { jsPDF } = window.jspdf;
const pdfContent = document.getElementById('pdf-content');
const pdfTitleEl = document.getElementById('pdf-title');
if (!pdfContent || downloadPdfBtn.disabled) return;
const meeting = meetings.find(m => m.id == meetingSelect.value);
pdfTitleEl.textContent = `Feedback Summary for: ${meeting.name}`;
html2canvas(pdfContent, { scale: 2, useCORS: true, logging: false })
.then(canvas => {
const imgData = canvas.toDataURL('image/png');
const pdf = new jsPDF({ orientation: 'p', unit: 'mm', format: 'a4' });
const pdfWidth = pdf.internal.pageSize.getWidth();
const ratio = canvas.width / canvas.height;
const imgHeight = (pdfWidth - 20) / ratio;
pdf.addImage(imgData, 'PNG', 10, 10, pdfWidth - 20, imgHeight);
pdf.save(`Feedback-Summary-${meeting.name.replace(/ /g, '_')}.pdf`);
pdfTitleEl.textContent = '';
});
}
// --- EVENT LISTENERS ---
function addEventListeners() {
tabButtons.forEach(button => {
button.addEventListener('click', () => {
const tab = button.dataset.tab;
tabButtons.forEach(btn => btn.classList.toggle('active', btn.dataset.tab === tab));
tabContents.forEach(content => content.classList.toggle('active', content.id.startsWith(tab)));
});
});
meetingSelect.addEventListener('change', updateDashboard);
feedbackForm.addEventListener('submit', handleFeedbackSubmit);
addMeetingForm.addEventListener('submit', (e) => handleAdd(e, 'meeting'));
addCriterionForm.addEventListener('submit', (e) => handleAdd(e, 'criterion'));
meetingList.addEventListener('click', handleDelete);
criterionList.addEventListener('click', handleDelete);
downloadPdfBtn.addEventListener('click', generatePdf);
}
initialize();
});