Meeting Agenda Generator

Meeting Agenda Generator

Build Your Agenda


Agenda Items

Live Preview

Manage Agenda Templates

Template NameActions

Date: ${date}

Attendees: ${attendees}


Agenda (Total Time: ${totalTime} mins)

${itemsHtml} `; }, renderTemplateSelect() { const select = this.elements.templateSelect; if (!select) return; select.innerHTML = ''; this.state.templates.forEach(t => { select.innerHTML += ``; }); }, renderTemplatesTable() { const tableBody = this.elements.templatesTableBody; if (!tableBody) return; tableBody.innerHTML = ''; this.state.templates.forEach(t => { tableBody.innerHTML += ` ${t.name} `; }); }, // --- EVENT HANDLERS & ACTIONS --- changeTab(tabIndex) { if (tabIndex < 0 || tabIndex >= this.elements.tabButtons.length) return; this.state.currentTab = tabIndex; this.elements.tabButtons.forEach((btn, i) => btn.classList.toggle('active', i === tabIndex)); this.elements.tabContents.forEach((content, i) => content.classList.toggle('active', i === tabIndex)); this.updateNavButtons(); }, updateNavButtons() { if (!this.elements.prevTabBtn || !this.elements.nextTabBtn) return; this.elements.prevTabBtn.style.visibility = this.state.currentTab === 0 ? 'hidden' : 'visible'; this.elements.nextTabBtn.style.visibility = this.state.currentTab === this.elements.tabButtons.length - 1 ? 'hidden' : 'visible'; }, addAgendaItem(item = { title: '', presenter: '', time: '' }) { this.state.agendaItems.push(item); this.renderAll(); }, handleItemChange(e) { const target = e.target; const itemEl = target.closest('.agenda-item'); if (!itemEl) return; const index = parseInt(itemEl.dataset.index); const prop = target.dataset.prop; this.state.agendaItems[index][prop] = target.value; this.renderPreview(); }, handleItemActions(e) { const target = e.target.closest('button'); if (!target) return; const itemEl = target.closest('.agenda-item'); if (!itemEl) return; const index = parseInt(itemEl.dataset.index); if (target.dataset.action === 'delete') { this.state.agendaItems.splice(index, 1); this.renderAll(); } }, handleTemplateLoad(e) { const templateId = parseInt(e.target.value); if (!templateId) { this.state.agendaItems = []; } else { const template = this.state.templates.find(t => t.id === templateId); if (template) { this.state.agendaItems = JSON.parse(JSON.stringify(template.items)); // Deep copy } } this.renderAll(); }, handleTemplateSubmit(e) { e.preventDefault(); const form = this.elements.templateForm; const id = parseInt(form.querySelector('#template-edit-id').value); const name = form.querySelector('#template-name').value; const itemsText = form.querySelector('#template-items').value; const items = itemsText.split('\n').map(line => { const [title, presenter, time] = line.split(','); return { title: title || '', presenter: presenter || '', time: parseInt(time) || 0 }; }).filter(item => item.title); if (items.length === 0) { this.showNotification('Template must have at least one valid item line.', 'error'); return; } if (id) { const template = this.state.templates.find(t => t.id === id); if (template) { template.name = name; template.items = items; } } else { this.state.templates.push({ id: this.getNextId(this.state.templates), name, items }); } form.reset(); form.querySelector('#template-edit-id').value = ''; this.renderAll(); this.showNotification('Template saved!', 'success'); }, handleTemplateTableActions(e) { const target = e.target.closest('button'); if (!target) return; const id = parseInt(target.dataset.id); if (target.dataset.action === 'edit') { const template = this.state.templates.find(t => t.id === id); if (template) { const form = this.elements.templateForm; form.querySelector('#template-edit-id').value = template.id; form.querySelector('#template-name').value = template.name; form.querySelector('#template-items').value = template.items.map(i => `${i.title},${i.presenter},${i.time}`).join('\n'); } } else if (target.dataset.action === 'delete') { if (confirm('Are you sure?')) { this.state.templates = this.state.templates.filter(t => t.id !== id); this.renderAll(); } } }, // --- Drag and Drop Handlers --- handleDragStart(e) { this.state.draggedItem = e.target; setTimeout(() => e.target.classList.add('dragging'), 0); }, handleDragOver(e) { e.preventDefault(); const container = this.elements.agendaItemsContainer; const afterElement = this.getDragAfterElement(container, e.clientY); const dragging = container.querySelector('.dragging'); if (afterElement == null) { container.appendChild(dragging); } else { container.insertBefore(dragging, afterElement); } }, handleDrop(e) { e.preventDefault(); const newOrder = Array.from(this.elements.agendaItemsContainer.children).map(el => { return this.state.agendaItems[parseInt(el.dataset.index)]; }); this.state.agendaItems = newOrder; this.renderAll(); }, handleDragEnd(e) { e.target.classList.remove('dragging'); }, getDragAfterElement(container, y) { const draggableElements = [...container.querySelectorAll('.agenda-item:not(.dragging)')]; return draggableElements.reduce((closest, child) => { const box = child.getBoundingClientRect(); const offset = y - box.top - box.height / 2; if (offset < 0 && offset > closest.offset) { return { offset: offset, element: child }; } else { return closest; } }, { offset: Number.NEGATIVE_INFINITY }).element; }, // --- PDF Generation --- downloadAgendaPDF() { const { jsPDF } = window.jspdf; const doc = new jsPDF(); const title = document.getElementById('meeting-title').value; const date = new Date(document.getElementById('meeting-date').value).toLocaleString(); const attendees = document.getElementById('meeting-attendees').value; doc.setFontSize(18); doc.text(title, 105, 22, { align: 'center' }); doc.setFontSize(11); doc.text(`Date: ${date}`, 14, 35); doc.text(`Attendees: ${attendees}`, 14, 42); const tableData = this.state.agendaItems.map(item => [item.title, item.presenter, `${item.time} mins`]); const totalTime = this.state.agendaItems.reduce((sum, i) => sum + (parseInt(i.time) || 0), 0); tableData.push(['Total', '', `${totalTime} mins`]); doc.autoTable({ startY: 55, head: [['Topic', 'Presenter', 'Duration']], body: tableData, theme: 'striped', headStyles: { fillColor: [5, 150, 105] }, didDrawCell: (data) => { if (data.row.index === tableData.length - 1) { doc.setFont(undefined, 'bold'); } } }); doc.save(`Agenda_${title.replace(/\s/g, '_')}.pdf`); }, // --- UTILITY FUNCTIONS --- loadDefaultTemplate() { const now = new Date(); now.setMinutes(now.getMinutes() - now.getTimezoneOffset()); now.setSeconds(0); now.setMilliseconds(0); document.getElementById('meeting-date').value = now.toISOString().slice(0,16); this.state.agendaItems = JSON.parse(JSON.stringify(this.state.templates[0].items)); }, getNextId(array) { return array.length > 0 ? Math.max(...array.map(item => item.id)) + 1 : 1; }, showNotification(message, type = 'success') { const box = this.elements.notificationBox; if (!box) return; box.textContent = message; box.className = `mag-notification ${type}`; box.classList.add('show'); setTimeout(() => { box.classList.remove('show'); }, 3000); } }; // Make MAG object globally accessible window.MAG = MAG; // Start the application MAG.init(); });
Scroll to Top