Smart Work Routine Optimizer

Smart Work Routine Optimizer

Log Daily Task/Activity

Logged Entries (Newest First)

DateTimeTaskTypePrio.EnergyFocusDur.Actions

Analyze Your Work Patterns

Optimize Routine for a Day

Tasks for the Day:

    ${type}: Avg. Focus ${data.avgFocus.toFixed(1)}/5 (from ${data.count} logs)

    `; swro_userPatterns.taskTypeFocusCorrelation[type] = data.avgFocus; }); swro_userPatterns.lastAnalyzedRange = {start: startDateStr, end: endDateStr}; document.getElementById('swro_patternsResultsContainer').style.display = 'block'; } // --- Tab 3: Optimize Routine --- function swro_addSchedulableTask() { const name = document.getElementById('swro_scheduleTaskName').value.trim(); const estHours = document.getElementById('swro_scheduleTaskHours').value; const estMinutesIn = document.getElementById('swro_scheduleTaskMinutes').value; const estTotalMinutes = swro_parseHHMMToMinutes(estHours, estMinutesIn); const priority = document.getElementById('swro_scheduleTaskPriority').value; const taskType = document.getElementById('swro_scheduleTaskType').value; const deadline = document.getElementById('swro_scheduleTaskDeadline').value || null; if (!name || estTotalMinutes <= 0) { alert("Task name and valid estimated duration are required."); return; } swro_tasksToSchedule.push({id: Date.now(), name, estMinutes: estTotalMinutes, priority, taskType, deadline}); document.getElementById('swro_scheduleTaskName').value = ''; document.getElementById('swro_scheduleTaskHours').value = ''; document.getElementById('swro_scheduleTaskMinutes').value = ''; document.getElementById('swro_scheduleTaskDeadline').value = ''; swro_renderSchedulableTasksList(); } function swro_removeSchedulableTask(taskId) { swro_tasksToSchedule = swro_tasksToSchedule.filter(t => t.id != taskId); swro_renderSchedulableTasksList(); } function swro_renderSchedulableTasksList() { const listUl = document.getElementById('swro_schedulableTasksList'); listUl.innerHTML = ''; if (swro_tasksToSchedule.length === 0) { listUl.innerHTML = "
  • No tasks added for planning yet.
  • "; return; } swro_tasksToSchedule.forEach(task => { const li = document.createElement('li'); li.textContent = `${task.name} (${swro_formatMinutesToHHMM(task.estMinutes)}) - Prio: ${task.priority}, Type: ${task.taskType}`; const removeBtn = document.createElement('button'); removeBtn.type = 'button'; removeBtn.textContent = 'Remove'; removeBtn.className = 'swro-button swro-delete-button swro-small-button'; removeBtn.onclick = () => swro_removeSchedulableTask(task.id); li.appendChild(removeBtn); listUl.appendChild(li); }); } function swro_generateOptimizedRoutine() { const optimizeDate = document.getElementById('swro_optimizeDate').value; const workStartTimeStr = document.getElementById('swro_optimizeWorkStart').value; const workEndTimeStr = document.getElementById('swro_optimizeWorkEnd').value; if (!optimizeDate || !workStartTimeStr || !workEndTimeStr) { alert("Please set date and work start/end times for optimization."); return; } if (swro_tasksToSchedule.length === 0) { alert("Add tasks to the plan first."); return; } if (swro_userPatterns.lastAnalyzedRange === null && swro_dailyLogs.length > 5) { if(!confirm("You haven't analyzed your patterns recently. Optimize using default assumptions or analyze patterns first for better suggestions? (Click OK for default, Cancel to go analyze)")){ swro_openTab(null, 'swro_patternsTab'); // Simulate click without event return; } } swro_optimizedRoutine = []; const warnings = []; let availableWorkMinutes = swro_timeStrToMinutes(workEndTimeStr) - swro_timeStrToMinutes(workStartTimeStr); let totalScheduledTaskMinutes = swro_tasksToSchedule.reduce((sum, task) => sum + task.estMinutes, 0); // Simplified heuristic: // 1. Sort tasks: Deadline, then Priority, then by type if it matches peak. // 2. Create time slots based on work hours and identified peak/low energy hours. // 3. Fill slots. const sortedTasks = [...swro_tasksToSchedule].sort((a, b) => { if (a.deadline && b.deadline) { if (a.deadline !== b.deadline) return new Date(a.deadline) - new Date(b.deadline); } else if (a.deadline) return -1; else if (b.deadline) return 1; if (swro_priorityMap[a.priority] !== swro_priorityMap[b.priority]) return swro_priorityMap[a.priority] - swro_priorityMap[b.priority]; // Prefer Deep Work for Peak times. This heuristic could be more complex. if (a.taskType === "Deep Work" && b.taskType !== "Deep Work") return -1; if (b.taskType === "Deep Work" && a.taskType !== "Deep Work") return 1; return a.name.localeCompare(b.name); }); let currentTime = swro_timeStrToMinutes(workStartTimeStr); const workEndMinutes = swro_timeStrToMinutes(workEndTimeStr); const peakTimes = swro_userPatterns.peakFocusHours.map(pt => ({start: swro_timeStrToMinutes(pt.start), end: swro_timeStrToMinutes(pt.end)})); sortedTasks.forEach(task => { let scheduledThisTask = false; let suggestedStartTime = -1; let reasoning = ""; // Try to schedule Deep Work / High Prio in peak times first if ((task.taskType === "Deep Work" || task.priority === "High") && peakTimes.length > 0) { for(const peakSlot of peakTimes) { const slotStart = Math.max(currentTime, peakSlot.start); const slotEnd = peakSlot.end; if (slotStart < workEndMinutes && slotStart < slotEnd && (slotEnd - slotStart) >= task.estMinutes) { if (slotStart + task.estMinutes <= workEndMinutes) { suggestedStartTime = slotStart; reasoning = "Scheduled in identified peak productivity slot."; scheduledThisTask = true; break; } } } } // If not scheduled in peak, try general scheduling if (!scheduledThisTask) { if (currentTime + task.estMinutes <= workEndMinutes) { suggestedStartTime = currentTime; reasoning = task.deadline ? "Prioritized by deadline." : "Scheduled by priority."; if (task.taskType === "Shallow Work" || task.taskType === "Admin") { // Check if this falls into a low energy period const currentHour = Math.floor(suggestedStartTime / 60); if(swro_userPatterns.lowEnergyHours.some(slot => currentHour >= Math.floor(swro_timeStrToMinutes(slot.start)/60) && currentHour < Math.floor(swro_timeStrToMinutes(slot.end)/60) )){ reasoning += " Good for low energy time."; } } scheduledThisTask = true; } } if (scheduledThisTask) { swro_optimizedRoutine.push({ taskName: task.name, estMinutes: task.estMinutes, priority: task.priority, taskType: task.taskType, deadline:task.deadline, suggestedStartTime: swro_minutesToTimeStr(suggestedStartTime), suggestedEndTime: swro_minutesToTimeStr(suggestedStartTime + task.estMinutes), reasoning: reasoning }); currentTime = suggestedStartTime + task.estMinutes; // This is greedy, doesn't look back to fill gaps from peak scheduling. // A more complex algorithm would manage available blocks. } else { warnings.push(`Could not schedule "${task.name}" (${swro_formatMinutesToHHMM(task.estMinutes)}).`); } }); // Simple check for total time vs available. if (currentTime > workEndMinutes && totalScheduledTaskMinutes > availableWorkMinutes) { warnings.push(`Total planned task time (${swro_formatMinutesToHHMM(totalScheduledTaskMinutes)}) exceeds available work hours (${swro_formatMinutesToHHMM(availableWorkMinutes)}).`); } // Render routine const routineTbody = document.getElementById('swro_optimizedRoutineTable').getElementsByTagName('tbody')[0]; routineTbody.innerHTML = ''; if (swro_optimizedRoutine.length === 0 && warnings.length === 0) { routineTbody.innerHTML = `No routine generated. Check tasks and work hours.`; } else { swro_optimizedRoutine.forEach(item => { const row = routineTbody.insertRow(); row.insertCell().textContent = `${item.suggestedStartTime} - ${item.suggestedEndTime}`; row.insertCell().textContent = item.taskName; row.insertCell().textContent = swro_formatMinutesToHHMM(item.estMinutes); const prioCell = row.insertCell(); prioCell.textContent = item.priority; prioCell.className = `swro-priority-${item.priority.toLowerCase()}`; row.insertCell().textContent = item.taskType; row.insertCell().textContent = item.reasoning; }); } document.getElementById('swro_routineWarningText').textContent = warnings.join(' '); document.getElementById('swro_optimizedRoutineContainer').style.display = 'block'; document.getElementById('swro_pdfButtonOptimize').style.display = 'block'; } // PDF for Optimized Routine function swro_downloadOptimizedRoutinePDF() { if (document.getElementById('swro_optimizedRoutineContainer').style.display === 'none') { alert("Please generate an optimized routine first."); return; } const doc = new jsPDF({orientation: 'landscape'}); const primaryColorPDF = getComputedStyle(document.documentElement).getPropertyValue('--primary-color').trim(); const textColorPDF = getComputedStyle(document.documentElement).getPropertyValue('--text-color').trim(); const whiteColorPDF = '#FFFFFF'; const optimizeDate = document.getElementById('swro_optimizeDate').value; const workStart = document.getElementById('swro_optimizeWorkStart').value; const workEnd = document.getElementById('swro_optimizeWorkEnd').value; doc.setFontSize(18); doc.setTextColor(primaryColorPDF); doc.text("Optimized Work Routine Plan", 14, 20); doc.setFontSize(10); doc.setTextColor(textColorPDF); doc.text(`For Date: ${optimizeDate}`, 14, 28); doc.text(`Work Hours: ${workStart} - ${workEnd}`, 14, 33); if(swro_userPatterns.peakFocusHours.length > 0){ doc.text(`Your Identified Peak Times: ${swro_userPatterns.peakFocusHours.map(p=>`${p.start}-${p.end}`).join(', ')}`, 14, 38); currentY = 43; } else { currentY = 38; } doc.text(`Generated On: ${SWRO_GENERATED_ON_STRING}`, 14, currentY); currentY += 10; const warnings = document.getElementById('swro_routineWarningText').textContent; if (warnings) { doc.setFontSize(10); doc.setTextColor(getComputedStyle(document.documentElement).getPropertyValue('--danger-color').trim()); const warningLines = doc.splitTextToSize(warnings, doc.internal.pageSize.getWidth() - 28); doc.text(warningLines, 14, currentY); currentY += (warningLines.length * 5) + 5; doc.setTextColor(textColorPDF); // Reset } doc.setFontSize(12); doc.setFont(undefined, 'bold'); doc.setTextColor(primaryColorPDF); if(currentY > 180) { doc.addPage(); currentY = 20; } doc.text("Suggested Routine:", 14, currentY); currentY += 7; doc.autoTable({ html: '#swro_optimizedRoutineTable', startY: currentY, theme: 'grid', headStyles: {fillColor: primaryColorPDF, textColor: whiteColorPDF, fontSize:9}, styles:{fontSize:8, cellPadding:1.5}, columnStyles: { 0:{cellWidth:25}, 1:{cellWidth:50}, 2:{cellWidth:20}, 3:{cellWidth:20}, 4:{cellWidth:30}, 5:{cellWidth:'auto'} } }); doc.save(`Optimized_Work_Routine_${optimizeDate}.pdf`); }
    Scroll to Top