`;
taskListUL.appendChild(li);
});
document.querySelectorAll('.edit-task-btn').forEach(btn => btn.addEventListener('click', (e) => populateTaskFormForEdit(e.target.dataset.id)));
document.querySelectorAll('.delete-task-btn').forEach(btn => btn.addEventListener('click', (e) => deleteTask(e.target.dataset.id)));
document.querySelectorAll('.toggle-status-btn').forEach(btn => btn.addEventListener('click', (e) => toggleTaskStatus(e.target.dataset.id)));
}
// --- Analysis Logic ---
analysisPeriodSelect.addEventListener('change', () => {
customDateRangeDiv.style.display = analysisPeriodSelect.value === 'custom' ? 'flex' : 'none';
});
analyzeBtn.addEventListener('click', () => {
let startDate, endDate;
const today = new Date();
const period = analysisPeriodSelect.value;
switch(period) {
case 'today':
startDate = new Date(today.setHours(0,0,0,0));
endDate = new Date(today.setHours(23,59,59,999));
break;
case 'past7days':
endDate = new Date(today.setHours(23,59,59,999));
startDate = new Date(today);
startDate.setDate(today.getDate() - 6); // Covers today + 6 previous days
startDate.setHours(0,0,0,0);
break;
case 'past30days':
endDate = new Date(today.setHours(23,59,59,999));
startDate = new Date(today);
startDate.setDate(today.getDate() - 29);
startDate.setHours(0,0,0,0);
break;
case 'custom':
if (!customStartDateInput.value || !customEndDateInput.value) {
alert('Please select a valid custom date range.');
return;
}
startDate = new Date(customStartDateInput.value + "T00:00:00");
endDate = new Date(customEndDateInput.value + "T23:59:59");
if (startDate > endDate) {
alert('Start date cannot be after end date.');
return;
}
break;
default: return;
}
performAnalysis(startDate, endDate);
});
function performAnalysis(startDate, endDate) {
let totalPlannedValue = 0;
let totalAchievedValue = 0;
let tasksCompleted = 0;
let tasksOnTime = 0;
let tasksLate = 0;
const periodPlannedTasks = [];
const periodCompletedTasks = [];
tasks.forEach(task => {
const taskDueDate = task.dueDate ? new Date(task.dueDate + "T00:00:00") : null;
const taskCreatedAt = new Date(task.createdAt + "T00:00:00"); // Ensure createdAt is treated as date
// Determine if task was planned for the period
let isPlannedForPeriod = false;
if (taskDueDate && taskDueDate >= startDate && taskDueDate <= endDate) {
isPlannedForPeriod = true;
} else if (!taskDueDate && taskCreatedAt >= startDate && taskCreatedAt <= endDate) {
// If no due date, it's planned if created within period
isPlannedForPeriod = true;
}
if (isPlannedForPeriod) {
totalPlannedValue += task.value;
periodPlannedTasks.push(task);
}
// Determine if task was completed in the period
if (task.status === 'done' && task.completionDate) {
const completionDate = new Date(task.completionDate + "T00:00:00");
if (completionDate >= startDate && completionDate <= endDate) {
tasksCompleted++;
let taskAchievedValue = task.value;
let timelinessStatus = 'N/A';
if (taskDueDate) {
if (completionDate <= taskDueDate) {
tasksOnTime++;
taskAchievedValue += task.value * (settings.onTimeBonusPercent / 100);
timelinessStatus = 'On Time';
} else {
tasksLate++;
timelinessStatus = 'Late';
}
}
totalAchievedValue += taskAchievedValue;
periodCompletedTasks.push({...task, timelinessStatus, achievedValueWithBonus: taskAchievedValue});
// If a task was completed in period but not "planned" (e.g. due earlier but done now)
// it still contributes to achieved value but might not have been in planned value if we are strict
// Current logic for planned value relies on due date or creation date.
// For simplicity, let's ensure its original value is added to planned if it wasn't already.
if (!isPlannedForPeriod) {
// This case can be debated: if a very old task is completed, should it inflate "planned"?
// For now, let's stick to the definition of planned above.
// The score might exceed 100% if old valuable tasks are cleared.
}
}
}
});
const productivityScore = totalPlannedValue > 0 ? Math.min(100, (totalAchievedValue / totalPlannedValue) * 100) : 0;
productivityScoreDiv.textContent = `${productivityScore.toFixed(0)}%`;
totalValuePlannedDiv.textContent = totalPlannedValue.toFixed(0);
totalValueAchievedDiv.textContent = totalAchievedValue.toFixed(1); // Show decimal for bonus
tasksCompletedCountDiv.textContent = tasksCompleted;
tasksOnTimeCountDiv.textContent = tasksOnTime;
tasksLateCountDiv.textContent = tasksLate;
const progressPercent = totalPlannedValue > 0 ? (totalAchievedValue / totalPlannedValue) * 100 : 0;
achievedProgressBar.style.width = `${Math.min(100, progressPercent)}%`; // Cap at 100% for visual
achievedProgressBarText.textContent = `${progressPercent.toFixed(0)}% Achieved`;
renderAnalysisTaskLists(periodPlannedTasks, periodCompletedTasks);
analysisResultsDiv.style.display = 'block';
}
function renderAnalysisTaskLists(planned, completed) {
plannedTasksListUL.innerHTML = '';
completedTasksListUL.innerHTML = '';
if(planned.length === 0) plannedTasksListUL.innerHTML = "