fix decisions and rank
This commit is contained in:
+294
-183
@@ -11,13 +11,18 @@
|
||||
<div class="text-muted">
|
||||
<?= !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' => 'fall', 'school_year' => $schoolYear ?? ''])) ?>">
|
||||
Decisions
|
||||
</a>
|
||||
<?php if (!empty($isYearMode)): ?>
|
||||
<a class="btn btn-outline-primary btn-sm"
|
||||
href="<?= site_url('grading/below-60/decisions?' . http_build_query([
|
||||
'semester' => 'year',
|
||||
'school_year' => $schoolYear ?? '',
|
||||
])) ?>">
|
||||
Decisions
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($canViewGrading)): ?>
|
||||
<a class="btn btn-outline-secondary btn-sm" href="<?= base_url('grading') ?>">
|
||||
Back to Grading
|
||||
@@ -31,14 +36,16 @@
|
||||
if ($value === null || $value === '') {
|
||||
return '—';
|
||||
}
|
||||
|
||||
if (is_numeric($value)) {
|
||||
return esc(number_format((float)$value, 2, '.', ''));
|
||||
}
|
||||
|
||||
return esc($value);
|
||||
};
|
||||
|
||||
// Fall mode displays Fall semester_score.
|
||||
// Whole Year mode displays the controller-provided annual score: (fall_score + spring_score) / 2.
|
||||
// Fall mode uses Fall.
|
||||
// Whole Year mode uses year.
|
||||
$actionSemester = !empty($isYearMode) ? 'year' : 'fall';
|
||||
?>
|
||||
|
||||
@@ -48,7 +55,9 @@
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="table-responsive below-sixty-table">
|
||||
<table class="table table-bordered table-striped align-middle w-100 no-mgmt-sticky below-sixty-dt" data-no-mgmt-sticky data-no-dt-fixedheader>
|
||||
<table class="table table-bordered table-striped align-middle w-100 no-mgmt-sticky below-sixty-dt"
|
||||
data-no-mgmt-sticky
|
||||
data-no-dt-fixedheader>
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Student Name</th>
|
||||
@@ -59,12 +68,15 @@
|
||||
<th>Schedule Meeting</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<?php foreach ($rows as $row): ?>
|
||||
<?php
|
||||
$scoreRaw = $row['semester_score'] ?? null;
|
||||
$scoreVal = is_numeric($scoreRaw) ? (float)$scoreRaw : null;
|
||||
|
||||
$scoreClass = '';
|
||||
|
||||
if ($scoreVal !== null) {
|
||||
if ($scoreVal < 50) {
|
||||
$scoreClass = 'grade-red';
|
||||
@@ -72,15 +84,19 @@
|
||||
$scoreClass = 'grade-orange';
|
||||
}
|
||||
}
|
||||
$studentName = trim((string)($row['firstname'] ?? '') . ' ' . (string)($row['lastname'] ?? ''));
|
||||
|
||||
$studentName = trim((string)($row['firstname'] ?? '') . ' ' . (string)($row['lastname'] ?? ''));
|
||||
$studentLabel = $studentName !== '' ? $studentName : 'N/A';
|
||||
$isClosed = ($row['status'] ?? 'Open') === 'Closed';
|
||||
$isClosed = ($row['status'] ?? 'Open') === 'Closed';
|
||||
?>
|
||||
|
||||
<tr class="<?= esc($scoreClass) ?>">
|
||||
<td><?= esc($studentLabel) ?></td>
|
||||
<td><?= esc($row['class_section_name'] ?? '—') ?></td>
|
||||
|
||||
<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;"
|
||||
@@ -90,23 +106,54 @@
|
||||
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">
|
||||
<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($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>
|
||||
<option value="Closed" <?= ($row['status'] ?? '') === 'Closed' ? 'selected' : '' ?>>Closed</option>
|
||||
|
||||
<input type="hidden"
|
||||
name="student_id"
|
||||
value="<?= esc((string)($row['student_id'] ?? '')) ?>">
|
||||
|
||||
<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>
|
||||
<option value="Closed" <?= ($row['status'] ?? '') === 'Closed' ? 'selected' : '' ?>>
|
||||
Closed
|
||||
</option>
|
||||
</select>
|
||||
<input type="text" name="note" class="form-control form-control-sm" style="width: 140px;" placeholder="Note (optional)" value="<?= esc((string)($row['note'] ?? '')) ?>">
|
||||
<button type="submit" class="btn btn-sm btn-outline-secondary">Update</button>
|
||||
|
||||
<input type="text"
|
||||
name="note"
|
||||
class="form-control form-control-sm"
|
||||
style="width: 140px;"
|
||||
placeholder="Note (optional)"
|
||||
value="<?= esc((string)($row['note'] ?? '')) ?>">
|
||||
|
||||
<button type="submit" class="btn btn-sm btn-outline-secondary">
|
||||
Update
|
||||
</button>
|
||||
</form>
|
||||
</td>
|
||||
|
||||
<td class="text-center">
|
||||
<?php if ($isClosed): ?>
|
||||
<button type="button" class="btn btn-sm btn-secondary" disabled>Send Email</button>
|
||||
<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($actionSemester) . '&school_year=' . rawurlencode((string)($schoolYear ?? ''))) ?>">
|
||||
@@ -114,9 +161,12 @@
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
|
||||
<td class="text-center">
|
||||
<?php if ($isClosed): ?>
|
||||
<button class="btn btn-sm btn-secondary" disabled>Schedule</button>
|
||||
<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($actionSemester) . '&school_year=' . rawurlencode((string)($schoolYear ?? ''))) ?>">
|
||||
@@ -141,13 +191,19 @@
|
||||
<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>
|
||||
<button type="button"
|
||||
class="btn btn-outline-secondary"
|
||||
data-bs-dismiss="modal">
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -157,181 +213,236 @@
|
||||
|
||||
<?= $this->section('scripts') ?>
|
||||
<style>
|
||||
.grade-orange td { background: #fff3cd !important; color: #8a5d00; font-weight: 600; }
|
||||
.grade-red td { background: #f8d7da !important; color: #842029; font-weight: 600; }
|
||||
.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; }
|
||||
.grade-orange td {
|
||||
background: #fff3cd !important;
|
||||
color: #8a5d00;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.grade-red td {
|
||||
background: #f8d7da !important;
|
||||
color: #842029;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.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() {
|
||||
function normalizeSemesterFilter() {
|
||||
const semesterSelect = document.querySelector('select[name="semester"]');
|
||||
if (!semesterSelect) return;
|
||||
(function () {
|
||||
function normalizeSemesterFilter() {
|
||||
const semesterSelect = document.querySelector('select[name="semester"]');
|
||||
|
||||
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';
|
||||
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>';
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', normalizeSemesterFilter);
|
||||
let html = '';
|
||||
|
||||
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 (_) {}
|
||||
});
|
||||
}
|
||||
semesters.forEach(function (sem) {
|
||||
html += '<h6 class="fw-bold mt-3 mb-2">' + esc(sem.semester || '') + ' Semester';
|
||||
|
||||
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>';
|
||||
if (sem.class_section_name) {
|
||||
html += ' <span class="text-muted fw-normal fs-6">— ' + esc(sem.class_section_name) + '</span>';
|
||||
}
|
||||
|
||||
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;
|
||||
});
|
||||
|
||||
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]);
|
||||
}
|
||||
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>';
|
||||
if (deduped.length > 0) {
|
||||
html += '<div class="mb-3">';
|
||||
html += '<p class="fw-semibold mb-1" style="font-size:0.9rem;">Comments</p>';
|
||||
|
||||
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;
|
||||
});
|
||||
deduped.forEach(function (entry) {
|
||||
const label = entry[0];
|
||||
const text = entry[1];
|
||||
|
||||
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 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;
|
||||
}
|
||||
|
||||
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>';
|
||||
});
|
||||
});
|
||||
}
|
||||
})();
|
||||
detailsModalBody.innerHTML = buildDetailsHtml(data.semesters);
|
||||
})
|
||||
.catch(function () {
|
||||
detailsModalBody.innerHTML = '<div class="alert alert-danger">Failed to load details.</div>';
|
||||
});
|
||||
});
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
<?= $this->endSection() ?>
|
||||
<?= $this->endSection() ?>
|
||||
Reference in New Issue
Block a user