Distraction Tracker
Log & View Today
Manage Categories
Analysis & Reports
Today's Distractions (0)
Use the "Log Distraction Now" button above or edit entries below.
Add New Distraction Category
My Distraction Categories
Filter Report Data
Report Summary ()
Total Distractions Logged: 0
Distractions by Category
Distractions by Hour of Day
Detailed Log (Last 100 entries for period)
×
Log Distraction
Notes: ${log.notes}
` : ''}${formatDate(log.timestamp.slice(0,10))} ${formatTime(log.timestamp)} - ${log.categoryName}
${log.taskBeingWorkedOn ? `While working on: ${log.taskBeingWorkedOn}
` : ''} ${log.notes ? `Notes: ${log.notes}
` : ''}No data for this period.
`; return;} const sortedKeys = Object.keys(data).sort((a,b) => { // Sort for consistent chart display if (labelPrefix === "Hour of Day") return parseInt(a.split(':')[0]) - parseInt(b.split(':')[0]); // Sort hours numerically return data[b] - data[a]; // Sort categories by count descending }); sortedKeys.forEach(key => { const value = data[key]; const barGroup = document.createElement('div'); barGroup.className = 'chart-bar-group'; const bar = document.createElement('div'); bar.className = 'chart-bar'; bar.style.height = `${(value / maxValue) * 100}%`; bar.style.backgroundColor = `hsl(${(Object.keys(data).indexOf(key) * 40) % 360}, 70%, 60%)`; // Cycle colors bar.textContent = value; bar.title = `${key}: ${value}`; const label = document.createElement('div'); label.className = 'chart-label'; label.textContent = key; barGroup.appendChild(bar); barGroup.appendChild(label); chartElement.appendChild(barGroup); }); } // --- PDF Download --- downloadDistractionReportPdfBtn.addEventListener('click', async () => { if (reportOutputDiv.style.display === 'none') { alert('Please generate a report first.'); return; } const { jsPDF } = window.jspdf; const doc = new jsPDF('p', 'pt', 'a4'); const margin = 40; let yPos = margin; const pageWidth = doc.internal.pageSize.getWidth(); doc.setFontSize(18); doc.setTextColor(varToRGB('--primary-color').r, varToRGB('--primary-color').g, varToRGB('--primary-color').b); doc.text('Distraction Analysis Report', pageWidth / 2, yPos, { align: 'center' }); yPos += 20; doc.setFontSize(11); doc.setTextColor(100); doc.text(`Period: ${reportPeriodDisplaySpan.textContent}`, pageWidth / 2, yPos, { align: 'center' }); yPos += 15; doc.text(`Generated: ${new Date().toLocaleString()}`, pageWidth / 2, yPos, { align: 'center' }); yPos += 25; doc.setFontSize(10); doc.text(`Total Distractions: ${reportTotalDistractionsSpan.textContent}`, margin, yPos); yPos += 20; async function addChartToPdf(chartContainerId, titleText, currentY) { const chartContainer = document.getElementById(chartContainerId); if (html2canvas && chartContainer && chartContainer.offsetHeight > 0) { if (currentY > doc.internal.pageSize.getHeight() - 180) { doc.addPage(); currentY = margin; } doc.setFontSize(12); doc.setTextColor(varToRGB('--primary-color').r, varToRGB('--primary-color').g, varToRGB('--primary-color').b); doc.text(titleText, margin, currentY); currentY += 15; try { const canvas = await html2canvas(chartContainer.querySelector('.chart'), { scale: 1.5, backgroundColor: getComputedStyle(document.documentElement).getPropertyValue('--light-bg').trim() }); const imgData = canvas.toDataURL('image/png'); const imgProps = doc.getImageProperties(imgData); const pdfImgWidth = pageWidth - 2 * margin; const pdfImgHeight = Math.min(150, (imgProps.height * pdfImgWidth) / imgProps.width); // Max height for chart doc.addImage(imgData, 'PNG', margin, currentY, pdfImgWidth, pdfImgHeight); currentY += pdfImgHeight + 10; } catch (e) { console.error("Chart to PDF error:", e); doc.setTextColor(255,0,0).text("Chart could not be rendered.", margin, currentY); currentY+=15; } } return currentY; } yPos = await addChartToPdf('categoryChartContainer', 'Distractions by Category', yPos); yPos = await addChartToPdf('timeOfDayChartContainer', 'Distractions by Hour of Day', yPos); if (yPos > doc.internal.pageSize.getHeight() - 80) { doc.addPage(); yPos = margin; } doc.setFontSize(12); doc.setTextColor(varToRGB('--primary-color').r, varToRGB('--primary-color').g, varToRGB('--primary-color').b); doc.text('Detailed Distraction Log (Filtered Period)', margin, yPos); yPos += 18; const detailedBody = []; // Re-filter for PDF to ensure it matches current view, not just UI slice let startDatePdf, endDatePdf; const periodPdf = reportDateRangeSelect.value; const todayObjPdf = new Date(todayStr + "T00:00:00"); switch(periodPdf) { /* Same logic as generateAnalysisReportBtn */ case 'today': startDatePdf = new Date(todayObjPdf); endDatePdf = new Date(todayObjPdf); break; case 'yesterday': startDatePdf = new Date(todayObjPdf); startDatePdf.setDate(todayObjPdf.getDate() - 1); endDatePdf = new Date(startDatePdf); break; case 'last7days': endDatePdf = new Date(todayObjPdf); startDatePdf = new Date(todayObjPdf); startDatePdf.setDate(todayObjPdf.getDate() - 6); break; case 'last30days': endDatePdf = new Date(todayObjPdf); startDatePdf = new Date(todayObjPdf); startDatePdf.setDate(todayObjPdf.getDate() - 29); break; case 'custom': startDatePdf = new Date(reportStartDateInput.value + "T00:00:00"); endDatePdf = new Date(reportEndDateInput.value + "T00:00:00"); break; } if(endDatePdf) endDatePdf.setHours(23,59,59,999); const logsForPdf = distractionLog.filter(log => { const logDate = new Date(log.timestamp); return logDate >= startDatePdf && logDate <= endDatePdf; }).sort((a,b) => new Date(a.timestamp) - new Date(b.timestamp)); // Chronological for PDF table logsForPdf.forEach(log => { detailedBody.push([ formatDate(log.timestamp.slice(0,10)) + " " + formatTime(log.timestamp), log.categoryName, log.taskBeingWorkedOn || '', log.notes || '' ]); }); if (detailedBody.length > 0) { doc.autoTable({ startY: yPos, head: [['Timestamp', 'Category', 'Task Worked On', 'Notes']], body: detailedBody, theme: 'grid', headStyles: { fillColor: varToRGB('--primary-color', true), textColor: varToRGB('--light-text', true) }, styles:{fontSize:8, cellPadding:3}, columnStyles: { 0:{cellWidth:80}, 1:{cellWidth:80}, 2:{cellWidth:100}, 3:{cellWidth:'auto'} } }); } else { doc.text("No detailed logs for this period.", margin, yPos); } doc.save(`Distraction_Analysis_${reportPeriodDisplaySpan.textContent.replace(/\s-\s/g,'_to_')}.pdf`); }); function varToRGB(varName, asArray = false) { const colorHex = getComputedStyle(document.documentElement).getPropertyValue(varName).trim(); if (!colorHex.startsWith('#')) { return asArray ? [0,0,0] : {r:0,g:0,b:0}; } const r = parseInt(colorHex.slice(1, 3), 16); const g = parseInt(colorHex.slice(3, 5), 16); const b = parseInt(colorHex.slice(5, 7), 16); return asArray ? [r,g,b] : {r,g,b}; } // --- Initializations --- if (distractionCategories.length === 0) { // First time use distractionCategories = [...DEFAULT_CATEGORIES]; saveCategories(); } renderCategoriesList(); renderTodaysDistractions(); setDefaultReportDates(); // generateAnalysisReportBtn.click(); // Optionally generate report on load for default period })();