Personal Work-Hour Analyzer
Logged Entries for Date:
Select Period for Analysis
(Analysis uses date selected on "Daily Log" tab for context)
Analysis for Period
Total Hours Logged: 0 hours
Time Distribution by Category:
| Category | Hours | Percentage |
|---|
Detailed Log for Period:
Manage Work Categories
Using the Work-Hour Analyzer
- 1. Define Your Categories (Categories Tab)
- Start by setting up categories that represent the different types of work you do or projects you're involved in (e.g., "Client Project A," "Administrative Tasks," "Meetings," "Learning & Development"). Assign a color to each for easier visual identification in reports.
- 2. Log Your Work Daily (Daily Log Tab)
- Select the date for which you want to log activities. Click "Add Work Entry." For each significant activity or task:
- Enter a clear **Description**.
- Select the appropriate **Category**.
- Input the **Duration** in hours (e.g., 1.5 for 1 hour 30 minutes).
- Add any **Notes** if needed.
- 3. Analyze Your Time (Analysis & Reports Tab)
-
Select the period you want to analyze:
- Selected Day: Shows data for the date currently chosen in the "Daily Log" tab.
- Selected Week: Analyzes the full week (Monday to Sunday) that includes the date selected in the "Daily Log" tab.
- Selected Month: Analyzes all entries for the full calendar month of the date selected in the "Daily Log" tab.
- Total hours logged for the period.
- A bar chart and table breaking down your time by category.
- A detailed list of all activities logged during that period.
- 4. Gain Insights
- Use the analysis to understand:
- Where is most of your time going?
- Are you spending enough time on high-priority categories/projects?
- Are there any time sinks (categories where you spend a lot of time with little perceived output)?
- How does your time distribution change day-to-day, week-to-week, or month-to-month?
- 5. Export for Records or Sharing
- You can download a PDF of the analysis for the selected period to keep for your records or share with your team/manager if applicable.
×
Add Work Entry
Duration: ${entry.durationHours}h
${cat ? `| ${cat.name}` : '| Uncategorized'}
${entry.notes ? `
Notes: ${entry.notes}` : ''}
Time by Category:
'; const maxCategoryHours = Math.max(...Object.values(analysisData.byCategory).map(c => c.hours), 0); for (const catName in analysisData.byCategory) { const catData = analysisData.byCategory[catName]; const percentageOfMax = maxCategoryHours > 0 ? (catData.hours / maxCategoryHours) * 100 : 0; const barContainer = document.createElement('div'); barContainer.className = 'pwha-chart-bar-container'; barContainer.innerHTML = `${catName}
${catData.hours.toFixed(1)}h
${analysisData.totalHours > 0 ? ((catData.hours / analysisData.totalHours) * 100).toFixed(1) : 0}%
`;
pwhaCategoryChartContainerEl.appendChild(barContainer);
}
if(Object.keys(analysisData.byCategory).length === 0 && analysisData.totalHours === 0){
pwhaCategoryChartContainerEl.innerHTML = 'No data to display in chart for this period.
- ';
analysisData.detailedLog.sort((a,b) => new Date(a.date + "T00:00:00Z") - new Date(b.date + "T00:00:00Z") ); // Sort by date
analysisData.detailedLog.forEach(entry => {
logHtml += `
- ${pwhaFormatDisplayDate(entry.date)} - ${entry.description} (${entry.durationHours}h) [${entry.categoryName}] ${entry.notes ? ' - ' + entry.notes : ''} `; }); logHtml += '
No detailed activities logged for this period.
'; } pwhaAnalysisResultsEl.style.display = 'block'; pwhaDownloadPdfBtn.style.display = 'block'; } // --- PDF Export --- function handlePdfDownload() { const periodType = pwhaAnalysisPeriodSelectEl.value; const selectedDateForContextKey = pwhaSelectedLogDateInput.value; if (!selectedDateForContextKey) { alert("Please select a date for context."); return; } const contextDate = new Date(selectedDateForContextKey + "T00:00:00Z"); let startDate, endDate; let periodDisplayStrFull = ""; if (periodType === "selected_day") { /* ... same logic as pwhaRunAnalysis ... */ startDate = new Date(contextDate); endDate = new Date(contextDate); periodDisplayStrFull = `Day: ${pwhaFormatDisplayDate(selectedDateForContextKey)}`; } else if (periodType === "current_week") { startDate = new Date(contextDate); const dayOfWeek = startDate.getUTCDay(); const diffToMonday = dayOfWeek === 0 ? -6 : 1 - dayOfWeek; startDate.setUTCDate(startDate.getUTCDate() + diffToMonday); endDate = new Date(startDate); endDate.setUTCDate(startDate.getUTCDate() + 6); periodDisplayStrFull = `Week: ${pwhaFormatDisplayDate(pwhaFormatDateKey(startDate))} to ${pwhaFormatDisplayDate(pwhaFormatDateKey(endDate))}`; } else if (periodType === "current_month") { startDate = new Date(Date.UTC(contextDate.getUTCFullYear(), contextDate.getUTCMonth(), 1)); endDate = new Date(Date.UTC(contextDate.getUTCFullYear(), contextDate.getUTCMonth() + 1, 0)); periodDisplayStrFull = `Month: ${contextDate.toLocaleDateString(undefined, { month: 'long', year: 'numeric' })}`; } const analysisData = { totalHours: 0, byCategory: {}, detailedLog: [] }; let currentDateIter = new Date(startDate); while(currentDateIter <= endDate) { /* ... same data aggregation as pwhaRunAnalysis ... */ const dateKey = pwhaFormatDateKey(currentDateIter); if (pwhaWorkLogEntries[dateKey]) { pwhaWorkLogEntries[dateKey].forEach(entry => { analysisData.totalHours += entry.durationHours; const cat = pwhaSettings.categories.find(c => c.id === entry.categoryId) || {name: "Uncategorized", color:"#cccccc"}; if (!analysisData.byCategory[cat.name]) { analysisData.byCategory[cat.name] = { hours: 0, color: cat.color }; } analysisData.byCategory[cat.name].hours += entry.durationHours; analysisData.detailedLog.push({...entry, date: dateKey, categoryName: cat.name}); }); } currentDateIter.setUTCDate(currentDateIter.getUTCDate() + 1); } if(analysisData.totalHours === 0 && analysisData.detailedLog.length === 0) { alert("No data to export for the selected period."); return; } const { jsPDF } = window.jspdf; // Local instance const doc = new jsPDF(); doc.setFontSize(18); doc.setTextColor(getComputedStyle(document.documentElement).getPropertyValue('--pwha-primary-color').trim()); doc.text("Personal Work-Hour Analysis", 14, 22); doc.setFontSize(12); doc.setTextColor(100); doc.text(`Period: ${periodDisplayStrFull}`, 14, 30); doc.text(`Total Hours Logged: ${analysisData.totalHours.toFixed(1)} hours`, 14, 38); let yPos = 50; doc.setFontSize(14); doc.setTextColor(getComputedStyle(document.documentElement).getPropertyValue('--pwha-primary-color').trim()); doc.text("Time Distribution by Category:", 14, yPos); yPos += 8; const tableCategoryColumn = ["Category", "Hours Spent", "% of Total"]; const tableCategoryRows = []; for (const catName in analysisData.byCategory) { const catData = analysisData.byCategory[catName]; const percentage = analysisData.totalHours > 0 ? ((catData.hours / analysisData.totalHours) * 100).toFixed(1) : 0; tableCategoryRows.push([catName, catData.hours.toFixed(1), percentage + "%"]); } tableCategoryRows.sort((a,b) => parseFloat(b[1]) - parseFloat(a[1])); // Sort by hours desc doc.autoTable({ head: [tableCategoryColumn], body: tableCategoryRows, startY: yPos, theme: 'striped', headStyles: { fillColor: getComputedStyle(document.documentElement).getPropertyValue('--pwha-secondary-color').trim() } }); yPos = doc.lastAutoTable.finalY + 15; if (analysisData.detailedLog.length > 0) { if (yPos > 250) { doc.addPage(); yPos = 20; } doc.setFontSize(14); doc.setTextColor(getComputedStyle(document.documentElement).getPropertyValue('--pwha-primary-color').trim()); doc.text("Detailed Activities:", 14, yPos); yPos += 8; const tableDetailColumn = ["Date", "Activity", "Category", "Duration (h)", "Notes"]; const tableDetailRows = []; analysisData.detailedLog.sort((a,b) => new Date(a.date + "T00:00:00Z") - new Date(b.date + "T00:00:00Z") ); analysisData.detailedLog.forEach(entry => { tableDetailRows.push([ pwhaFormatDisplayDate(entry.date), entry.description, entry.categoryName, entry.durationHours.toFixed(1), entry.notes || "" ]); }); doc.autoTable({ head: [tableDetailColumn], body: tableDetailRows, startY: yPos, theme: 'grid', headStyles: { fillColor: getComputedStyle(document.documentElement).getPropertyValue('--pwha-secondary-color').trim() }, columnStyles: { 1: { cellWidth: 60 }, 4: { cellWidth: 'auto'} } // Activity desc, Notes auto }); } doc.save(`WorkHourAnalysis_${periodDisplayStrFull.replace(/[^a-zA-Z0-9]/g, '_')}.pdf`); } // --- Initialization --- document.addEventListener('DOMContentLoaded', () => { // Assign DOM elements pwhaSelectedLogDateInput = document.getElementById('pwhaSelectedLogDate'); pwhaLogDateDisplay1El = document.getElementById('pwhaLogDateDisplay1'); pwhaLogDateDisplay2El = document.getElementById('pwhaLogDateDisplay2'); pwhaLoggedEntriesListEl = document.getElementById('pwhaLoggedEntriesList'); pwhaAddCategoryForm = document.getElementById('pwhaAddCategoryForm'); pwhaCategoryNameInput = document.getElementById('pwhaCategoryNameInput'); pwhaCategoryColorInput = document.getElementById('pwhaCategoryColorInput'); pwhaCategoriesListEl = document.getElementById('pwhaCategoriesList'); pwhaLogEntryModalEl = document.getElementById('pwhaLogEntryModal'); pwhaLogEntryModalTitleEl = document.getElementById('pwhaLogEntryModalTitle'); pwhaLogEntryForm = document.getElementById('pwhaLogEntryForm'); pwhaLogEntryIdInput = document.getElementById('pwhaLogEntryId'); pwhaLogEntryDateKeyInput = document.getElementById('pwhaLogEntryDateKey'); pwhaEntryDescriptionInput = document.getElementById('pwhaEntryDescription'); pwhaEntryCategorySelectEl = document.getElementById('pwhaEntryCategory'); pwhaEntryDurationInput = document.getElementById('pwhaEntryDuration'); pwhaEntryNotesInput = document.getElementById('pwhaEntryNotes'); pwhaAnalysisPeriodSelectEl = document.getElementById('pwhaAnalysisPeriodSelect'); pwhaAnalysisResultsEl = document.getElementById('pwhaAnalysisResults'); pwhaAnalysisPeriodDisplayEl = document.getElementById('pwhaAnalysisPeriodDisplay'); pwhaTotalHoursAnalyzedEl = document.getElementById('pwhaTotalHoursAnalyzed'); pwhaCategoryChartContainerEl = document.getElementById('pwhaCategoryChartContainer'); pwhaCategorySummaryTableBodyEl = document.querySelector('#pwhaCategorySummaryTable tbody'); pwhaDetailedLogForPeriodEl = document.getElementById('pwhaDetailedLogForPeriod'); pwhaDownloadPdfBtn = document.getElementById('pwhaDownloadPdfButton'); // Attach event listeners if(pwhaAddCategoryForm) pwhaAddCategoryForm.addEventListener('submit', handleAddCategoryFormSubmit); if(pwhaLogEntryForm) pwhaLogEntryForm.addEventListener('submit', pwhaLogEntryForm.onsubmit); // Check this, should be the function name directly if(pwhaSelectedLogDateInput) pwhaSelectedLogDateInput.addEventListener('change', pwhaHandleLogDateChange); // Analysis button is handled by its onclick in HTML directly, or add listener here if preferred. if(pwhaDownloadPdfBtn) pwhaDownloadPdfBtn.addEventListener('click', handlePdfDownload); // Set default date for log entry and load data const today = new Date(2025, 4, 14); // May 14, 2025 if(pwhaSelectedLogDateInput) pwhaSelectedLogDateInput.value = pwhaFormatDateKey(today); pwhaLoadData(); const firstTabButton = document.querySelector('#personalWorkHourAnalyzerTool .pwha-tab-button'); if (firstTabButton) { firstTabButton.click(); } window.addEventListener('click', function(event) { if (event.target.classList.contains('pwha-modal')) { pwhaCloseModal(event.target.id); } }); });