×
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');
}
}