Personal Time Usage & Deviation Analyzer
Today's Planned Work Blocks/Tasks
Live Activity Tracking & Deviation Log
Working on: | Started: | Elapsed: 00:00:00
ON DEVIATION:
Log Deviation from Current Work
Analyze Time Usage
Analysis for
No deviations logged for this date.
Totals for Day: Planned: ${ptuda_formatDuration(totalPlannedMin)} | Actual Productive: ${ptuda_formatDuration(totalActualProdMin)} | Deviations: ${ptuda_formatDuration(totalDeviationMin)}
`; // Deviation Summary if (Object.keys(deviationByType).length > 0) { let ul = '- ';
for (const type in deviationByType) {
ul += `
- ${type}: ${ptuda_formatDuration(deviationByType[type])} `; } ul += '
No deviations logged for this date.
'; } document.getElementById('ptuda-analysis-results-area').style.display = 'block'; } // --- PDF and Clear --- function ptuda_clearAllLoggedData() { if (confirm("Clear ALL planned work, actual tracking, and deviations? This cannot be undone.")) { ptuda_plannedWork = []; ptuda_planIdCounter = 0; if(ptuda_currentFocus && ptuda_currentFocus.timerInterval) clearInterval(ptuda_currentFocus.timerInterval); ptuda_currentFocus = null; ptuda_renderPlannedWorkForDay(); ptuda_updateLiveTrackerDisplay(); ptuda_renderAnalysis(); // Will show empty } } function ptuda_downloadPDF() { if (!tpc_jsPDF_loaded_PTUDA || !tpc_autoTable_loaded_PTUDA) { alert("PTUDA Error: PDF libraries not loaded."); return; } const analyzeDateStr = document.getElementById('ptuda-analyze-date').value; if (!analyzeDateStr) { alert("Please select a date to generate report for."); return; } // Ensure data for PDF is current from analysis ptuda_renderAnalysis(); // This updates the displayed analysis const tasksForDate = ptuda_plannedWork.filter(p => p.date === analyzeDateStr); if (tasksForDate.length === 0) { alert("No data for selected date to export."); return; } const doc = new TPC_jsPDF_PTUDA(); 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(); const analysisDateDisplay = new Date(analyzeDateStr+"T00:00:00Z").toLocaleDateString(undefined, {timeZone:'UTC', year:'numeric',month:'long',day:'numeric'}); doc.setFontSize(18); doc.setTextColor(primaryColor); doc.text("Personal Time Usage Analysis", doc.internal.pageSize.getWidth() / 2, finalY, { align: 'center' }); finalY += 8; doc.setFontSize(10); doc.setTextColor(darkColor); doc.text(`Report Date: ${reportDateStr} | Analysis For: ${analysisDateDisplay}`, doc.internal.pageSize.getWidth() / 2, finalY, { align: 'center'}); finalY += 12; doc.setFontSize(12); doc.setTextColor(primaryColor); doc.text("Planned vs. Actual Productive Time & Deviations", 14, finalY); finalY += 7; let totalPlannedMin = 0, totalActualProdMin = 0, totalDeviationMin = 0; const deviationByType = {}; const tableBody = tasksForDate.map(plan => { totalPlannedMin += plan.plannedDurationMin; let currentDeviationsTotalMin = 0; plan.deviations.forEach(dev => { currentDeviationsTotalMin += dev.durationMin; deviationByType[dev.type] = (deviationByType[dev.type] || 0) + dev.durationMin; }); totalDeviationMin += currentDeviationsTotalMin; let actualProdMin = 0; if (plan.actualStartTime && plan.actualEndTime) { actualProdMin = Math.max(0, Math.round((plan.actualEndTime.getTime() - plan.actualStartTime.getTime()) / (60*1000)) - currentDeviationsTotalMin); totalActualProdMin += actualProdMin; } const variance = plan.actualStartTime ? actualProdMin - plan.plannedDurationMin : null; return [ plan.name, ptuda_formatDuration(plan.plannedDurationMin), plan.actualStartTime ? ptuda_formatDuration(actualProdMin) : 'Not Tracked', ptuda_formatDuration(currentDeviationsTotalMin), variance !== null ? ptuda_formatDuration(variance) : '-' ]; }); doc.autoTable({ startY: finalY, head: [['Activity', 'Planned', 'Actual Prod.', 'Deviations', 'Variance']], body: tableBody, theme: 'grid', headStyles: { fillColor: primaryColor, textColor: '#ffffff', fontSize: 9 }, styles: { fontSize: 8, cellPadding: 1.5, overflow: 'linebreak' } }); finalY = doc.lastAutoTable.finalY + 5; doc.setFontSize(9); doc.setTextColor(darkColor); doc.text(`Totals: Planned: ${ptuda_formatDuration(totalPlannedMin)} | Actual Productive: ${ptuda_formatDuration(totalActualProdMin)} | Deviations: ${ptuda_formatDuration(totalDeviationMin)}`, 14, finalY); finalY += 10; if (Object.keys(deviationByType).length > 0) { doc.setFontSize(12); doc.setTextColor(primaryColor); doc.text("Deviation Summary by Type:", 14, finalY); finalY += 6; const devSummaryBody = Object.entries(deviationByType).map(([type, mins]) => [type, ptuda_formatDuration(mins)]); doc.autoTable({ startY: finalY, head: [['Deviation Type', 'Total Time Spent']], body: devSummaryBody, theme: 'striped', headStyles: {fillColor:primaryColor, textColor:'#fff',fontSize:9}, styles:{fontSize:8, cellPadding:1.5} }); } doc.save(`Time_Usage_Analysis_${analyzeDateStr}.pdf`); }