';
// Time by Activity (Top 5)
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`);
}
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 += '
