Setup Tasks and Checklists
Task Overview
| Task Title | Due Date | Assigned To | Status | Checklist % | Actions |
|---|
No main tasks defined yet.
Track Progress & Review Tasks
No tasks available for tracking. Add tasks on Tab 1.
Automated Review Findings
No immediate issues flagged based on current status and checklists.
×
Checklist for Task
Checklist: ${atrsCalculateChecklistCompletion(task.checklist)}% complete
`; atrsTaskTrackingAreaEl.appendChild(taskDiv); }); } function atrsUpdateTaskStatus(taskId, newStatus) { const task = atrsTasksData.find(t => t.id === taskId); if (task) { task.status = newStatus; atrsSaveDataToStorage(); atrsRenderMainTaskList(); const taskDivInTracking = Array.from(document.getElementById('atrsTaskTrackingArea').children).find(div => div.querySelector('h4')?.textContent.includes(`(ID: ${taskId})`)); if(taskDivInTracking) { taskDivInTracking.className = 'atrs-review-item'; // Reset classes taskDivInTracking.classList.add(`status-${newStatus.toLowerCase().replace(/\s+/g, '')}`); } // Clear previous system notes when status is manually changed by user const reviewNoteElTrack = document.getElementById(`reviewNoteTrack-${taskId}`); if(reviewNoteElTrack) reviewNoteElTrack.textContent = ''; } } function atrsPerformGlobalReview() { if(!atrsReviewResultItemsEl || !atrsNoReviewIssuesMessageEl || !atrsReviewResultsDisplayAreaEl || !atrsDownloadReportBtnEl) return; atrsReviewResultItemsEl.innerHTML = ''; let issuesFound = 0; const today = new Date(); today.setHours(0,0,0,0); atrsTasksData.forEach(task => { let notes = []; const checklistCompletion = atrsCalculateChecklistCompletion(task.checklist); if (task.dueDate) { const dueDate = new Date(task.dueDate); // Already YYYY-MM-DD, new Date will parse as local dueDate.setHours(0,0,0,0); if (dueDate < today && task.status !== 'Completed') { notes.push("Task is OVERDUE."); } } if (task.status === 'Blocked') notes.push("Task is BLOCKED. Requires attention."); if (task.status === 'Pending Review' && checklistCompletion < 100) notes.push("'Pending Review' but checklist is not 100% complete."); if (task.status === 'Completed' && checklistCompletion < 100) notes.push("'Completed' but checklist was not 100% complete (Potential Discrepancy)."); if (task.status !== 'Completed' && checklistCompletion === 100 && task.status !== 'Pending Review') notes.push("Checklist 100% complete, but task not 'Completed' or 'Pending Review'. Consider updating status."); const reviewNoteElTrack = document.getElementById(`reviewNoteTrack-${task.id}`); if(reviewNoteElTrack) reviewNoteElTrack.textContent = notes.join(' '); if (notes.length > 0) { issuesFound++; const itemDiv = document.createElement('div'); itemDiv.classList.add('atrs-review-item'); if(notes.some(n => n.includes("OVERDUE"))) itemDiv.classList.add('status-overdue'); else if(notes.some(n => n.includes("BLOCKED"))) itemDiv.classList.add('status-blocked'); else if(notes.some(n => n.includes("Pending Review"))) itemDiv.classList.add('status-pendingreview', 'incomplete'); else if(notes.some(n => n.includes("Completed") && n.includes("Discrepancy"))) itemDiv.classList.add('status-completed', 'discrepancy'); else if(notes.some(n => n.includes("Consider updating status"))) itemDiv.classList.add('status-completed','ok'); itemDiv.innerHTML = `${atrsEscapeHtml(task.title)} (ID: ${task.id} | Status: ${task.status})
${notes.map(atrsEscapeHtml).join('
')}
/gi, "\n"); // Convert
to newlines for PDF yPos = checkPdfPageBreak(doc, yPos, 45); // Estimate space needed doc.setFontSize(10); doc.setFont(undefined,'bold'); doc.text(titleText, leftMargin, yPos); yPos += 14; doc.setFontSize(9); doc.setFont(undefined,'italic'); const noteLines = doc.splitTextToSize(notesText, contentWidth - 10); // Small indent doc.text(noteLines, leftMargin + 10, yPos); yPos += (noteLines.length * 11) + 8; }); } else if (atrsTasksData.length > 0) { doc.setFontSize(12); doc.setTextColor(primaryColorPDF); doc.text("No specific review issues flagged based on automated checks.", leftMargin, yPos); yPos += 20; } if (atrsTasksData.length > 0) { yPos = checkPdfPageBreak(doc, yPos, 50); doc.setFontSize(12); doc.setFont(undefined, 'bold'); doc.setTextColor(primaryColorPDF); doc.text("All Tasks Overview:", leftMargin, yPos); yPos += 20; const tableColumns = ["ID", "Task Title", "Due Date", "Assigned To", "Status", "Checklist %"]; const tableRows = atrsTasksData.map(task => [ task.id, task.title, task.dueDate ? new Date(task.dueDate+'T00:00:00Z').toLocaleDateString() : 'N/A', task.assignedTo || 'N/A', task.status, `${atrsCalculateChecklistCompletion(task.checklist)}%` ]); doc.autoTable({ head: [tableColumns], body: tableRows, startY: yPos, theme: 'grid', headStyles: { fillColor: primaryColorPDF, textColor: whiteColorPDF, fontSize: 9, fontStyle: 'bold' }, styles: { fontSize: 8, cellPadding: 3, textColor: textColorPDF, overflow: 'linebreak' }, columnStyles: { 1: {cellWidth: 'auto'}} }); } else { yPos = checkPdfPageBreak(doc, yPos, 20); doc.setFontSize(10); doc.text("No tasks were defined in the system for this report.", leftMargin, yPos); } doc.save(`TaskReviewReport_${todayStr.replace(/\//g,'-')}.pdf`); } function checkPdfPageBreak(doc, currentY, spaceNeeded) { if (currentY + spaceNeeded > doc.internal.pageSize.getHeight() - 40) { doc.addPage(); return 40; } return currentY; } function atrsEscapeHtml(unsafe) { if (typeof unsafe !== 'string') return ''; return unsafe.replace(/&/g, "&").replace(//g, ">").replace(/"/g, """).replace(/'/g, "'"); }
