Weekly Schedule & Time Blocking
Summary & Review for week of
Weekly Reflection
×
Create/Edit Time Block
No goals set for the week.
';
wpa_goals.forEach(goal => {
const tasksForGoal = wpa_tasks.filter(t => t.goalId === goal.id);
const completedTasks = tasksForGoal.filter(t => t.isDone).length;
const item = document.createElement('div'); item.classList.add('wpa-summary-item');
item.innerHTML = `
${goal.name}
Progress: ${completedTasks} / ${tasksForGoal.length} tasks completed.
`;
goalProgressDiv.appendChild(item);
});
// Time Allocation
const timeAllocDiv = document.getElementById('wpa-timeAllocationSummary');
timeAllocDiv.innerHTML = '';
const timePerGoal = {};
wpa_goals.forEach(g => timePerGoal[g.id] = { name: g.name, color: g.color, totalMinutes: 0 });
const timePerDay = {mon:0, tue:0, wed:0, thu:0, fri:0, sat:0, sun:0};
wpa_scheduledBlocks.forEach(block => {
const durationMins = wpa_timeStringToMinutes(block.endTime) - wpa_timeStringToMinutes(block.startTime);
if (block.type === 'task') {
const task = wpa_tasks.find(t => t.id === block.contentId);
if (task && task.goalId && timePerGoal[task.goalId]) {
timePerGoal[task.goalId].totalMinutes += durationMins;
}
}
const dayIdx = new Date(block.date+"T00:00:00").getDay(); // Sun=0, Mon=1...
const dayKey = wpa_daysOfWeek[dayIdx === 0 ? 6 : dayIdx - 1];
if (timePerDay.hasOwnProperty(dayKey)) timePerDay[dayKey] += durationMins;
});
const goalAllocItem = document.createElement('div'); goalAllocItem.classList.add('wpa-summary-item');
goalAllocItem.innerHTML = '
Time Allocated per Goal
';
const goalUl = document.createElement('ul');
for(const goalId in timePerGoal) {
const goalData = timePerGoal[goalId];
goalUl.innerHTML += `
${goalData.name}: ${Math.floor(goalData.totalMinutes/60)}h ${goalData.totalMinutes%60}m`;
}
goalAllocItem.appendChild(goalUl); timeAllocDiv.appendChild(goalAllocItem);
const dayAllocItem = document.createElement('div'); dayAllocItem.classList.add('wpa-summary-item');
dayAllocItem.innerHTML = '
Time Allocated per Day
';
const dayUl = document.createElement('ul');
wpa_daysOfWeek.forEach((dayKey, index) => {
const totalMins = timePerDay[dayKey];
dayUl.innerHTML += `
${wpa_dayNamesFull[index]}: ${Math.floor(totalMins/60)}h ${totalMins%60}m`;
});
dayAllocItem.appendChild(dayUl); timeAllocDiv.appendChild(dayAllocItem);
}
function wpa_saveReflection() { wpa_weeklyReflection = document.getElementById('wpa-weeklyReflectionNotes').value; wpa_saveData(); }
// --- PDF Download ---
document.getElementById('wpa-downloadPdfBtn').onclick = async () => {
if (!wpa_weekToPlan) { alert("Please select a week to plan first."); return; }
const { jsPDF } = window.jspdf;
const pdf = new jsPDF('l', 'mm', 'a4'); // Landscape
let currentY = 15; const margin = 10; const contentWidth = pdf.internal.pageSize.getWidth() - 2 * margin;
const accentColor = '#2ECC71'; const textColor = '#34495E';
pdf.setFontSize(20); pdf.setTextColor(accentColor);
pdf.text(`Weekly Plan: ${new Date(wpa_weekToPlan+"T00:00:00").toLocaleDateString()}`, pdf.internal.pageSize.getWidth() / 2, currentY, { align: 'center' });
currentY += 10;
// Goals
pdf.setFontSize(14); pdf.setTextColor(accentColor);
pdf.text("Weekly Goals", margin, currentY); currentY += 6;
pdf.setFontSize(10); pdf.setTextColor(textColor);
wpa_goals.forEach(goal => {
const goalColorRgb = wpa_hexToRgb(goal.color);
if (goalColorRgb) pdf.setFillColor(goalColorRgb.r, goalColorRgb.g, goalColorRgb.b); else pdf.setFillColor(200,200,200);
pdf.rect(margin, currentY - 3.5, 4, 4, 'F');
pdf.text(goal.name, margin + 7, currentY); currentY += 6;
});
currentY += 4;
// Schedule Snapshot
const scheduleTableEl = document.getElementById('wpa-scheduleTableCaptureArea');
const calendarWeekDisplayEl = document.getElementById('wpa-calendarWeekDisplay');
calendarWeekDisplayEl.style.display = 'block'; // Ensure header is visible for capture
try {
const canvas = await html2canvas(scheduleTableEl, { scale: 1.2, backgroundColor: '#FFFFFF', width: scheduleTableEl.scrollWidth, height: scheduleTableEl.scrollHeight });
calendarWeekDisplayEl.style.display = 'none'; // Hide after capture for normal view
const imgData = canvas.toDataURL('image/png');
const imgProps = pdf.getImageProperties(imgData);
let pdfImgWidth = contentWidth; let pdfImgHeight = (imgProps.height * pdfImgWidth) / imgProps.width;
const pageHeight = pdf.internal.pageSize.getHeight();
if (currentY + pdfImgHeight + 10 > pageHeight - margin) { // +10 for next section spacing
pdf.addPage(); currentY = margin;
}
if (pdfImgHeight > pageHeight - margin * 2) { pdfImgHeight = pageHeight - margin * 2; pdfImgWidth = (imgProps.width * pdfImgHeight) / imgProps.height; } // Scale if too tall for a page
pdf.addImage(imgData, 'PNG', margin, currentY, pdfImgWidth, pdfImgHeight, undefined, 'FAST');
currentY += pdfImgHeight + 8;
} catch (e) { calendarWeekDisplayEl.style.display = 'none'; console.error("PDF schedule capture error:", e); currentY+=5; }
// Tasks by Goal (New Page might be needed)
if (currentY > pdf.internal.pageSize.getHeight() - 50 || wpa_tasks.length > 10) { pdf.addPage(); currentY = margin; }
pdf.setFontSize(14); pdf.setTextColor(accentColor);
pdf.text("Tasks & Progress", margin, currentY); currentY += 7;
wpa_goals.forEach(goal => {
if (currentY > pdf.internal.pageSize.getHeight() - 20) { pdf.addPage(); currentY = margin; }
const goalColorRgb = wpa_hexToRgb(goal.color);
if (goalColorRgb) pdf.setFillColor(goalColorRgb.r, goalColorRgb.g, goalColorRgb.b); else pdf.setFillColor(200,200,200);
pdf.rect(margin, currentY - 3.5, 4, 4, 'F');
pdf.setFontSize(11); pdf.setTextColor(goal.color); pdf.text(goal.name, margin + 7, currentY); currentY +=6;
const tasksForGoal = wpa_tasks.filter(t => t.goalId === goal.id);
if(tasksForGoal.length > 0) {
const taskBody = tasksForGoal.map(t => [t.name, `${t.duration} min`, t.priority, t.isDone ? 'Done' : 'To Do']);
pdf.autoTable({
head: [["Task", "Duration", "Priority", "Status"]], body: taskBody, startY: currentY,
theme: 'grid', headStyles: { fillColor: '#f0f0f0', textColor: textColor }, styles: { fontSize: 8, cellPadding: 1.5 }
});
currentY = pdf.lastAutoTable.finalY + 5;
} else {
pdf.setFontSize(9); pdf.setTextColor(textColor); pdf.text(" - No tasks for this goal.", margin + 5, currentY); currentY += 5;
}
});
currentY += 5;
// Unscheduled Tasks
const scheduledTaskIds = wpa_scheduledBlocks.filter(b => b.type === 'task').map(b => b.contentId);
const unscheduledForPdf = wpa_tasks.filter(t => !t.isDone && !scheduledTaskIds.includes(t.id));
if (unscheduledForPdf.length > 0) {
if (currentY > pdf.internal.pageSize.getHeight() - 30) { pdf.addPage(); currentY = margin; }
pdf.setFontSize(12); pdf.setTextColor(accentColor); pdf.text("Unscheduled Tasks", margin, currentY); currentY +=6;
const unscheduledBody = unscheduledForPdf.map(t => {
const g = wpa_goals.find(gl => gl.id === t.goalId); return [t.name, g?g.name:'-', `${t.duration} min`, t.priority];
});
pdf.autoTable({
head: [["Task", "Goal", "Duration", "Priority"]], body: unscheduledBody, startY: currentY,
theme: 'striped', headStyles: { fillColor: '#f0f0f0', textColor: textColor }, styles: { fontSize: 8, cellPadding: 1.5 }
});
currentY = pdf.lastAutoTable.finalY + 8;
}
// Reflection
if (wpa_weeklyReflection) {
if (currentY > pdf.internal.pageSize.getHeight() - 40) { pdf.addPage(); currentY = margin; }
pdf.setFontSize(12); pdf.setTextColor(accentColor); pdf.text("Weekly Reflection", margin, currentY); currentY +=6;
pdf.setFontSize(10); pdf.setTextColor(textColor);
const reflectionLines = pdf.splitTextToSize(wpa_weeklyReflection, contentWidth);
pdf.text(reflectionLines, margin, currentY);
}
pdf.save(`Weekly_Plan_${wpa_weekToPlan}.pdf`);
};
function wpa_hexToRgb(hex) { const r = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return r ? {r:parseInt(r[1],16),g:parseInt(r[2],16),b:parseInt(r[3],16)}:null;}
// --- Initial Load ---
document.addEventListener('DOMContentLoaded', () => {
wpa_openTab(null, wpa_tabs[0]);
const firstTabButton = document.querySelector(`.wpa-tab-button[onclick*="${wpa_tabs[0]}"]`);
if (firstTabButton) firstTabButton.classList.add('active');
wpa_updateNavButtons();
});