How to Manage Student and Tutor Appointments in Flutter Calendar?
In this article, we will explain how to programmatically manage the student and tutor appointments using the SfCalendar which provides functionality to add accepted appointments into the dataSource of the SfCalendar.
To enhance the student and tutor appointment system, we have to implement two separate screens: one for the tutor and one for the student. The student can request an appointment, and the tutor can accept it. This can be achieved by using two SfCalendar one for the student and one for the tutor.
When the student requests an appointment from their calendar through a custom AlertDialog, the student’s request is added to a pending list, which will be displayed on the tutor’s calendar.
When the tutor accepts the request, an Appointment is created and added to the dataSource of both calendars by dynamically updating the CalendarDataSource. If the tutor rejects the request, the request is removed from the pending list, and a rejection notification is displayed on the student’s calendar.
The following steps explains how to create a students and tutors appointment system in Flutter Calendar:
Step 1: Initialize the student and tutor Calendars
Create two separate calendars to display appointments for both the student and the tutor. The Row widget arranges the two calendars side by side, with the student calendar on the left and the tutor calendar on the right.
Each calendar is wrapped in a Column with a title, and the SfCalendar is used to display the calendars in CalendarView.month view. The MonthViewSettings is used to specify that appointments should display directly within each day slot. The Expanded widget ensures each calendar takes up equal space in the row layout.
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Appointment System'),
),
body: Row(
children: [
// Student's calendar on the left.
Expanded(
child: Column(
children: [
const Text(
'Student Calendar',
style: TextStyle(fontSize: 18),
),
SizedBox(
height: 400,
child: SfCalendar(
view: CalendarView.month,
monthViewSettings: const MonthViewSettings(
appointmentDisplayMode:
MonthAppointmentDisplayMode.appointment,
),
),
),
],
),
),
const VerticalDivider(),
// Tutor's calendar on the right.
Expanded(
child: Column(
children: [
const Text('Tutor Calendar', style: TextStyle(fontSize: 18)),
SizedBox(
height: 400,
child: SfCalendar(
view: CalendarView.month,
monthViewSettings: const MonthViewSettings(
appointmentDisplayMode:
MonthAppointmentDisplayMode.appointment,
),
),
),
],
),
),
],
),
);
}
Step 2: Set the appointment data source
Assign a data source to both calendars using an _AppointmentDataSource class that provides appointment data. This class extends CalendarDataSource and sets up the calendar to display appointments.
The appointments list holds instances of Appointment, which are displayed in both calendars. By setting the same dataSource for both calendars, any updates to appointments will reflect in both calendars simultaneously.
List<Appointment> appointments = [];
@override
Widget build(BuildContext context) {
return Scaffold(
.....
children: [
// Student's calendar on the left.
Expanded(
child: Column(
children: [
.....
SizedBox(
height: 400,
child: SfCalendar(
view: CalendarView.month,
dataSource: _AppointmentDataSource(appointments),
.....
),
),
],
),
),
const VerticalDivider(),
// Tutor's calendar on the right.
.....
child: SfCalendar(
view: CalendarView.month,
// Same data source.
dataSource: _AppointmentDataSource(appointments),
.....
}
// Class to represent an appointment request.
class AppointmentRequest {
String studentName;
DateTime startTime;
bool isAccepted;
AppointmentRequest(
this.studentName,
this.startTime,
this.isAccepted,
);
}
// Data source for the Syncfusion calendar.
class _AppointmentDataSource extends CalendarDataSource {
_AppointmentDataSource(List<Appointment> source) {
appointments = source;
}
}
Step 3: Initialize the pending requests list
Create a list to manage and display pending appointment requests. The pendingRequests list holds appointment requests from students before they are accepted or rejected by the tutor. This list stores instances of AppointmentRequest, a class representing a student’s request, including their name, requested time, and acceptance status. Later, this list will be displayed for the tutor to review.
List<AppointmentRequest> pendingRequests = [];
Step 4: Create an appointment request function
Create a function to capture student appointment requests with the specified date and time. The requestAppointment method is triggered when a student submits an appointment request. This method accepts the student’s name and the appointment start time as parameters, then adds a new AppointmentRequest to the pendingRequests list, marking it as unaccepted initially. The setState method is called to refresh the UI and reflect the updated list of requests.
void requestAppointment(String studentName, DateTime startTime) {
setState(() {
pendingRequests.add(
AppointmentRequest(studentName, startTime, false),
);
});
}
Step 5: Implement the appointment request dialog
Create a dialog for students to input their name and select an appointment date and time. The _showRequestDialog method opens a dialog where the student can input their name and select an appointment time. It uses showDatePicker and showTimePicker to allow the student to select a date and time.
Once the request is confirmed, requestAppointment is called to add the request to the pending list. This dialog enables students to provide necessary details for the appointment.
void _showRequestDialog(BuildContext context) {
final nameController = TextEditingController();
DateTime selectedTime = DateTime.now();
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Request Appointment'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(
controller: nameController,
decoration: const InputDecoration(labelText: 'Student Name'),
),
const SizedBox(height: 10),
ElevatedButton(
child: const Text('Pick Date & Time'),
onPressed: () async {
DateTime? pickedDate = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime.now(),
lastDate: DateTime(2100),
);
if (pickedDate != null) {
TimeOfDay? pickedTime = await showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
);
if (pickedTime != null) {
selectedTime = DateTime(
pickedDate.year,
pickedDate.month,
pickedDate.day,
pickedTime.hour,
pickedTime.minute,
);
}
}
},
),
],
),
actions: [
TextButton(
onPressed: () {
if (nameController.text.isNotEmpty) {
requestAppointment(nameController.text, selectedTime);
}
Navigator.pop(context);
},
child: const Text('Request'),
),
],
),
);
}
Step 6: Assign the appointment request dialog to the student Calendar
Add a button to trigger the request dialog from the student calendar. A “Request Appointment” button is added below the student calendar, and tapping it triggers _showRequestDialog. This button provides a convenient way for students to access the request dialog. By placing the button near the student calendar, it creates a logical workflow for students to request appointments.
const Text(
'Student Calendar',
style: TextStyle(fontSize: 18),
),
SizedBox(
height: 400,
child: SfCalendar(
.....
),
),
ElevatedButton(
onPressed: () => _showRequestDialog(context),
child: const Text('Request Appointment'),
),
Step 7: Display pending requests on the tutor Calendar
To show a list of pending requests for the tutor to review in their calendar view, a ListView.builder displays the pending appointment requests for the tutor. Each item in the list shows the student’s name and the requested time. This setup helps the tutor quickly see all requests and choose whether to accept or reject each one. The pending requests section is located below the tutor calendar, aligning the layout intuitively for the tutor.
const Text('Tutor Calendar', style: TextStyle(fontSize: 18)),
SizedBox(
height: 400,
child: SfCalendar(
.....
),
),
const SizedBox(height: 20),
const Text(
'Pending Appointment Requests:',
style: TextStyle(fontSize: 16),
),
Expanded(
child: ListView.builder(
itemCount: pendingRequests.length,
itemBuilder: (context, index) {
var request = pendingRequests[index];
return ListTile(
title: Text('Request from ${request.studentName}'),
subtitle: Text('Time: ${request.startTime}'),
);
},
),
),
Step 8: Create an appointments accept function
Create a function that moves accepted appointments to the tutor’s calendar. The acceptAppointment method processes a pending appointment by adding it to the appointments list as an accepted Appointment and removing it from the pendingRequests list.
The Appointment is marked with a green color and an “Accepted” label to distinguish it from other appointments. This allows tutors to accept and confirm student requests.
void acceptAppointment(int index) {
setState(() {
var request = pendingRequests[index];
var acceptedAppointment = Appointment(
startTime: request.startTime,
endTime: request.startTime.add(const Duration(minutes: 30)),
subject: '${request.studentName} - Accepted',
color: Colors.green,
);
appointments.add(acceptedAppointment);
pendingRequests.removeAt(index);
});
}
Step 9: Create an appointments reject function
Create a function to remove and track rejected appointments. The rejectAppointment method removes a selected request from pendingRequests and adds the student’s name to rejectedRequests, which keeps a record of rejected appointments. This list will later be used to inform students about rejections. Removing requests from pendingRequests streamlines the list, showing only pending or accepted appointments.
void rejectAppointment(int index) {
setState(() {
var request = pendingRequests[index];
rejectedRequests.add(request.studentName);
pendingRequests.removeAt(index);
});
}
Step 10: Enable acceptance and rejection controls for tutor
Add action buttons in the pending requests list for tutors to accept or reject. For each pending request, the ListTile displays an accept and reject icon button. When the tutor clicks the accept icon, acceptAppointment is called to add the appointment. If the reject icon is tapped, rejectAppointment is triggered to remove the request. This interactive layout allows the tutor to quickly manage student requests.
return ListTile(
title: Text('Request from ${request.studentName}'),
subtitle: Text('Time: ${request.startTime}'),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: const Icon(Icons.check, color: Colors.green),
onPressed: () => acceptAppointment(index),
),
IconButton(
icon: const Icon(Icons.close, color: Colors.red),
onPressed: () => rejectAppointment(index),
),
],
),
);
Step 11: Notify students of rejected appointments
If a request is rejected, the student is notified via the rejectedRequests list, which is displayed below the request button. Each rejected student is informed with a message indicating that their appointment was declined, providing clear feedback on the status of their request. This step ensures the student is kept informed about the appointment outcome.
ElevatedButton(
onPressed: () => _showRequestDialog(context),
child: const Text('Request Appointment'),
),
// Display rejected requests.
if (rejectedRequests.isNotEmpty) ...[
const SizedBox(height: 20),
const Text('Rejected Requests:', style: TextStyle(fontSize: 16)),
...rejectedRequests
.map((name) => Text('Request from $name was rejected.'))
.toList(),
],
Now, the tutor appointment system in Flutter Calendar has been implemented as shown below.
View the GitHub sample here: Create a student and tutor appointment system in Flutter Calendar
Conclusion
I hope you enjoyed learning about how to create a student and tutor appointment in Flutter Calendar.
You can refer to our Flutter Calendar feature tour page to know about its other groundbreaking feature representations documentation. You can also explore our Flutter Calendar example to understand how to create and manipulate data.
For current customers, you can check out our components from the License and Downloads page. If you are new to Syncfusion®, you can try our 30-day free trialto check out our other controls.
If you have any queries or require clarifications, please let us know in the comments section below. You can also contact us through our support forums, Direct-Trac, or feedback portal. We are always happy to assist you!