Absence Management Dashboard

Team & Year Setup

Define your team, the operational year, and manage your employee roster.


Employee Roster

Log New Absence

Record an absence for an employee. Dates are inclusive.


Logged Absences

Team Name

Year

Key Metrics

Absence Calendar

Employee Summary

${type}

`).join('')} `; } renderCalendar() { this.dom.calendarGrid.innerHTML = ''; const year = this.state.year; const monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; for (let month = 0; month < 12; month++) { const monthContainer = document.createElement('div'); monthContainer.className = 'month-container'; const firstDay = new Date(year, month, 1); const daysInMonth = new Date(year, month + 1, 0).getDate(); let startingDay = firstDay.getDay(); // 0 = Sunday if (startingDay === 0) startingDay = 7; // Adjust to start week on Monday if desired, but 0=Sun is standard let dayHtml = `
${monthNames[month]} ${year}
`; dayHtml += '
'; ['S', 'M', 'T', 'W', 'T', 'F', 'S'].forEach(d => dayHtml += `
${d}
`); for (let i = 0; i < startingDay; i++) { dayHtml += '
'; } for (let day = 1; day <= daysInMonth; day++) { const currentDate = new Date(year, month, day); const dateStr = currentDate.toISOString().split('T')[0]; const todayStr = new Date().toISOString().split('T')[0]; let classes = 'calendar-day'; if(dateStr === todayStr) classes += ' today'; const absencesOnDay = this.state.absences.filter(ab => { const start = new Date(ab.startDate); const end = new Date(ab.endDate); return currentDate >= start && currentDate <= end; }); let markers = ''; if(absencesOnDay.length > 0) { markers = `
${absencesOnDay.map(ab => `
`).join('')}
`; } dayHtml += `
${day}${markers}
`; } dayHtml += '
'; monthContainer.innerHTML = dayHtml; this.dom.calendarGrid.appendChild(monthContainer); } } renderEmployeeSummary() { const head = this.dom.summaryTableHead; const body = this.dom.summaryTableBody; head.innerHTML = `Employee${this.state.absenceTypes.map(t => `${t}`).join('')}Total`; body.innerHTML = ''; this.state.employees.forEach(emp => { let totalDays = 0; const row = document.createElement('tr'); let rowHtml = `${emp.name}`; this.state.absenceTypes.forEach(type => { const daysForType = this.state.absences .filter(ab => ab.employeeId === emp.id && ab.type === type) .reduce((sum, ab) => sum + ab.days, 0); rowHtml += `${daysForType}`; totalDays += daysForType; }); rowHtml += `${totalDays}`; row.innerHTML = rowHtml; body.appendChild(row); }); } // --- NAVIGATION & PDF --- openTab(event, tabName) { this.state.activeTab = tabName; this.updateUI(); } navigateTabs(direction) { const currentIndex = this.TABS_ORDER.indexOf(this.state.activeTab); let newIndex = currentIndex; if (direction === 'next' && currentIndex < this.TABS_ORDER.length - 1) newIndex++; if (direction === 'prev' && currentIndex > 0) newIndex--; this.state.activeTab = this.TABS_ORDER[newIndex]; this.updateUI(); } async generatePdf() { const { jsPDF } = window.jspdf; const pdfOutputElement = this.dom.pdfOutput; this.dom.downloadPdfBtn.disabled = true; this.dom.downloadPdfBtn.textContent = 'Generating...'; try { const canvas = await html2canvas(pdfOutputElement, { scale: 2, useCORS: true, logging: false }); const imgData = canvas.toDataURL('image/png'); const pdf = new jsPDF({ orientation: 'portrait', unit: 'pt', format: 'a4' }); const pdfWidth = pdf.internal.pageSize.getWidth(); const pdfHeight = pdf.internal.pageSize.getHeight(); const canvasAspectRatio = canvas.width / canvas.height; const margin = 40; const imgWidth = pdfWidth - (margin * 2); const imgHeight = imgWidth / canvasAspectRatio; let heightLeft = imgHeight; let position = margin; pdf.addImage(imgData, 'PNG', margin, position, imgWidth, imgHeight); heightLeft -= (pdfHeight - margin * 2); while (heightLeft > 0) { position = -heightLeft - margin; pdf.addPage(); pdf.addImage(imgData, 'PNG', margin, position, imgWidth, imgHeight); heightLeft -= pdfHeight; } const fileName = `Absence_Dashboard_${this.state.teamName.replace(/\s+/g, '_')}_${this.state.year}.pdf`; pdf.save(fileName); } catch (error) { console.error("PDF Generation Error:", error); alert("Sorry, an error occurred while creating the PDF."); } finally { this.dom.downloadPdfBtn.disabled = false; this.dom.downloadPdfBtn.textContent = 'Download Dashboard as PDF'; } } } const app = new AbsenceManager();
Scroll to Top