`;
});
board.appendChild(column);
});
addDragDropListeners();
}
function renderBurndownChart() {
const startDate = new Date(document.getElementById('start-date').value);
const endDate = new Date(document.getElementById('end-date').value);
const totalPoints = tasksData.reduce((sum, t) => sum + t.Points, 0);
const sprintDays = [];
for (let d = new Date(startDate); d <= endDate; d.setDate(d.getDate() + 1)) {
sprintDays.push(new Date(d));
}
const idealData = sprintDays.map((_, i) => totalPoints - (totalPoints / (sprintDays.length - 1)) * i);
const actualData = sprintDays.map(day => {
const completedPoints = tasksData.filter(t => t.Status === 'Done' && new Date(t.CompletedDate) <= day).reduce((sum, t) => sum + t.Points, 0);
return totalPoints - completedPoints;
});
const ctx = document.getElementById('spd-burndown-chart').getContext('2d');
if(burndownChart) burndownChart.destroy();
burndownChart = new Chart(ctx, {
type: 'line',
data: {
labels: sprintDays.map(d=>d.toISOString().split('T')[0]),
datasets: [
{ label: 'Ideal Burndown', data: idealData, borderColor: '#64748b', borderDash: [5,5], pointRadius: 0 },
{ label: 'Actual Burndown', data: actualData, borderColor: '#4f46e5', tension: 0.1, fill: true }
]
},
options: { responsive: true, maintainAspectRatio: false, scales: { x: { type: 'time', time: { unit: 'day' } }, y: { beginAtZero: true, title: {display:true, text:'Story Points Remaining'} } } }
});
}
function renderTasksTable() {
const table = document.getElementById('tasks-table');
table.innerHTML = `
| Description | Assignee | Points | Status | Blocked | Actions |
${tasksData.map(t => `
|
|
|
|
|
|
`).join('')}
`;
}
function addDragDropListeners() {
document.querySelectorAll('.spd-task-card').forEach(card => card.addEventListener('dragstart', e => e.dataTransfer.setData('text/plain', e.target.dataset.id)));
document.querySelectorAll('.spd-board-column').forEach(col => {
col.addEventListener('dragover', e => e.preventDefault());
col.addEventListener('drop', e => {
e.preventDefault();
const id = parseInt(e.dataTransfer.getData('text/plain'));
const newStatus = e.currentTarget.dataset.status;
const task = tasksData.find(t => t.id === id);
if (task && task.Status !== newStatus) {
task.Status = newStatus;
if (newStatus === 'Done') task.CompletedDate = new Date().toISOString().split('T')[0];
else task.CompletedDate = null;
renderAll();
}
});
});
}
function addTask() {
tasksData.push({ id: Date.now(), Description: 'New Task', Assignee: 'Unassigned', Points: 3, Status: 'To Do', Blocked: false, CompletedDate: null });
renderAll();
}
function handleTableEvents(e) {
const target = e.target; if (!target) return;
const id = parseInt(target.closest('tr')?.dataset.id); if (!id) return;
if (target.classList.contains('remove-task-btn')) {
tasksData = tasksData.filter(t => t.id !== id);
} else if (target.tagName === 'INPUT' || target.tagName === 'SELECT') {
const key = target.dataset.key;
const item = tasksData.find(t => t.id === id);
if (item) {
if (target.type === 'checkbox') item[key] = target.checked;
else if (target.type === 'number') item[key] = parseInt(target.value) || 0;
else item[key] = target.value;
}
}
renderAll();
}
document.getElementById('spd-add-task-btn').addEventListener('click', addTask);
document.getElementById('tasks-table').addEventListener('change', handleTableEvents);
document.getElementById('tasks-table').addEventListener('click', handleTableEvents);
allControls.forEach(input => input.addEventListener('change', renderAll));
function initialize() {
const today = new Date("2025-07-13");
const startDate = new Date(today);
startDate.setDate(today.getDate() - today.getDay() + 1); // Start on Monday of current week
const endDate = new Date(startDate);
endDate.setDate(startDate.getDate() + 11); // 12-day sprint
document.getElementById('start-date').value = startDate.toISOString().split('T')[0];
document.getElementById('end-date').value = endDate.toISOString().split('T')[0];
tasksData = [
{ id: 1, Description: 'Set up user authentication API', Assignee: 'Alice', Points: 5, Status: 'Done', Blocked: false, CompletedDate: '2025-07-08' },
{ id: 2, Description: 'Design profile page UI/UX', Assignee: 'Charlie', Points: 3, Status: 'Done', Blocked: false, CompletedDate: '2025-07-09' },
{ id: 3, Description: 'Build frontend profile component', Assignee: 'Bob', Points: 8, Status: 'In Progress', Blocked: false, CompletedDate: null },
{ id: 4, Description: 'Connect UI to authentication API', Assignee: 'Bob', Points: 5, Status: 'To Do', Blocked: true, CompletedDate: null },
{ id: 5, Description: 'Write unit tests for profile service', Assignee: 'Alice', Points: 3, Status: 'To Do', Blocked: false, CompletedDate: null },
];
renderAll();
}
initialize();
});