${item.duration ? `Dur: ${item.duration}` : ''}
Prio: ${item.priority}
Status: ${item.status}
`;
ul.appendChild(li);
});
ul.querySelectorAll('.edit-daily-item-btn').forEach(btn => btn.addEventListener('click', (e) => {
const dayName = dailyPlanGridDiv.querySelector(`.add-daily-item-btn[data-day-id="${e.target.dataset.dayId}"]`)?.dataset.dayName || "";
const fullDate = dailyPlanGridDiv.querySelector(`.add-daily-item-btn[data-day-id="${e.target.dataset.dayId}"]`)?.dataset.fullName || "";
openDailyItemModal(e.target.dataset.dayId, `Edit Item for ${dayName}, ${fullDate}`, e.target.dataset.itemId);
}));
ul.querySelectorAll('.delete-daily-item-btn').forEach(btn => btn.addEventListener('click', (e) => deleteDailyItem(e.target.dataset.dayId, e.target.dataset.itemId)));
}
function openDailyItemModal(dayId, title, itemId = null) {
dailyItemModalTitle.textContent = title;
dailyItemDateInput.value = dayId; // Store the day this item belongs to
dailyItemIdInput.value = itemId || '';
currentEditingDailyItemId = itemId;
if (itemId) {
const item = weeklyPlans[currentSelectedWeekId]?.dailyItems[dayId]?.find(i => i.id === itemId);
if (item) {
itemDescriptionInput.value = item.description;
itemTimeInput.value = item.time || '';
itemDurationInput.value = item.duration || '';
itemPriorityInput.value = item.priority;
itemStatusInput.value = item.status;
}
} else { // Reset for new item
itemDescriptionInput.value = ''; itemTimeInput.value = ''; itemDurationInput.value = '';
itemPriorityInput.value = 'medium'; itemStatusInput.value = 'planned';
}
dailyItemModal.style.display = 'block';
}
closeDailyItemModalBtn.onclick = () => dailyItemModal.style.display = 'none';
saveDailyItemBtn.addEventListener('click', () => {
const dayId = dailyItemDateInput.value;
const description = itemDescriptionInput.value.trim();
if (!description || !dayId || !currentSelectedWeekId) {
alert('Description is required and week/day context must be set.'); return;
}
const itemData = {
id: currentEditingDailyItemId || generateId(),
description,
time: itemTimeInput.value.trim() || null,
duration: itemDurationInput.value.trim() || null,
priority: itemPriorityInput.value,
status: itemStatusInput.value
};
const dayItems = weeklyPlans[currentSelectedWeekId].dailyItems[dayId] || [];
if (currentEditingDailyItemId) {
const index = dayItems.findIndex(i => i.id === currentEditingDailyItemId);
if (index > -1) dayItems[index] = itemData;
} else {
dayItems.push(itemData);
}
weeklyPlans[currentSelectedWeekId].dailyItems[dayId] = dayItems;
saveCurrentWeekPlan();
renderDailyItemsForDay(dayId);
dailyItemModal.style.display = 'none';
currentEditingDailyItemId = null;
});
function deleteDailyItem(dayId, itemId) {
if (confirm('Delete this item?')) {
const dayItems = weeklyPlans[currentSelectedWeekId]?.dailyItems[dayId] || [];
weeklyPlans[currentSelectedWeekId].dailyItems[dayId] = dayItems.filter(i => i.id !== itemId);
saveCurrentWeekPlan();
renderDailyItemsForDay(dayId);
}
}
// --- Global Actions ---
savePlanBtn.addEventListener('click', () => {
saveCurrentWeekPlan(); // Explicit save, though auto-save on item changes implemented
alert('Weekly plan saved!');
});
clearPlanBtn.addEventListener('click', () => {
if (currentSelectedWeekId && confirm(`Are you sure you want to clear the entire plan for week starting ${formatDate(new Date(currentSelectedWeekId+"T00:00:00"))}? This cannot be undone.`)) {
delete weeklyPlans[currentSelectedWeekId];
saveCurrentWeekPlan(); // This will save the object without this week's key
// Re-load or re-initialize the view for this week
const {start} = getWeekRange(new Date(currentSelectedWeekId+"T00:00:00"), parseInt(planWeekStartDaySelect.value));
loadOrCreatePlanForWeek(currentSelectedWeekId, start);
}
});
// --- PDF Download ---
downloadPlanPdfBtn.addEventListener('click', () => {
if (!currentSelectedWeekId || !weeklyPlans[currentSelectedWeekId]) {
alert('No plan selected or available to download.'); return;
}
const plan = weeklyPlans[currentSelectedWeekId];
const { jsPDF } = window.jspdf;
const doc = new jsPDF('p', 'pt', 'a4');
const margin = 40; let yPos = margin;
const pageWidth = doc.internal.pageSize.getWidth();
doc.setFontSize(18);
doc.setTextColor(varToRGB('--primary-color').r, varToRGB('--primary-color').g, varToRGB('--primary-color').b);
doc.text('Weekly Work Plan', pageWidth / 2, yPos, { align: 'center' });
yPos += 20;
doc.setFontSize(12); doc.setTextColor(100);
doc.text(`Plan for Week: ${formatDate(new Date(plan.weekStartDate+"T00:00:00"))} - ${formatDate(new Date(plan.weekEndDate+"T00:00:00"))}`, pageWidth / 2, yPos, { align: 'center' });
yPos += 15;
doc.setFontSize(10);
doc.text(`Generated: ${new Date().toLocaleString()}`, pageWidth / 2, yPos, { align: 'center' });
yPos += 25;
// Weekly Priorities
if (plan.weeklyPriorities.length > 0) {
doc.setFontSize(14); doc.setTextColor(varToRGB('--primary-color').r, varToRGB('--primary-color').g, varToRGB('--primary-color').b);
doc.text('Weekly Priorities / Goals:', margin, yPos); yPos += 18;
doc.setFontSize(10); doc.setTextColor(50);
plan.weeklyPriorities.forEach(prio => {
const lines = doc.splitTextToSize(`• ${prio.description}`, pageWidth - 2 * margin - 5);
if (yPos + lines.length * 12 > doc.internal.pageSize.getHeight() - margin) { doc.addPage(); yPos = margin; }
doc.text(lines, margin + 5, yPos); yPos += lines.length * 12 + 3;
});
yPos += 10;
}
// Daily Plan
doc.setFontSize(14); doc.setTextColor(varToRGB('--primary-color').r, varToRGB('--primary-color').g, varToRGB('--primary-color').b);
doc.text('Daily Plan:', margin, yPos); yPos += 18;
const dayNamesForPdf = parseInt(planWeekStartDaySelect.value) === 1
? ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
for (let i = 0; i < 7; i++) {
const dayDate = new Date(plan.weekStartDate + "T00:00:00");
dayDate.setDate(new Date(plan.weekStartDate + "T00:00:00").getDate() + i);
const dayId = getWeekId(dayDate);
const items = plan.dailyItems[dayId] || [];
items.sort((a,b) => (a.time || "").localeCompare(b.time || ""));
if (yPos > doc.internal.pageSize.getHeight() - 60 && items.length > 0) { doc.addPage(); yPos = margin; }
doc.setFontSize(12); doc.setTextColor(varToRGB('--dark-text').r, varToRGB('--dark-text').g, varToRGB('--dark-text').b);
doc.text(`${dayNamesForPdf[i]}, ${formatDate(dayDate)}`, margin, yPos); yPos += 15;
if (items.length > 0) {
const body = items.map(item => [
item.time || 'Any Time',
item.description,
item.duration || 'N/A',
item.priority.charAt(0).toUpperCase() + item.priority.slice(1),
item.status.charAt(0).toUpperCase() + item.status.slice(1)
]);
doc.autoTable({
startY: yPos,
head: [['Time', 'Description', 'Duration', 'Priority', 'Status']],
body: body, theme: 'grid',
headStyles: { fillColor: varToRGB('--primary-color', true), textColor: varToRGB('--light-text', true) },
styles: { fontSize: 9, cellPadding:3 },
columnStyles: { 1: { cellWidth: 'auto' } } // Description column wider
});
yPos = doc.lastAutoTable.finalY + 10;
} else {
doc.setFontSize(9); doc.setTextColor(150);
doc.text('No items planned for this day.', margin + 5, yPos); yPos += 12;
}
yPos += 5; // Space between days
}
doc.save(`Weekly_Plan_${plan.weekStartDate}_to_${plan.weekEndDate}.pdf`);
});
function varToRGB(varName, asArray = false) {
const colorHex = getComputedStyle(document.documentElement).getPropertyValue(varName).trim();
if (!colorHex.startsWith('#')) { return asArray ? [0,0,0] : {r:0,g:0,b:0}; }
const r = parseInt(colorHex.slice(1, 3), 16);
const g = parseInt(colorHex.slice(3, 5), 16);
const b = parseInt(colorHex.slice(5, 7), 16);
return asArray ? [r,g,b] : {r,g,b};
}
// --- Initializations ---
const initialWeekStartDate = getWeekStart(today, parseInt(planWeekStartDaySelect.value));
planWeekPicker.value = getWeekId(initialWeekStartDate); // Set date picker to start of current week
selectAndDisplayWeek(initialWeekStartDate); // Load and display the plan for initially selected week
})();