Automated Team Task Status Reporter

Automated Team Task Status Reporter

Manage Team Members

Log Task Statuses for Reporting Date:

Logged Entries for Date:

Status Report for Date

Effective Team Status Reporting

1. Set Up Your Team
In the "Team & Task Input" tab, add the names of your team members. This helps in assigning tasks and organizing the report.
2. Select Reporting Date
Choose the date for which you are reporting status. This is typically the current day for daily reports.
3. Log Task Statuses
For each team member and for the selected date, add task status entries:
  • Task Description: What task was worked on or is planned?
  • Status:
    • Completed Today: Tasks finished on the reporting date.
    • In Progress: Tasks actively being worked on but not yet finished.
    • Blocked: Tasks that cannot proceed. Specify the reason in "Blocker Reason".
    • Planned for Next Period: Tasks scheduled for the next day or reporting cycle.
  • % Complete: (Optional) The current completion percentage for "In Progress" tasks.
  • Notes/Updates: Any relevant details, challenges, or accomplishments related to the task.
4. Generate and Review Report
Go to the "View Report" tab and click "Generate/Refresh Report". The tool will compile all entries for the selected date, grouping them by team member and then by status. Review for clarity and completeness.
5. Export to PDF
Once satisfied, use the "Download Report as PDF" button to get a shareable document.
Tips for Good Reports:
  • Be Timely: Submit reports consistently.
  • Be Clear and Concise: Use clear language. Get straight to the point.
  • Highlight Blockers: Make any impediments highly visible.
  • Focus on Outcomes: Where possible, mention results and impact, not just activities.
  • Mention Next Steps: "Planned for Next Period" helps in understanding continuity.

Please select a reporting date.

'; return; } if(attsrCurrentDateDisplayEl) attsrCurrentDateDisplayEl.textContent = attsrFormatDisplayDate(selectedDateKey); if(attsrReportDateDisplayEl) attsrReportDateDisplayEl.textContent = attsrFormatDisplayDate(selectedDateKey); attsrRenderTaskStatusEntries(selectedDateKey); } function attsrRenderTaskStatusEntries(dateKey) { if (!attsrTaskStatusEntriesListEl) return; attsrTaskStatusEntriesListEl.innerHTML = ''; const entries = attsrDailyTaskStatuses[dateKey] || []; if (entries.length === 0) { attsrTaskStatusEntriesListEl.innerHTML = '

No task status entries logged for this date.

'; return; } entries.forEach(entry => { const member = attsrTeamMembers.find(m => m.id === entry.teamMemberId); const itemEl = document.createElement('div'); itemEl.className = 'attsr-list-item'; itemEl.innerHTML = `

${entry.taskDescription}

By: ${member ? member.name : 'Unknown'} | Status: ${entry.status} ${entry.percentComplete !== undefined ? `(${entry.percentComplete}%)` : ''} ${entry.status === 'Blocked' && entry.blockerReason ? `
Blocked: ${entry.blockerReason}` : ''} ${entry.notes ? `
Notes: ${entry.notes}` : ''}

