AVP-78 Feature to check if parents looked at report card

This commit is contained in:
root
2026-02-27 01:21:39 -05:00
parent fe7b99581d
commit 3cc5546733
37 changed files with 743 additions and 107 deletions
+44 -1
View File
@@ -48,6 +48,7 @@
<a id="downloadStudentBtn" href="#" class="btn btn-success external-link" target="_blank">Download</a>
</div>
</div>
<div class="text-muted small text-center" id="ackStatus"></div>
</form>
<div class="card shadow-sm mb-3">
@@ -67,10 +68,12 @@
<table class="table table-sm table-bordered align-middle mb-0">
<thead class="table-light">
<tr>
<th style="width: 35%;">Student</th>
<th style="width: 28%;">Student</th>
<th style="width: 15%;">Status</th>
<th>Missing</th>
<th>Warnings</th>
<th style="width: 16%;">Viewed</th>
<th style="width: 16%;">Signed</th>
</tr>
</thead>
<tbody id="completenessBody"></tbody>
@@ -91,6 +94,7 @@
document.addEventListener('DOMContentLoaded', function(){
const API = <?= json_encode(site_url('api/printables/report-card/meta')) ?>;
const COMPLETENESS_API = <?= json_encode(site_url('api/printables/report-card/completeness')) ?>;
const ACK_API = <?= json_encode(site_url('api/printables/report-card/ack')) ?>;
// add cache-busting cb param
const withCB = (u) => u + (u.includes('?') ? '&' : '?') + 'cb=' + Date.now();
@@ -119,6 +123,7 @@ document.addEventListener('DOMContentLoaded', function(){
const $completenessSummary = document.getElementById('completenessSummary');
const $completenessWrap = document.getElementById('completenessTableWrap');
const $completenessBody = document.getElementById('completenessBody');
const $ackStatus = document.getElementById('ackStatus');
function opt(el, val, label) {
const o = document.createElement('option'); o.value = String(val); o.textContent = label; el.appendChild(o);
@@ -157,10 +162,40 @@ document.addEventListener('DOMContentLoaded', function(){
// Classes
$class.innerHTML = '';
(data.classSections || []).forEach(c => opt($class, c.class_section_id || c.id, c.class_section_name));
updateAckStatus();
}
async function updateAckStatus() {
if (! $ackStatus) return;
const sid = $student.value;
const y = $year.value || '';
const s = $sem.value || '';
if (!sid) {
$ackStatus.textContent = '';
return;
}
try {
const url = `${ACK_API}?student_id=${encodeURIComponent(sid)}&school_year=${encodeURIComponent(y)}&semester=${encodeURIComponent(s)}`;
const res = await fetch(url, { credentials: 'same-origin' });
const data = await res.json();
if (!res.ok || data?.ok === false) {
$ackStatus.textContent = 'Parent acknowledgement: unavailable';
return;
}
const viewed = data.viewed_at ? `Viewed: ${data.viewed_at}` : 'Viewed: not yet';
const signed = data.signed_at
? `Signed: ${data.signed_at} (${data.signed_name || 'name missing'})`
: 'Signed: not yet';
$ackStatus.textContent = `Parent acknowledgement — ${viewed} · ${signed}`;
} catch (err) {
$ackStatus.textContent = 'Parent acknowledgement: unavailable';
}
}
$year.addEventListener('change', function(){ loadMeta(this.value, $sem.value).catch(console.error); });
$sem.addEventListener('change', function(){ loadMeta($year.value, this.value).catch(console.error); });
$student.addEventListener('change', function(){ updateAckStatus(); });
$viewS.addEventListener('click', function(){
const sid = $student.value; const y = $year.value; const s=$sem.value;
@@ -254,10 +289,18 @@ document.addEventListener('DOMContentLoaded', function(){
tdMissing.textContent = missing.length ? missing.join(', ') : 'None';
const tdWarnings = document.createElement('td');
tdWarnings.textContent = warningsList.length ? warningsList.join(', ') : 'None';
const tdViewed = document.createElement('td');
tdViewed.textContent = row.viewed_at ? row.viewed_at : 'Not viewed';
const tdSigned = document.createElement('td');
tdSigned.textContent = row.signed_at
? `${row.signed_at}${row.signed_name ? ` (${row.signed_name})` : ''}`
: 'Not signed';
tr.appendChild(tdName);
tr.appendChild(tdStatus);
tr.appendChild(tdMissing);
tr.appendChild(tdWarnings);
tr.appendChild(tdViewed);
tr.appendChild(tdSigned);
$completenessBody.appendChild(tr);
});
$completenessWrap.hidden = false;