Nothing waiting to be graded ๐
diff --git a/public/admin.js b/public/admin.js index 28e56de..5e3dbc1 100644 --- a/public/admin.js +++ b/public/admin.js @@ -1391,8 +1391,9 @@ function renderDayCell(day, tasks, compact = false, spellingTests = [], today = `; }).join(''); + const fmtDate = (d) => { const dt = new Date(d + 'T00:00:00'); return dt.toLocaleString('default', { month: 'short', day: 'numeric' }); }; return `โ
` : '')} @@ -1782,7 +1783,19 @@ function showEvidenceLightbox(notes, photo) { const STUDENT_NOTE_LABEL = { needs_help: '๐ Needs help', not_sure: '๐ค Not sure' }; async function loadGrading() { - const rows = await api('/api/grading-queue'); + const allRows = await api('/api/grading-queue'); + + // Populate student filter + const filterEl = $('#grading-student-filter'); + const prevFilter = filterEl.value; + const seen = new Set(); + filterEl.innerHTML = '' + + allRows.filter((r) => { if (seen.has(r.studentId)) return false; seen.add(r.studentId); return true; }) + .map((r) => ``).join(''); + if (prevFilter) filterEl.value = prevFilter; + + const rows = filterEl.value ? allRows.filter((r) => String(r.studentId) === filterEl.value) : allRows; + $('#grading-empty').hidden = rows.length > 0; $('#grading-rows').innerHTML = rows .map((r) => { @@ -1814,7 +1827,6 @@ async function loadGrading() { document.querySelectorAll('[data-evidence-notes]').forEach((btn) => { btn.addEventListener('click', async () => { - // photo may be truncated in the attribute โ fetch full evidence via API const subId = btn.dataset.subId; let photo = null; if (btn.dataset.evidencePhoto === 'yes') { @@ -1825,22 +1837,29 @@ async function loadGrading() { }); }); - document.querySelectorAll('[data-save-grade]').forEach((btn) => { - btn.addEventListener('click', async () => { - const input = document.querySelector(`.grade-input[data-sub="${btn.dataset.saveGrade}"]`); - const commentInput = document.querySelector(`.comment-input[data-comment-sub="${btn.dataset.saveGrade}"]`); - if (input.value === '') return; - await api(`/api/submissions/${btn.dataset.saveGrade}/grade`, { - method: 'PUT', - body: { score: Number(input.value), parentComment: commentInput?.value || '' }, - }); - msg('Grade saved.'); - loadGrading(); - loadGradingBadge(); + async function saveGrade(subId) { + const input = document.querySelector(`.grade-input[data-sub="${subId}"]`); + const commentInput = document.querySelector(`.comment-input[data-comment-sub="${subId}"]`); + if (!input || input.value === '') return; + await api(`/api/submissions/${subId}/grade`, { + method: 'PUT', + body: { score: Number(input.value), parentComment: commentInput?.value || '', pointsPossible: Number(input.max) || 100 }, }); - }); + msg('Grade saved.'); + loadGrading(); + loadGradingBadge(); + } + + document.querySelectorAll('[data-save-grade]').forEach((btn) => + btn.addEventListener('click', () => saveGrade(btn.dataset.saveGrade)) + ); + document.querySelectorAll('.grade-input').forEach((input) => + input.addEventListener('keydown', (e) => { if (e.key === 'Enter') saveGrade(input.dataset.sub); }) + ); } +$('#grading-student-filter').addEventListener('change', loadGrading); + // ============================================================ // Gradebook // ============================================================ diff --git a/public/app.js b/public/app.js index 2929c7b..eb17b03 100644 --- a/public/app.js +++ b/public/app.js @@ -258,6 +258,28 @@ async function loadHome() { // ---------- kid home: Today / Courses / Spelling ---------- +let currentCourseItems = []; // flat [{id, type, title}] from most-recently opened course + +function findNextCourseItem(currentId) { + const idx = currentCourseItems.findIndex((it) => it.id === currentId); + if (idx === -1 || idx >= currentCourseItems.length - 1) return null; + return currentCourseItems[idx + 1]; +} + +function showNextActions(containerId, currentItemId) { + const next = findNextCourseItem(currentItemId); + const el = document.getElementById(containerId); + if (!el) return; + if (!next) { backTarget(); return; } + el.hidden = false; + el.innerHTML = ` + + + `; + document.getElementById('next-item-btn').addEventListener('click', () => { el.hidden = true; openItem(next.id, next.type); }); + document.getElementById('back-course-btn').addEventListener('click', () => { el.hidden = true; backTarget(); }); +} + document.querySelectorAll('.nav-pill').forEach((pill) => pill.addEventListener('click', () => switchTab(pill.dataset.tab)) ); @@ -902,6 +924,7 @@ function activeUnitIndex(units) { async function openCourse(courseId) { const course = await api(`/api/courses/${courseId}/detail?studentId=${currentStudent.id}`); + currentCourseItems = course.units.flatMap((u) => u.items.map((it) => ({ id: it.id, type: it.type, title: it.title }))); $('#course-title').textContent = course.name; const activeIdx = activeUnitIndex(course.units); $('#course-units').innerHTML = course.units @@ -992,12 +1015,15 @@ async function openLesson(itemId) { show('lesson'); const btn = $('#lesson-done-btn'); + const nextActions = $('#lesson-next-actions'); + nextActions.hidden = true; btn.textContent = item.submission ? 'โ Read' : 'Done reading โ'; btn.onclick = async () => { await api(`/api/items/${itemId}/complete`, { method: 'POST', body: { studentId: currentStudent.id, date: todayStr() } }); showMiniCelebration('๐ Lesson complete!'); await showDoneStamp(); - backTarget(); + btn.disabled = true; + showNextActions('lesson-next-actions', itemId); }; } @@ -1009,6 +1035,7 @@ async function openAssignment(itemId) { $('#assignment-photo-input').value = ''; $('#assignment-evidence-notes').value = ''; $('#assignment-student-note').value = ''; + $('#assignment-next-actions').hidden = true; const item = await api(`/api/items/${itemId}?studentId=${currentStudent.id}`); $('#assignment-kicker').textContent = `${item.course_name} ยท ${item.unit_name}`; @@ -1068,7 +1095,11 @@ async function openAssignment(itemId) { await api(`/api/items/${itemId}/complete`, { method: 'POST', body }); showMiniCelebration('๐ Turned in!'); await showDoneStamp(); - openAssignment(itemId); + btn.hidden = true; + status.hidden = false; + status.className = 'status-banner'; + status.textContent = 'โณ Turned in โ waiting for a parent to grade it.'; + showNextActions('assignment-next-actions', itemId); }; } show('assignment'); diff --git a/public/index.html b/public/index.html index db9d3fa..e5f7553 100644 --- a/public/index.html +++ b/public/index.html @@ -101,6 +101,7 @@ +