Month Year

Agenda View

    Manage Event Types

    Existing Event Types:

      ×

      Add/Edit Event

      ×

      Events for Date

        Type: ${eventType ? eventType.name : 'Unknown'}

        ${event.description ? `

        Details: ${event.description}

        ` : ''} ${event.location ? `

        Location: ${event.location}

        ` : ''}
        `; wc_agendaEventListEl.appendChild(li); }); } // Event Types Management function wc_renderEventTypesManager() { wc_eventTypeManagerListEl.innerHTML = ''; wc_eventTypes.forEach(type => { const li = document.createElement('li'); const colorPreview = document.createElement('span'); colorPreview.classList.add('wc-event-type-color-preview'); colorPreview.style.backgroundColor = type.color; const nameSpan = document.createElement('span'); nameSpan.textContent = type.name; const controlsDiv = document.createElement('div'); if (type.isDefault) { const defaultLabel = document.createElement('span'); defaultLabel.textContent = '(Default)'; defaultLabel.style.fontSize = '0.8em'; defaultLabel.style.color = '#777'; defaultLabel.style.marginRight = '10px'; controlsDiv.appendChild(defaultLabel); } else { const deleteBtn = document.createElement('button'); deleteBtn.textContent = 'Delete'; deleteBtn.classList.add('wc-button', 'danger'); deleteBtn.style.fontSize = '0.8em'; deleteBtn.style.padding = '3px 6px'; deleteBtn.onclick = () => wc_deleteEventType(type.id); controlsDiv.appendChild(deleteBtn); } li.appendChild(colorPreview); li.appendChild(nameSpan); li.appendChild(controlsDiv); wc_eventTypeManagerListEl.appendChild(li); }); } function wc_addEventType() { const name = wc_newEventTypeNameInput.value.trim(); const color = wc_newEventTypeColorInput.value; if (name && !wc_eventTypes.find(et => et.name.toLowerCase() === name.toLowerCase())) { wc_eventTypes.push({ id: wc_generateId(), name, color, isDefault: false }); wc_saveData(); wc_renderEventTypesManager(); wc_populateEventTypesDropdown(); // Update dropdowns elsewhere wc_newEventTypeNameInput.value = ''; } else if (!name) { alert("Event type name cannot be empty."); } else { alert("Event type name already exists."); } } function wc_deleteEventType(typeId) { const typeToDelete = wc_eventTypes.find(et => et.id === typeId); if (typeToDelete && typeToDelete.isDefault) { alert("Cannot delete default event types."); return; } if (confirm('Are you sure you want to delete this event type? Events using it will show "Unknown Type".')) { // Check if type is in use const isInUse = wc_events.some(event => event.type === typeId); if (isInUse) { alert("This event type is currently assigned to one or more events. Deleting it will mark those events as 'Unknown Type'."); } wc_eventTypes = wc_eventTypes.filter(et => et.id !== typeId); wc_saveData(); wc_renderEventTypesManager(); wc_populateEventTypesDropdown(); wc_renderCalendar(); // Events on calendar might change appearance wc_renderAgendaView(); // Events in agenda might change appearance } } // PDF Download document.getElementById('wc-downloadPdfBtn').onclick = async () => { const { jsPDF } = window.jspdf; const pdf = new jsPDF('p', 'mm', 'a4'); let currentY = 15; const margin = 15; const pageWidth = pdf.internal.pageSize.getWidth(); const contentWidth = pageWidth - 2 * margin; // Title pdf.setFontSize(22); pdf.setTextColor('#007BFF'); pdf.text("Work Schedule Report", pageWidth / 2, currentY, { align: 'center' }); currentY += 8; pdf.setFontSize(10); pdf.setTextColor('#333333'); pdf.text(`Generated on: ${new Date().toLocaleDateString()} ${new Date().toLocaleTimeString()}`, pageWidth / 2, currentY, { align: 'center' }); currentY += 10; // Calendar Snapshot (if calendar view is active or desired) const calendarCaptureEl = document.getElementById('wc-calendarToCapture'); if (calendarCaptureEl && document.getElementById('wc-calendarViewTab').classList.contains('active')) { pdf.setFontSize(16); pdf.setTextColor('#007BFF'); pdf.text(`Calendar: ${wc_currentMonthYearEl.textContent}`, margin, currentY); currentY += 8; try { const canvas = await html2canvas(calendarCaptureEl, { scale: 1.5, backgroundColor: '#FFFFFF' }); const imgData = canvas.toDataURL('image/png'); const imgProps = pdf.getImageProperties(imgData); const pdfImgWidth = contentWidth; const pdfImgHeight = (imgProps.height * pdfImgWidth) / imgProps.width; if (currentY + pdfImgHeight > pdf.internal.pageSize.getHeight() - margin) { pdf.addPage(); currentY = margin; } pdf.addImage(imgData, 'PNG', margin, currentY, pdfImgWidth, pdfImgHeight); currentY += pdfImgHeight + 10; } catch(e) { console.error("Error capturing calendar for PDF:", e); pdf.setTextColor('#DC3545'); pdf.text("Could not capture calendar view.", margin, currentY); pdf.setTextColor('#333333'); currentY += 8; } } // Agenda / Event List if (currentY > pdf.internal.pageSize.getHeight() - margin - 20) { // Check for page break pdf.addPage(); currentY = margin; } pdf.setFontSize(16); pdf.setTextColor('#007BFF'); const agendaRangeText = wc_agendaDateRangeSelect.options[wc_agendaDateRangeSelect.selectedIndex].text; const agendaSearchTerm = wc_agendaSearchInput.value; pdf.text(`Event List (Filter: ${agendaRangeText}${agendaSearchTerm ? ', Search: '+agendaSearchTerm : ''})`, margin, currentY); currentY += 8; const eventsForPdf = wc_getAgendaEventsForPdf(); // Use same filtering as agenda view for consistency if (eventsForPdf.length > 0) { const tableHeaders = ["Date", "Time", "Title", "Type", "Location", "Details"]; const tableBody = eventsForPdf.map(event => { const eventType = wc_eventTypes.find(et => et.id === event.type); const eventDateObj = new Date(event.date + "T00:00:00"); const displayDate = eventDateObj.toLocaleDateString('en-CA'); // YYYY-MM-DD for sorting/consistency return [ displayDate, event.allDay ? "All-day" : `${event.startTime || ''} - ${event.endTime || ''}`, event.title, eventType ? eventType.name : 'Unknown', event.location || '-', event.description || '-' ]; }); pdf.autoTable({ head: [tableHeaders], body: tableBody, startY: currentY, theme: 'grid', headStyles: { fillColor: '#007BFF', textColor: '#FFFFFF' }, styles: { fontSize: 8, cellPadding: 1.5, overflow: 'linebreak' }, columnStyles: { 0: { cellWidth: 22 }, // Date 1: { cellWidth: 25 }, // Time 2: { cellWidth: 40 }, // Title 3: { cellWidth: 25 }, // Type 4: { cellWidth: 25 }, // Location 5: { cellWidth: 'auto' } // Description }, didParseCell: function (data) { // Color rows by event type const rowIndex = data.row.index; if (data.section === 'body' && eventsForPdf[rowIndex]) { const eventType = wc_eventTypes.find(et => et.id === eventsForPdf[rowIndex].type); if (eventType) { // Simple way to add a colored line or subtle background. jsPDF-AutoTable styling options are limited. // For simplicity, direct cell background might not be easy. // We can add a small colored rectangle if needed, or rely on text color. // Here, we could make the Type text colored if (data.column.dataKey === 3) { // "Type" column data.cell.styles.textColor = eventType.color; } } } }, margin: { left: margin, right: margin } }); } else { pdf.setFontSize(10); pdf.text("No events match the current agenda filter for the report.", margin, currentY); } pdf.save(`Work_Schedule_${new Date().toISOString().slice(0,10)}.pdf`); alert('PDF report is being downloaded.'); }; function wc_getAgendaEventsForPdf() { // Replicates agenda filtering for PDF const range = wc_agendaDateRangeSelect.value; const searchTerm = wc_agendaSearchInput.value.toLowerCase(); let filteredEvents = [...wc_events]; const today = new Date(); today.setHours(0,0,0,0); if (range === "upcoming7") { const endDate = new Date(today); endDate.setDate(today.getDate() + 7); filteredEvents = filteredEvents.filter(e => new Date(e.date + "T00:00:00") >= today && new Date(e.date + "T00:00:00") < endDate); } else if (range === "upcoming30") { const endDate = new Date(today); endDate.setDate(today.getDate() + 30); filteredEvents = filteredEvents.filter(e => new Date(e.date + "T00:00:00") >= today && new Date(e.date + "T00:00:00") < endDate); } else if (range === "thisMonth") { const currentActualMonth = new Date().getMonth(); const currentActualYear = new Date().getFullYear(); filteredEvents = filteredEvents.filter(e => { const eventDate = new Date(e.date + "T00:00:00"); return eventDate.getMonth() === currentActualMonth && eventDate.getFullYear() === currentActualYear; }); } if (searchTerm) { filteredEvents = filteredEvents.filter(e => e.title.toLowerCase().includes(searchTerm) || (e.description && e.description.toLowerCase().includes(searchTerm))); } filteredEvents.sort((a,b) => new Date(a.date + (a.allDay || !a.startTime ? "T00:00:00" : "T" + a.startTime)) - new Date(b.date + (b.allDay || !b.startTime ? "T00:00:00" : "T" + b.startTime))); return filteredEvents; } // Initial Load document.addEventListener('DOMContentLoaded', () => { wc_populateEventTypesDropdown(); wc_renderEventTypesManager(); // Also populates manager list wc_openView(null, wc_viewIds[0]); // Open Calendar view by default const firstTabButton = document.querySelector(`.wc-tab-button[onclick*="${wc_viewIds[0]}"]`); if (firstTabButton) firstTabButton.classList.add('active'); wc_updateNavButtons(); }); // Close modals if escape key is pressed window.addEventListener('keydown', function (event) { if (event.key === 'Escape') { wc_closeModal('wc-eventModal'); wc_closeModal('wc-dayEventsModal'); } }); // Close modals if clicked outside content window.onclick = function(event) { if (event.target == wc_eventModal) { wc_closeModal('wc-eventModal'); } if (event.target == wc_dayEventsModal) { wc_closeModal('wc-dayEventsModal'); } }
        Scroll to Top