Online Daily Work Routine Optimizer

Daily Work Routine Optimizer

Your Optimized Daily Routine

${task.duration} minutes • ${task.type}

`; routineTimeline.appendChild(itemDiv); }); }; const renderEnergyLevels = () => { energyLevelsContainer.innerHTML = ''; const startHour = parseInt(workStartTimeEl.value.split(':')[0]); const endHour = parseInt(workEndTimeEl.value.split(':')[0]); for (let hour = startHour; hour < endHour; hour++) { const timeLabel = `${formatTime(hour + ':00')} - ${formatTime((hour + 1) + ':00')}`; const row = document.createElement('div'); row.className = 'grid grid-cols-3 gap-4 items-center'; row.innerHTML = ` `; energyLevelsContainer.appendChild(row); } }; const addTaskRow = (task = {}) => { const newRow = document.createElement('div'); newRow.className = 'task-row p-4 border border-gray-200 rounded-lg bg-gray-50 grid grid-cols-1 md:grid-cols-12 gap-4 items-center'; newRow.innerHTML = `
`; tasksContainer.appendChild(newRow); newRow.querySelector('.remove-task-btn').addEventListener('click', () => newRow.remove()); }; // --- DATA & LOGIC --- const generateRoutine = () => { // 1. Get all inputs const startHour = parseInt(workStartTimeEl.value.split(':')[0]); const endHour = parseInt(workEndTimeEl.value.split(':')[0]); state.energyMap = {}; document.querySelectorAll('.energy-level-select').forEach(sel => { state.energyMap[sel.dataset.hour] = sel.value; }); state.tasks = []; document.querySelectorAll('.task-row').forEach(row => { const name = row.querySelector('.task-name').value.trim(); const duration = parseInt(row.querySelector('.task-duration').value); const type = row.querySelector('.task-type').value; if (name && duration) state.tasks.push({ name, duration, type }); }); if (state.tasks.length === 0) { alert('Please add at least one task.'); return; } // 2. Create time slots const timeSlots = []; for (let h = startHour; h < endHour; h++) { for (let m = 0; m < 60; m += 15) { timeSlots.push({ time: `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}`, energy: state.energyMap[h], task: null }); } } // 3. Sort tasks by cognitive load const typePriority = { 'Deep Work': 3, 'Shallow Work': 2, 'Break': 1 }; const sortedTasks = [...state.tasks].sort((a, b) => typePriority[b.type] - typePriority[a.type]); // 4. Allocate tasks to time slots let unscheduledTasks = []; for (const task of sortedTasks) { let scheduled = false; const requiredSlots = task.duration / 15; // Try to find the best-fit slot for (let i = 0; i <= timeSlots.length - requiredSlots; i++) { const energyLevel = timeSlots[i].energy; const canFit = timeSlots.slice(i, i + requiredSlots).every(slot => !slot.task); // Matching logic: Deep work in High energy, Shallow in Medium/Low const energyMatch = (task.type === 'Deep Work' && energyLevel === 'High') || (task.type === 'Shallow Work' && (energyLevel === 'Medium' || energyLevel === 'Low')) || (task.type === 'Break'); if (canFit && energyMatch) { for (let j = 0; j < requiredSlots; j++) { timeSlots[i + j].task = task; } scheduled = true; break; } } if (!scheduled) unscheduledTasks.push(task.name); } // 5. Consolidate schedule state.routine = []; let currentTask = null; for (const slot of timeSlots) { if (slot.task && slot.task !== currentTask?.task) { currentTask = { task: slot.task, startTime: slot.time }; } else if (!slot.task && currentTask) { const endTime = slot.time; state.routine.push({ ...currentTask.task, startTime: currentTask.startTime, endTime }); currentTask = null; } } if (currentTask) { // Add last task if it goes to the end of the day const endTime = `${String(endHour).padStart(2, '0')}:00`; state.routine.push({ ...currentTask.task, startTime: currentTask.startTime, endTime }); } if(unscheduledTasks.length > 0) { alert(`Routine generated, but could not schedule the following tasks: ${unscheduledTasks.join(', ')}`); } else { alert('Routine generated successfully!'); } renderRoutine(); switchTab('routine'); }; // --- HELPERS & NAVIGATION --- const formatTime = (timeStr) => { const [h, m] = timeStr.split(':'); return new Date(0, 0, 0, h, m).toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit', hour12: true }); }; const formatDuration = (mins) => `${Math.floor(mins / 60)}h ${mins % 60}m`; const switchTab = (tabName) => { state.activeTab = tabName; Object.values(tabs).forEach(tab => { tab.btn.classList.remove('active'); tab.panel.classList.add('hidden'); }); tabs[tabName].btn.classList.add('active'); tabs[tabName].panel.classList.remove('hidden'); updateNavButtons(); }; const updateNavButtons = () => { const tabKeys = Object.keys(tabs); const currentIndex = tabKeys.indexOf(state.activeTab); navButtons.prev.disabled = currentIndex === 0; navButtons.next.disabled = currentIndex === tabKeys.length - 1; }; const handlePdfDownload = () => { const { jsPDF } = window.jspdf; const pdfContent = document.getElementById('pdf-export-area'); html2canvas(pdfContent, { scale: 2 }).then(canvas => { const imgData = canvas.toDataURL('image/png'); const pdf = new jsPDF({ orientation: 'portrait', unit: 'pt', format: 'a4' }); const margin = 40; const pdfWidth = pdf.internal.pageSize.getWidth() - (margin * 2); const pdfHeight = (canvas.height * pdfWidth) / canvas.width; pdf.addImage(imgData, 'PNG', margin, margin, pdfWidth, pdfHeight); pdf.save('daily-work-routine.pdf'); }); }; // --- EVENT LISTENERS --- Object.keys(tabs).forEach(tabName => tabs[tabName].btn.addEventListener('click', () => switchTab(tabName))); navButtons.next.addEventListener('click', () => { const tabKeys = Object.keys(tabs); const currentIndex = tabKeys.indexOf(state.activeTab); if (currentIndex < tabKeys.length - 1) switchTab(tabKeys[currentIndex + 1]); }); navButtons.prev.addEventListener('click', () => { const tabKeys = Object.keys(tabs); const currentIndex = tabKeys.indexOf(state.activeTab); if (currentIndex > 0) switchTab(tabKeys[currentIndex - 1]); }); [workStartTimeEl, workEndTimeEl].forEach(el => el.addEventListener('change', renderEnergyLevels)); addTaskBtn.addEventListener('click', () => addTaskRow()); generateRoutineBtn.addEventListener('click', generateRoutine); downloadPdfBtn.addEventListener('click', handlePdfDownload); // --- INITIALIZATION --- const init = () => { renderEnergyLevels(); addTaskRow({ name: 'Write project brief', duration: 90, type: 'Deep Work' }); addTaskRow({ name: 'Team stand-up', duration: 30, type: 'Shallow Work' }); addTaskRow({ name: 'Lunch', duration: 60, type: 'Break' }); addTaskRow({ name: 'Clear email inbox', duration: 45, type: 'Shallow Work' }); addTaskRow({ name: 'Code new feature', duration: 120, type: 'Deep Work' }); generateRoutine(); switchTab('routine'); }; init(); });
Scroll to Top