fix below 60 pages
This commit is contained in:
@@ -9,12 +9,12 @@
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-3 flex-wrap gap-2">
|
||||
<div class="text-muted">
|
||||
<?= !empty($isYearMode) ? 'Whole Year' : esc(ucfirst($semester ?? '')) ?> • <?= esc($schoolYear ?? '') ?>
|
||||
<?= !empty($isYearMode) ? 'Whole Year' : 'Fall' ?> • <?= esc($schoolYear ?? '') ?>
|
||||
</div>
|
||||
<div class="d-flex gap-2">
|
||||
<?php if (empty($isYearMode)): ?>
|
||||
<a class="btn btn-outline-primary btn-sm"
|
||||
href="<?= site_url('grading/below-60/decisions?' . http_build_query(['semester' => $semester ?? '', 'school_year' => $schoolYear ?? ''])) ?>">
|
||||
href="<?= site_url('grading/below-60/decisions?' . http_build_query(['semester' => 'fall', 'school_year' => $schoolYear ?? ''])) ?>">
|
||||
Decisions
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
@@ -36,6 +36,10 @@
|
||||
}
|
||||
return esc($value);
|
||||
};
|
||||
|
||||
// Fall mode displays Fall semester_score.
|
||||
// Whole Year mode displays the controller-provided annual score: (fall_score + spring_score) / 2.
|
||||
$actionSemester = !empty($isYearMode) ? 'year' : 'fall';
|
||||
?>
|
||||
|
||||
<?php if (empty($rows)): ?>
|
||||
@@ -49,20 +53,10 @@
|
||||
<tr>
|
||||
<th>Student Name</th>
|
||||
<th>Section</th>
|
||||
<?php if (!empty($isYearMode)): ?><th>Semester</th><?php endif; ?>
|
||||
<th>Hwk Avg</th>
|
||||
<th>Project Avg</th>
|
||||
<th>Participation</th>
|
||||
<th>Test Avg</th>
|
||||
<th>PTAP Score</th>
|
||||
<th>Attendance</th>
|
||||
<th>Midterm Score</th>
|
||||
<th><?= !empty($isYearMode) ? 'Semester Score' : (strcasecmp($semester ?? '', 'fall') === 0 ? '1st Semester Score' : 'Semester Score') ?></th>
|
||||
<?php if (empty($isYearMode)): ?>
|
||||
<th class="text-center">Score</th>
|
||||
<th>Status</th>
|
||||
<th>Email Parent</th>
|
||||
<th>Schedule Meeting</th>
|
||||
<?php endif; ?>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -79,29 +73,28 @@
|
||||
}
|
||||
}
|
||||
$studentName = trim((string)($row['firstname'] ?? '') . ' ' . (string)($row['lastname'] ?? ''));
|
||||
$studentLabel = $studentName !== '' ? $studentName : 'N/A';
|
||||
$isClosed = ($row['status'] ?? 'Open') === 'Closed';
|
||||
?>
|
||||
<?php $isClosed = ($row['status'] ?? 'Open') === 'Closed'; ?>
|
||||
<?php $rowSemester = ucfirst(strtolower(trim((string)($row['semester'] ?? ($semester ?? ''))))); ?>
|
||||
<tr class="<?= esc($scoreClass) ?>">
|
||||
<td><?= esc($studentName !== '' ? $studentName : 'N/A') ?></td>
|
||||
<td><?= esc($studentLabel) ?></td>
|
||||
<td><?= esc($row['class_section_name'] ?? '—') ?></td>
|
||||
<?php if (!empty($isYearMode)): ?>
|
||||
<td class="text-center"><?= esc($rowSemester) ?></td>
|
||||
<?php endif; ?>
|
||||
<td class="text-center"><?= $displayScore($row['homework_avg'] ?? null) ?></td>
|
||||
<td class="text-center"><?= $displayScore($row['project_avg'] ?? null) ?></td>
|
||||
<td class="text-center"><?= $displayScore($row['participation_score'] ?? null) ?></td>
|
||||
<td class="text-center"><?= $displayScore($row['test_avg'] ?? null) ?></td>
|
||||
<td class="text-center"><?= $displayScore($row['ptap_score'] ?? null) ?></td>
|
||||
<td class="text-center"><?= $displayScore($row['attendance_score'] ?? null) ?></td>
|
||||
<td class="text-center"><?= $displayScore($row['midterm_exam_score'] ?? null) ?></td>
|
||||
<td class="text-center"><?= $displayScore($row['semester_score'] ?? null) ?></td>
|
||||
<?php if (empty($isYearMode)): ?>
|
||||
<td class="text-center">
|
||||
<div class="fw-semibold"><?= $displayScore($scoreRaw) ?></div>
|
||||
<button type="button"
|
||||
class="btn btn-outline-secondary btn-xs mt-1 btn-show-details"
|
||||
style="font-size:0.72rem;padding:1px 7px;"
|
||||
data-student-id="<?= (int)($row['student_id'] ?? 0) ?>"
|
||||
data-student-name="<?= esc($studentLabel) ?>"
|
||||
data-school-year="<?= esc((string)($schoolYear ?? '')) ?>">
|
||||
Details
|
||||
</button>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<form method="post" action="<?= site_url('grading/below-60/status') ?>" class="d-flex align-items-center gap-2 justify-content-center">
|
||||
<?= csrf_field() ?>
|
||||
<input type="hidden" name="student_id" value="<?= esc((string)($row['student_id'] ?? '')) ?>">
|
||||
<input type="hidden" name="semester" value="<?= esc((string)($semester ?? '')) ?>">
|
||||
<input type="hidden" name="semester" value="<?= esc($actionSemester) ?>">
|
||||
<input type="hidden" name="school_year" value="<?= esc((string)($schoolYear ?? '')) ?>">
|
||||
<select name="status" class="form-select form-select-sm" style="width: 110px;">
|
||||
<option value="Open" <?= ($row['status'] ?? 'Open') === 'Open' ? 'selected' : '' ?>>Open</option>
|
||||
@@ -116,7 +109,7 @@
|
||||
<button type="button" class="btn btn-sm btn-secondary" disabled>Send Email</button>
|
||||
<?php else: ?>
|
||||
<a class="btn btn-sm btn-outline-primary"
|
||||
href="<?= site_url('grading/below-60/email/edit?student_id=' . (int)($row['student_id'] ?? 0) . '&semester=' . rawurlencode((string)($semester ?? '')) . '&school_year=' . rawurlencode((string)($schoolYear ?? ''))) ?>">
|
||||
href="<?= site_url('grading/below-60/email/edit?student_id=' . (int)($row['student_id'] ?? 0) . '&semester=' . rawurlencode($actionSemester) . '&school_year=' . rawurlencode((string)($schoolYear ?? ''))) ?>">
|
||||
Send Email
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
@@ -126,12 +119,11 @@
|
||||
<button class="btn btn-sm btn-secondary" disabled>Schedule</button>
|
||||
<?php else: ?>
|
||||
<a class="btn btn-sm btn-outline-secondary"
|
||||
href="<?= site_url('grading/below-60/schedule?student_id=' . (int)($row['student_id'] ?? 0) . '&semester=' . rawurlencode((string)($semester ?? '')) . '&school_year=' . rawurlencode((string)($schoolYear ?? ''))) ?>">
|
||||
href="<?= site_url('grading/below-60/schedule?student_id=' . (int)($row['student_id'] ?? 0) . '&semester=' . rawurlencode($actionSemester) . '&school_year=' . rawurlencode((string)($schoolYear ?? ''))) ?>">
|
||||
Schedule
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<?php endif; ?>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
@@ -141,6 +133,26 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Score details modal -->
|
||||
<div class="modal fade" id="detailsModal" tabindex="-1" aria-labelledby="detailsModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg modal-dialog-scrollable">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="detailsModalLabel">Score Details</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body" id="detailsModalBody">
|
||||
<div class="text-center py-4">
|
||||
<div class="spinner-border text-primary" role="status"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
<?= $this->section('scripts') ?>
|
||||
@@ -150,22 +162,176 @@
|
||||
.below-sixty-wrapper { padding-top: 0.75rem; }
|
||||
.below-sixty-title { position: relative; z-index: 1; margin-bottom: 1.25rem; }
|
||||
.below-sixty-table { margin-top: 0.75rem; }
|
||||
.below-sixty-dt td { vertical-align: top; }
|
||||
</style>
|
||||
<script>
|
||||
(function() {
|
||||
if (!window.$ || !$.fn || !$.fn.DataTable) return;
|
||||
$(function() {
|
||||
const table = $('.below-sixty-dt');
|
||||
if (!table.length) return;
|
||||
try {
|
||||
const semesterOffset = <?= !empty($isYearMode) ? '1' : '0' ?>;
|
||||
table.DataTable({
|
||||
order: [[8 + semesterOffset, 'asc']],
|
||||
pageLength: 100,
|
||||
lengthMenu: [10, 25, 50, 100, 200]
|
||||
function normalizeSemesterFilter() {
|
||||
const semesterSelect = document.querySelector('select[name="semester"]');
|
||||
if (!semesterSelect) return;
|
||||
|
||||
const wholeYearSelected = <?= !empty($isYearMode) ? 'true' : 'false' ?>;
|
||||
semesterSelect.innerHTML = '';
|
||||
semesterSelect.add(new Option('Fall', 'fall', !wholeYearSelected, !wholeYearSelected));
|
||||
semesterSelect.add(new Option('Whole Year', 'year', wholeYearSelected, wholeYearSelected));
|
||||
semesterSelect.value = wholeYearSelected ? 'year' : 'fall';
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', normalizeSemesterFilter);
|
||||
|
||||
if (window.$ && $.fn && $.fn.DataTable) {
|
||||
$(function() {
|
||||
const table = $('.below-sixty-dt');
|
||||
if (!table.length) return;
|
||||
try {
|
||||
table.DataTable({
|
||||
order: [[2, 'asc']],
|
||||
pageLength: 100,
|
||||
lengthMenu: [10, 25, 50, 100, 200],
|
||||
columnDefs: [{ orderable: false, targets: [3, 4, 5] }]
|
||||
});
|
||||
} catch (_) {}
|
||||
});
|
||||
}
|
||||
|
||||
const detailsModal = document.getElementById('detailsModal');
|
||||
const detailsModalBody = document.getElementById('detailsModalBody');
|
||||
const detailsModalTitle = document.getElementById('detailsModalLabel');
|
||||
|
||||
const SCORE_LABELS = {
|
||||
homework_avg: 'Homework Avg',
|
||||
project_avg: 'Project Avg',
|
||||
participation_score: 'Participation',
|
||||
test_avg: 'Test Avg',
|
||||
ptap_score: 'PTAP Score',
|
||||
attendance_score: 'Attendance',
|
||||
midterm_exam_score: 'Midterm Score',
|
||||
final_exam_score: 'Final Exam',
|
||||
semester_score: 'Semester Score'
|
||||
};
|
||||
|
||||
const COMMENT_TYPE_LABELS = {
|
||||
general: 'General',
|
||||
attendance: 'Attendance',
|
||||
attendance_comment: 'Attendance',
|
||||
midterm: 'Midterm',
|
||||
final: 'Final Exam',
|
||||
ptap: 'PTAP'
|
||||
};
|
||||
|
||||
function fmtScore(value) {
|
||||
if (value === null || value === '' || value === undefined) return '—';
|
||||
const parsed = parseFloat(value);
|
||||
return isNaN(parsed) ? value : parsed.toFixed(2);
|
||||
}
|
||||
|
||||
function esc(str) {
|
||||
return String(str)
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"');
|
||||
}
|
||||
|
||||
function buildDetailsHtml(semesters) {
|
||||
if (!semesters || semesters.length === 0) {
|
||||
return '<div class="alert alert-warning mb-0">No score data found.</div>';
|
||||
}
|
||||
|
||||
let html = '';
|
||||
semesters.forEach(function(sem) {
|
||||
html += '<h6 class="fw-bold mt-3 mb-2">' + esc(sem.semester || '') + ' Semester';
|
||||
if (sem.class_section_name) {
|
||||
html += ' <span class="text-muted fw-normal fs-6">— ' + esc(sem.class_section_name) + '</span>';
|
||||
}
|
||||
html += '</h6>';
|
||||
|
||||
html += '<table class="table table-sm table-bordered mb-2">';
|
||||
html += '<thead class="table-light"><tr><th>Item</th><th class="text-center">Score</th></tr></thead><tbody>';
|
||||
|
||||
let hasScoreRow = false;
|
||||
Object.entries(SCORE_LABELS).forEach(function(entry) {
|
||||
const key = entry[0];
|
||||
const label = entry[1];
|
||||
const value = sem[key];
|
||||
if (value === null || value === '' || value === undefined) return;
|
||||
const bold = key === 'semester_score' ? ' fw-bold' : '';
|
||||
html += '<tr><td>' + esc(label) + '</td><td class="text-center' + bold + '">' + esc(fmtScore(value)) + '</td></tr>';
|
||||
hasScoreRow = true;
|
||||
});
|
||||
} catch (_) {}
|
||||
});
|
||||
|
||||
if (!hasScoreRow) {
|
||||
html += '<tr><td colspan="2" class="text-muted">No scores recorded.</td></tr>';
|
||||
}
|
||||
html += '</tbody></table>';
|
||||
|
||||
const comments = sem.comments || {};
|
||||
const commentEntries = Object.entries(comments).filter(function(entry) {
|
||||
return entry[1] && String(entry[1]).trim();
|
||||
});
|
||||
|
||||
const seen = {};
|
||||
const deduped = [];
|
||||
commentEntries.forEach(function(entry) {
|
||||
const type = entry[0];
|
||||
const text = String(entry[1]);
|
||||
const label = COMMENT_TYPE_LABELS[type] || type;
|
||||
const key = label + '|' + text.trim();
|
||||
if (!seen[key]) {
|
||||
seen[key] = true;
|
||||
deduped.push([label, text]);
|
||||
}
|
||||
});
|
||||
|
||||
if (deduped.length > 0) {
|
||||
html += '<div class="mb-3">';
|
||||
html += '<p class="fw-semibold mb-1" style="font-size:0.9rem;">Comments</p>';
|
||||
deduped.forEach(function(entry) {
|
||||
const label = entry[0];
|
||||
const text = entry[1];
|
||||
html += '<div class="mb-2 p-2 bg-light rounded border-start border-3 border-secondary">';
|
||||
html += '<span class="badge bg-secondary me-1" style="font-size:0.7rem;">' + esc(label) + '</span>';
|
||||
html += '<span class="text-dark" style="font-size:0.9rem;">' + esc(text).replace(/\n/g, '<br>') + '</span>';
|
||||
html += '</div>';
|
||||
});
|
||||
html += '</div>';
|
||||
}
|
||||
});
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
if (detailsModal) {
|
||||
document.addEventListener('click', function(e) {
|
||||
const btn = e.target.closest('.btn-show-details');
|
||||
if (!btn) return;
|
||||
|
||||
const studentId = btn.dataset.studentId;
|
||||
const studentName = btn.dataset.studentName;
|
||||
const schoolYear = btn.dataset.schoolYear;
|
||||
|
||||
detailsModalTitle.textContent = studentName + ' — Score Details';
|
||||
detailsModalBody.innerHTML = '<div class="text-center py-4"><div class="spinner-border text-primary" role="status"></div></div>';
|
||||
bootstrap.Modal.getOrCreateInstance(detailsModal).show();
|
||||
|
||||
const url = '<?= site_url('grading/below-60/decisions/student-details') ?>'
|
||||
+ '?student_id=' + encodeURIComponent(studentId)
|
||||
+ '&school_year=' + encodeURIComponent(schoolYear);
|
||||
|
||||
fetch(url, { headers: { 'X-Requested-With': 'XMLHttpRequest' } })
|
||||
.then(function(response) { return response.json(); })
|
||||
.then(function(data) {
|
||||
if (data.error) {
|
||||
detailsModalBody.innerHTML = '<div class="alert alert-danger">' + esc(data.error) + '</div>';
|
||||
return;
|
||||
}
|
||||
detailsModalBody.innerHTML = buildDetailsHtml(data.semesters);
|
||||
})
|
||||
.catch(function() {
|
||||
detailsModalBody.innerHTML = '<div class="alert alert-danger">Failed to load details.</div>';
|
||||
});
|
||||
});
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
Reference in New Issue
Block a user