Team Task Dashboard
Team Task Dashboard

Team Members

Task Categories/Projects

Add / Edit Tasks

Current Tasks List (for quick edit/delete)

NameAssignedStatusPriorityDueActions

Prio: ${task.priority}

Due: ${task.dueDate ? new Date(task.dueDate+"T00:00:00Z").toLocaleDateString(undefined,{timeZone:'UTC'}) : 'N/A'}

`; return card; } function ttd_changeTaskStatusFromCard(taskId, newStatus) { const task = tasks_TTD.find(t => t.id === taskId); if (task) { task.status = newStatus; ttd_renderDashboard(); // Re-render the current dashboard view ttd_renderManageTasksTable(); // Also update the management table } } function ttd_renderKanbanView(tasksToDisplay, parentElement) { const board = document.createElement('div'); board.className = 'ttd-kanban-board'; KANBAN_STATUSES_TTD.forEach(status => { const column = document.createElement('div'); column.className = 'ttd-kanban-column'; column.dataset.status = status; // For drop identification column.style.backgroundColor = `var(--status-${status.toLowerCase().replace(/\s+/g, '')}-bg, var(--light-color))`; column.innerHTML = `

${status} (${tasksToDisplay.filter(t => t.status === status).length})

`; column.ondragover = (event) => { event.preventDefault(); column.classList.add('drag-over'); }; // Allow drop column.ondragleave = () => { column.classList.remove('drag-over'); }; column.ondrop = (event) => { event.preventDefault(); column.classList.remove('drag-over'); const droppedTaskId = event.dataTransfer.getData('text/plain'); const targetStatus = column.dataset.status; const task = tasks_TTD.find(t => t.id === droppedTaskId); if (task && task.status !== targetStatus) { task.status = targetStatus; ttd_renderDashboard(); // Re-render Kanban ttd_renderManageTasksTable(); // Also update the management table } draggedTaskElement_TTD = null; }; tasksToDisplay.filter(task => task.status === status).forEach(task => { column.appendChild(ttd_createTaskCard(task)); }); board.appendChild(column); }); parentElement.appendChild(board); } function ttd_renderTeamLoadView(tasksToDisplay, parentElement) { const view = document.createElement('div'); view.className = 'ttd-team-load-view'; if (teamMembers_TTD.length === 0) { view.innerHTML = "

No team members defined. Add members in the Setup tab.

"; parentElement.appendChild(view); return; } teamMembers_TTD.forEach(member => { const memberCol = document.createElement('div'); memberCol.className = 'ttd-member-column'; const memberTasks = tasksToDisplay.filter(t => t.assignedTo === member.id); memberCol.innerHTML = `

${member.name} (${memberTasks.length} tasks)

`; memberTasks.forEach(task => { memberCol.appendChild(ttd_createTaskCard(task)); // Re-use task card style }); if(memberTasks.length === 0) memberCol.innerHTML += '

No tasks assigned.

'; view.appendChild(memberCol); }); // Unassigned tasks const unassignedTasks = tasksToDisplay.filter(t => !t.assignedTo || t.assignedTo === ""); if(unassignedTasks.length > 0){ const unassignedCol = document.createElement('div'); unassignedCol.className = 'ttd-member-column'; unassignedCol.innerHTML = `

Unassigned (${unassignedTasks.length} tasks)

