`;
html += '
Time by Category:
';
const sortedCategories = Object.entries(timeByCategory).sort(([,a],[,b]) => b-a);
if(sortedCategories.length > 0) {
const maxCatTime = sortedCategories.length > 0 ? sortedCategories[0][1] : 1;
sortedCategories.forEach(([cat, mins]) => {
const percentage = maxCatTime > 0 ? Math.max(5, (mins / maxCatTime * 100)) : 5; // Min 5% width for visibility
html += `
${cat} (${pual_formatDurationForDisplay(mins)})
${pual_formatDurationForDisplay(mins)}
`;
});
} else { html += "
No time logged with duration.
"; }
html += '
';
html += '
Most Frequent Activities:
';
const sortedActivities = Object.entries(activityCounts).sort(([,a],[,b]) => b-a).slice(0,5); // Top 5
if(sortedActivities.length > 0){
sortedActivities.forEach(([desc, count]) => {
html += `- ${desc}: ${count} times
`;
});
} else { html += "- No specific activities logged.
"; }
html += '
';
resultsDiv.innerHTML = html;
}
// --- PDF and Clear All ---
function pual_clearAllLogData() {
if (confirm("Are you sure you want to clear ALL logged unproductive activities? Categories will remain.")) {
pual_loggedActivities = []; pual_logIdCounter = 0;
pual_editLogId = null; // Clear any edit state
pual_clearLogForm(); // Reset form on tab 1
pual_applyFiltersAndAnalyze(); // Re-renders empty log and analytics
}
}
function pual_downloadPDF() {
if (!tpc_jsPDF_loaded_PUAL || !tpc_autoTable_loaded_PUAL) { alert("PUAL Error: PDF libraries not loaded."); return; }
const fromDateStr = document.getElementById('pual-filter-from-date').value;
const toDateStr = document.getElementById('pual-filter-to-date').value;
const catFilter = document.getElementById('pual-filter-category').value;
const activityFilter = document.getElementById('pual-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 = pual_loggedActivities.filter(entry => {
const entryDate = new Date(`${entry.date}T${entry.startTime}`);
if (fromDate && entryDate < fromDate) return false;
if (toDate && entryDate > toDate) return false;
if (catFilter && entry.categoryId !== catFilter) return false;
if (activityFilter && !entry.description.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_PUAL();
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("Personal Unproductive Activity 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: Period: ${fromDateStr || 'Any'} to ${toDateStr || 'Any'}. `;
if(catFilter) filterText += `Category: ${pual_unproductiveCategories.find(c=>c.id === catFilter)?.name || 'N/A'}. `;
if(activityFilter) filterText += `Activity Desc Contains: "${activityFilter}".`;
finalY += 5; doc.text(filterText, 14, finalY, {maxWidth: doc.internal.pageSize.getWidth() - 28});
finalY += 10;
let totalUnproductiveMinutes = 0; const timeByCategory = {};
dataForPdf.forEach(entry => {
if (entry.durationMinutes !== null) {
totalUnproductiveMinutes += 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 Unproductive Time (in filtered log): ${pual_formatDurationForDisplay(totalUnproductiveMinutes)} from ${dataForPdf.length} entries.`, 14, finalY); finalY +=5;
if(Object.keys(timeByCategory).length > 0){
finalY = doc.autoTable({
startY: finalY,
head: [['Unproductive Category', 'Total Time Spent']],
body: Object.entries(timeByCategory).map(([cat, mins]) => [cat, pual_formatDurationForDisplay(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.date ? new Date(entry.date+"T00:00:00Z").toLocaleDateString(undefined,{timeZone:'UTC'}) : 'N/A',
entry.startTime, entry.endTime,
pual_formatDurationForDisplay(entry.durationMinutes),
entry.categoryName, entry.description, entry.affectedTask || '-'
]);
doc.autoTable({
startY: finalY,
head: [['Date', 'Start', 'End', 'Duration', 'Category', 'Description', 'Affected Task']],
body: tableBody, theme: 'grid',
headStyles: { fillColor: primaryColor, textColor: '#ffffff', fontSize: 9 },
styles: { fontSize: 8, cellPadding: 1.5, overflow: 'linebreak' }
});
doc.save(`Unproductive_Activity_Report_${new Date().toISOString().slice(0,10)}.pdf`);
}