${task.title}
${task.description}
Due: ${task.dueDate || 'N/A'}
`;
card.addEventListener('dragstart', handleDragStart);
column.appendChild(card);
});
column.addEventListener('dragover', handleDragOver);
column.addEventListener('dragleave', handleDragLeave);
column.addEventListener('drop', handleDrop);
taskBoard.appendChild(column);
});
};
const renderCharts = () => {
const statusCtx = document.getElementById('statusChart').getContext('2d');
const priorityCtx = document.getElementById('priorityChart').getContext('2d');
const statusCounts = statuses.map(s => tasks.filter(t => t.status === s).length);
const priorityCounts = priorities.map(p => tasks.filter(t => t.priority === p).length);
if (statusChart) statusChart.destroy();
statusChart = new Chart(statusCtx, {
type: 'doughnut',
data: {
labels: statuses,
datasets: [{
data: statusCounts,
backgroundColor: ['#60a5fa', '#fbbf24', '#34d399'], // Blue, Amber, Green
}]
},
options: { responsive: true, maintainAspectRatio: false }
});
if (priorityChart) priorityChart.destroy();
priorityChart = new Chart(priorityCtx, {
type: 'pie',
data: {
labels: priorities,
datasets: [{
data: priorityCounts,
backgroundColor: [priorityColors.Low, priorityColors.Medium, priorityColors.High],
}]
},
options: { responsive: true, maintainAspectRatio: false }
});
};
const renderTaskListEditor = () => {
const container = taskListEditor.querySelector('.space-y-2');
container.innerHTML = '';
if (tasks.length === 0) {
container.innerHTML = '
No tasks yet. Add one using the form above.
';
return;
}
tasks.forEach(task => {
const el = document.createElement('div');
el.className = 'flex items-center justify-between p-3 bg-gray-50 rounded-md';
el.innerHTML = `
${task.title} (${task.status})
Priority: ${task.priority} | Due: ${task.dueDate || 'N/A'}
`;
container.appendChild(el);
});
};
// --- EVENT HANDLERS ---
// Form Submission (Add/Update)
taskForm.addEventListener('submit', (e) => {
e.preventDefault();
const idInput = document.getElementById('task-id');
const title = document.getElementById('task-title').value;
const description = document.getElementById('task-desc').value;
const dueDate = document.getElementById('task-due-date').value;
const priority = document.getElementById('task-priority').value;
if (idInput.value) { // Update existing task
const task = tasks.find(t => t.id == idInput.value);
if (task) {
task.title = title;
task.description = description;
task.dueDate = dueDate;
task.priority = priority;
}
} else { // Add new task
const newId = tasks.length > 0 ? Math.max(...tasks.map(t => t.id)) + 1 : 1;
tasks.push({ id: newId, title, description, dueDate, priority, status: 'To Do' });
}
resetForm();
renderAll();
});
// Edit/Delete buttons
taskListEditor.addEventListener('click', (e) => {
if (e.target.classList.contains('edit-btn')) {
const taskId = e.target.dataset.taskId;
const task = tasks.find(t => t.id == taskId);
if (task) populateFormForEdit(task);
}
if (e.target.classList.contains('delete-btn')) {
const taskId = e.target.dataset.taskId;
if (confirm('Are you sure you want to delete this task?')) {
tasks = tasks.filter(t => t.id != taskId);
renderAll();
}
}
});
cancelEditBtn.addEventListener('click', resetForm);
// Drag and Drop Handlers
let draggedItemId = null;
function handleDragStart(e) {
draggedItemId = e.target.dataset.taskId;
e.target.classList.add('dragging');
}
function handleDragOver(e) {
e.preventDefault();
e.currentTarget.classList.add('drag-over');
}
function handleDragLeave(e) {
e.currentTarget.classList.remove('drag-over');
}
function handleDrop(e) {
e.preventDefault();
e.currentTarget.classList.remove('drag-over');
const newStatus = e.currentTarget.dataset.status;
const task = tasks.find(t => t.id == draggedItemId);
if (task) {
task.status = newStatus;
document.querySelector('.dragging')?.classList.remove('dragging');
renderAll();
}
draggedItemId = null;
}
// PDF Download
downloadPdfBtn.addEventListener('click', () => {
const exportArea = document.getElementById('dashboard-export-area');
const mainTitleEl = document.querySelector('#task-tool-container h1');
if (!exportArea || !mainTitleEl) return;
const originalBtnText = downloadPdfBtn.innerHTML;
downloadPdfBtn.disabled = true;
downloadPdfBtn.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(`task-dashboard-report-${new Date().toISOString().slice(0,10)}.pdf`);
})
.catch(err => { console.error("PDF generation failed:", err); alert("Error generating PDF."); })
.finally(() => {
downloadPdfBtn.disabled = false;
downloadPdfBtn.innerHTML = originalBtnText;
});
});
// --- HELPER FUNCTIONS ---
function populateFormForEdit(task) {
document.getElementById('task-id').value = task.id;
document.getElementById('task-title').value = task.title;
document.getElementById('task-desc').value = task.description;
document.getElementById('task-due-date').value = task.dueDate;
document.getElementById('task-priority').value = task.priority;
taskForm.querySelector('button[type="submit"]').textContent = 'Update Task';
cancelEditBtn.classList.remove('hidden');
taskForm.scrollIntoView({ behavior: 'smooth' });
}
function resetForm() {
taskForm.reset();
document.getElementById('task-id').value = '';
taskForm.querySelector('button[type="submit"]').textContent = 'Add Task';
cancelEditBtn.classList.add('hidden');
}
// --- INITIALIZATION ---
tabDashboardBtn.addEventListener('click', () => switchTab('dashboard'));
tabConfigBtn.addEventListener('click', () => switchTab('config'));
prevTabBtn.addEventListener('click', () => switchTab('dashboard'));
nextTabBtn.addEventListener('click', () => switchTab('config'));
switchTab('dashboard');
renderAll();
});