Summary
${log.summary}
Achievements
${log.achievements}
Challenges
${log.challenges}
${employee.name}
Report Not Submitted
${team.name}
`).join('') || 'No teams created.
'; employeeTeamSelect.innerHTML = state.teams.map(t => ``).join(''); employeesList.innerHTML = state.employees.map(emp => { const team = state.teams.find(t => t.id === emp.teamId); return `
${emp.name} (${team?.name || 'No team'})
`}).join('') || 'No employees added.
'; } // SECTION: Event Handlers function handleTabClick(tabName) { state.activeTab = tabName; render(); } function handleNavClick(dir) { const i = TABS.indexOf(state.activeTab); const newI = i + dir; if (newI >= 0 && newI < TABS.length) { state.activeTab = TABS[newI]; render(); } } function handleAddTeam(e) { e.preventDefault(); const name = teamNameInput.value.trim(); if (name) { const newTeam = { id: Date.now(), name }; state.teams.push(newTeam); if (state.teams.length === 1) state.selectedTeamId = newTeam.id; teamNameInput.value = ''; saveState(); render(); } } function handleDeleteTeam(teamId) { state.teams = state.teams.filter(t => t.id !== teamId); state.employees = state.employees.filter(e => e.teamId !== teamId); if (state.selectedTeamId === teamId) { state.selectedTeamId = state.teams.length > 0 ? state.teams[0].id : null; } saveState(); render(); } function handleAddEmployee(e) { e.preventDefault(); const name = employeeNameInput.value.trim(); const teamId = parseInt(employeeTeamSelect.value); if (name && teamId) { state.employees.push({ id: Date.now(), name, teamId }); employeeNameInput.value = ''; saveState(); render(); } } function handleDeleteEmployee(employeeId) { state.employees = state.employees.filter(e => e.id !== employeeId); state.workLogs = state.workLogs.filter(l => l.employeeId !== employeeId); saveState(); render(); } function handleLogSubmit(e) { e.preventDefault(); const employeeId = parseInt(logEmployeeSelect.value); const weekStartDate = toISODateString(getStartOfWeek(new Date(logWeekStartInput.value))); const logData = { employeeId, weekStartDate, summary: logSummaryText.value, achievements: logAchievementsText.value, challenges: logChallengesText.value, productivityScore: parseInt(logProductivityRange.value) }; const existingLogIndex = state.workLogs.findIndex(l => l.employeeId === employeeId && l.weekStartDate === weekStartDate); if (existingLogIndex > -1) { state.workLogs[existingLogIndex] = { ...state.workLogs[existingLogIndex], ...logData }; } else { state.workLogs.push({ id: Date.now(), ...logData }); } saveState(); logSummaryForm.reset(); alert('Work summary submitted successfully!'); state.activeTab = 'dashboard'; render(); } function handleFilterChange() { state.selectedTeamId = parseInt(teamFilter.value); state.selectedWeekStartDate = getStartOfWeek(weekStartFilter.value); renderDashboard(); } function generatePDF() { const { jsPDF } = window.jspdf; const doc = new jsPDF({ orientation: 'p', unit: 'mm', format: 'a4' }); if (!state.selectedTeamId) { alert("Please select a team."); return; } const selectedTeam = state.teams.find(t => t.id === state.selectedTeamId); const weekStart = state.selectedWeekStartDate; const weekEnd = new Date(weekStart); weekEnd.setDate(weekEnd.getDate() + 6); const dateRange = `${weekStart.toLocaleDateString()} - ${weekEnd.toLocaleDateString()}`; doc.setFontSize(22); doc.setFont('helvetica', 'bold'); doc.text('Weekly Work Summary Report', 105, 20, { align: 'center' }); doc.setFontSize(16); doc.setFont('helvetica', 'normal'); doc.text(`Team: ${selectedTeam.name}`, 105, 30, { align: 'center' }); doc.setFontSize(10); doc.setTextColor(150); doc.text(`Week of: ${dateRange}`, 105, 35, { align: 'center' }); const employeesInTeam = state.employees.filter(e => e.teamId === state.selectedTeamId); const weekStartString = toISODateString(state.selectedWeekStartDate); const tableBody = []; employeesInTeam.forEach(employee => { const log = state.workLogs.find(l => l.employeeId === employee.id && l.weekStartDate === weekStartString); const content = log ? `Score: ${log.productivityScore}/5\n\nSummary:\n${log.summary}\n\nAchievements:\n${log.achievements}\n\nChallenges:\n${log.challenges}` : 'Report not submitted for this week.'; tableBody.push([ { content: employee.name, styles: { fontStyle: 'bold', fillColor: '#f1f5f9' } }, { content: content } ]); }); doc.autoTable({ body: tableBody, startY: 45, theme: 'grid', columnStyles: { 0: { cellWidth: 40 }, 1: { cellWidth: 'auto' } }, styles: { cellPadding: 3, fontSize: 10, valign: 'middle', halign: 'left' }, didDrawPage: data => { doc.setFontSize(8); doc.setTextColor(150); doc.text('Page ' + data.pageNumber, data.settings.margin.left, doc.internal.pageSize.height - 10); } }); doc.save(`${selectedTeam.name}_Summary_${weekStartString}.pdf`); } // SECTION: Event Listeners Object.keys(tabButtons).forEach(id => tabButtons[id]?.addEventListener('click', () => handleTabClick(id))); prevTabBtn?.addEventListener('click', () => handleNavClick(-1)); nextTabBtn?.addEventListener('click', () => handleNavClick(1)); teamFilter?.addEventListener('change', handleFilterChange); weekStartFilter?.addEventListener('change', handleFilterChange); downloadPdfBtn?.addEventListener('click', generatePDF); logSummaryForm?.addEventListener('submit', handleLogSubmit); addTeamForm?.addEventListener('submit', handleAddTeam); addEmployeeForm?.addEventListener('submit', handleAddEmployee); teamsList?.addEventListener('click', e => { if (e.target.classList.contains('delete-team-btn')) { if (confirm('Delete team and all its employees?')) handleDeleteTeam(parseInt(e.target.dataset.id)); } }); employeesList?.addEventListener('click', e => { if (e.target.classList.contains('delete-employee-btn')) { if (confirm('Delete employee?')) handleDeleteEmployee(parseInt(e.target.dataset.id)); } }); // SECTION: Initial Load loadState(); render(); });