From 8eda711bce8539cf6b703cb33665397201b5ebe6 Mon Sep 17 00:00:00 2001 From: ssbg04 Date: Tue, 18 Aug 2026 20:32:05 +0800 Subject: [PATCH] fix: hide graduated status for ineligible students and avoid false update success message --- backend/src/controllers/studentController.js | 13 +++++++++ .../students/widgets/edit_student_modal.dart | 28 +++++++++++++++++-- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/backend/src/controllers/studentController.js b/backend/src/controllers/studentController.js index 3ef3930..71f098e 100644 --- a/backend/src/controllers/studentController.js +++ b/backend/src/controllers/studentController.js @@ -758,6 +758,19 @@ exports.bulkStatusStudents = (req, res) => { if (!status || !['Enrolled', 'Graduated', 'Transferred', 'Dropped', 'Inactive'].includes(status)) { return res.status(400).json({ message: 'Invalid status value' }); } + if (status === 'Graduated') { + const eligibleStudents = db.prepare(` + SELECT DISTINCT s.id + FROM students s + JOIN enrollments e ON s.id = e.student_id + WHERE s.id IN (${studentIds.map(() => '?').join(',')}) + AND e.grade_level IN (10, 12) + `).all(...studentIds); + const eligibleIds = eligibleStudents.map(s => s.id); + if (eligibleIds.length === 0) { + return res.status(400).json({ message: 'None of the selected students are enrolled in Grade 10 or Grade 12 to be marked as Graduated.' }); + } + } try { db.transaction(() => { const stmt = db.prepare('UPDATE students SET status = ? WHERE id = ?'); diff --git a/frontend/lib/ui/screens/students/widgets/edit_student_modal.dart b/frontend/lib/ui/screens/students/widgets/edit_student_modal.dart index 5cb8c2d..df69868 100644 --- a/frontend/lib/ui/screens/students/widgets/edit_student_modal.dart +++ b/frontend/lib/ui/screens/students/widgets/edit_student_modal.dart @@ -237,6 +237,15 @@ class _EditStudentModalState extends ConsumerState { return grade == 10 || grade == 12; } + List get _availableStatuses { + if (_hasGraduationEligibleGrade() || + _selectedStatus == 'Graduated' || + _initialStudent.status == 'Graduated') { + return _statuses; + } + return _statuses.where((s) => s != 'Graduated').toList(); + } + int? _getLatestGradeLevel() { if (_loadedEnrollments != null && _loadedEnrollments!.isNotEmpty) { final latestEnrollment = _loadedEnrollments!.reduce((a, b) { @@ -281,6 +290,11 @@ class _EditStudentModalState extends ConsumerState { } } + if (!_hasChanges) { + Navigator.of(context).pop(false); + return; + } + setState(() => _isLoading = true); try { final notifier = ref.read(studentMutationProvider.notifier); @@ -375,14 +389,22 @@ class _EditStudentModalState extends ConsumerState { }, ); + final isEligibleForGraduation = + _hasGraduationEligibleGrade() || + _initialStudent.status == 'Graduated'; + final currentGrade = _getLatestGradeLevel(); + final statusDropdown = DropdownButtonFormField( key: ValueKey('edit_status_dropdown_${_selectedStatus}_$_statusDropdownKey'), initialValue: _selectedStatus, - decoration: const InputDecoration( + decoration: InputDecoration( labelText: 'STATUS', - prefixIcon: Icon(Icons.info_outline), + prefixIcon: const Icon(Icons.info_outline), + helperText: !isEligibleForGraduation + ? 'Graduation requires Grade 10 or 12 (${currentGrade != null ? 'Grade $currentGrade' : 'No Grade 10/12'})' + : null, ), - items: _statuses + items: _availableStatuses .map((s) => DropdownMenuItem(value: s, child: Text(s))) .toList(), onChanged: (v) {