235 lines
12 KiB
PHP
Executable File
235 lines
12 KiB
PHP
Executable File
<?= $this->extend('layout/management_layout') ?>
|
|
<?= $this->section('content') ?>
|
|
|
|
<?php
|
|
// Helpers for labels
|
|
$labelFor = function (int $cid): string {
|
|
if ($cid === 13) return 'KG';
|
|
if ($cid === 12) return 'Youth';
|
|
if ($cid >= 1 && $cid <= 11) return 'Grade ' . $cid;
|
|
return 'Class ' . $cid;
|
|
};
|
|
|
|
// Pre-format header dates for display
|
|
$headerDates = array_map(function ($ymd) {
|
|
$dt = \DateTime::createFromFormat('Y-m-d', $ymd, new \DateTimeZone('UTC'));
|
|
return $dt ? $dt->format('m-d-Y') : $ymd;
|
|
}, $sundays ?? []);
|
|
$todayYmd = local_date(utc_now(), 'Y-m-d');
|
|
?>
|
|
|
|
<div class="container-fluid py-3">
|
|
<div class="px-3">
|
|
<div class="d-flex justify-content-between align-items-center mb-3 flex-wrap gap-2">
|
|
<h2 class="text-center mt-4 mb-3">Homework Tracking</h2>
|
|
<div class="text-muted"><?= esc(ucfirst($semester ?? '')) ?> • <?= esc($schoolYear ?? '') ?></div>
|
|
</div>
|
|
|
|
<div class="mb-2 small">
|
|
<span class="badge text-bg-success">Entered</span>
|
|
<span class="badge text-bg-danger">Missing</span>
|
|
<span class="badge text-bg-warning">No School</span>
|
|
<span class="badge bg-future text-dark border">Future</span>
|
|
</div>
|
|
|
|
<?php if (empty($teachers)): ?>
|
|
<div class="alert alert-light border">No teacher assignments found for the current term.</div>
|
|
<?php else: ?>
|
|
<?php
|
|
$page = max(1, (int)($page ?? 1));
|
|
$totalPages = max(1, (int)($totalPages ?? 1));
|
|
$baseUrl = base_url('grading/homework-tracking');
|
|
$mkHref = function($p) use ($baseUrl) { return $baseUrl . '?page=' . (int)$p; };
|
|
?>
|
|
|
|
<div class="d-flex justify-content-end mb-2 gap-2">
|
|
<div class="btn-group" role="group" aria-label="Pagination top">
|
|
<a class="btn btn-outline-secondary <?= $page <= 1 ? 'disabled' : '' ?>" href="<?= $mkHref(1) ?>">First</a>
|
|
<a class="btn btn-outline-secondary <?= $page <= 1 ? 'disabled' : '' ?>" href="<?= $mkHref(max(1, $page-1)) ?>">Prev</a>
|
|
<span class="btn btn-outline-secondary disabled">Page <?= $page ?> / <?= $totalPages ?></span>
|
|
<a class="btn btn-outline-secondary <?= $page >= $totalPages ? 'disabled' : '' ?>" href="<?= $mkHref(min($totalPages, $page+1)) ?>">Next</a>
|
|
<a class="btn btn-outline-secondary <?= $page >= $totalPages ? 'disabled' : '' ?>" href="<?= $mkHref($totalPages) ?>">Last</a>
|
|
</div>
|
|
</div>
|
|
<?= $this->section('styles') ?>
|
|
<style>
|
|
/* Header is handled by JS polyfill to avoid covering content; keep a light bg */
|
|
.table-sticky thead th { background: var(--bs-light, #f8f9fa) !important; }
|
|
.table-sticky .sticky-col { position: sticky; left: 0; z-index: 5; background: var(--bs-table-bg, #fff); }
|
|
/* Use a CSS variable for the second sticky column's left offset so it can adapt to content width */
|
|
.table-sticky .sticky-col-2 { position: sticky; left: var(--sticky-left-2, 240px); z-index: 5; background: var(--bs-table-bg, #fff); }
|
|
.table-sticky th.sticky-col, .table-sticky th.sticky-col-2 { z-index: 8; }
|
|
.table-sticky td, .table-sticky th { white-space: nowrap; }
|
|
.bg-future { background-color: #e7f1ff !important; }
|
|
</style>
|
|
<?= $this->endSection() ?>
|
|
|
|
<div class="table-responsive">
|
|
<table id="homeworkTrackTable" class="table table-bordered align-middle table-sticky no-mgmt-sticky">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th class="sticky-col">Grade</th>
|
|
<th class="sticky-col-2" style="min-width:300px; width:300px;">Teacher & TAs</th>
|
|
<th class="text-center">HW Submitted</th>
|
|
<?php foreach (($headerDates ?? []) as $i => $label): $ymd = $sundays[$i] ?? ''; ?>
|
|
<?php $isCal = !empty($eventDays[$ymd]); $isFuture = ($ymd > $todayYmd); ?>
|
|
<th class="text-center <?= $isCal ? 'bg-warning' : ($isFuture ? 'bg-future' : '') ?>" title="<?= esc($ymd) ?>"><?= esc($label) ?></th>
|
|
<?php endforeach; ?>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($teachers as $row): ?>
|
|
<?php
|
|
$cid = (int)($row['class_id'] ?? 0);
|
|
$csid = (int)($row['class_section_id'] ?? 0);
|
|
$cname = (string)($row['class_section_name'] ?? '');
|
|
$teacherNames = (array)($row['teachers'] ?? []);
|
|
$taNames = (array)($row['tas'] ?? []);
|
|
?>
|
|
<tr>
|
|
<td class="sticky-col" style="background: var(--bs-table-bg, #fff);">
|
|
<?= esc($labelFor($cid)) ?>
|
|
<?php if (!empty($cname)): ?>
|
|
<div class="text-muted small">Section: <?= esc($cname) ?></div>
|
|
<?php endif; ?>
|
|
</td>
|
|
<td class="sticky-col-2" style="min-width:300px; width:300px; background: var(--bs-table-bg, #fff);">
|
|
<?php if (!empty($teacherNames)): ?>
|
|
<div><strong>Teacher<?= count($teacherNames) > 1 ? 's' : '' ?>:</strong> <?= esc(implode(', ', $teacherNames)) ?></div>
|
|
<?php else: ?>
|
|
<div><strong>Teacher:</strong> N/A</div>
|
|
<?php endif; ?>
|
|
<div><strong>TA<?= count($taNames) !== 1 ? 's' : '' ?>:</strong> <?= !empty($taNames) ? esc(implode(', ', $taNames)) : '—' ?></div>
|
|
</td>
|
|
<td class="text-center">
|
|
<?= (int)($homeworkSubmissionCounts[$csid] ?? 0) ?>
|
|
</td>
|
|
<?php foreach (($sundays ?? []) as $ymd): ?>
|
|
<?php if (!empty($eventDays[$ymd])): ?>
|
|
<td class="bg-warning text-center">—</td>
|
|
<?php else: ?>
|
|
<?php $isFuture = ($ymd > $todayYmd); ?>
|
|
<?php if ($isFuture): ?>
|
|
<td class="text-center bg-future">—</td>
|
|
<?php else: ?>
|
|
<?php $ok = !empty($hasHomeworkByDate[$csid][$ymd] ?? null); ?>
|
|
<?php if ($ok): ?>
|
|
<?php
|
|
$rawDate = $hwEnteredAtByDate[$csid][$ymd] ?? '';
|
|
$disp = '';
|
|
if ($rawDate) { $disp = local_date($rawDate, 'm-d-Y'); }
|
|
?>
|
|
<td class="text-center text-white" style="background-color:#198754;"><?= esc($disp ?: '✓') ?></td>
|
|
<?php else: ?>
|
|
<td class="text-center text-white" style="background-color:#dc3545;">✖</td>
|
|
<?php endif; ?>
|
|
<?php endif; ?>
|
|
<?php endif; ?>
|
|
<?php endforeach; ?>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<?= $this->section('scripts') ?>
|
|
<script>
|
|
(function(){
|
|
function updateStickyOffsets(){
|
|
document.querySelectorAll('table.table-sticky').forEach(function(tbl){
|
|
const firstHeader = tbl.querySelector('thead th.sticky-col');
|
|
const firstCell = tbl.querySelector('tbody td.sticky-col');
|
|
const ref = firstHeader || firstCell;
|
|
if (!ref) return;
|
|
const width = ref.offsetWidth || ref.getBoundingClientRect().width || 240;
|
|
tbl.style.setProperty('--sticky-left-2', width + 'px');
|
|
});
|
|
}
|
|
window.addEventListener('load', updateStickyOffsets);
|
|
window.addEventListener('resize', updateStickyOffsets);
|
|
})();
|
|
</script>
|
|
<script>
|
|
// JS sticky header polyfill for homework tracking
|
|
(function(){
|
|
function getFixedHeaderOffset(){
|
|
var total = 0;
|
|
try {
|
|
var sels = ['header.navbar.sticky-top','header.navbar.fixed-top','#navbarManagement.navbar.sticky-top','#navbarManagement.navbar.fixed-top'];
|
|
var seen = [];
|
|
sels.forEach(function(s){ document.querySelectorAll(s).forEach(function(el){ if (seen.indexOf(el) === -1) seen.push(el); }); });
|
|
document.querySelectorAll('.navbar.sticky-top, .navbar.fixed-top').forEach(function(el){ if (seen.indexOf(el) === -1) seen.push(el); });
|
|
seen.forEach(function(el){ var h = el.offsetHeight || (el.getBoundingClientRect && el.getBoundingClientRect().height) || 0; total += Math.max(0, Math.round(h)); });
|
|
} catch(_) {}
|
|
return total;
|
|
}
|
|
function installStickyPolyfill(tbl){
|
|
if (!tbl || tbl.dataset.stickyPolyfill === '1') return;
|
|
var thead = tbl.tHead; if (!thead) return;
|
|
var cloneTable = document.createElement('table');
|
|
cloneTable.className = tbl.className;
|
|
cloneTable.style.position = 'fixed';
|
|
cloneTable.style.top = getFixedHeaderOffset() + 'px';
|
|
cloneTable.style.left = '0px';
|
|
cloneTable.style.zIndex = '1045';
|
|
cloneTable.style.display = 'none';
|
|
cloneTable.style.background = 'var(--bs-light, #f8f9fa)';
|
|
cloneTable.style.borderCollapse = 'separate';
|
|
var cloneThead = thead.cloneNode(true);
|
|
cloneTable.appendChild(cloneThead);
|
|
document.body.appendChild(cloneTable);
|
|
|
|
function syncSizes(){
|
|
var rect = tbl.getBoundingClientRect();
|
|
var width = Math.round(rect.width);
|
|
cloneTable.style.width = width + 'px';
|
|
var origThs = thead.querySelectorAll('tr:first-child th');
|
|
var cloneThs = cloneThead.querySelectorAll('tr:first-child th');
|
|
for (var i=0; i<cloneThs.length; i++){
|
|
var w = (origThs[i] && origThs[i].getBoundingClientRect().width) || 0;
|
|
cloneThs[i].style.width = Math.round(w) + 'px';
|
|
}
|
|
}
|
|
function update(){
|
|
var rect = tbl.getBoundingClientRect();
|
|
var off = getFixedHeaderOffset();
|
|
var headH = (thead.getBoundingClientRect && thead.getBoundingClientRect().height) || 40;
|
|
if (rect.top < off && rect.bottom > off + headH){
|
|
syncSizes();
|
|
cloneTable.style.left = Math.round(rect.left) + 'px';
|
|
cloneTable.style.top = off + 'px';
|
|
cloneTable.style.display = '';
|
|
} else {
|
|
cloneTable.style.display = 'none';
|
|
}
|
|
}
|
|
window.addEventListener('scroll', update, { passive: true });
|
|
window.addEventListener('resize', function(){ syncSizes(); update(); });
|
|
setTimeout(function(){ syncSizes(); update(); }, 300);
|
|
tbl.dataset.stickyPolyfill = '1';
|
|
}
|
|
document.addEventListener('DOMContentLoaded', function(){
|
|
var tbl = document.getElementById('homeworkTrackTable');
|
|
if (tbl) installStickyPolyfill(tbl);
|
|
});
|
|
})();
|
|
</script>
|
|
<?= $this->endSection() ?>
|
|
|
|
<div class="d-flex justify-content-end mt-2 gap-2">
|
|
<div class="btn-group" role="group" aria-label="Pagination bottom">
|
|
<a class="btn btn-outline-secondary <?= $page <= 1 ? 'disabled' : '' ?>" href="<?= $mkHref(1) ?>">First</a>
|
|
<a class="btn btn-outline-secondary <?= $page <= 1 ? 'disabled' : '' ?>" href="<?= $mkHref(max(1, $page-1)) ?>">Prev</a>
|
|
<span class="btn btn-outline-secondary disabled">Page <?= $page ?> / <?= $totalPages ?></span>
|
|
<a class="btn btn-outline-secondary <?= $page >= $totalPages ? 'disabled' : '' ?>" href="<?= $mkHref(min($totalPages, $page+1)) ?>">Next</a>
|
|
<a class="btn btn-outline-secondary <?= $page >= $totalPages ? 'disabled' : '' ?>" href="<?= $mkHref($totalPages) ?>">Last</a>
|
|
</div>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
<div class="mt-2 small text-muted">Dates are Sundays within the current school term. Yellow indicates a No School day; light blue indicates a future Sunday.</div>
|
|
<div class="small text-muted">Homework indices are mapped in order to non-event Sundays.</div>
|
|
</div>
|
|
|
|
<?= $this->endSection() ?>
|