Personal Daily Routines Tracker

Personal Daily Routines Tracker

Completion Trends

Weekly Completion Rate (%)

Routine Performance

Add/Edit Routines

Manage Tasks for Selected Routine

Data Configuration

All your routines and logs are saved in your browser. You can clear all data to start fresh.

Please add a routine first in the 'Manage Routines' tab.

`; return; } elements.dailyLogContainer.innerHTML = state.routines.map(r => `

${r.name}

${r.tasks.map(t => ` `).join('')}
`).join(''); }; const renderDashboardCharts = () => { // Weekly Completion Chart const today = new Date(elements.logDatePicker.value); const labels = []; const data = []; for (let i = 6; i >= 0; i--) { const date = new Date(today); date.setDate(date.getDate() - i); const dateStr = formatDate(date); labels.push(date.toLocaleDateString('en-US', { weekday: 'short' })); const totalTasks = state.routines.reduce((acc, r) => acc + r.tasks.length, 0); if (totalTasks === 0) { data.push(0); continue; } const completedTasks = Object.keys(state.logs[dateStr] || {}).filter(taskId => state.logs[dateStr][taskId]).length; data.push((completedTasks / totalTasks) * 100); } if (weeklyChartInstance) weeklyChartInstance.destroy(); weeklyChartInstance = new Chart(elements.weeklyChart, { type: 'bar', data: { labels, datasets: [{ label: 'Completion %', data, backgroundColor: 'rgba(59, 130, 246, 0.5)', borderColor: 'rgb(59, 130, 246)' }] }, options: { scales: { y: { beginAtZero: true, max: 100 } } } }); // Routine Performance Chart const routineLabels = state.routines.map(r => r.name); const routineData = state.routines.map(r => { let totalPossible = 0; let totalCompleted = 0; Object.keys(state.logs).forEach(dateStr => { totalPossible += r.tasks.length; r.tasks.forEach(task => { if (state.logs[dateStr][task.id]) { totalCompleted++; } }); }); return totalPossible === 0 ? 0 : (totalCompleted / totalPossible) * 100; }); if (routineChartInstance) routineChartInstance.destroy(); routineChartInstance = new Chart(elements.routineChart, { type: 'doughnut', data: { labels: routineLabels, datasets: [{ label: 'Overall Completion %', data: routineData, backgroundColor: ['#3B82F6', '#10B981', '#F59E0B', '#EF4444'] }] } }); }; // --- EVENT HANDLERS --- window.selectRoutine = (id) => { state.selectedRoutineId = id; saveState(); renderRoutineList(); renderTasksForSelectedRoutine(); }; elements.addRoutineBtn.addEventListener('click', () => { const name = elements.routineNameInput.value.trim(); if (name) { state.routines.push({ id: Date.now(), name, tasks: [] }); elements.routineNameInput.value = ''; saveState(); renderAll(); } }); window.deleteRoutine = (id) => { state.routines = state.routines.filter(r => r.id !== id); if (state.selectedRoutineId === id) state.selectedRoutineId = null; saveState(); renderAll(); }; elements.addTaskBtn.addEventListener('click', () => { const name = elements.taskNameInput.value.trim(); const routine = state.routines.find(r => r.id === state.selectedRoutineId); if (name && routine) { routine.tasks.push({ id: Date.now(), name }); elements.taskNameInput.value = ''; saveState(); renderAll(); } }); window.deleteTask = (taskId) => { const routine = state.routines.find(r => r.id === state.selectedRoutineId); if (routine) { routine.tasks = routine.tasks.filter(t => t.id !== taskId); saveState(); renderAll(); } }; elements.logDatePicker.addEventListener('change', renderDailyLog); window.toggleTaskLog = (dateStr, taskId) => { if (!state.logs[dateStr]) state.logs[dateStr] = {}; state.logs[dateStr][taskId] = !state.logs[dateStr][taskId]; saveState(); renderDashboardCharts(); // Update charts on log change }; elements.clearDataBtn.addEventListener('click', () => { if (confirm('Are you sure you want to clear all data? This cannot be undone.')) { localStorage.removeItem('dailyRoutinesTracker'); state = { routines: [], logs: {}, selectedRoutineId: null }; renderAll(); } }); elements.downloadPdfBtn.addEventListener('click', () => { const { jsPDF } = window.jspdf; const doc = new jsPDF(); doc.setFontSize(18); doc.text("Daily Routines Report", 14, 22); const weeklyCanvas = document.getElementById('weeklyChart'); const routineCanvas = document.getElementById('routineChart'); doc.text("Weekly Completion Rate (%)", 14, 40); doc.addImage(weeklyCanvas.toDataURL('image/png'), 'PNG', 15, 45, 180, 90); doc.text("Routine Performance", 14, 150); doc.addImage(routineCanvas.toDataURL('image/png'), 'PNG', 15, 155, 90, 90); doc.addPage(); doc.text("Detailed Log", 14, 22); const head = [['Date', 'Routine', 'Task', 'Status']]; const body = []; Object.keys(state.logs).sort().forEach(dateStr => { state.routines.forEach(r => { r.tasks.forEach(t => { const logged = state.logs[dateStr][t.id]; if (logged !== undefined) { body.push([dateStr, r.name, t.name, logged ? 'Completed' : 'Not Done']); } }); }); }); doc.autoTable({ head, body, startY: 30 }); doc.save('daily-routines-report.pdf'); }); // Tab Navigation Logic let currentTabIndex = 0; const updateNavButtons = () => { elements.prevTabBtn.disabled = currentTabIndex === 0; elements.nextTabBtn.disabled = currentTabIndex === elements.tabs.length - 1; elements.prevTabBtn.classList.toggle('opacity-50', elements.prevTabBtn.disabled); elements.nextTabBtn.classList.toggle('opacity-50', elements.nextTabBtn.disabled); }; window.changeTab = (event, tabId) => { elements.tabContents.forEach(c => c.classList.remove('active')); elements.tabs.forEach(t => t.classList.remove('active')); document.getElementById(tabId).classList.add('active'); event.currentTarget.classList.add('active'); currentTabIndex = Array.from(elements.tabs).indexOf(event.currentTarget); updateNavButtons(); if (tabId === 'dashboard') renderDashboardCharts(); }; const navigateTabs = (direction) => { const newIndex = currentTabIndex + direction; if (newIndex >= 0 && newIndex < elements.tabs.length) { elements.tabs[newIndex].click(); } }; elements.nextTabBtn.addEventListener('click', () => navigateTabs(1)); elements.prevTabBtn.addEventListener('click', () => navigateTabs(-1)); // --- INITIALIZATION --- elements.logDatePicker.value = formatDate(new Date()); loadState(); renderAll(); updateNavButtons(); });
Scroll to Top