`; unassignedTasks.forEach(task => unassignedCol.appendChild(ttd_createTaskCard(task))); view.appendChild(unassignedCol); } parentElement.appendChild(view); } function ttd_renderMasterListView(tasksToDisplay, parentElement) { const tableContainer = document.createElement('div'); tableContainer.style.overflowX = 'auto'; const table = document.createElement('table'); table.className = 'ttd-master-list-table'; table.innerHTML = ` NameAssigned ToStatusPriority Due DateEffortCategory `; const tbody = table.querySelector('tbody'); if (tasksToDisplay.length === 0) { tbody.innerHTML = 'No tasks to display.'; } else { tasksToDisplay.forEach(task => { const row = tbody.insertRow(); row.insertCell().textContent = task.name; const assignee = teamMembers_TTD.find(m => m.id === task.assignedTo); row.insertCell().textContent = assignee ? assignee.name : 'Unassigned'; row.insertCell().textContent = task.status; row.insertCell().textContent = task.priority; row.insertCell().textContent = task.dueDate ? new Date(task.dueDate+"T00:00:00Z").toLocaleDateString(undefined,{timeZone:'UTC'}) : 'N/A'; row.insertCell().textContent = task.effort ? `${task.effort} ${task.effortUnit}` : 'N/A'; const category = taskCategories_TTD.find(c => c.id === task.category); row.insertCell().textContent = category ? category.name : 'N/A'; }); } tableContainer.appendChild(table); parentElement.appendChild(tableContainer); } // --- PDF and Data Clearing --- function ttd_clearAllData() { if (confirm("Are you sure you want to clear ALL data (team, categories, tasks)?")) { teamMembers_TTD = []; memberIdCounter_TTD = 0; taskCategories_TTD = []; categoryIdCounter_TTD = 0; tasks_TTD = []; taskIdCounter_TTD = 0; ttd_renderMembersList(); ttd_renderCategoriesList(); ttd_updateFilterDropdowns(); ttd_updateAssigneeDropdowns(); ttd_updateCategoryDropdowns(); ttd_clearTaskForm(); ttd_renderManageTasksTable(); ttd_renderDashboard(); alert("All data cleared."); } } function ttd_downloadPDF() { if (!tpc_jsPDF_loaded_TTD || !tpc_autoTable_loaded_TTD) { alert("TTD Error: PDF libraries not loaded."); return; } const filteredTasks = ttd_getFilteredTasks(); // Get currently filtered tasks for the report const doc = new TPC_jsPDF_TTD(); const primaryColor = getComputedStyle(document.documentElement).getPropertyValue('--primary-color').trim(); const darkColor = getComputedStyle(document.documentElement).getPropertyValue('--dark-color').trim(); let finalY = 15; const reportDateStr = new Date().toLocaleDateString(); const today = new Date(); today.setHours(0,0,0,0); doc.setFontSize(18); doc.setTextColor(primaryColor); doc.text("Team Task Dashboard Report", doc.internal.pageSize.getWidth() / 2, finalY, { align: 'center' }); finalY += 8; doc.setFontSize(10); doc.setTextColor(darkColor); doc.text(`Report Date: ${reportDateStr}`, doc.internal.pageSize.getWidth() / 2, finalY, { align: 'center'}); finalY += 12; // Summary Stats for PDF (based on filtered tasks) doc.setFontSize(14); doc.setTextColor(primaryColor); doc.text("Summary Statistics (Based on Current Filters)", 14, finalY); finalY += 7; const totalTasks = filteredTasks.length; const statusCounts = KANBAN_STATUSES_TTD.reduce((acc, status) => { acc[status] = 0; return acc; }, {}); let overdueCount = 0; filteredTasks.forEach(task => { if (statusCounts.hasOwnProperty(task.status)) statusCounts[task.status]++; if (task.dueDate && new Date(task.dueDate+"T00:00:00Z") < today && task.status !== 'Done') overdueCount++; }); let summaryText = `Total Tasks: ${totalTasks} | Overdue: ${overdueCount} | `; KANBAN_STATUSES_TTD.forEach(s => summaryText += `${s}: ${statusCounts[s]} | `); doc.setFontSize(9); doc.setTextColor(darkColor); doc.text(summaryText.slice(0,-3), 14, finalY, {maxWidth: doc.internal.pageSize.getWidth() - 28}); finalY += (Math.ceil(doc.getTextDimensions(summaryText).h / (doc.internal.pageSize.getWidth() - 28)) * 4) + 8 ; doc.setFontSize(14); doc.setTextColor(primaryColor); doc.text("Filtered Task List", 14, finalY); finalY += 7; if (filteredTasks.length > 0) { const taskTableBody = filteredTasks.map(task => { const assignee = teamMembers_TTD.find(m => m.id === task.assignedTo); const category = taskCategories_TTD.find(c => c.id === task.category); return [ task.name, assignee ? assignee.name : 'Unassigned', task.status, task.priority, task.dueDate ? new Date(task.dueDate+"T00:00:00Z").toLocaleDateString(undefined,{timeZone:'UTC'}) : 'N/A', task.effort ? `${task.effort} ${task.effortUnit}` : 'N/A', category ? category.name : 'N/A' ]; }); doc.autoTable({ startY: finalY, head: [['Name', 'Assigned', 'Status', 'Priority', 'Due', 'Effort', 'Category']], body: taskTableBody, theme: 'grid', headStyles: { fillColor: primaryColor, textColor: '#ffffff', fontSize: 9 }, styles: { fontSize: 8, cellPadding: 1.5, overflow: 'linebreak' } }); } else { doc.setFontSize(10); doc.setTextColor(darkColor); doc.text("No tasks match current filters.", 14, finalY); } doc.save(`Team_Task_Dashboard_${new Date().toISOString().slice(0,10)}.pdf`); }
Scroll to Top