Show course name and assignment content in planner print

Week print: tasks grouped by day, each showing course name, type,
and full assignment body text. Month print: course name in calendar
cells + an Assignment Detail section below the calendar with body text.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Sonnet 4.6 committed 2026-07-21 16:53:46 -04:00
1 parent 934919e392
commit 9889da3462
2 files changed
+81 -23

No files matched your search

+79 -21
View File
@@ -880,11 +880,31 @@ function toggleAddTaskForm(date) {
});
}
function renderPrintTaskBlock(t) {
const title = t.itemTitle || t.offlineTitle;
const course = t.courseName ? `<span class="task-course">${esc(t.courseName)}</span>` : `<span class="task-course offline">Offline</span>`;
const status = t.done ? `<span class="done-tag">✓ done</span>` : '';
const typeTag = t.type ? `<span class="type-tag">${TYPE_LABEL[t.type] || t.type}</span>` : '';
let body = '';
if (t.body) body = `<div class="task-body">${t.body.split(/\n\n+/).map((p) => `<p>${esc(p.trim())}</p>`).join('')}</div>`;
return `<div class="task-block">
<div class="task-header">${course} ${typeTag} <strong>${esc(title)}</strong> ${status}</div>
${body}
</div>`;
}
async function printWeekReport(studentId, start) {
const r = await api(`/api/week-report/${studentId}?start=${start}`);
const taskRows = r.tasks
.map((t) => `<tr><td>${t.date}</td><td>${esc(t.itemTitle || t.offlineTitle)}</td><td>${esc(t.courseName || 'Offline')}</td><td>${t.done ? '✓ done' : '—'}</td></tr>`)
.join('');
// Group tasks by date
const byDate = {};
for (const t of r.tasks) { (byDate[t.date] = byDate[t.date] || []).push(t); }
const dayBlocks = Object.entries(byDate).map(([date, tasks]) =>
`<div class="day-block">
<h3>${date}</h3>
${tasks.map(renderPrintTaskBlock).join('')}
</div>`
).join('') || '<p class="empty">Nothing scheduled this week.</p>';
const gradedRows = r.graded
.map((g) => `<tr><td>${esc(g.itemTitle)}</td><td>${esc(g.courseName)}</td><td>${g.score}/${g.points_possible}</td></tr>`)
.join('');
@@ -892,22 +912,34 @@ async function printWeekReport(studentId, start) {
.map((t) => `<tr><td>${esc(t.list)}</td><td>${t.score}/${t.total}</td></tr>`)
.join('');
const win = window.open('', '_blank');
win.document.write(`<!DOCTYPE html><html><head><title>Weekly Report</title>
win.document.write(`<!DOCTYPE html><html><head><title>Weekly Plan — ${esc(r.student)}</title>
<style>
body { font-family: Georgia, serif; max-width: 640px; margin: 2rem auto; color: #222; }
h1 { font-size: 1.4rem; border-bottom: 2px solid #222; padding-bottom: 0.4rem; }
h2 { font-size: 1.1rem; margin-top: 1.5rem; }
table { width: 100%; border-collapse: collapse; margin-top: 0.5rem; }
td, th { border: 1px solid #999; padding: 0.4rem 0.6rem; text-align: left; }
body { font-family: Georgia, serif; max-width: 680px; margin: 2rem auto; color: #222; font-size: .95rem; }
h1 { font-size: 1.4rem; border-bottom: 2px solid #222; padding-bottom: .4rem; }
h2 { font-size: 1.1rem; margin: 1.5rem 0 .5rem; border-bottom: 1px solid #ccc; padding-bottom: .2rem; }
h3 { font-size: 1rem; margin: 1rem 0 .3rem; color: #555; }
.day-block { margin-bottom: .75rem; }
.task-block { border-left: 3px solid #bbb; padding: .3rem .7rem; margin-bottom: .5rem; break-inside: avoid; }
.task-header { font-size: .95rem; margin-bottom: .2rem; }
.task-course { font-weight: 700; color: #3a6fd8; }
.task-course.offline { color: #888; font-weight: 400; }
.type-tag { font-size: .78rem; color: #888; font-style: italic; }
.done-tag { font-size: .78rem; color: #2e9e5b; font-weight: 700; }
.task-body p { margin: .2rem 0; font-size: .88rem; color: #444; line-height: 1.5; }
table { width: 100%; border-collapse: collapse; margin-top: .4rem; }
td, th { border: 1px solid #bbb; padding: .35rem .6rem; text-align: left; font-size: .88rem; }
th { background: #f0f0f0; }
.empty { color: #888; font-style: italic; }
@media print { h2 { break-after: avoid; } .task-block { break-inside: avoid; } }
</style></head><body>
<h1>Weekly Report — ${esc(r.student)}</h1>
<h1>Weekly Plan — ${esc(r.student)}</h1>
<p>Week of ${r.start}</p>
<h2>Schedule</h2>
<table><tr><th>Date</th><th>Task</th><th>Course</th><th>Status</th></tr>${taskRows || '<tr><td colspan="4">Nothing scheduled</td></tr>'}</table>
${dayBlocks}
<h2>Graded work</h2>
<table><tr><th>Item</th><th>Course</th><th>Score</th></tr>${gradedRows || '<tr><td colspan="3">Nothing graded this week</td></tr>'}</table>
${gradedRows ? `<table><tr><th>Item</th><th>Course</th><th>Score</th></tr>${gradedRows}</table>` : '<p class="empty">Nothing graded this week.</p>'}
<h2>Spelling tests</h2>
<table><tr><th>List</th><th>Score</th></tr>${spellingRows || '<tr><td colspan="2">No spelling tests this week</td></tr>'}</table>
${spellingRows ? `<table><tr><th>List</th><th>Score</th></tr>${spellingRows}</table>` : '<p class="empty">No spelling tests this week.</p>'}
<script>window.print()<\/script></body></html>`);
win.document.close();
}
@@ -933,26 +965,52 @@ async function printMonthReport(studentId, monthMonday, monthRef) {
const calRows = weeks.map((week) =>
`<tr>${week.map((day) => {
const dayTasks = tasks.filter((t) => t.date === day.date);
const items = dayTasks.map((t) => `<div class="cell-task${t.done ? ' done' : ''}">${t.itemTitle || t.offlineTitle}</div>`).join('');
const items = dayTasks.map((t) => {
const label = t.itemTitle || t.offlineTitle;
const course = t.courseName ? `<span class="cell-course">${esc(t.courseName)}</span> ` : '';
return `<div class="cell-task${t.done ? ' done' : ''}">${course}${esc(label)}</div>`;
}).join('');
return `<td><div class="date-num">${day.date.slice(5)}</div>${items || ''}</td>`;
}).join('')}</tr>`
).join('');
// Detail section: all days that have tasks, grouped by date
const taskDays = weeks.flatMap((w) => w).filter((day) => tasks.some((t) => t.date === day.date));
const detailBlocks = taskDays.map((day) => {
const dayTasks = tasks.filter((t) => t.date === day.date);
return `<div class="detail-day">
<h3>${day.date}</h3>
${dayTasks.map(renderPrintTaskBlock).join('')}
</div>`;
}).join('');
const win = window.open('', '_blank');
win.document.write(`<!DOCTYPE html><html><head><title>${monthLabel(monthRef)} — ${student?.name || ''}</title>
<style>
body { font-family: Georgia, serif; margin: 1.5cm; color: #222; }
h1 { font-size: 1.4rem; border-bottom: 2px solid #222; padding-bottom: .4rem; margin-bottom: .75rem; }
body { font-family: Georgia, serif; margin: 1cm; color: #222; font-size: .88rem; }
h1 { font-size: 1.3rem; border-bottom: 2px solid #222; padding-bottom: .4rem; margin-bottom: .75rem; }
h2 { font-size: 1rem; margin: 1.5rem 0 .5rem; border-bottom: 1px solid #ccc; padding-bottom: .2rem; }
h3 { font-size: .9rem; color: #555; margin: .75rem 0 .25rem; }
table { width: 100%; border-collapse: collapse; }
th { background: #f0f0f0; padding: .4rem; font-size: .85rem; border: 1px solid #bbb; }
td { vertical-align: top; border: 1px solid #bbb; padding: .4rem; min-height: 3.5rem; width: 20%; }
.date-num { font-size: .75rem; color: #888; font-weight: 700; margin-bottom: .25rem; }
.cell-task { font-size: .78rem; margin: .1rem 0; padding: .1rem .3rem; background: #e8f0ff; border-radius: 3px; }
th { background: #f0f0f0; padding: .3rem; font-size: .8rem; border: 1px solid #bbb; }
td { vertical-align: top; border: 1px solid #bbb; padding: .3rem; min-height: 3rem; width: 20%; }
.date-num { font-size: .7rem; color: #888; font-weight: 700; margin-bottom: .2rem; }
.cell-course { font-weight: 700; color: #3a6fd8; font-size: .7rem; }
.cell-task { font-size: .72rem; margin: .1rem 0; padding: .1rem .3rem; background: #e8f0ff; border-radius: 3px; }
.cell-task.done { background: #e8f7ee; text-decoration: line-through; color: #666; }
@media print { @page { size: landscape; margin: 1cm; } }
.task-block { border-left: 3px solid #bbb; padding: .3rem .6rem; margin-bottom: .4rem; break-inside: avoid; }
.task-header { font-size: .88rem; }
.task-course { font-weight: 700; color: #3a6fd8; }
.task-course.offline { color: #888; font-weight: 400; }
.type-tag { font-size: .75rem; color: #888; font-style: italic; }
.done-tag { font-size: .75rem; color: #2e9e5b; font-weight: 700; }
.task-body p { margin: .15rem 0; font-size: .82rem; color: #444; line-height: 1.4; }
.empty { color: #888; font-style: italic; }
@media print { @page { size: landscape; margin: .75cm; } h2 { break-after: avoid; } .task-block { break-inside: avoid; } }
</style></head><body>
<h1>${monthLabel(monthRef)} — ${esc(student?.name || '')}</h1>
<table><tr>${DAY_SHORT.map((d) => `<th>${d}</th>`).join('')}</tr>${calRows}</table>
${detailBlocks ? `<h2>Assignment Detail</h2>${detailBlocks}` : ''}
<script>window.print()<\/script></body></html>`);
win.document.close();
}