import 'package:diplomaticquarterapp/config/shared_pref_kay.dart'; import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart'; import 'package:diplomaticquarterapp/models/Appointments/DoctorListResponse.dart'; import 'package:diplomaticquarterapp/models/Appointments/FreeSlot.dart'; import 'package:diplomaticquarterapp/models/Appointments/timeSlot.dart'; import 'package:diplomaticquarterapp/services/appointment_services/GetDoctorsList.dart'; import 'package:diplomaticquarterapp/theme/colors.dart'; import 'package:diplomaticquarterapp/uitl/app_shared_preferences.dart'; import 'package:diplomaticquarterapp/uitl/app_toast.dart'; import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart'; import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; import 'package:diplomaticquarterapp/uitl/utils_new.dart'; import 'package:diplomaticquarterapp/widgets/buttons/custom_text_button.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; import 'package:syncfusion_flutter_calendar/calendar.dart'; import '../../../uitl/date_uitl.dart'; class DocAvailableAppointments extends StatefulWidget { DoctorList doctor; static bool areSlotsAvailable = false; static bool areAppointmentsAvailable = false; static DateTime selectedAppoDateTime; static String selectedDate; static String selectedTime; bool isLiveCareAppointment; final dynamic doctorSchedule; static int initialSlotDuration; DocAvailableAppointments({@required this.doctor, this.doctorSchedule, @required this.isLiveCareAppointment}); @override _DocAvailableAppointmentsState createState() => _DocAvailableAppointmentsState(); } class _DocAvailableAppointmentsState extends State with TickerProviderStateMixin { Map _events; AnimationController _animationController; CalendarController _calendarController; AppSharedPreferences sharedPref = new AppSharedPreferences(); var selectedDate = ""; dynamic selectedDateJSON; dynamic jsonFreeSlots; List docFreeSlots = []; List dayEvents = []; int selectedButtonIndex = 0; dynamic freeSlotsResponse; ScrollController _scrollController; var language; bool isLiveCareSchedule; @override void didUpdateWidget(covariant DocAvailableAppointments oldWidget) { if (oldWidget.doctorSchedule != widget.doctorSchedule) { _onDaySelected(DateUtil.convertStringToDate(widget.doctorSchedule['Date'])); _calendarController.selectedDate = DateUtil.convertStringToDate(widget.doctorSchedule['Date']); } super.didUpdateWidget(oldWidget); } @override void initState() { // TODO: implement initState super.initState(); final _selectedDay = DateTime.now(); _scrollController = new ScrollController(); _events = { _selectedDay: ['Event A0'] }; WidgetsBinding.instance.addPostFrameCallback((_) async { getCurrentLanguage(); isLiveCareSchedule = await this.sharedPref.getBool(IS_LIVECARE_APPOINTMENT); if (isLiveCareSchedule != null && isLiveCareSchedule) getDoctorScheduledFreeSlots(context, widget.doctor); else { getDoctorFreeSlots(context, widget.doctor); } }); _calendarController = CalendarController(); _animationController = AnimationController( vsync: this, duration: const Duration(milliseconds: 50), ); _animationController.forward(); } @override void dispose() { _animationController.dispose(); _calendarController.dispose(); super.dispose(); } void _onDaySelected(DateTime day) { final DateFormat formatter = DateFormat('yyyy-MM-dd'); setState(() { this.selectedDate = DateUtil.getWeekDayMonthDayYearDateFormatted(day, language); openTimeSlotsPickerForDate(day, docFreeSlots); DocAvailableAppointments.selectedDate = formatter.format(day); _calendarController.selectedDate = day; print(_calendarController.selectedDate); }); } ProjectViewModel projectViewModel; @override Widget build(BuildContext context) { projectViewModel = Provider.of(context); return SingleChildScrollView( child: Container( child: Column( mainAxisSize: MainAxisSize.max, crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildTableCalendarWithBuilders(), Padding( padding: const EdgeInsets.only(left: 16, right: 16, bottom: 16), child: Text(selectedDate, style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.w600, letterSpacing: -0.64)), ), DocAvailableAppointments.areSlotsAvailable ? Container( height: 40, child: ListView.builder( controller: _scrollController, scrollDirection: Axis.horizontal, itemCount: dayEvents.length, itemBuilder: (context, index) { return Container( margin: EdgeInsets.only(right: (index == dayEvents.length - 1) ? 16 : 5.0, left: index == 0 ? 16 : 5), child: index == selectedButtonIndex ? getSelectedButton(index) : getNormalButton(index), ); }, ), ) : Center( child: Padding( padding: const EdgeInsets.only(left: 12.0, right: 12.0), child: Text(TranslationBase.of(context).noSlotsError, style: TextStyle(fontSize: 14.0, fontWeight: FontWeight.w600, letterSpacing: -0.46, color: CustomColors.grey)), )), ], ), ), ); } Widget _buildTableCalendarWithBuilders() { return Container( decoration: cardRadius(12), margin: EdgeInsets.all(16), clipBehavior: Clip.antiAlias, child: Padding( padding: const EdgeInsets.only(bottom: 12), child: Container( child: SfCalendar( controller: _calendarController, minDate: DateTime.now(), // showNavigationArrow: true, headerStyle: CalendarHeaderStyle(textAlign: TextAlign.center, textStyle: TextStyle(fontSize: 14.0, fontWeight: FontWeight.w600, letterSpacing: -0.46)), viewHeaderStyle: ViewHeaderStyle(dayTextStyle: TextStyle(fontSize: 12.0, fontWeight: FontWeight.w600, letterSpacing: -0.46, color: CustomColors.black)), view: CalendarView.month, todayHighlightColor: CustomColors.green, selectionDecoration: containerColorRadiusBorderWidthCircular(Colors.transparent, 4, CustomColors.green, 2.5), cellBorderColor: Colors.white, dataSource: MeetingDataSource(_getDataSource()), monthViewSettings: const MonthViewSettings(appointmentDisplayMode: MonthAppointmentDisplayMode.indicator, showTrailingAndLeadingDates: false, appointmentDisplayCount: 1), onTap: (CalendarTapDetails details) { _calendarController.selectedDate = details.date; _onDaySelected(details.date); }, ), ), )); } List _getDataSource() { final List meetings = []; _events.forEach((key, value) { final DateTime startTime = DateTime(key.year, key.month, key.day, 9, 0, 0); final DateTime endTime = startTime.add(const Duration(hours: 2)); meetings.add(Meeting("", startTime, endTime, CustomColors.green, false)); }); return meetings; } openTimeSlotsPickerForDate(DateTime dateStart, List freeSlots) { dayEvents.clear(); DateTime dateStartObj = new DateTime(dateStart.year, dateStart.month, dateStart.day, 0, 0, 0, 0, 0); freeSlots.forEach((v) { if (v.start == dateStartObj) dayEvents.add(v); }); setState(() { if (dayEvents.length != 0) { DocAvailableAppointments.areSlotsAvailable = true; selectedButtonIndex = 0; DocAvailableAppointments.selectedTime = dayEvents[selectedButtonIndex].isoTime; } else DocAvailableAppointments.areSlotsAvailable = false; }); } Future> _getJSONSlots() async { Map _eventsParsed; List slotsList = []; DateTime date; final DateFormat formatter = DateFormat('HH:mm'); final DateFormat dateFormatter = DateFormat('yyyy-MM-dd'); for (var i = 0; i < freeSlotsResponse.length; i++) { date = (isLiveCareSchedule != null && isLiveCareSchedule) ? DateUtil.convertStringToDate(freeSlotsResponse[i]) : DateUtil.convertStringToDateSaudiTimezone(freeSlotsResponse[i], widget.doctor.projectID); slotsList.add(FreeSlot(date, ['slot'])); docFreeSlots.add(TimeSlot(isoTime: formatter.format(date), start: new DateTime(date.year, date.month, date.day, 0, 0, 0, 0), end: date)); } _eventsParsed = Map.fromIterable(slotsList, key: (e) => e.slot, value: (e) => e.event); setState(() { DocAvailableAppointments.selectedDate = dateFormatter.format((isLiveCareSchedule != null && isLiveCareSchedule) ? DateUtil.convertStringToDate(freeSlotsResponse[0]) : DateUtil.convertStringToDateSaudiTimezone(freeSlotsResponse[0], widget.doctor.projectID)); DocAvailableAppointments.selectedAppoDateTime = (isLiveCareSchedule != null && isLiveCareSchedule) ? DateUtil.convertStringToDate(freeSlotsResponse[0]) : DateUtil.convertStringToDateSaudiTimezone(freeSlotsResponse[0], widget.doctor.projectID); selectedDate = DateUtil.getWeekDayMonthDayYearDateFormatted( (isLiveCareSchedule != null && isLiveCareSchedule) ? DateUtil.convertStringToDate(freeSlotsResponse[0]) : DateUtil.convertStringToDateSaudiTimezone(freeSlotsResponse[0], widget.doctor.projectID), language); selectedDateJSON = freeSlotsResponse[0]; }); openTimeSlotsPickerForDate( (isLiveCareSchedule != null && isLiveCareSchedule) ? DateUtil.convertStringToDate(selectedDateJSON) : DateUtil.convertStringToDateSaudiTimezone(selectedDateJSON, widget.doctor.projectID), docFreeSlots); _calendarController.selectedDate = (isLiveCareSchedule != null && isLiveCareSchedule) ? DateUtil.convertStringToDate(selectedDateJSON) : DateUtil.convertStringToDateSaudiTimezone(selectedDateJSON, widget.doctor.projectID); _calendarController.displayDate = _calendarController.selectedDate; return _eventsParsed; } Widget getNormalButton(int index) { return CustomTextButton( backgroundColor: Colors.white, elevation: 0, side: BorderSide( color: Colors.black, //Color of the border style: BorderStyle.solid, //Style of the border width: 1.5 //width of the border ), onPressed: () { final timeslot = dayEvents[index]; DocAvailableAppointments.selectedAppoDateTime = timeslot.end; setState(() { selectedButtonIndex = index; DocAvailableAppointments.selectedTime = dayEvents[index].isoTime; print(DocAvailableAppointments.selectedTime); }); projectViewModel.analytics.appointment.book_appointment_time_selection(appointment_type: 'regular', dateTime: timeslot.end, doctor: widget.doctor); }, child: Text(dayEvents[index].isoTime, style: TextStyle(fontSize: 12.0, color: Color(0xFF60686b))), ); } Widget getSelectedButton(int index) { return CustomTextButton( backgroundColor: CustomColors.green, elevation: 0, side: BorderSide( color: CustomColors.green, //Color of the border style: BorderStyle.solid, //Style of the border width: 1.5 //width of the border ), onPressed: () { setState(() { selectedButtonIndex = index; DocAvailableAppointments.selectedTime = dayEvents[index].isoTime; print(DocAvailableAppointments.selectedTime); }); }, child: Text(dayEvents[index].isoTime, style: TextStyle(fontSize: 12.0, color: Colors.white)), ); } getDoctorFreeSlots(context, DoctorList docObject) { GifLoaderDialogUtils.showMyDialog(context); DoctorsListService service = new DoctorsListService(); service.getDoctorFreeSlots(docObject.doctorID, docObject.clinicID, docObject.projectID, context).then((res) { GifLoaderDialogUtils.hideDialog(context); if (res['MessageStatus'] == 1) { if (res['FreeTimeSlots'].length != 0) { DocAvailableAppointments.initialSlotDuration = res['InitialSlotDuration']; DocAvailableAppointments.areAppointmentsAvailable = true; freeSlotsResponse = res['FreeTimeSlots']; _getJSONSlots().then((value) { setState(() => { _events.clear(), _events = value, if (widget.doctorSchedule != null) {_onDaySelected(DateUtil.convertStringToDate(widget.doctorSchedule['Date'])), _calendarController.selectedDate = DateUtil.convertStringToDate(widget.doctorSchedule['Date'])} }); }); } else { DocAvailableAppointments.areAppointmentsAvailable = false; DocAvailableAppointments.areSlotsAvailable = false; AppToast.showErrorToast(message: res['ErrorEndUserMessage']); } } else { AppToast.showErrorToast(message: res['ErrorEndUserMessage']); } }).catchError((err) { GifLoaderDialogUtils.hideDialog(context); AppToast.showErrorToast(message: err); print(err); }); } getDoctorScheduledFreeSlots(context, DoctorList docObject) { GifLoaderDialogUtils.showMyDialog(context); DoctorsListService service = new DoctorsListService(); service.getDoctorScheduledFreeSlots(docObject.doctorID, docObject.clinicID, docObject.projectID, docObject.serviceID, context).then((res) { GifLoaderDialogUtils.hideDialog(context); if (res['MessageStatus'] == 1) { if (res['PatientER_DoctorFreeSlots'].length != 0) { DocAvailableAppointments.areAppointmentsAvailable = true; freeSlotsResponse = res['PatientER_DoctorFreeSlots']; _getJSONSlots().then((value) => { setState(() => {_events.clear(), _events = value}) }); } else { DocAvailableAppointments.areAppointmentsAvailable = false; } } else { AppToast.showErrorToast(message: res['ErrorEndUserMessage']); } }).catchError((err) { GifLoaderDialogUtils.hideDialog(context); AppToast.showErrorToast(message: err); print(err); }); } getCurrentLanguage() async { var languageID = await sharedPref.getStringWithDefaultValue(APP_LANGUAGE, 'ar'); setState(() { this.language = languageID; }); } } class MeetingDataSource extends CalendarDataSource { MeetingDataSource(List source) { appointments = source; } @override DateTime getStartTime(int index) { return _getMeetingData(index).from; } @override DateTime getEndTime(int index) { return _getMeetingData(index).to; } @override String getSubject(int index) { return _getMeetingData(index).eventName; } @override Color getColor(int index) { return _getMeetingData(index).background; } @override bool isAllDay(int index) { return _getMeetingData(index).isAllDay; } Meeting _getMeetingData(int index) { final dynamic meeting = appointments[index]; Meeting meetingData; if (meeting is Meeting) { meetingData = meeting; } return meetingData; } } class Meeting { Meeting(this.eventName, this.from, this.to, this.background, this.isAllDay); String eventName; DateTime from; DateTime to; Color background; bool isAllDay; }