feat(settings): clean academic setup buttons and rename screen to Academic & Class Management

- Update screen, settings card, and dashboard titles to 'Academic & Class Management'

- Clean and balance Academic Structure toolbar for mobile and desktop

- Remove redundant buttons on section cards in favor of interactive adviser chip

- Modernize teacher action button to OutlinedButton.icon 'Sections'

- Add responsive bulk academic structure import support across backend and frontend
This commit is contained in:
ssbg04 committed 2026-09-27 02:05:47 +08:00
1 parent a9c2ab0da5
commit bd2a8acbfe
8 files changed
+1228 -454

No files matched your search

@@ -30,6 +30,16 @@ class SectionModel {
final int gradeLevel;
final int? academicYearId;
final String? academicYearRange;
final int? teacherId;
final String? teacherFirstName;
final String? teacherLastName;
String? get teacherFullName {
if (teacherLastName != null && teacherFirstName != null) {
return '$teacherLastName, $teacherFirstName';
}
return teacherFirstName ?? teacherLastName;
}
SectionModel({
required this.id,
@@ -37,6 +47,9 @@ class SectionModel {
required this.gradeLevel,
this.academicYearId,
this.academicYearRange,
this.teacherId,
this.teacherFirstName,
this.teacherLastName,
});
factory SectionModel.fromJson(Map<String, dynamic> json) {
@@ -48,6 +61,11 @@ class SectionModel {
? (json['academic_year_id'] as num).toInt()
: null,
academicYearRange: json['academic_year_range'] as String?,
teacherId: json['teacher_id'] != null
? (json['teacher_id'] as num).toInt()
: null,
teacherFirstName: json['teacher_first_name'] as String?,
teacherLastName: json['teacher_last_name'] as String?,
);
}
}
@@ -167,6 +167,7 @@ class SetupRepository {
required String name,
required int gradeLevel,
required int academicYearId,
int? teacherId,
}) async {
try {
final options = await _getAuthOptions();
@@ -177,6 +178,7 @@ class SetupRepository {
'name': name,
'gradeLevel': gradeLevel,
'academicYearId': academicYearId,
if (teacherId != null) 'teacherId': teacherId,
},
);
} on DioException catch (e) {
@@ -208,6 +210,7 @@ class SetupRepository {
required String name,
required int gradeLevel,
required int academicYearId,
int? teacherId,
}) async {
try {
final options = await _getAuthOptions();
@@ -218,6 +221,7 @@ class SetupRepository {
'name': name,
'gradeLevel': gradeLevel,
'academicYearId': academicYearId,
'teacherId': teacherId,
},
);
} on DioException catch (e) {
@@ -225,6 +229,22 @@ class SetupRepository {
}
}
Future<void> setSectionAdviser({
required int sectionId,
int? teacherId,
}) async {
try {
final options = await _getAuthOptions();
await _dio.put(
'/setup/sections/$sectionId/adviser',
options: options,
data: {'teacherId': teacherId},
);
} on DioException catch (e) {
throw Exception(_extractErrorMessage(e, 'Failed to update section adviser.'));
}
}
Future<void> deleteSection(int id) async {
try {
final options = await _getAuthOptions();