Work Routine Optimizer
General Work Hours
Define Time Block Types
Create Daily Template Schedule
Tasks for Date
Scheduled Routine for Date
Work Routine Optimization Guide
- 1. Understand Your Energy Levels
- Identify times of the day when you are most alert and focused (for "Focus Work") and when you might be better suited for lighter tasks ("Admin/Emails") or meetings.
- 2. Time Blocking
- Allocate specific blocks of time for specific types of tasks. The "Daily Template" helps you do this. Stick to your blocks as much as possible.
- 3. Prioritize ruthlessly
- Use the priority field for tasks. When scheduling, try to fit high-priority items into your most productive blocks.
- 4. Estimate Task Durations
- Accurately estimating how long tasks will take is crucial for effective scheduling. Be realistic and add a small buffer if unsure. This tool helps you see if you're overcommitting time in a block.
- 5. Batch Similar Tasks
- Group similar tasks together (e.g., do all email responses in one "Admin" block). This reduces context switching and improves efficiency.
- 6. Include Breaks
- Don't forget to schedule short breaks throughout your day. Define a "Break" block type. Regular breaks prevent burnout and can actually increase overall productivity (e.g., Pomodoro Technique).
- 7. Minimize Distractions
- During "Focus Work" blocks, try to minimize interruptions. Turn off notifications or find a quiet space.
- 8. Review and Adjust
- Your ideal routine might take time to perfect. At the end of each day or week, review what worked and what didn't. Adjust your `Daily Template` or task categorization in the `Settings & Template` tab as needed.
- 9. Single Task Focus
- While a block might contain multiple small tasks of the same type, try to focus on completing one task before moving to the next, especially during "Focus Work" blocks.
×
Add Task for Day
×
Assign Tasks to Block
Select a date to see the schedule.
'; if(wroSelectedDateDisplay1El) wroSelectedDateDisplay1El.textContent = "N/A"; if(wroSelectedDateDisplay2El) wroSelectedDateDisplay2El.textContent = "N/A"; wroDownloadPdfBtn.style.display = 'none'; return; } const displayDate = new Date(selectedDateKey + "T00:00:00").toLocaleDateString(undefined, {month:'short', day:'numeric'}); if(wroSelectedDateDisplay1El) wroSelectedDateDisplay1El.textContent = displayDate; if(wroSelectedDateDisplay2El) wroSelectedDateDisplay2El.textContent = displayDate; // Ensure the day's schedule structure exists, based on template if (!wroDailySchedules[selectedDateKey]) { wroDailySchedules[selectedDateKey] = { dayTasksList: [], // Master list of tasks planned for this day scheduledBlocks: JSON.parse(JSON.stringify(wroSettings.dailyTemplate)).map(tb => ({ // Deep clone template blocks ...tb, // spread template block properties like id (templateBlockId), name, startTime, endTime, blockTypeId id: 'dsb-' + Date.now() + '-' + Math.random().toString(16).slice(2), // Unique instance ID for this day's block templateBlockId: tb.id, // Keep reference to original template block tasks: [] // Task IDs scheduled in this specific block instance })) }; } else if (!wroDailySchedules[selectedDateKey].scheduledBlocks || wroDailySchedules[selectedDateKey].scheduledBlocks.length !== wroSettings.dailyTemplate.length) { // If template changed, try to reconcile or rebuild. For simplicity, rebuild if lengths differ or if scheduledBlocks is missing. // A more sophisticated merge could be done if needed. const existingDayTasks = wroDailySchedules[selectedDateKey].dayTasksList || []; wroDailySchedules[selectedDateKey] = { dayTasksList: existingDayTasks, scheduledBlocks: JSON.parse(JSON.stringify(wroSettings.dailyTemplate)).map(tb => ({ ...tb, id: 'dsb-' + Date.now() + '-' + Math.random().toString(16).slice(2), templateBlockId: tb.id, tasks: [] })) }; } wroRenderDayTasksList(selectedDateKey); wroRenderDailyScheduleView(selectedDateKey); wroDownloadPdfBtn.style.display = 'block'; } function wroRenderDayTasksList(dateKey) { wroDayTasksListEl.innerHTML = ''; const dayData = wroDailySchedules[dateKey]; if (!dayData || !dayData.dayTasksList || dayData.dayTasksList.length === 0) { wroDayTasksListEl.innerHTML = 'No tasks added for this day yet.
'; return; } dayData.dayTasksList.forEach(task => { const taskType = wroSettings.timeBlockTypes.find(t => t.id === task.taskTypeId); const itemEl = document.createElement('div'); itemEl.className = 'wro-task-to-schedule-item'; itemEl.innerHTML = `${task.name}
Est: ${task.estimatedTimeMinutes}m | Type: ${taskType ? taskType.name : 'N/A'} | P: ${task.priority} | Status: ${task.status}
`; wroDayTasksListEl.appendChild(itemEl); }); } // For Daily Tasks (not yet scheduled into blocks, or general list for the day) window.wroOpenDailyTaskModal = function(taskId = null) { const selectedDateKey = wroSelectedDateInput.value; if (!selectedDateKey) { alert("Please select a date first."); return; } wroDailyTaskForm.reset(); wroDailyTaskIdInput.value = ''; wroPopulateBlockTypeSelects(); // Ensure task type dropdown is fresh if (taskId) { const dayData = wroDailySchedules[selectedDateKey]; const task = dayData ? dayData.dayTasksList.find(t => t.id === taskId) : null; if (task) { wroDailyTaskModalTitleEl.textContent = 'Edit Daily Task'; wroDailyTaskIdInput.value = task.id; wroDailyTaskNameInput.value = task.name; wroDailyTaskEstTimeInput.value = task.estimatedTimeMinutes; wroDailyTaskTypeInputEl.value = task.taskTypeId; wroDailyTaskPriorityInput.value = task.priority; wroDailyTaskStatusInput.value = task.status; } } else { wroDailyTaskModalTitleEl.textContent = 'Add New Task for ' + new Date(selectedDateKey+"T00:00:00").toLocaleDateString(); } wroDailyTaskModalEl.style.display = 'block'; } if(wroDailyTaskForm) wroDailyTaskForm.addEventListener('submit', function(e) { e.preventDefault(); const selectedDateKey = wroSelectedDateInput.value; if (!selectedDateKey) { alert("Error: No date selected for task."); return; } if (!wroDailySchedules[selectedDateKey]) { wroHandleDateChange(); // Initialize if somehow not present } const taskId = wroDailyTaskIdInput.value; const taskData = { name: wroDailyTaskNameInput.value.trim(), estimatedTimeMinutes: parseInt(wroDailyTaskEstTimeInput.value), taskTypeId: wroDailyTaskTypeInputEl.value, priority: wroDailyTaskPriorityInput.value, status: wroDailyTaskStatusInput.value }; if (!taskData.name || isNaN(taskData.estimatedTimeMinutes) || taskData.estimatedTimeMinutes <= 0) { alert("Task name and a valid positive estimated time are required."); return; } if (taskId) { // Editing const taskIndex = wroDailySchedules[selectedDateKey].dayTasksList.findIndex(t => t.id === taskId); if (taskIndex > -1) { wroDailySchedules[selectedDateKey].dayTasksList[taskIndex] = { ...wroDailySchedules[selectedDateKey].dayTasksList[taskIndex], ...taskData }; } } else { // Adding new const newTask = { id: 'dtask-' + Date.now(), ...taskData, assignedToBlockInstanceId: null }; wroDailySchedules[selectedDateKey].dayTasksList.push(newTask); } wroSaveDailySchedule(selectedDateKey); wroRenderDayTasksList(selectedDateKey); wroRenderDailyScheduleView(selectedDateKey); // Update schedule view if task details changed wroCloseModal('wroDailyTaskModal'); }); window.wroDeleteDailyTask = function(taskId) { const selectedDateKey = wroSelectedDateInput.value; if (!selectedDateKey || !wroDailySchedules[selectedDateKey]) return; if (confirm("Are you sure you want to delete this task from the day's list? It will also be removed from any scheduled block.")) { // Remove from master list wroDailySchedules[selectedDateKey].dayTasksList = wroDailySchedules[selectedDateKey].dayTasksList.filter(t => t.id !== taskId); // Remove from any scheduled blocks wroDailySchedules[selectedDateKey].scheduledBlocks.forEach(block => { block.tasks = block.tasks.filter(id => id !== taskId); }); wroSaveDailySchedule(selectedDateKey); wroRenderDayTasksList(selectedDateKey); wroRenderDailyScheduleView(selectedDateKey); } } // --- Scheduling tasks into blocks --- function wroRenderDailyScheduleView(dateKey) { wroDailyScheduleOutputEl.innerHTML = ''; const daySchedule = wroDailySchedules[dateKey]; if (!daySchedule || !daySchedule.scheduledBlocks) { wroDailyScheduleOutputEl.innerHTML = 'Daily template not set or no schedule for this day.
'; return; } daySchedule.scheduledBlocks.forEach(blockInstance => { const blockType = wroSettings.timeBlockTypes.find(t => t.id === blockInstance.blockTypeId); const blockDiv = document.createElement('div'); blockDiv.className = 'wro-schedule-block-display'; blockDiv.style.borderLeftColor = blockType ? blockType.color : 'var(--wro-accent-color)'; let totalTaskTimeInBlock = 0; let tasksHTML = ''; if (blockInstance.tasks && blockInstance.tasks.length > 0) { blockInstance.tasks.forEach(taskId => { const task = daySchedule.dayTasksList.find(t => t.id === taskId); if (task) { totalTaskTimeInBlock += task.estimatedTimeMinutes; tasksHTML += `
${task.name} (${task.estimatedTimeMinutes}m) - P: ${task.priority}
`;
}
});
} else {
tasksHTML = 'No tasks assigned to this block.
'; } const blockDurationMinutes = wroTimeDiffInMinutes(blockInstance.startTime, blockInstance.endTime); const remainingTime = blockDurationMinutes - totalTaskTimeInBlock; const capacityText = `Capacity: ${totalTaskTimeInBlock}m / ${blockDurationMinutes}m used. (${remainingTime}m remaining)`; blockDiv.innerHTML = `
${wroFormatTime(blockInstance.startTime)} - ${wroFormatTime(blockInstance.endTime)}
${blockInstance.name || (blockType ? blockType.name : 'Block')}
${capacityText}
${tasksHTML}
`;
wroDailyScheduleOutputEl.appendChild(blockDiv);
});
}
window.wroOpenAssignTaskModal = function(blockInstanceId) {
const selectedDateKey = wroSelectedDateInput.value;
if (!selectedDateKey || !wroDailySchedules[selectedDateKey]) return;
const blockInstance = wroDailySchedules[selectedDateKey].scheduledBlocks.find(b => b.id === blockInstanceId);
if (!blockInstance) return;
wroAssignTargetBlockInstanceIdInput.value = blockInstanceId;
wroAssignTaskModalTitleEl.textContent = `Assign Tasks to: ${blockInstance.name || 'Block'} (${wroFormatTime(blockInstance.startTime)}-${wroFormatTime(blockInstance.endTime)})`;
wroAssignableTasksListEl.innerHTML = '';
const dayTasks = wroDailySchedules[selectedDateKey].dayTasksList;
const assignableTasks = dayTasks.filter(task =>
!wroIsTaskAssignedToAnyBlock(task.id, selectedDateKey) && // Not already assigned to *any* block
(task.taskTypeId === blockInstance.blockTypeId || !blockInstance.blockTypeId) // Match block type or if block has no type
);
if (assignableTasks.length === 0) {
wroAssignableTasksListEl.innerHTML = 'No suitable unassigned tasks available for this block type, or all tasks are already scheduled.
'; } else { assignableTasks.forEach(task => { const div = document.createElement('div'); div.innerHTML = ``; wroAssignableTasksListEl.appendChild(div); }); } wroAssignTaskModalEl.style.display = 'block'; } function wroIsTaskAssignedToAnyBlock(taskId, dateKey) { if (!wroDailySchedules[dateKey] || !wroDailySchedules[dateKey].scheduledBlocks) return false; return wroDailySchedules[dateKey].scheduledBlocks.some(block => block.tasks.includes(taskId)); } window.wroConfirmTaskAssignment = function() { const selectedDateKey = wroSelectedDateInput.value; const blockInstanceId = wroAssignTargetBlockInstanceIdInput.value; if (!selectedDateKey || !blockInstanceId || !wroDailySchedules[selectedDateKey]) return; const blockInstance = wroDailySchedules[selectedDateKey].scheduledBlocks.find(b => b.id === blockInstanceId); if (!blockInstance) return; const selectedTaskCheckboxes = wroAssignableTasksListEl.querySelectorAll('input[name="assignableTask"]:checked'); let assignedTaskTotalTime = blockInstance.tasks.reduce((sum, tid) => { const task = wroDailySchedules[selectedDateKey].dayTasksList.find(t => t.id === tid); return sum + (task ? task.estimatedTimeMinutes : 0); }, 0); const blockDuration = wroTimeDiffInMinutes(blockInstance.startTime, blockInstance.endTime); selectedTaskCheckboxes.forEach(checkbox => { const taskId = checkbox.value; const taskToAdd = wroDailySchedules[selectedDateKey].dayTasksList.find(t => t.id === taskId); if (taskToAdd && (assignedTaskTotalTime + taskToAdd.estimatedTimeMinutes <= blockDuration)) { if (!blockInstance.tasks.includes(taskId)) { blockInstance.tasks.push(taskId); assignedTaskTotalTime += taskToAdd.estimatedTimeMinutes; } } else if (taskToAdd) { alert(`Cannot add task "${taskToAdd.name}". Exceeds block capacity of ${blockDuration} minutes.`); } }); wroSaveDailySchedule(selectedDateKey); wroRenderDayTasksList(selectedDateKey); // To update if any tasks are now visually "scheduled" wroRenderDailyScheduleView(selectedDateKey); wroCloseModal('wroAssignTaskModal'); } window.wroUnassignTaskFromBlock = function(blockInstanceId, taskId) { const selectedDateKey = wroSelectedDateInput.value; if (!selectedDateKey || !blockInstanceId || !taskId || !wroDailySchedules[selectedDateKey]) return; const blockInstance = wroDailySchedules[selectedDateKey].scheduledBlocks.find(b => b.id === blockInstanceId); if (blockInstance) { blockInstance.tasks = blockInstance.tasks.filter(id => id !== taskId); wroSaveDailySchedule(selectedDateKey); wroRenderDailyScheduleView(selectedDateKey); wroRenderDayTasksList(selectedDateKey); // Refresh tasks list too } } // --- PDF Export --- if(wroDownloadPdfBtn) wroDownloadPdfBtn.addEventListener('click', function() { const selectedDateKey = wroSelectedDateInput.value; if (!selectedDateKey || !wroDailySchedules[selectedDateKey]) { alert("Please select a date with a planned routine to download."); return; } const daySchedule = wroDailySchedules[selectedDateKey]; const { jsPDF } = window.jspdf; const doc = new jsPDF(); doc.setFontSize(18); doc.setTextColor(getComputedStyle(document.documentElement).getPropertyValue('--wro-primary-color').trim()); doc.text(`Work Routine for: ${dtsgFormatDisplayDate(selectedDateKey)}`, 14, 22); let yPos = 35; doc.setFontSize(10); doc.setTextColor(50); doc.text(`Work Hours: ${wroFormatTime(wroSettings.workStartTime)} - ${wroFormatTime(wroSettings.workEndTime)}`, 14, yPos); yPos += 10; daySchedule.scheduledBlocks.forEach(blockInstance => { if (yPos > 260) { doc.addPage(); yPos = 20; } const blockType = wroSettings.timeBlockTypes.find(t => t.id === blockInstance.blockTypeId); const blockColor = blockType ? blockType.color : '#cccccc'; doc.setFontSize(12); // Simulate colored header for block - difficult to get actual CSS var value reliably in jsPDF without parsing // For now, just use a standard color or pass the hex directly doc.setFillColor(blockColor.startsWith('var') ? '#dddddd' : blockColor); // Fallback for CSS vars doc.rect(14, yPos - 4, doc.internal.pageSize.getWidth() - 28, 7, 'F'); doc.setTextColor(blockColor === '#F39C12' || blockColor === '#2ECC71' ? 50 : 255); // Text color based on perceived BG doc.text(`${wroFormatTime(blockInstance.startTime)} - ${wroFormatTime(blockInstance.endTime)}: ${blockInstance.name || (blockType ? blockType.name : 'Block')}`, 15, yPos); yPos += 8; doc.setTextColor(50); // Reset text color doc.setFontSize(9); if (blockInstance.tasks && blockInstance.tasks.length > 0) { blockInstance.tasks.forEach(taskId => { if (yPos > 270) { doc.addPage(); yPos = 20; } const task = daySchedule.dayTasksList.find(t => t.id === taskId); if (task) { const taskTypeForPdf = wroSettings.timeBlockTypes.find(t => t.id === task.taskTypeId); doc.text(` \u2022 ${task.name} (${task.estimatedTimeMinutes}m) - P: ${task.priority}, S: ${task.status}, Type: ${taskTypeForPdf ? taskTypeForPdf.name : 'N/A'}`, 18, yPos); yPos += 5; } }); } else { if (yPos > 270) { doc.addPage(); yPos = 20; } doc.text(" No tasks scheduled in this block.", 18, yPos); yPos += 5; } yPos += 3; // Space after block }); doc.save(`WorkRoutine_${selectedDateKey}.pdf`); }); // --- Initialization --- document.addEventListener('DOMContentLoaded', () => { wroLoadSettings(); wroLoadDailySchedules(); const today = new Date(2025, 4, 14); // May 14, 2025 for default wroSelectedDateInput.value = wroFormatDateKey(today); wroHandleDateChange(); // Initial render for selected/default date const firstTabButton = document.querySelector('#workRoutineOptimizerTool .wro-tab-button'); if (firstTabButton) { firstTabButton.click(); } // Close modals if clicked outside window.addEventListener('click', function(event) { if (event.target.classList.contains('wro-modal')) { wroCloseModal(event.target.id); } }); });