`; attsrTaskStatusEntriesListEl.appendChild(itemEl); }); } // Task Status Modal & CRUD window.attsrOpenTaskStatusModal = function(entryId = null) { const selectedDateKey = attsrReportingDateInput.value; if (!selectedDateKey) { alert("Please select a reporting date first."); return; } if (attsrTeamMembers.length === 0) { alert("Please add team members first in the 'Team & Task Input' tab."); return; } attsrTaskStatusForm.reset(); attsrTaskStatusEntryIdInput.value = ''; attsrBlockerReasonGroupEl.style.display = 'none'; // Hide by default attsrTaskBlockerReasonInput.required = false; attsrTaskPercentCompleteValueEl.textContent = '0%'; if (entryId) { const entries = attsrDailyTaskStatuses[selectedDateKey] || []; const entry = entries.find(e => e.id === entryId); if (entry) { attsrModalTitleEl.textContent = 'Edit Task Status Entry'; attsrTaskStatusEntryIdInput.value = entry.id; attsrTaskTeamMemberSelectEl.value = entry.teamMemberId; attsrTaskDescriptionInput.value = entry.taskDescription; attsrTaskStatusSelectEl.value = entry.status; if (entry.status === 'Blocked') { attsrBlockerReasonGroupEl.style.display = 'block'; attsrTaskBlockerReasonInput.value = entry.blockerReason || ''; attsrTaskBlockerReasonInput.required = true; } attsrTaskPercentCompleteInput.value = entry.percentComplete || 0; attsrTaskPercentCompleteValueEl.textContent = (entry.percentComplete || 0) + '%'; attsrTaskNotesInput.value = entry.notes || ''; } } else { attsrModalTitleEl.textContent = 'Add Task Status Entry for ' + attsrFormatDisplayDate(selectedDateKey); attsrTaskPercentCompleteInput.value = 0; // Default for new attsrTaskPercentCompleteValueEl.textContent = '0%'; } attsrTaskStatusModalEl.style.display = 'block'; } window.attsrCloseModal = (modalId) => { const modal = document.getElementById(modalId); if(modal) modal.style.display = 'none'; } if(attsrTaskStatusSelectEl) attsrTaskStatusSelectEl.addEventListener('change', function() { if (this.value === 'Blocked') { attsrBlockerReasonGroupEl.style.display = 'block'; attsrTaskBlockerReasonInput.required = true; } else { attsrBlockerReasonGroupEl.style.display = 'none'; attsrTaskBlockerReasonInput.required = false; } }); if(attsrTaskStatusForm) attsrTaskStatusForm.addEventListener('submit', function(e) { e.preventDefault(); const selectedDateKey = attsrReportingDateInput.value; if (!selectedDateKey) { alert("Error: No reporting date selected."); return; } if (!attsrDailyTaskStatuses[selectedDateKey]) { attsrDailyTaskStatuses[selectedDateKey] = []; } const entryId = attsrTaskStatusEntryIdInput.value; const entryData = { taskDescription: attsrTaskDescriptionInput.value.trim(), teamMemberId: attsrTaskTeamMemberSelectEl.value, status: attsrTaskStatusSelectEl.value, blockerReason: attsrTaskStatusSelectEl.value === 'Blocked' ? attsrTaskBlockerReasonInput.value.trim() : "", percentComplete: parseInt(attsrTaskPercentCompleteInput.value), notes: attsrTaskNotesInput.value.trim() }; if (!entryData.taskDescription || !entryData.teamMemberId) { alert("Task description and team member are required."); return; } if (entryData.status === 'Blocked' && !entryData.blockerReason) { alert("Blocker reason is required when status is 'Blocked'."); return; } if (entryId) { // Editing const index = attsrDailyTaskStatuses[selectedDateKey].findIndex(e => e.id === entryId); if (index > -1) { attsrDailyTaskStatuses[selectedDateKey][index] = { ...attsrDailyTaskStatuses[selectedDateKey][index], ...entryData }; } } else { // Adding new const newEntry = { id: 'attsr-entry-' + Date.now(), ...entryData }; attsrDailyTaskStatuses[selectedDateKey].push(newEntry); } attsrSaveDailyTaskStatuses(); attsrRenderTaskStatusEntries(selectedDateKey); attsrCloseModal('attsrTaskStatusModal'); }); window.attsrDeleteTaskStatusEntry = function(entryId) { const selectedDateKey = attsrReportingDateInput.value; if (!selectedDateKey || !attsrDailyTaskStatuses[selectedDateKey]) return; if (confirm('Are you sure you want to delete this task status entry?')) { attsrDailyTaskStatuses[selectedDateKey] = attsrDailyTaskStatuses[selectedDateKey].filter(e => e.id !== entryId); attsrSaveDailyTaskStatuses(); attsrRenderTaskStatusEntries(selectedDateKey); } } // --- Report Generation --- window.attsrGenerateReport = function() { if (!attsrReportOutputEl) return; const selectedDateKey = attsrReportingDateInput.value; if (!selectedDateKey) { attsrReportOutputEl.innerHTML = '

Please select a reporting date on the "Team & Task Input" tab first.

'; if(attsrReportDateDisplayEl) attsrReportDateDisplayEl.textContent = "N/A"; if(attsrDownloadPdfBtn) attsrDownloadPdfBtn.style.display = 'none'; return; } if(attsrReportDateDisplayEl) attsrReportDateDisplayEl.textContent = attsrFormatDisplayDate(selectedDateKey); const entries = attsrDailyTaskStatuses[selectedDateKey] || []; if (entries.length === 0) { attsrReportOutputEl.innerHTML = '

No task status entries logged for this date.

'; if(attsrDownloadPdfBtn) attsrDownloadPdfBtn.style.display = 'none'; return; } let reportHTML = ''; const entriesByMember = {}; attsrTeamMembers.forEach(member => { // Ensure all team members are listed even if no tasks entriesByMember[member.id] = { name: member.name, tasksByStatus: { "Completed Today": [], "In Progress": [], "Blocked": [], "Planned for Next Period": [] }}; }); entries.forEach(entry => { if (entriesByMember[entry.teamMemberId]) { if (entriesByMember[entry.teamMemberId].tasksByStatus[entry.status]) { entriesByMember[entry.teamMemberId].tasksByStatus[entry.status].push(entry); } } }); for (const memberId in entriesByMember) { const memberData = entriesByMember[memberId]; let memberHTML = `
${memberData.name}
`; let hasTasksForMember = false; for (const status in memberData.tasksByStatus) { if (memberData.tasksByStatus[status].length > 0) { hasTasksForMember = true; memberHTML += `
${status}
    `; memberData.tasksByStatus[status].forEach(task => { memberHTML += `
  • ${task.taskDescription} ${task.percentComplete !== undefined ? `(${task.percentComplete}%)` : ''}`; if (status === 'Blocked' && task.blockerReason) { memberHTML += `
    Blocked by: ${task.blockerReason}`; } if (task.notes) { memberHTML += `
    Notes: ${task.notes}`; } memberHTML += `
  • `; }); memberHTML += `
