fix below 60 pages
This commit is contained in:
@@ -1070,14 +1070,15 @@ class GradingController extends Controller
|
|||||||
|
|
||||||
public function belowSixty()
|
public function belowSixty()
|
||||||
{
|
{
|
||||||
$configuredSemester = (string) $this->semester;
|
|
||||||
$configuredYear = (string) $this->schoolYear;
|
$configuredYear = (string) $this->schoolYear;
|
||||||
|
|
||||||
$requestedSemester = trim((string)($this->request->getGet('semester') ?? ''));
|
$requestedSemester = strtolower(trim((string)($this->request->getGet('semester') ?? '')));
|
||||||
$requestedYear = trim((string)($this->request->getGet('school_year') ?? ''));
|
$requestedYear = trim((string)($this->request->getGet('school_year') ?? ''));
|
||||||
|
|
||||||
$isYearMode = (strtolower($requestedSemester) === 'year');
|
// This page intentionally supports only Fall and Whole Year.
|
||||||
$semester = $isYearMode ? 'year' : ($requestedSemester !== '' ? $requestedSemester : ($configuredSemester !== '' ? $configuredSemester : 'Fall'));
|
// Spring is still used internally for the Whole Year calculation, but it is not selectable here.
|
||||||
|
$isYearMode = ($requestedSemester === 'year');
|
||||||
|
$semester = $isYearMode ? 'year' : 'Fall';
|
||||||
$schoolYear = $requestedYear !== '' ? $requestedYear : $configuredYear;
|
$schoolYear = $requestedYear !== '' ? $requestedYear : $configuredYear;
|
||||||
|
|
||||||
$schoolYears = $this->getSchoolYearsForScores($schoolYear);
|
$schoolYears = $this->getSchoolYearsForScores($schoolYear);
|
||||||
@@ -1092,10 +1093,12 @@ class GradingController extends Controller
|
|||||||
'schoolYears' => $schoolYears,
|
'schoolYears' => $schoolYears,
|
||||||
'canViewGrading' => $canViewGrading,
|
'canViewGrading' => $canViewGrading,
|
||||||
'isYearMode' => $isYearMode,
|
'isYearMode' => $isYearMode,
|
||||||
|
'semesterOptions' => ['Fall'],
|
||||||
'showAllSemesterOption' => true,
|
'showAllSemesterOption' => true,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function editBelowSixtyEmail()
|
public function editBelowSixtyEmail()
|
||||||
{
|
{
|
||||||
$studentId = (int)$this->request->getGet('student_id');
|
$studentId = (int)$this->request->getGet('student_id');
|
||||||
@@ -1766,7 +1769,95 @@ class GradingController extends Controller
|
|||||||
private function fetchBelowSixtyRows(string $schoolYear, string $semester): array
|
private function fetchBelowSixtyRows(string $schoolYear, string $semester): array
|
||||||
{
|
{
|
||||||
$isYearMode = strtolower(trim($semester)) === 'year';
|
$isYearMode = strtolower(trim($semester)) === 'year';
|
||||||
$semesterKey = $isYearMode ? '' : strtolower(trim($semester));
|
|
||||||
|
if ($isYearMode) {
|
||||||
|
$rows = $this->db->table('semester_scores ss')
|
||||||
|
->select('s.id AS student_id')
|
||||||
|
->select('s.school_id')
|
||||||
|
->select('s.firstname')
|
||||||
|
->select('s.lastname')
|
||||||
|
->select('cs.class_section_name')
|
||||||
|
->select("'year' AS semester", false)
|
||||||
|
->select("MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'fall' THEN ss.homework_avg END) AS fall_homework_avg", false)
|
||||||
|
->select("MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'spring' THEN ss.homework_avg END) AS spring_homework_avg", false)
|
||||||
|
->select("MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'fall' THEN ss.project_avg END) AS fall_project_avg", false)
|
||||||
|
->select("MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'spring' THEN ss.project_avg END) AS spring_project_avg", false)
|
||||||
|
->select("MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'fall' THEN ss.participation_score END) AS fall_participation_score", false)
|
||||||
|
->select("MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'spring' THEN ss.participation_score END) AS spring_participation_score", false)
|
||||||
|
->select("MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'fall' THEN COALESCE(ss.test_avg, ss.quiz_avg) END) AS fall_test_avg", false)
|
||||||
|
->select("MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'spring' THEN COALESCE(ss.test_avg, ss.quiz_avg) END) AS spring_test_avg", false)
|
||||||
|
->select("MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'fall' THEN ss.ptap_score END) AS fall_ptap_score", false)
|
||||||
|
->select("MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'spring' THEN ss.ptap_score END) AS spring_ptap_score", false)
|
||||||
|
->select("MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'fall' THEN ss.attendance_score END) AS fall_attendance_score", false)
|
||||||
|
->select("MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'spring' THEN ss.attendance_score END) AS spring_attendance_score", false)
|
||||||
|
->select("MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'fall' THEN ss.midterm_exam_score END) AS fall_midterm_exam_score", false)
|
||||||
|
->select("MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'spring' THEN ss.midterm_exam_score END) AS spring_midterm_exam_score", false)
|
||||||
|
->select("MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'fall' THEN ss.final_exam_score END) AS fall_final_exam_score", false)
|
||||||
|
->select("MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'spring' THEN ss.final_exam_score END) AS spring_final_exam_score", false)
|
||||||
|
->select("MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'fall' THEN ss.semester_score END) AS fall_score", false)
|
||||||
|
->select("MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'spring' THEN ss.semester_score END) AS spring_score", false)
|
||||||
|
->select("(
|
||||||
|
MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'fall' THEN ss.semester_score END)
|
||||||
|
+ MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'spring' THEN ss.semester_score END)
|
||||||
|
) / 2 AS semester_score", false)
|
||||||
|
->select("(
|
||||||
|
MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'fall' THEN ss.homework_avg END)
|
||||||
|
+ MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'spring' THEN ss.homework_avg END)
|
||||||
|
) / 2 AS homework_avg", false)
|
||||||
|
->select("(
|
||||||
|
MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'fall' THEN ss.project_avg END)
|
||||||
|
+ MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'spring' THEN ss.project_avg END)
|
||||||
|
) / 2 AS project_avg", false)
|
||||||
|
->select("(
|
||||||
|
MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'fall' THEN ss.participation_score END)
|
||||||
|
+ MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'spring' THEN ss.participation_score END)
|
||||||
|
) / 2 AS participation_score", false)
|
||||||
|
->select("(
|
||||||
|
MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'fall' THEN COALESCE(ss.test_avg, ss.quiz_avg) END)
|
||||||
|
+ MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'spring' THEN COALESCE(ss.test_avg, ss.quiz_avg) END)
|
||||||
|
) / 2 AS test_avg", false)
|
||||||
|
->select("(
|
||||||
|
MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'fall' THEN ss.ptap_score END)
|
||||||
|
+ MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'spring' THEN ss.ptap_score END)
|
||||||
|
) / 2 AS ptap_score", false)
|
||||||
|
->select("(
|
||||||
|
MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'fall' THEN ss.attendance_score END)
|
||||||
|
+ MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'spring' THEN ss.attendance_score END)
|
||||||
|
) / 2 AS attendance_score", false)
|
||||||
|
->select("(
|
||||||
|
MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'fall' THEN ss.midterm_exam_score END)
|
||||||
|
+ MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'spring' THEN ss.midterm_exam_score END)
|
||||||
|
) / 2 AS midterm_exam_score", false)
|
||||||
|
->select("(
|
||||||
|
MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'fall' THEN ss.final_exam_score END)
|
||||||
|
+ MAX(CASE WHEN LOWER(TRIM(ss.semester)) = 'spring' THEN ss.final_exam_score END)
|
||||||
|
) / 2 AS final_exam_score", false)
|
||||||
|
->join('students s', 's.id = ss.student_id', 'inner')
|
||||||
|
->join('classSection cs', 'cs.class_section_id = ss.class_section_id', 'left')
|
||||||
|
->where('s.is_active', 1)
|
||||||
|
->where('ss.school_year', $schoolYear)
|
||||||
|
->where('ss.semester_score IS NOT NULL', null, false)
|
||||||
|
->where("LOWER(TRIM(ss.semester)) IN ('fall', 'spring')", null, false)
|
||||||
|
->groupBy('s.id, s.school_id, s.firstname, s.lastname, ss.class_section_id, cs.class_section_name')
|
||||||
|
->having('fall_score IS NOT NULL', null, false)
|
||||||
|
->having('spring_score IS NOT NULL', null, false)
|
||||||
|
->having('semester_score <', 60)
|
||||||
|
->orderBy('s.lastname', 'ASC')
|
||||||
|
->orderBy('s.firstname', 'ASC')
|
||||||
|
->get()
|
||||||
|
->getResultArray();
|
||||||
|
|
||||||
|
foreach ($rows as &$row) {
|
||||||
|
$row['comment'] = '';
|
||||||
|
$row['status'] = 'Open';
|
||||||
|
$row['note'] = '';
|
||||||
|
}
|
||||||
|
unset($row);
|
||||||
|
|
||||||
|
return $rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
$semesterKey = 'fall';
|
||||||
$builder = $this->db->table('semester_scores ss')
|
$builder = $this->db->table('semester_scores ss')
|
||||||
->select([
|
->select([
|
||||||
's.id AS student_id',
|
's.id AS student_id',
|
||||||
@@ -1790,11 +1881,8 @@ class GradingController extends Controller
|
|||||||
->where('s.is_active', 1)
|
->where('s.is_active', 1)
|
||||||
->where('ss.school_year', $schoolYear)
|
->where('ss.school_year', $schoolYear)
|
||||||
->where('ss.semester_score IS NOT NULL', null, false)
|
->where('ss.semester_score IS NOT NULL', null, false)
|
||||||
->where('ss.semester_score <', 60);
|
->where('ss.semester_score <', 60)
|
||||||
|
->where("LOWER(TRIM(ss.semester))", $semesterKey);
|
||||||
if (!$isYearMode) {
|
|
||||||
$builder->where("LOWER(TRIM(ss.semester))", $semesterKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
$rows = $builder
|
$rows = $builder
|
||||||
->orderBy('s.lastname', 'ASC')
|
->orderBy('s.lastname', 'ASC')
|
||||||
@@ -1815,16 +1903,15 @@ class GradingController extends Controller
|
|||||||
|
|
||||||
$commentMap = [];
|
$commentMap = [];
|
||||||
if (!empty($studentIds)) {
|
if (!empty($studentIds)) {
|
||||||
$commentBuilder = $this->db->table('score_comments')
|
$commentRows = $this->db->table('score_comments')
|
||||||
->select('student_id, semester, comment, created_at')
|
->select('student_id, semester, comment, created_at')
|
||||||
->where('score_type', 'general')
|
->where('score_type', 'general')
|
||||||
->where('school_year', $schoolYear)
|
->where('school_year', $schoolYear)
|
||||||
->whereIn('student_id', $studentIds)
|
->whereIn('student_id', $studentIds)
|
||||||
->orderBy('created_at', 'DESC');
|
->where("LOWER(TRIM(semester))", $semesterKey)
|
||||||
if (!$isYearMode) {
|
->orderBy('created_at', 'DESC')
|
||||||
$commentBuilder->where("LOWER(TRIM(semester))", $semesterKey);
|
->get()
|
||||||
}
|
->getResultArray();
|
||||||
$commentRows = $commentBuilder->get()->getResultArray();
|
|
||||||
foreach ($commentRows as $row) {
|
foreach ($commentRows as $row) {
|
||||||
$sid = (int)($row['student_id'] ?? 0);
|
$sid = (int)($row['student_id'] ?? 0);
|
||||||
$sem = strtolower(trim((string)($row['semester'] ?? '')));
|
$sem = strtolower(trim((string)($row['semester'] ?? '')));
|
||||||
@@ -1838,15 +1925,14 @@ class GradingController extends Controller
|
|||||||
$statusMap = [];
|
$statusMap = [];
|
||||||
$noteMap = [];
|
$noteMap = [];
|
||||||
if (!empty($studentIds)) {
|
if (!empty($studentIds)) {
|
||||||
$flagBuilder = $this->db->table('current_flag')
|
$flagRows = $this->db->table('current_flag')
|
||||||
->select('student_id, semester, flag_state, open_description, close_description')
|
->select('student_id, semester, flag_state, open_description, close_description')
|
||||||
->where('flag', 'grade')
|
->where('flag', 'grade')
|
||||||
->where('school_year', $schoolYear)
|
->where('school_year', $schoolYear)
|
||||||
->whereIn('student_id', $studentIds);
|
->whereIn('student_id', $studentIds)
|
||||||
if (!$isYearMode) {
|
->where("LOWER(TRIM(semester))", $semesterKey)
|
||||||
$flagBuilder->where("LOWER(TRIM(semester))", $semesterKey);
|
->get()
|
||||||
}
|
->getResultArray();
|
||||||
$flagRows = $flagBuilder->get()->getResultArray();
|
|
||||||
foreach ($flagRows as $row) {
|
foreach ($flagRows as $row) {
|
||||||
$sid = (int)($row['student_id'] ?? 0);
|
$sid = (int)($row['student_id'] ?? 0);
|
||||||
if ($sid <= 0) continue;
|
if ($sid <= 0) continue;
|
||||||
@@ -1884,6 +1970,7 @@ class GradingController extends Controller
|
|||||||
return $rows;
|
return $rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private function fetchBelowSixtyEmailRow(int $studentId, string $schoolYear, string $semester): array
|
private function fetchBelowSixtyEmailRow(int $studentId, string $schoolYear, string $semester): array
|
||||||
{
|
{
|
||||||
$semesterKey = strtolower(trim($semester));
|
$semesterKey = strtolower(trim($semester));
|
||||||
|
|||||||
@@ -9,12 +9,12 @@
|
|||||||
|
|
||||||
<div class="d-flex justify-content-between align-items-center mb-3 flex-wrap gap-2">
|
<div class="d-flex justify-content-between align-items-center mb-3 flex-wrap gap-2">
|
||||||
<div class="text-muted">
|
<div class="text-muted">
|
||||||
<?= !empty($isYearMode) ? 'Whole Year' : esc(ucfirst($semester ?? '')) ?> • <?= esc($schoolYear ?? '') ?>
|
<?= !empty($isYearMode) ? 'Whole Year' : 'Fall' ?> • <?= esc($schoolYear ?? '') ?>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex gap-2">
|
<div class="d-flex gap-2">
|
||||||
<?php if (empty($isYearMode)): ?>
|
<?php if (empty($isYearMode)): ?>
|
||||||
<a class="btn btn-outline-primary btn-sm"
|
<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
|
Decisions
|
||||||
</a>
|
</a>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
@@ -36,6 +36,10 @@
|
|||||||
}
|
}
|
||||||
return esc($value);
|
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)): ?>
|
<?php if (empty($rows)): ?>
|
||||||
@@ -49,20 +53,10 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th>Student Name</th>
|
<th>Student Name</th>
|
||||||
<th>Section</th>
|
<th>Section</th>
|
||||||
<?php if (!empty($isYearMode)): ?><th>Semester</th><?php endif; ?>
|
<th class="text-center">Score</th>
|
||||||
<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>Status</th>
|
<th>Status</th>
|
||||||
<th>Email Parent</th>
|
<th>Email Parent</th>
|
||||||
<th>Schedule Meeting</th>
|
<th>Schedule Meeting</th>
|
||||||
<?php endif; ?>
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -79,29 +73,28 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
$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';
|
||||||
?>
|
?>
|
||||||
<?php $isClosed = ($row['status'] ?? 'Open') === 'Closed'; ?>
|
|
||||||
<?php $rowSemester = ucfirst(strtolower(trim((string)($row['semester'] ?? ($semester ?? ''))))); ?>
|
|
||||||
<tr class="<?= esc($scoreClass) ?>">
|
<tr class="<?= esc($scoreClass) ?>">
|
||||||
<td><?= esc($studentName !== '' ? $studentName : 'N/A') ?></td>
|
<td><?= esc($studentLabel) ?></td>
|
||||||
<td><?= esc($row['class_section_name'] ?? '—') ?></td>
|
<td><?= esc($row['class_section_name'] ?? '—') ?></td>
|
||||||
<?php if (!empty($isYearMode)): ?>
|
<td class="text-center">
|
||||||
<td class="text-center"><?= esc($rowSemester) ?></td>
|
<div class="fw-semibold"><?= $displayScore($scoreRaw) ?></div>
|
||||||
<?php endif; ?>
|
<button type="button"
|
||||||
<td class="text-center"><?= $displayScore($row['homework_avg'] ?? null) ?></td>
|
class="btn btn-outline-secondary btn-xs mt-1 btn-show-details"
|
||||||
<td class="text-center"><?= $displayScore($row['project_avg'] ?? null) ?></td>
|
style="font-size:0.72rem;padding:1px 7px;"
|
||||||
<td class="text-center"><?= $displayScore($row['participation_score'] ?? null) ?></td>
|
data-student-id="<?= (int)($row['student_id'] ?? 0) ?>"
|
||||||
<td class="text-center"><?= $displayScore($row['test_avg'] ?? null) ?></td>
|
data-student-name="<?= esc($studentLabel) ?>"
|
||||||
<td class="text-center"><?= $displayScore($row['ptap_score'] ?? null) ?></td>
|
data-school-year="<?= esc((string)($schoolYear ?? '')) ?>">
|
||||||
<td class="text-center"><?= $displayScore($row['attendance_score'] ?? null) ?></td>
|
Details
|
||||||
<td class="text-center"><?= $displayScore($row['midterm_exam_score'] ?? null) ?></td>
|
</button>
|
||||||
<td class="text-center"><?= $displayScore($row['semester_score'] ?? null) ?></td>
|
</td>
|
||||||
<?php if (empty($isYearMode)): ?>
|
|
||||||
<td class="text-center">
|
<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() ?>
|
<?= csrf_field() ?>
|
||||||
<input type="hidden" name="student_id" value="<?= esc((string)($row['student_id'] ?? '')) ?>">
|
<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 ?? '')) ?>">
|
<input type="hidden" name="school_year" value="<?= esc((string)($schoolYear ?? '')) ?>">
|
||||||
<select name="status" class="form-select form-select-sm" style="width: 110px;">
|
<select name="status" class="form-select form-select-sm" style="width: 110px;">
|
||||||
<option value="Open" <?= ($row['status'] ?? 'Open') === 'Open' ? 'selected' : '' ?>>Open</option>
|
<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>
|
<button type="button" class="btn btn-sm btn-secondary" disabled>Send Email</button>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<a class="btn btn-sm btn-outline-primary"
|
<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
|
Send Email
|
||||||
</a>
|
</a>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
@@ -126,12 +119,11 @@
|
|||||||
<button class="btn btn-sm btn-secondary" disabled>Schedule</button>
|
<button class="btn btn-sm btn-secondary" disabled>Schedule</button>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<a class="btn btn-sm btn-outline-secondary"
|
<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
|
Schedule
|
||||||
</a>
|
</a>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</td>
|
</td>
|
||||||
<?php endif; ?>
|
|
||||||
</tr>
|
</tr>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</tbody>
|
</tbody>
|
||||||
@@ -141,6 +133,26 @@
|
|||||||
</div>
|
</div>
|
||||||
</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->endSection() ?>
|
||||||
|
|
||||||
<?= $this->section('scripts') ?>
|
<?= $this->section('scripts') ?>
|
||||||
@@ -150,22 +162,176 @@
|
|||||||
.below-sixty-wrapper { padding-top: 0.75rem; }
|
.below-sixty-wrapper { padding-top: 0.75rem; }
|
||||||
.below-sixty-title { position: relative; z-index: 1; margin-bottom: 1.25rem; }
|
.below-sixty-title { position: relative; z-index: 1; margin-bottom: 1.25rem; }
|
||||||
.below-sixty-table { margin-top: 0.75rem; }
|
.below-sixty-table { margin-top: 0.75rem; }
|
||||||
|
.below-sixty-dt td { vertical-align: top; }
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
(function() {
|
(function() {
|
||||||
if (!window.$ || !$.fn || !$.fn.DataTable) return;
|
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() {
|
$(function() {
|
||||||
const table = $('.below-sixty-dt');
|
const table = $('.below-sixty-dt');
|
||||||
if (!table.length) return;
|
if (!table.length) return;
|
||||||
try {
|
try {
|
||||||
const semesterOffset = <?= !empty($isYearMode) ? '1' : '0' ?>;
|
|
||||||
table.DataTable({
|
table.DataTable({
|
||||||
order: [[8 + semesterOffset, 'asc']],
|
order: [[2, 'asc']],
|
||||||
pageLength: 100,
|
pageLength: 100,
|
||||||
lengthMenu: [10, 25, 50, 100, 200]
|
lengthMenu: [10, 25, 50, 100, 200],
|
||||||
|
columnDefs: [{ orderable: false, targets: [3, 4, 5] }]
|
||||||
});
|
});
|
||||||
} catch (_) {}
|
} 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;
|
||||||
|
});
|
||||||
|
|
||||||
|
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>
|
</script>
|
||||||
<?= $this->endSection() ?>
|
<?= $this->endSection() ?>
|
||||||
|
|||||||
Reference in New Issue
Block a user