Students
View and mark student boarding/alighting at each stop.
Student Statuses
| Status | Meaning |
|---|---|
waiting | Student not yet boarded |
boarded | Student has boarded the bus |
alighted | Student has gotten off at stop |
absent | Student marked as absent at stop |
no_show | Student did not appear at stop |
Get Assigned Students
GET /driver/bus-tracking/get-assigned-students
Returns all students assigned to the driver across all routes.
Get Students for a Trip Stop
GET /driver/bus-tracking/trips/{tripId}/students
GET /driver/bus-tracking/trips/{tripId}/students?stopId={stopId}
{
"data": {
"students": [
{
"studentId": "uuid",
"studentName": "John Doe",
"status": "waiting",
"pickupStopId": "uuid",
"pickupStopName": "Phoenix Marketcity",
"dropoffStopId": "uuid",
"dropoffStopName": "Whitefield"
}
]
}
}
Mark Student Status
POST /driver/bus-tracking/trips/{tripId}/students/mark
{
"data": {
"stopId": "uuid",
"studentId": "uuid",
"status": "boarded"
}
}
Statuses: boarded | alighted | absent | no_show
UI — Students View
class StudentsView extends StatelessWidget {
final String tripId;
final String? stopId;
@override
Widget build(BuildContext context) {
final vm = context.watch<StudentsViewModel>();
return Scaffold(
appBar: AppBar(
title: const Text('Students'),
actions: [
PopupMenuButton<String>(
onSelected: (status) => vm.markAllAtStop(stopId!, status),
itemBuilder: (_) => [
const PopupMenuItem(value: 'boarded', child: Text('Mark All Boarded')),
const PopupMenuItem(value: 'absent', child: Text('Mark All Absent')),
],
),
],
),
body: ListView.builder(
itemCount: vm.students.length,
itemBuilder: (_, i) {
final student = vm.students[i];
return StudentCard(
student: student,
onStatusChanged: (status) => vm.markStudent(
tripId,
vm.stopId!,
student.studentId,
status,
),
);
},
),
);
}
}
UI — Student Card
class StudentCard extends StatelessWidget {
final StudentModel student;
final Function(String) onStatusChanged;
@override
Widget build(BuildContext context) {
final color = {
'waiting': Colors.grey,
'boarded': Colors.green,
'alighted': Colors.blue,
'absent': Colors.red,
'no_show': Colors.orange,
}[student.status]!;
return Card(
child: ListTile(
leading: CircleAvatar(
backgroundColor: color.withOpacity(0.2),
child: Icon(Icons.person, color: color),
),
title: Text(student.studentName),
subtitle: Text(
student.status.toUpperCase(),
style: TextStyle(color: color, fontWeight: FontWeight.bold),
),
trailing: DropdownButton<String>(
value: student.status,
underline: const SizedBox(),
onChanged: (v) => onStatusChanged(v!),
items: ['waiting', 'boarded', 'alighted', 'absent', 'no_show']
.map((s) => DropdownMenuItem(value: s, child: Text(s)))
.toList(),
),
),
);
}
}