Files
2026-02-10 22:11:06 -05:00

254 lines
11 KiB
PHP

<?= $this->extend('layout/management_layout') ?>
<?= $this->section('content') ?>
<?php
$schoolYear = $schoolYear ?? '';
$students = $students ?? [];
$batches = $batches ?? [];
$batchDetails = $batchDetails ?? [];
$placementTest = $placementTest ?? '';
$showStudents = $showStudents ?? false;
?>
<div class="container-fluid">
<div class="d-flex flex-wrap align-items-center justify-content-between mb-3 gap-2">
<div>
<h2 class="mb-1">Placement Scores</h2>
<p class="text-muted mb-0">Select a placement test, enter scores, and save as a batch.</p>
</div>
<a href="<?= base_url('grading') ?>" class="btn btn-outline-secondary btn-sm">Back to grading</a>
</div>
<div class="card shadow-sm mb-4">
<div class="card-header bg-white">
<h5 class="mb-0">Choose placement test</h5>
</div>
<div class="card-body pt-2">
<form method="get" action="<?= base_url('grading/placement') ?>" class="row g-3 align-items-end">
<input type="hidden" name="open" value="1">
<div class="col-12 col-md-6 col-lg-5">
<label class="form-label">Choose placement test</label>
<select name="placement_test" class="form-select" required>
<option value="">Select a placement test</option>
<option value="islamic" <?= $placementTest === 'islamic' ? 'selected' : '' ?>>Islamic Studies</option>
<option value="quran" <?= $placementTest === 'quran' ? 'selected' : '' ?>>Quran</option>
<option value="arabic" <?= $placementTest === 'arabic' ? 'selected' : '' ?>>Arabic</option>
</select>
</div>
<div class="col-12 col-md-4 col-lg-3">
<label class="form-label">School Year</label>
<input type="text" name="school_year" class="form-control" value="<?= esc($schoolYear) ?>" placeholder="YYYY-YYYY" required>
</div>
<div class="col-12 col-md-2 col-lg-2 d-flex gap-2">
<button type="submit" class="btn btn-primary w-100">Set Placement Scores</button>
<a href="<?= base_url('grading/placement') ?>" class="btn btn-outline-secondary">Cancel</a>
</div>
</form>
<?php if ($showStudents && !empty($students)): ?>
<form method="post" action="<?= base_url('grading/placement-all') ?>" class="mt-3">
<?= csrf_field() ?>
<input type="hidden" name="placement_test" value="<?= esc($placementTest) ?>">
<input type="hidden" name="school_year" value="<?= esc($schoolYear) ?>">
<div class="table-responsive">
<table class="table table-bordered table-striped align-middle mt-2" data-sortable>
<thead class="table-light">
<tr>
<th data-sort-type="number">School ID</th>
<th data-sort-type="text">First Name</th>
<th data-sort-type="text">Last Name</th>
<th data-sort-type="text">Class Section</th>
<th data-sort-type="number" style="width: 160px;">Placement Score</th>
</tr>
</thead>
<tbody>
<?php foreach ($students as $student): ?>
<?php
$sid = (int) ($student['student_id'] ?? 0);
$sectionName = (string) ($student['class_section_name'] ?? '');
$className = (string) ($student['class_name'] ?? '');
$sectionLabel = $className !== '' ? ($className . ' — ' . $sectionName) : $sectionName;
?>
<tr>
<td><?= esc($student['school_id'] ?? '') ?></td>
<td><?= esc($student['firstname'] ?? '') ?></td>
<td><?= esc($student['lastname'] ?? '') ?></td>
<td><?= esc($sectionLabel ?: '—') ?></td>
<td>
<input type="number"
name="placement_level[<?= esc((string) $sid) ?>]"
class="form-control form-control-sm"
min="0"
max="100"
step="1"
value=""
placeholder="0-100">
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<div class="d-flex justify-content-end gap-2">
<a href="<?= base_url('grading/placement') ?>" class="btn btn-outline-secondary">Cancel</a>
<button type="submit" class="btn btn-primary">Save batch</button>
</div>
</form>
<?php endif; ?>
</div>
</div>
<div class="card shadow-sm">
<div class="card-header bg-white d-flex align-items-center justify-content-between">
<h5 class="mb-0">Placement batches</h5>
<span class="text-muted small"><?= count($batches) ?> batch<?= count($batches) === 1 ? '' : 'es' ?></span>
</div>
<div class="card-body pt-2">
<?php if (empty($batches)): ?>
<div class="alert alert-light border text-center mb-0">No placement batches yet.</div>
<?php else: ?>
<div class="table-responsive">
<table class="table table-bordered table-striped align-middle mt-2" data-no-mgmt-sticky>
<thead class="table-light">
<tr>
<th>Placement Test</th>
<th>School Year</th>
<th>Created</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($batches as $batch): ?>
<?php
$label = ucfirst((string) ($batch['placement_test'] ?? ''));
$createdAt = $batch['created_at'] ?? '';
$createdLabel = $createdAt ? date('M d, Y H:i', strtotime($createdAt)) : '';
$batchId = (int) ($batch['id'] ?? 0);
$detailRows = $batchDetails[$batchId] ?? [];
$collapseId = 'batch-' . $batchId;
?>
<tr>
<td>
<button class="btn btn-link p-0 text-decoration-none" type="button" data-bs-toggle="collapse" data-bs-target="#<?= esc($collapseId) ?>" aria-expanded="false" aria-controls="<?= esc($collapseId) ?>">
<?= esc($label) ?><?= $createdLabel ? ' — ' . esc($createdLabel) : '' ?>
</button>
</td>
<td><?= esc($batch['school_year'] ?? '') ?></td>
<td><?= esc($createdLabel) ?></td>
<td>
<a href="<?= base_url('grading/placement/batch/' . (int) $batch['id']) ?>" class="btn btn-sm btn-outline-primary">Edit</a>
</td>
</tr>
<tr class="collapse" id="<?= esc($collapseId) ?>">
<td colspan="4">
<?php if (empty($detailRows)): ?>
<div class="text-muted">No students with scores in this batch.</div>
<?php else: ?>
<div class="table-responsive">
<table class="table table-sm table-bordered align-middle mb-0" data-no-mgmt-sticky>
<thead class="table-light">
<tr>
<th>School ID</th>
<th>First Name</th>
<th>Last Name</th>
<th>Class Section</th>
<th>Score</th>
</tr>
</thead>
<tbody>
<?php foreach ($detailRows as $row): ?>
<?php
$sectionName = (string) ($row['class_section_name'] ?? '');
$className = (string) ($row['class_name'] ?? '');
$sectionLabel = $className !== '' ? ($className . ' — ' . $sectionName) : $sectionName;
?>
<tr>
<td><?= esc($row['school_id'] ?? '') ?></td>
<td><?= esc($row['firstname'] ?? '') ?></td>
<td><?= esc($row['lastname'] ?? '') ?></td>
<td><?= esc($sectionLabel ?: '—') ?></td>
<td><?= esc($row['score'] ?? '') ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
</div>
</div>
<?= $this->endSection() ?>
<?= $this->section('scripts') ?>
<script>
(() => {
const tables = document.querySelectorAll('table[data-sortable]');
tables.forEach((table) => {
const tbody = table.tBodies[0];
const headers = table.tHead ? Array.from(table.tHead.querySelectorAll('th')) : [];
if (!tbody || headers.length === 0) {
return;
}
const getCellValue = (cell) => {
const input = cell.querySelector('input');
if (input) {
return input.value.trim();
}
return cell.textContent.trim();
};
const parseValue = (value, type) => {
if (type === 'number') {
const num = parseFloat(value.replace(/[^0-9.\-]/g, ''));
return Number.isNaN(num) ? null : num;
}
return value.toLowerCase();
};
headers.forEach((th, index) => {
th.style.cursor = 'pointer';
th.setAttribute('role', 'button');
th.setAttribute('aria-sort', 'none');
th.addEventListener('click', () => {
const sortType = th.dataset.sortType || 'text';
const rows = Array.from(tbody.querySelectorAll('tr')).map((row, idx) => ({
row,
idx,
value: parseValue(getCellValue(row.children[index] || row.cells[index]), sortType),
}));
const current = th.getAttribute('aria-sort') || 'none';
const nextDir = current === 'ascending' ? 'descending' : 'ascending';
headers.forEach((h) => h.setAttribute('aria-sort', 'none'));
th.setAttribute('aria-sort', nextDir);
rows.sort((a, b) => {
if (a.value === b.value) {
return a.idx - b.idx;
}
if (a.value === null) return 1;
if (b.value === null) return -1;
if (a.value < b.value) return nextDir === 'ascending' ? -1 : 1;
return nextDir === 'ascending' ? 1 : -1;
});
const fragment = document.createDocumentFragment();
rows.forEach(({ row }) => fragment.appendChild(row));
tbody.appendChild(fragment);
});
});
});
})();
</script>
<?= $this->endSection() ?>