`; } } if (!hasTasksForMember) { memberHTML += `

No updates for this period.

`; } memberHTML += `
`; reportHTML += memberHTML; } attsrReportOutputEl.innerHTML = reportHTML; if(attsrDownloadPdfBtn) attsrDownloadPdfBtn.style.display = 'block'; } // --- PDF Export --- if(attsrDownloadPdfBtn) attsrDownloadPdfBtn.addEventListener('click', function() { const selectedDateKey = attsrReportingDateInput.value; if (!selectedDateKey || !attsrDailyTaskStatuses[selectedDateKey] || attsrDailyTaskStatuses[selectedDateKey].length === 0) { alert("No data for the selected date to export."); return; } const entries = attsrDailyTaskStatuses[selectedDateKey]; const { jsPDF } = window.jspdf; const doc = new jsPDF(); const primaryColor = getComputedStyle(document.documentElement).getPropertyValue('--attsr-primary-color').trim(); doc.setFontSize(18); doc.setTextColor(primaryColor); doc.text(`Team Task Status Report - ${attsrFormatDisplayDate(selectedDateKey)}`, 14, 22); let yPos = 35; const entriesByMember = {}; attsrTeamMembers.forEach(member => { entriesByMember[member.id] = { name: member.name, tasksByStatus: { "Completed Today": [], "In Progress": [], "Blocked": [], "Planned for Next Period": [] }}; }); entries.forEach(entry => { if (entriesByMember[entry.teamMemberId] && entriesByMember[entry.teamMemberId].tasksByStatus[entry.status]) { entriesByMember[entry.teamMemberId].tasksByStatus[entry.status].push(entry); } }); for (const memberId in entriesByMember) { const memberData = entriesByMember[memberId]; if (yPos > 260) { doc.addPage(); yPos = 20; } doc.setFontSize(14); doc.setTextColor(primaryColor); doc.text(memberData.name, 14, yPos); yPos += 8; let memberHasTasks = false; for (const status in memberData.tasksByStatus) { if (memberData.tasksByStatus[status].length > 0) { memberHasTasks = true; if (yPos > 265) { doc.addPage(); yPos = 20; } doc.setFontSize(11); doc.setTextColor(getComputedStyle(document.documentElement).getPropertyValue('--attsr-text-color').trim()); doc.setFont(undefined, 'bold'); doc.text(status, 16, yPos); yPos += 6; doc.setFont(undefined, 'normal'); doc.setFontSize(9); memberData.tasksByStatus[status].forEach(task => { if (yPos > 270) { doc.addPage(); yPos = 20; } let taskLine = `\u2022 ${task.taskDescription} ${task.percentComplete !== undefined ? `(${task.percentComplete}%)` : ''}`; const splitTaskLine = doc.splitTextToSize(taskLine, doc.internal.pageSize.getWidth() - 40); doc.text(splitTaskLine, 18, yPos); yPos += splitTaskLine.length * 4; if (status === 'Blocked' && task.blockerReason) { if (yPos > 270) { doc.addPage(); yPos = 20; } const blockerLine = ` Blocked by: ${task.blockerReason}`; const splitBlocker = doc.splitTextToSize(blockerLine, doc.internal.pageSize.getWidth() - 44); doc.setTextColor(getComputedStyle(document.documentElement).getPropertyValue('--attsr-danger-color').trim()); doc.text(splitBlocker, 20, yPos); doc.setTextColor(getComputedStyle(document.documentElement).getPropertyValue('--attsr-text-color').trim()); yPos += splitBlocker.length * 4; } if (task.notes) { if (yPos > 270) { doc.addPage(); yPos = 20; } const notesLine = ` Notes: ${task.notes}`; const splitNotes = doc.splitTextToSize(notesLine, doc.internal.pageSize.getWidth() - 44); doc.setTextColor(120,120,120); // Grey for notes doc.text(splitNotes, 20, yPos); doc.setTextColor(getComputedStyle(document.documentElement).getPropertyValue('--attsr-text-color').trim()); yPos += splitNotes.length * 4; } yPos += 1; // Small gap between tasks }); yPos += 3; // Gap after status group } } if (!memberHasTasks) { if (yPos > 270) { doc.addPage(); yPos = 20; } doc.setFontSize(9); doc.setTextColor(120,120,120); doc.text("No updates for this period.", 18, yPos); yPos += 5; } yPos += 5; // Gap after member block } doc.save(`TeamStatusReport_${selectedDateKey}.pdf`); }); // --- Initialization --- document.addEventListener('DOMContentLoaded', () => { const today = new Date(2025, 4, 14); // May 14, 2025, month is 0-indexed attsrReportingDateInput.value = attsrFormatDateKey(today); attsrLoadData(); const firstTabButton = document.querySelector('#teamTaskStatusReporterTool .attsr-tab-button'); if (firstTabButton) { firstTabButton.click(); } // Close modal if clicked outside window.addEventListener('click', function(event) { const modal = document.getElementById('attsrTaskStatusModal'); if (modal && event.target == modal) { attsrCloseModal('attsrTaskStatusModal'); } }); // Update progress value display when slider changes in add/edit modal if(attsrTaskPercentCompleteInput && attsrTaskPercentCompleteValueEl) { attsrTaskPercentCompleteInput.addEventListener('input', function() { attsrTaskPercentCompleteValueEl.textContent = this.value + '%'; }); } });
Scroll to Top