Please add a routine first in the 'Manage Routines' tab.
`;
return;
}
elements.dailyLogContainer.innerHTML = state.routines.map(r => `
`).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();
});