feat(ui): implement Priority 2 student search, filtering, and compact list rows

This commit is contained in:
ssbg04 committed 2026-10-09 09:19:59 +08:00
1 parent 489e87834e
commit 680cb859eb
3 files changed
+696 -729

No files matched your search

+2 -2
View File
@@ -1061,8 +1061,8 @@ Files backup/restore - mirror mode or zip -->
- [x] Direct inline document workflows (View, Upload, Verify, Print Queue) from student document tab.
## Priority 2: Student Search & Filtering
- [ ] Transition student list to compact rows with direct status badges, LRN, and completion counters.
- [ ] Implement mobile bottom sheet for filtering (grade, section, status, school year) with active filter chips.
- [x] Transition student list to compact rows with direct status badges, LRN, and completion counters.
- [x] Implement mobile bottom sheet for filtering (grade, section, status, school year) with active filter chips.
## Priority 3: Status-Driven Documents & Requirements Workflow
- [ ] Integrate document requirements directly into Documents module workflow (All Documents, Requirements, Upload/Import, Print Queue).
File diff suppressed because it is too large. Load diff
@@ -8,11 +8,13 @@ import '../../../providers/student_provider.dart';
class StudentFilterDialog extends ConsumerStatefulWidget {
final StudentQueryParams initialQuery;
final bool isEnrolledTab;
final bool isBottomSheet;
const StudentFilterDialog({
super.key,
required this.initialQuery,
this.isEnrolledTab = false,
this.isBottomSheet = false,
});
static Future<void> show(
@@ -20,6 +22,28 @@ class StudentFilterDialog extends ConsumerStatefulWidget {
required StudentQueryParams query,
bool isEnrolledTab = false,
}) {
final isMobile = MediaQuery.of(context).size.width < 700 ||
Theme.of(context).platform == TargetPlatform.android;
if (isMobile) {
return showModalBottomSheet(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (ctx) => FractionallySizedBox(
heightFactor: 0.88,
child: ClipRRect(
borderRadius: const BorderRadius.vertical(top: Radius.circular(20)),
child: StudentFilterDialog(
initialQuery: query,
isEnrolledTab: isEnrolledTab,
isBottomSheet: true,
),
),
),
);
}
return showDialog(
context: context,
barrierColor: Colors.black.withValues(alpha: 0.35),
@@ -196,7 +220,9 @@ class _StudentFilterDialogState extends ConsumerState<StudentFilterDialog> {
return Container(
decoration: BoxDecoration(
color: isDark ? AppColors.darkSurfaceCard : AppColors.surfaceWhite,
borderRadius: BorderRadius.circular(16),
borderRadius: widget.isBottomSheet
? const BorderRadius.vertical(top: Radius.circular(20))
: BorderRadius.circular(16),
border: Border.all(
color: isDark ? AppColors.darkBorder : Colors.grey.shade200,
),
@@ -212,9 +238,28 @@ class _StudentFilterDialogState extends ConsumerState<StudentFilterDialog> {
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
if (widget.isBottomSheet) ...[
const SizedBox(height: 10),
Center(
child: Container(
width: 38,
height: 4.5,
decoration: BoxDecoration(
color: isDark ? Colors.white24 : Colors.grey.shade300,
borderRadius: BorderRadius.circular(2),
),
),
),
],
// ── Header ──
Padding(
padding: const EdgeInsets.fromLTRB(20, 18, 16, 0),
padding: EdgeInsets.fromLTRB(
20,
widget.isBottomSheet ? 10 : 18,
16,
0,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [