From 539d0eb2209db6b29e9b081ef5b9e11257fe3b5e Mon Sep 17 00:00:00 2001 From: root Date: Fri, 17 Jul 2026 00:02:53 -0400 Subject: [PATCH] fix parent pages to adopt the school year logic --- app/Controllers/ParentProgressController.php | 115 +++++++++++++++--- .../ParentReportCardController.php | 25 +++- .../View/ParentAttendanceReportController.php | 25 +++- app/Controllers/View/ParentController.php | 22 +++- .../View/SchoolYearSelectionController.php | 11 ++ app/Services/SchoolYearContextService.php | 2 + app/Views/parent/register_student.php | 20 ++- app/Views/parent/report_attendance.php | 45 +++++-- app/Views/parent/report_cards.php | 13 +- app/Views/partials/school_year_selector.php | 12 +- public/assets/js/phone_validation.js | 17 ++- .../Services/SchoolYearContextServiceTest.php | 2 + 12 files changed, 258 insertions(+), 51 deletions(-) diff --git a/app/Controllers/ParentProgressController.php b/app/Controllers/ParentProgressController.php index 94ce102..785f898 100644 --- a/app/Controllers/ParentProgressController.php +++ b/app/Controllers/ParentProgressController.php @@ -5,7 +5,9 @@ namespace App\Controllers; use App\Controllers\ClassProgressController; use App\Models\ClassProgressAttachmentModel; use App\Models\ClassProgressReportModel; +use App\Models\ConfigurationModel; use App\Models\EnrollmentModel; +use App\Services\SemesterRangeService; use CodeIgniter\Database\BaseConnection; use CodeIgniter\Exceptions\PageNotFoundException; use Config\Database; @@ -15,8 +17,10 @@ class ParentProgressController extends BaseController protected ClassProgressReportModel $reportModel; protected ClassProgressAttachmentModel $attachmentModel; protected EnrollmentModel $enrollmentModel; + protected ConfigurationModel $configModel; protected BaseConnection $db; private ?array $parentSectionIds = null; + private array $parentSectionIdsByYear = []; public function __construct() { @@ -24,6 +28,7 @@ class ParentProgressController extends BaseController $this->reportModel = new ClassProgressReportModel(); $this->attachmentModel = new ClassProgressAttachmentModel(); $this->enrollmentModel = new EnrollmentModel(); + $this->configModel = new ConfigurationModel(); $this->db = Database::connect(); } @@ -43,8 +48,8 @@ class ParentProgressController extends BaseController ->select('class_progress_reports.*, cs.class_section_name, CONCAT(IFNULL(u.firstname, ""), " ", IFNULL(u.lastname, "")) AS teacher_name') ->join('classSection cs', 'cs.class_section_id = class_progress_reports.class_section_id', 'left') ->join('users u', 'u.id = class_progress_reports.teacher_id', 'left') - ->whereIn('class_progress_reports.class_section_id', $sectionIds) - ->where('class_progress_reports.school_year', $schoolYear); + ->whereIn('class_progress_reports.class_section_id', $sectionIds); + $this->applyProgressSchoolYearScope($builder, $schoolYear); $rows = $builder ->orderBy('week_start', 'DESC') @@ -82,21 +87,29 @@ class ParentProgressController extends BaseController ->select('class_progress_reports.*, cs.class_section_name, CONCAT(IFNULL(u.firstname, ""), " ", IFNULL(u.lastname, "")) AS teacher_name') ->join('classSection cs', 'cs.class_section_id = class_progress_reports.class_section_id', 'left') ->join('users u', 'u.id = class_progress_reports.teacher_id', 'left') - ->where('class_progress_reports.school_year', $schoolYear) - ->find((int) $id); + ->where('class_progress_reports.id', (int) $id) + ->first(); - if (! $row || ! $this->isSectionAccessible($row['class_section_id'] ?? null)) { + if (! $row) { + throw new PageNotFoundException('Progress report not found.'); + } + + $reportSchoolYear = trim((string) ($row['school_year'] ?? '')); + $effectiveSchoolYear = $reportSchoolYear !== '' ? $reportSchoolYear : $schoolYear; + + if (! $this->isSectionAccessible($row['class_section_id'] ?? null, $effectiveSchoolYear)) { throw new PageNotFoundException('Progress report not found.'); } $row['status_label'] = ClassProgressController::STATUS_OPTIONS[$row['status']] ?? 'Unknown'; $row['flags'] = $this->decodeFlags($row['flags_json']); - $weeklyReports = $this->reportModel + $weeklyReportsQuery = $this->reportModel ->select('class_progress_reports.*') ->where('class_section_id', $row['class_section_id']) - ->where('week_start', $row['week_start']) - ->where('school_year', $schoolYear) + ->where('week_start', $row['week_start']); + $this->applyProgressSchoolYearScope($weeklyReportsQuery, $effectiveSchoolYear); + $weeklyReports = $weeklyReportsQuery ->orderBy('subject', 'ASC') ->findAll(); @@ -122,7 +135,14 @@ class ParentProgressController extends BaseController public function attachment($id) { $row = $this->reportModel->find((int) $id); - if (! $row || ! $this->isSectionAccessible($row['class_section_id'] ?? null) || empty($row['attachment_path'])) { + if (! $row) { + throw new PageNotFoundException('Attachment not found.'); + } + + $reportSchoolYear = trim((string) ($row['school_year'] ?? '')); + $effectiveSchoolYear = $reportSchoolYear !== '' ? $reportSchoolYear : $this->currentSchoolYearName(); + + if (! $this->isSectionAccessible($row['class_section_id'] ?? null, $effectiveSchoolYear) || empty($row['attachment_path'])) { throw new PageNotFoundException('Attachment not found.'); } @@ -142,7 +162,14 @@ class ParentProgressController extends BaseController } $report = $this->reportModel->find((int) ($attachment['report_id'] ?? 0)); - if (! $report || ! $this->isSectionAccessible($report['class_section_id'] ?? null)) { + if (! $report) { + throw new PageNotFoundException('Attachment not found.'); + } + + $reportSchoolYear = trim((string) ($report['school_year'] ?? '')); + $effectiveSchoolYear = $reportSchoolYear !== '' ? $reportSchoolYear : $this->currentSchoolYearName(); + + if (! $this->isSectionAccessible($report['class_section_id'] ?? null, $effectiveSchoolYear)) { throw new PageNotFoundException('Attachment not found.'); } @@ -155,22 +182,30 @@ class ParentProgressController extends BaseController return $this->response->download($file, null)->setFileName($downloadName); } - protected function getParentSectionIds(): array + protected function getParentSectionIds(?string $schoolYear = null): array { - if ($this->parentSectionIds !== null) { + $schoolYear = trim((string) ($schoolYear ?? $this->currentSchoolYearName())); + if ($schoolYear === $this->currentSchoolYearName() && $this->parentSectionIds !== null) { return $this->parentSectionIds; } + if (isset($this->parentSectionIdsByYear[$schoolYear])) { + return $this->parentSectionIdsByYear[$schoolYear]; + } + $parentId = (int) session()->get('user_id'); if ($parentId === 0) { - $this->parentSectionIds = []; - return $this->parentSectionIds; + $this->parentSectionIdsByYear[$schoolYear] = []; + if ($schoolYear === $this->currentSchoolYearName()) { + $this->parentSectionIds = []; + } + return []; } $rows = $this->enrollmentModel ->select('class_section_id') ->where('parent_id', $parentId) - ->where('school_year', $this->currentSchoolYearName()) + ->where('school_year', $schoolYear) ->where('is_withdrawn', 0) ->groupBy('class_section_id') ->findAll(); @@ -183,8 +218,12 @@ class ParentProgressController extends BaseController } } - $this->parentSectionIds = array_values(array_unique($ids)); - return $this->parentSectionIds; + $ids = array_values(array_unique($ids)); + $this->parentSectionIdsByYear[$schoolYear] = $ids; + if ($schoolYear === $this->currentSchoolYearName()) { + $this->parentSectionIds = $ids; + } + return $ids; } protected function buildSectionOptions(array $sectionIds): array @@ -263,12 +302,50 @@ class ParentProgressController extends BaseController return $reportGroups; } - protected function isSectionAccessible(?int $classSectionId): bool + protected function isSectionAccessible(?int $classSectionId, ?string $schoolYear = null): bool { if (! $classSectionId) { return false; } - return in_array((int) $classSectionId, $this->getParentSectionIds(), true); + return in_array((int) $classSectionId, $this->getParentSectionIds($schoolYear), true); + } + + protected function applyProgressSchoolYearScope($builder, string $schoolYear): void + { + if ($schoolYear === '') { + return; + } + + $hasReportYear = $this->db->fieldExists('school_year', 'class_progress_reports'); + $semesterResolver = new SemesterRangeService($this->configModel); + [$rangeStart, $rangeEnd] = $semesterResolver->getSchoolYearRange($schoolYear); + + if ($hasReportYear) { + if ($rangeStart !== '' && $rangeEnd !== '') { + $builder + ->groupStart() + ->where('class_progress_reports.school_year', $schoolYear) + ->orGroupStart() + ->groupStart() + ->where('class_progress_reports.school_year IS NULL', null, false) + ->orWhere('class_progress_reports.school_year', '') + ->groupEnd() + ->where('class_progress_reports.week_start >=', $rangeStart) + ->where('class_progress_reports.week_start <=', $rangeEnd) + ->groupEnd() + ->groupEnd(); + return; + } + + $builder->where('class_progress_reports.school_year', $schoolYear); + return; + } + + if ($rangeStart !== '' && $rangeEnd !== '') { + $builder + ->where('class_progress_reports.week_start >=', $rangeStart) + ->where('class_progress_reports.week_start <=', $rangeEnd); + } } protected function resolveAttachmentFile(array $row): ?string diff --git a/app/Controllers/ParentReportCardController.php b/app/Controllers/ParentReportCardController.php index 776057e..c1388f9 100644 --- a/app/Controllers/ParentReportCardController.php +++ b/app/Controllers/ParentReportCardController.php @@ -2,6 +2,7 @@ namespace App\Controllers; +use App\Exceptions\SchoolYear\SchoolYearWriteConflictException; use App\Models\ConfigurationModel; use App\Models\ReportCardAcknowledgementModel; use App\Models\StudentModel; @@ -31,7 +32,8 @@ class ParentReportCardController extends BaseController return redirect()->back()->with('error', 'Unable to retrieve student data. Please contact support.'); } - $schoolYear = trim((string) $this->currentSchoolYearName()); + $schoolYearContext = $this->resolveSchoolYearContext(); + $schoolYear = trim($schoolYearContext->yearName()); $semester = trim((string) ($this->request->getGet('semester') ?? $this->configModel->getConfig('semester') ?? '')); $builder = $this->db->table('students s') @@ -67,6 +69,7 @@ class ParentReportCardController extends BaseController 'ackMap' => $ackMap, 'schoolYear' => $schoolYear, 'semester' => $semester, + 'isEditable' => ! $schoolYearContext->isReadonly(), ]); } @@ -82,12 +85,15 @@ class ParentReportCardController extends BaseController throw new PageNotFoundException('Student not found.'); } - $schoolYear = trim((string) $this->currentSchoolYearName()); + $schoolYearContext = $this->resolveSchoolYearContext(); + $schoolYear = trim($schoolYearContext->yearName()); $semester = trim((string) ($this->request->getGet('semester') ?? $this->configModel->getConfig('semester') ?? '')); - $this->touchAcknowledgement($parentId, (int) $studentId, $schoolYear, $semester, [ - 'viewed_at' => date('Y-m-d H:i:s'), - ]); + if (! $schoolYearContext->isReadonly()) { + $this->touchAcknowledgement($parentId, (int) $studentId, $schoolYear, $semester, [ + 'viewed_at' => date('Y-m-d H:i:s'), + ]); + } $url = site_url('report-card/student/' . (int) $studentId); $query = []; @@ -111,6 +117,13 @@ class ParentReportCardController extends BaseController return redirect()->back()->with('error', 'Unable to retrieve student data. Please contact support.'); } + $schoolYearContext = $this->resolveSchoolYearContext(); + try { + $this->assertSchoolYearWritable($schoolYearContext); + } catch (SchoolYearWriteConflictException $e) { + return redirect()->back()->withInput()->with('error', $e->getMessage()); + } + $student = $this->studentModel->find((int) $studentId); if (! $student || (int) ($student['parent_id'] ?? 0) !== $parentId) { throw new PageNotFoundException('Student not found.'); @@ -121,7 +134,7 @@ class ParentReportCardController extends BaseController return redirect()->back()->with('error', 'Please type your full name to sign.'); } - $schoolYear = trim((string) $this->currentSchoolYearName()); + $schoolYear = trim($schoolYearContext->yearName()); $semester = trim((string) ($this->configModel->getConfig('semester') ?? '')); $now = date('Y-m-d H:i:s'); $this->touchAcknowledgement($parentId, (int) $studentId, $schoolYear, $semester, [ diff --git a/app/Controllers/View/ParentAttendanceReportController.php b/app/Controllers/View/ParentAttendanceReportController.php index a48bd0d..4fab84e 100644 --- a/app/Controllers/View/ParentAttendanceReportController.php +++ b/app/Controllers/View/ParentAttendanceReportController.php @@ -11,6 +11,7 @@ use App\Models\StudentClassModel; use App\Models\ClassSectionModel; use App\Models\AttendanceDataModel; use App\Models\AttendanceRecordModel; +use App\Exceptions\SchoolYear\SchoolYearWriteConflictException; use App\Services\SemesterRangeService; class ParentAttendanceReportController extends BaseController @@ -58,7 +59,8 @@ class ParentAttendanceReportController extends BaseController [$sundays, $defaultDate] = $this->computeSundays(); // Load upcoming reports for preview/edit (today and forward within this school year) - $schoolYear = $this->currentSchoolYearName((string) ($this->configModel->getConfig('school_year') ?? '')); + $schoolYearContext = $this->resolveSchoolYearContext(); + $schoolYear = $schoolYearContext->yearName(); $todayYmd = local_date(utc_now(), 'Y-m-d'); $previewRows = $this->reportModel->builder() ->select('parent_attendance_reports.*, s.firstname, s.lastname') @@ -80,6 +82,8 @@ class ParentAttendanceReportController extends BaseController 'defaultDate' => $defaultDate, // preselected date (upcoming Sunday) 'myReports' => $previewRows, 'cutoffThreshold' => $cutoffThreshold, + 'selectedYear' => $schoolYear, + 'isEditable' => ! $schoolYearContext->isReadonly(), ]); } @@ -91,6 +95,13 @@ class ParentAttendanceReportController extends BaseController return redirect()->to('/login'); } + $schoolYearContext = $this->resolveSchoolYearContext(); + try { + $this->assertSchoolYearWritable($schoolYearContext); + } catch (SchoolYearWriteConflictException $e) { + return redirect()->back()->withInput()->with('error', $e->getMessage()); + } + $post = $this->request->getPost(); $rules = [ @@ -141,7 +152,7 @@ class ParentAttendanceReportController extends BaseController $dismissTime = $post['dismiss_time'] ?? null; $reasonRaw = $post['reason'] ?? null; $reason = is_string($reasonRaw) ? trim($reasonRaw) : null; - $schoolYear = $this->currentSchoolYearName((string) ($this->configModel->getConfig('school_year') ?? '')); + $schoolYear = $schoolYearContext->yearName(); // Enforce Sunday-only and future-or-today selection $todayCheck = new \DateTime('today'); @@ -1508,6 +1519,13 @@ class ParentAttendanceReportController extends BaseController return redirect()->to('/login'); } + $schoolYearContext = $this->resolveSchoolYearContext(); + try { + $this->assertSchoolYearWritable($schoolYearContext); + } catch (SchoolYearWriteConflictException $e) { + return redirect()->back()->with('error', $e->getMessage()); + } + $id = (int) ($this->request->getPost('id') ?? 0); if ($id <= 0) { return redirect()->back()->with('error', 'Invalid report.'); @@ -1517,6 +1535,9 @@ class ParentAttendanceReportController extends BaseController if (!$row || (int)($row['parent_id'] ?? 0) !== (int)$parentId) { return redirect()->back()->with('error', 'Report not found.'); } + if ((string) ($row['school_year'] ?? '') !== $schoolYearContext->yearName()) { + return redirect()->back()->with('error', 'Report not found for the selected school year.'); + } // Only allow editing for 'new' status entries $status = (string) ($row['status'] ?? ''); diff --git a/app/Controllers/View/ParentController.php b/app/Controllers/View/ParentController.php index af04cac..71af5f7 100644 --- a/app/Controllers/View/ParentController.php +++ b/app/Controllers/View/ParentController.php @@ -1064,6 +1064,10 @@ class ParentController extends BaseController $schoolIdService = new SchoolIdService(); $parentId = session()->get('user_id'); + $schoolYearContext = $this->resolveSchoolYearContext(); + $this->assertSchoolYearWritable($schoolYearContext); + $selectedSchoolYear = $schoolYearContext->yearName(); + $this->schoolYear = $selectedSchoolYear; if (!$this->lastDayOfRegistration || !strtotime($this->lastDayOfRegistration)) { throw new \Exception('Invalid enrollment deadline date.'); @@ -1270,7 +1274,9 @@ class ParentController extends BaseController private function getRegistrationData(int $parentId): array { - $enrollments = $this->getEnrollmentsByParent($parentId, $this->schoolYear); + $schoolYearContext = $this->resolveSchoolYearContext(); + $selectedSchoolYear = $schoolYearContext->yearName(); + $enrollments = $this->getEnrollmentsByParent($parentId, $selectedSchoolYear); $enrollmentMap = []; if (!empty($enrollments)) { @@ -1306,6 +1312,8 @@ class ParentController extends BaseController 'maxChilds' => $this->maxChilds, 'maxEmergency' => $this->maxEmergency, 'enrollments' => $enrollments, + 'selectedYear' => $selectedSchoolYear, + 'isEditable' => ! $schoolYearContext->isReadonly(), ]; } @@ -1636,6 +1644,9 @@ $existing = $this->studentModel public function editEmergencyContact($id = null) { + $schoolYearContext = $this->resolveSchoolYearContext(); + $this->assertSchoolYearWritable($schoolYearContext); + if ($id === null) { $parentId = session()->get('user_id'); $contacts = $this->emergencyContactModel->where('parent_id', $parentId)->findAll(); @@ -1681,8 +1692,8 @@ $existing = $this->studentModel } $parentId = session()->get('user_id'); - $semester = session()->get('active_semester'); - $schoolYear = session()->get('active_school_year'); + $semester = $this->semester; + $schoolYear = $schoolYearContext->yearName(); $this->saveEmergencyContact($parentId, $semester, $schoolYear, [ 'first_name' => $this->request->getPost('emergency_first_name'), @@ -1699,6 +1710,9 @@ $existing = $this->studentModel public function editStudent($id) { + $schoolYearContext = $this->resolveSchoolYearContext(); + $this->assertSchoolYearWritable($schoolYearContext); + $this->schoolYear = $schoolYearContext->yearName(); $schoolIdService = new \App\Services\SchoolIdService(); if (strtolower($this->request->getMethod()) !== 'post') { @@ -1752,6 +1766,8 @@ $existing = $this->studentModel public function deleteStudent($id) { + $this->assertSchoolYearWritable($this->resolveSchoolYearContext()); + if (strtolower($this->request->getMethod()) !== 'post') { return redirect()->back()->with('error', 'Invalid request method.'); } diff --git a/app/Controllers/View/SchoolYearSelectionController.php b/app/Controllers/View/SchoolYearSelectionController.php index 92532ff..b1d30e6 100644 --- a/app/Controllers/View/SchoolYearSelectionController.php +++ b/app/Controllers/View/SchoolYearSelectionController.php @@ -60,6 +60,8 @@ final class SchoolYearSelectionController extends BaseController return $fallback; } + $path = $this->normalizeSchoolYearReturnPath($path); + $query = []; if (! empty($parts['query'])) { parse_str((string) $parts['query'], $query); @@ -73,6 +75,15 @@ final class SchoolYearSelectionController extends BaseController return $path . ($cleanQuery !== '' ? '?' . $cleanQuery : ''); } + private function normalizeSchoolYearReturnPath(string $path): string + { + if (preg_match('#^/(parent|teacher|admin)/progress/view/\d+$#', $path, $matches) === 1) { + return '/' . $matches[1] . '/progress'; + } + + return $path; + } + private function dashboardRoute(): string { try { diff --git a/app/Services/SchoolYearContextService.php b/app/Services/SchoolYearContextService.php index 7c1287a..c7b8af1 100644 --- a/app/Services/SchoolYearContextService.php +++ b/app/Services/SchoolYearContextService.php @@ -122,6 +122,7 @@ final class SchoolYearContextService { session()->remove('selected_school_year_id'); session()->remove('selected_school_year'); + $this->clearDependentSessionState(); } public function active(): SchoolYearContext @@ -188,6 +189,7 @@ final class SchoolYearContextService 'class_section_id', 'semester', 'active_semester', + 'active_school_year', 'teacher_scores_selected_semester', 'grading_selected_semester', ]); diff --git a/app/Views/parent/register_student.php b/app/Views/parent/register_student.php index 1a40f68..bbb17de 100644 --- a/app/Views/parent/register_student.php +++ b/app/Views/parent/register_student.php @@ -1,4 +1,6 @@ = $maxChilds; $disableEmergencyBtn = count($emergencies) >= $maxEmergency; ?> @@ -7,6 +9,14 @@ $disableEmergencyBtn = count($emergencies) >= $maxEmergency; section('content') ?>

Student Registration

+ +
School year:
+ + +
+ This school year is read-only. Switch to the active school year to register or edit students. +
+
You've reached the maximum number of students ().
@@ -100,7 +110,7 @@ $disableEmergencyBtn = count($emergencies) >= $maxEmergency; ?> - +
@@ -116,7 +126,7 @@ $disableEmergencyBtn = count($emergencies) >= $maxEmergency;
- @@ -162,7 +172,7 @@ $disableEmergencyBtn = count($emergencies) >= $maxEmergency; = $lastDayOfRegistration); - $disableAll = $disableStudentBtn || $disableDueToDate; + $disableAll = $disableStudentBtn || $disableDueToDate || ! $isEditable; ?>
= $maxEmergency; title="= $maxEmergency; title=" + +
+ You are viewing . Attendance report actions are read-only for closed years. +
+ +
Upcoming Submissions (Preview & Edit)
@@ -53,7 +62,7 @@ $cutoff = null; $editable = false; try { $cutoff = new DateTime($reportDate . ' 09:00:00', new DateTimeZone($tzName)); } catch (\Throwable $e) { $cutoff = null; } if ($cutoff) { - $editable = ($status === 'new') && ($nowTz < $cutoff); + $editable = $isEditable && ($status === 'new') && ($nowTz < $cutoff); } ?> @@ -149,7 +158,8 @@ data-cutoff-date="" data-cutoff-time="" data-cutoff-threshold="" - data-cutoff-blocked="0"> + data-cutoff-blocked="0" + data-readonly=""> @@ -168,7 +178,7 @@ $oldStudents = (array) old('student_ids'); $isChecked = in_array((string)$s['id'], array_map('strval', $oldStudents ?? []), true); ?> - > + > @@ -187,7 +197,7 @@
- >
- > @@ -223,22 +233,22 @@
- +
Required for Absence/Late so we can support your child.
- + Cancel
@@ -325,6 +335,14 @@ const dateSel = form.querySelector('select[name="dates[]"]'); const submitBtn = form.querySelector('button[type="submit"]'); const alertBox = document.getElementById('clientCheckAlert'); + const isReadonly = form.getAttribute('data-readonly') === '1'; + + if (isReadonly) { + if (submitBtn) { + submitBtn.disabled = true; + } + return; + } function selectedIds() { const ids = []; @@ -520,6 +538,11 @@ const cutoffDate = form.getAttribute('data-cutoff-date') || ''; const cutoffTime = form.getAttribute('data-cutoff-time') || ''; const cutoffThreshold = form.getAttribute('data-cutoff-threshold') || '09:00'; + const isReadonly = form.getAttribute('data-readonly') === '1'; + + if (isReadonly && submitBtn) { + submitBtn.disabled = true; + } function parseTimeToMinutes(val) { const parts = (val || '').split(':'); @@ -544,6 +567,10 @@ if (cutoffAlert) { cutoffAlert.classList.toggle('d-none', !blocked); } + if (submitBtn && isReadonly) { + submitBtn.disabled = true; + return; + } if (submitBtn && blocked) { submitBtn.disabled = true; } diff --git a/app/Views/parent/report_cards.php b/app/Views/parent/report_cards.php index 40dd404..8e8ff48 100644 --- a/app/Views/parent/report_cards.php +++ b/app/Views/parent/report_cards.php @@ -1,5 +1,9 @@ extend('layout/main_layout') ?> section('content') ?> +
@@ -16,6 +20,11 @@ getFlashdata('success')): ?>
getFlashdata('success')) ?>
+ +
+ You are viewing . Report card signatures are read-only for closed years. +
+
No students available for report cards.
@@ -57,8 +66,8 @@ - - + > + diff --git a/app/Views/partials/school_year_selector.php b/app/Views/partials/school_year_selector.php index 66f27d8..d2cb40e 100644 --- a/app/Views/partials/school_year_selector.php +++ b/app/Views/partials/school_year_selector.php @@ -17,6 +17,13 @@ getUri()->getQuery(); $returnTo = current_url() . ($query !== '' ? '?' . $query : ''); + $activeSchoolYearId = null; + foreach ($schoolYearOptions as $year) { + if (strtolower((string) ($year['status'] ?? '')) === 'active') { + $activeSchoolYearId = (int) ($year['id'] ?? 0); + break; + } + } ?>
@@ -55,10 +62,11 @@ yearName()) ?> - isExplicitSelection()): ?> -
+ isExplicitSelection() && $activeSchoolYearId !== null): ?> + + diff --git a/public/assets/js/phone_validation.js b/public/assets/js/phone_validation.js index 051ca9b..82c5dde 100644 --- a/public/assets/js/phone_validation.js +++ b/public/assets/js/phone_validation.js @@ -37,11 +37,15 @@ export function validatePhoneLive(inputEl) { // Prevent form submission if phone is invalid function preventInvalidSubmission() { - const forms = document.querySelectorAll('form'); - forms.forEach(form => { + const phoneInputs = document.querySelectorAll('#phoneInput'); + phoneInputs.forEach(phoneInput => { + const form = phoneInput.closest('form'); + if (!form) { + return; + } + form.addEventListener('submit', function (e) { - const phoneInput = document.getElementById('phoneInput'); - if (phoneInput && !validatePhoneLive(phoneInput)) { + if (!validatePhoneLive(phoneInput)) { e.preventDefault(); phoneInput.focus(); return false; @@ -53,6 +57,9 @@ function preventInvalidSubmission() { // Initialize the event listener when the page loads document.addEventListener('DOMContentLoaded', function () { const phoneInput = document.getElementById('phoneInput'); + if (!phoneInput) { + return; + } // Add input event listener for live validation and formatting phoneInput.addEventListener('input', function () { @@ -71,4 +78,4 @@ document.addEventListener('DOMContentLoaded', function () { // Prevent form submission for invalid phone numbers preventInvalidSubmission(); -}); \ No newline at end of file +}); diff --git a/tests/app/Services/SchoolYearContextServiceTest.php b/tests/app/Services/SchoolYearContextServiceTest.php index 0da63c8..4d0a269 100644 --- a/tests/app/Services/SchoolYearContextServiceTest.php +++ b/tests/app/Services/SchoolYearContextServiceTest.php @@ -99,6 +99,7 @@ final class SchoolYearContextServiceTest extends CIUnitTestCase session()->set('selected_school_year_id', 1); session()->set('class_section_id', 44); session()->set('semester', 'Fall'); + session()->set('active_school_year', '2025-2026'); $service = new SchoolYearContextService(new SchoolYearContextFakeModel([ 1 => ['id' => 1, 'name' => '2025-2026', 'status' => 'closed'], @@ -113,5 +114,6 @@ final class SchoolYearContextServiceTest extends CIUnitTestCase $this->assertNull(session()->get('selected_school_year_id')); $this->assertNull(session()->get('class_section_id')); $this->assertNull(session()->get('semester')); + $this->assertNull(session()->get('active_school_year')); } }