High Priority
${highPriorityTasks}
`;
};
const renderStatusChart = () => {
const ctx = document.getElementById('statusChart').getContext('2d');
const statusCounts = statuses.map(status => tasks.filter(t => t.status === status).length);
if (statusChart) statusChart.destroy();
statusChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: statuses,
datasets: [{
data: statusCounts,
backgroundColor: ['#60a5fa', '#3b82f6', '#22c55e', '#ef4444'], // Light Blue, Dark Blue, Green, Red
}]
},
options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'bottom' } } }
});
};
const renderPriorityChart = () => {
const ctx = document.getElementById('priorityChart').getContext('2d');
const priorityCounts = priorities.map(p => tasks.filter(t => t.priority === p).length);
if (priorityChart) priorityChart.destroy();
priorityChart = new Chart(ctx, {
type: 'bar',
data: {
labels: priorities,
datasets: [{
label: 'Task Count',
data: priorityCounts,
backgroundColor: ['#34d399', '#fbbf24', '#f87171'], // Green, Amber, Red
}]
},
options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, ticks: { stepSize: 1 } } } }
});
};
const renderTaskTable = () => {
const container = document.getElementById('task-table-container');
const sortedTasks = [...tasks].sort((a, b) => (a.dueDate && b.dueDate) ? new Date(a.dueDate) - new Date(b.dueDate) : a.dueDate ? -1 : 1);
let tableHtml = `
| Task |
Due Date |
Priority |
Status |
`;
sortedTasks.forEach(task => {
let priorityClass = task.priority === 'High' ? 'text-red-600' : task.priority === 'Medium' ? 'text-amber-600' : 'text-gray-500';
let statusClass = task.status === 'Done' ? 'bg-green-100 text-green-800' : task.status === 'In Progress' ? 'bg-blue-100 text-blue-800' : task.status === 'Overdue' ? 'bg-red-100 text-red-800' : 'bg-gray-100 text-gray-800';
tableHtml += `
| ${task.title} |
${task.dueDate || 'N/A'} |
${task.priority} |
${task.status} |
`;
});
tableHtml += `
`;
container.innerHTML = tableHtml;
};
const renderTaskListEditor = () => {
const container = document.getElementById('task-list-editor').querySelector('.space-y-2');
container.innerHTML = tasks.map(task => `
${task.title}
Due: ${task.dueDate || 'N/A'} | Priority: ${task.priority} | Status: ${task.status}
`).join('');
};
// --- EVENT HANDLERS ---
document.getElementById('task-form').addEventListener('submit', e => {
e.preventDefault();
const id = document.getElementById('task-id').value;
const newTask = {
title: document.getElementById('task-title').value,
dueDate: document.getElementById('task-due-date').value,
priority: document.getElementById('task-priority').value,
status: document.getElementById('task-status').value,
};
if (id) {
const index = tasks.findIndex(t => t.id == id);
tasks[index] = { ...tasks[index], ...newTask };
} else {
newTask.id = tasks.length > 0 ? Math.max(...tasks.map(t => t.id)) + 1 : 1;
tasks.push(newTask);
}
resetForm();
renderAll();
});
document.getElementById('task-list-editor').addEventListener('click', e => {
if (e.target.classList.contains('edit-btn')) {
const id = e.target.dataset.id;
const task = tasks.find(t => t.id == id);
if (task) populateFormForEdit(task);
}
if (e.target.classList.contains('delete-btn')) {
const id = e.target.dataset.id;
if (confirm('Are you sure you want to delete this task?')) {
tasks = tasks.filter(t => t.id != id);
renderAll();
}
}
});
document.getElementById('cancel-edit-btn').addEventListener('click', resetForm);
document.getElementById('download-pdf-btn').addEventListener('click', () => {
const exportArea = document.getElementById('dashboard-export-area');
const mainTitleEl = document.querySelector('#todo-tool-container h1');
if (!exportArea || !mainTitleEl) return;
const btn = document.getElementById('download-pdf-btn');
const originalBtnText = btn.innerHTML;
btn.disabled = true;
btn.innerHTML = `
Processing...`;
html2canvas(exportArea, { scale: 2, useCORS: true, windowWidth: exportArea.scrollWidth, windowHeight: exportArea.scrollHeight })
.then(canvas => {
const { jsPDF } = window.jspdf;
const imgData = canvas.toDataURL('image/png');
const pdf = new jsPDF({ orientation: 'landscape', unit: 'mm', format: 'a4' });
const pageMargin = 15;
const pdfPageWidth = pdf.internal.pageSize.getWidth();
const pdfPageHeight = pdf.internal.pageSize.getHeight();
const pdfContentWidth = pdfPageWidth - (2 * pageMargin);
const canvasAspectRatio = canvas.width / canvas.height;
const pdfImgHeight = pdfContentWidth / canvasAspectRatio;
let yPos = pageMargin;
pdf.setFontSize(18).setFont('helvetica', 'bold');
pdf.text(mainTitleEl.innerText, pdfPageWidth / 2, yPos, { align: 'center' });
yPos += 12;
let heightLeft = pdfImgHeight;
let positionOnCanvas = 0;
pdf.addImage(imgData, 'PNG', pageMargin, yPos, pdfContentWidth, pdfImgHeight);
heightLeft -= (pdfPageHeight - yPos - pageMargin);
while (heightLeft > 0) {
positionOnCanvas -= (pdfPageHeight - (2 * pageMargin));
pdf.addPage();
pdf.addImage(imgData, 'PNG', pageMargin, positionOnCanvas + pageMargin, pdfContentWidth, pdfImgHeight);
heightLeft -= (pdfPageHeight - (2 * pageMargin));
}
pdf.save(`todo-list-dashboard-${new Date().toISOString().slice(0,10)}.pdf`);
})
.catch(err => { console.error("PDF generation failed:", err); alert("Error generating PDF."); })
.finally(() => {
btn.disabled = false;
btn.innerHTML = originalBtnText;
});
});
// --- HELPER FUNCTIONS ---
function populateFormForEdit(task) {
document.getElementById('task-id').value = task.id;
document.getElementById('task-title').value = task.title;
document.getElementById('task-due-date').value = task.dueDate;
document.getElementById('task-priority').value = task.priority;
// If status was 'Overdue', let user select a new, valid status
document.getElementById('task-status').value = task.status === 'Overdue' ? 'To Do' : task.status;
document.getElementById('task-form').querySelector('button[type="submit"]').textContent = 'Update Task';
document.getElementById('cancel-edit-btn').classList.remove('hidden');
document.getElementById('task-form').scrollIntoView({ behavior: 'smooth' });
}
function resetForm() {
document.getElementById('task-form').reset();
document.getElementById('task-id').value = '';
document.getElementById('task-form').querySelector('button[type="submit"]').textContent = 'Add Task';
document.getElementById('cancel-edit-btn').classList.add('hidden');
}
// --- INITIALIZATION ---
const switchTab = (tabName) => {
const tabDashboardBtn = document.getElementById('tab-dashboard-btn');
const tabConfigBtn = document.getElementById('tab-config-btn');
const tabDashboardContent = document.getElementById('tab-dashboard-content');
const tabConfigContent = document.getElementById('tab-config-content');
const prevTabBtn = document.getElementById('prev-tab-btn');
const nextTabBtn = document.getElementById('next-tab-btn');
if (tabName === 'dashboard') {
tabDashboardBtn.classList.add('active');
tabConfigBtn.classList.remove('active');
tabDashboardContent.classList.remove('hidden');
tabConfigContent.classList.add('hidden');
prevTabBtn.disabled = true;
nextTabBtn.disabled = false;
} else {
tabDashboardBtn.classList.remove('active');
tabConfigBtn.classList.add('active');
tabDashboardContent.classList.add('hidden');
tabConfigContent.classList.remove('hidden');
prevTabBtn.disabled = false;
nextTabBtn.disabled = true;
}
};
document.getElementById('tab-dashboard-btn').addEventListener('click', () => switchTab('dashboard'));
document.getElementById('tab-config-btn').addEventListener('click', () => switchTab('config'));
document.getElementById('prev-tab-btn').addEventListener('click', () => switchTab('dashboard'));
document.getElementById('next-tab-btn').addEventListener('click', () => switchTab('config'));
switchTab('dashboard');
renderAll();
});