Time Audit Tool
Time Audit Tool

Manage Categories


Real-time Activity Tracker


Manual Log Entry

Filter & Search Log

Detailed Time Log

DateStartEndDurationActivityCategoryActions

No time tracked with duration.

"; } html += '
'; // Time by Activity (Top 5) html += '

Time by Top Activities:

    '; const sortedActivities = Object.entries(timeByActivity).sort(([,a],[,b]) => b-a).slice(0,5); if(sortedActivities.length > 0){ sortedActivities.forEach(([act, mins]) => { html += `
  • ${act}: ${tat_formatDuration(mins)}
  • `; }); } else { html += "
  • No specific activities with duration tracked.
  • "; } html += '
'; resultsDiv.innerHTML = html; } // PDF and Clear function tat_clearAllLogData() { if (confirm("Are you sure you want to clear ALL logged time entries? This cannot be undone.")) { if (tat_currentTrackedActivity && tat_currentTrackedActivity.timerInterval) clearInterval(tat_currentTrackedActivity.timerInterval); tat_currentTrackedActivity = null; tat_logEntries = []; tat_logIdCounter = 0; document.getElementById('tat-tracker-display').style.display = 'none'; document.getElementById('tat-tracker-start-btn').disabled = false; document.getElementById('tat-tracker-stop-btn').disabled = true; tat_applyFilters(); // Re-renders empty log and analytics } } function tat_downloadPDF() { if (!tpc_jsPDF_loaded_TAT || !tpc_autoTable_loaded_TAT) { alert("TAT Error: PDF libraries not loaded."); return; } const fromDateStr = document.getElementById('tat-filter-from-date').value; const toDateStr = document.getElementById('tat-filter-to-date').value; const catFilter = document.getElementById('tat-filter-category').value; const activityFilter = document.getElementById('tat-filter-activity').value.toLowerCase(); const fromDate = fromDateStr ? new Date(fromDateStr + "T00:00:00") : null; const toDate = toDateStr ? new Date(toDateStr + "T23:59:59") : null; const dataForPdf = tat_logEntries.filter(entry => { if (!entry.startTime) return false; if (fromDate && entry.startTime < fromDate) return false; if (toDate && entry.startTime > toDate) return false; if (catFilter && entry.categoryId !== catFilter) return false; if (activityFilter && !entry.activityName.toLowerCase().includes(activityFilter)) return false; return true; }); if (dataForPdf.length === 0) { alert("No log entries (matching current filters) to export."); return; } const doc = new TPC_jsPDF_TAT(); 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(); doc.setFontSize(18); doc.setTextColor(primaryColor); doc.text("Time Audit 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'}); let filterText = `Filters Applied: Period: ${fromDateStr || 'Any'} to ${toDateStr || 'Any'}. `; if(catFilter) filterText += `Category: ${tat_categories.find(c=>c.id === catFilter)?.name || 'N/A'}. `; if(activityFilter) filterText += `Activity Contains: "${activityFilter}".`; finalY += 5; doc.text(filterText, doc.internal.pageSize.getWidth() / 2, finalY, { align: 'center'}); finalY += 10; // Analytics for PDF let totalTrackedMinutes = 0; const timeByCategory = {}; dataForPdf.forEach(entry => { if (entry.durationMinutes !== null) { totalTrackedMinutes += entry.durationMinutes; timeByCategory[entry.categoryName] = (timeByCategory[entry.categoryName] || 0) + entry.durationMinutes; } }); doc.setFontSize(12); doc.setTextColor(primaryColor); doc.text("Summary:", 14, finalY); finalY += 6; doc.setFontSize(9); doc.setTextColor(darkColor); doc.text(`Total Time Logged (with duration): ${tat_formatDuration(totalTrackedMinutes)} from ${dataForPdf.filter(e=>e.durationMinutes!==null).length} entries.`, 14, finalY); finalY +=5; if(Object.keys(timeByCategory).length > 0){ finalY = doc.autoTable({ startY: finalY, head: [['Category', 'Time Spent']], body: Object.entries(timeByCategory).map(([cat, mins]) => [cat, tat_formatDuration(mins)]), theme: 'striped', headStyles: {fillColor:primaryColor, textColor:'#fff', fontSize:9}, styles:{fontSize:8, cellPadding:1.5}, margin: {left: 14, right: 14} }).finalY + 7; } doc.setFontSize(12); doc.setTextColor(primaryColor); doc.text("Detailed Log:", 14, finalY); finalY += 6; const tableBody = dataForPdf.map(entry => [ entry.startTime ? entry.startTime.toLocaleDateString() : 'N/A', entry.startTime ? entry.startTime.toLocaleTimeString() : 'N/A', entry.endTime ? entry.endTime.toLocaleTimeString() : (entry.eventType === 'Start' ? 'In Progress' : 'N/A'), entry.durationMinutes !== null ? tat_formatDuration(entry.durationMinutes) : '-', entry.activityName, entry.categoryName, entry.details || '-' ]); doc.autoTable({ startY: finalY, head: [['Date', 'Start', 'End', 'Duration', 'Activity', 'Category', 'Details']], body: tableBody, theme: 'grid', headStyles: { fillColor: primaryColor, textColor: '#ffffff', fontSize: 9 }, styles: { fontSize: 8, cellPadding: 1.5, overflow: 'linebreak' } }); doc.save(`Time_Audit_Report_${new Date().toISOString().slice(0,10)}.pdf`); }
Scroll to Top