import 'dart:async'; import 'package:car_provider_app/views/dashboard/widget/general_appointment_widget.dart'; import 'package:mc_common_app/config/routes.dart'; import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/generated/locale_keys.g.dart'; import 'package:mc_common_app/models/provider_branches_models/branch_detail_model.dart'; import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/utils/date_helper.dart'; import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/utils/navigator.dart'; import 'package:mc_common_app/utils/utils.dart'; import 'package:mc_common_app/view_models/appointments_view_model.dart'; import 'package:mc_common_app/widgets/common_widgets/filters_list.dart'; import 'package:mc_common_app/widgets/empty_widget.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:flutter/material.dart'; import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; import 'package:percent_indicator/percent_indicator.dart'; import 'package:provider/provider.dart'; import 'package:easy_localization/easy_localization.dart'; class AppointmentPage extends StatefulWidget { final BranchDetailModel branch; const AppointmentPage({required this.branch, super.key}); @override State createState() => _AppointmentPageState(); } class _AppointmentPageState extends State { late AppointmentsVM appointmentsVM; GlobalKey refreshIndicatorKey = GlobalKey(); Future _pullRefresh(BuildContext context) async { var futures = >[ appointmentsVM.getAppointmentSlotsInfo(branchID: widget.branch.id!), appointmentsVM.applyFilterOnAppointmentsVMForProviders( appointmentStatusEnum: AppointmentStatusEnum.allAppointments, isNeedCustomerFilter: true, ), ]; // Wait for both futures to complete await Future.wait(futures); } @override void initState() { super.initState(); appointmentsVM = context.read(); appointmentsVM.selectedBranchIdForAppointments = widget.branch.id!; scheduleMicrotask(() { appointmentsVM.selectedDateForAppointments = DateHelper.formatAsYearMonthDay(DateTime.now()); appointmentsVM.populateAppointmentsFilterList(); _pullRefresh(context); }); } @override Widget build(BuildContext context) { return Scaffold( appBar: CustomAppBar( //profileImageUrl: MyAssets.carBanner, title: widget.branch.branchName, actions: [ Consumer(builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) { return Padding( padding: EdgeInsets.only(top: appointmentsVM.appointmentFiltersCounter > 0 ? 20 : 0, right: 21), child: Badge( isLabelVisible: appointmentsVM.appointmentFiltersCounter > 0, largeSize: 15, smallSize: 20, backgroundColor: MyColors.darkPrimaryColor, label: Text('${appointmentsVM.appointmentFiltersCounter}'), child: MyAssets.searchIcon.buildSvg(), ), ).onPress(() { navigateWithName(context, AppRoutes.appoinmentSearchFilterPage); }); }), ], ), body: SizedBox( width: double.infinity, height: double.infinity, child: Consumer(builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) { return RefreshIndicator( onRefresh: () => _pullRefresh(context), key: refreshIndicatorKey, child: SingleChildScrollView( physics: const AlwaysScrollableScrollPhysics(), child: Column( children: [ slotDetailsWidget(context, appointmentsVM), FiltersList( filterList: appointmentsVM.appointmentsFilterOptions, padding: const EdgeInsets.symmetric(horizontal: 18), onFilterTapped: (index, selectedFilterId) { if (appointmentsVM.isAppointmentLoading) { return; } appointmentsVM.applyFilterOnAppointmentsVMForProviders( appointmentStatusEnum: selectedFilterId.toAppointmentStatusEnum(), isNeedCustomerFilter: true, ); }, ), if (appointmentsVM.isAppointmentLoading) ...[ const Column( children: [ SizedBox(height: 50), Center(child: CircularProgressIndicator()), ], ), ] else ...[ if (appointmentsVM.myFilteredAppointmentsForProvider.isEmpty) EmptyWidget( spacerWidget: const SizedBox(height: 25), text: LocaleKeys.noAppointmentFound.tr(), ) else ...[ ListView.separated( itemBuilder: (context, index) { return GeneralAppointmentWidget( isNeedToShowItems: true, appointmentListModel: appointmentsVM.myFilteredAppointmentsForProvider[index], isNeedTotalPayment: false, onTap: () { appointmentsVM.selectedAppointmentIndex = index; navigateWithName( context, AppRoutes.appointmentDetailList, ); }, ); }, separatorBuilder: (context, snapchat) => 21.height, itemCount: appointmentsVM.myFilteredAppointmentsForProvider.length, physics: const NeverScrollableScrollPhysics(), shrinkWrap: true, padding: const EdgeInsets.all(21), ), ], ], ], ), ), ); }), ), ); } Widget slotDetailsWidget(BuildContext context, AppointmentsVM appointmentsVM) { if (appointmentsVM.isSlotsLoading) { return const SizedBox(height: 200, child: Center(child: CircularProgressIndicator())); } double percent = 0.0; if (appointmentsVM.appointmentSlots != null) { percent = appointmentsVM.appointmentSlots!.occupiedSlots / appointmentsVM.appointmentSlots!.totalSlots; } return Column( children: [ Row( children: [ Expanded( child: LocaleKeys.slotsOverview.tr().toText( fontSize: 16, fontWeight: FontWeight.bold, ), ), Row( children: [ appointmentsVM.selectedDateForAppointments.toText( fontWeight: FontWeight.bold, ), const Icon( Icons.keyboard_arrow_down_outlined, size: 16, ), ], ) .toContainer( backgroundColor: MyColors.lightGreyEAColor, borderRadius: 100, padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 6, ), ) .onPress( () async { String date = await Utils.pickDateFromDatePicker(context, firstDate: DateTime(2023)); appointmentsVM.selectedDateForAppointments = date; await appointmentsVM.getAppointmentSlotsInfo(branchID: widget.branch.id!); }, ), ], ), 24.height, Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( width: 14, height: 14, color: MyColors.lightGreyEAColor, ), 4.width, ("${LocaleKeys.empty.tr()}:").toText( fontSize: 8, color: Colors.white, ), (appointmentsVM.appointmentSlots?.emptySlots ?? 0).toString().toText( fontSize: 9, fontWeight: FontWeight.bold, color: Colors.white, ), ], ).toContainer( backgroundColor: MyColors.darkIconColor, ), 8.height, Row( children: [ Container( width: 14, height: 14, color: MyColors.darkPrimaryColor, ), 4.width, ("${LocaleKeys.occupied.tr()}:").toText( fontSize: 8, color: Colors.white, ), (appointmentsVM.appointmentSlots?.occupiedSlots ?? 0).toString().toText( fontSize: 9, fontWeight: FontWeight.bold, color: Colors.white, ), ], ).toContainer( backgroundColor: MyColors.darkIconColor, ), ], ), CircularPercentIndicator( radius: 60.0, lineWidth: 12.0, percent: percent, circularStrokeCap: CircularStrokeCap.round, center: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ LocaleKeys.totalSlots.tr().toText( fontSize: 13, fontWeight: FontWeight.bold, ), (appointmentsVM.appointmentSlots?.totalSlots ?? 0).toString().toText( fontSize: 24, fontWeight: FontWeight.bold, ), ], ), backgroundColor: MyColors.lightGreyEAColor, progressColor: MyColors.darkPrimaryColor, ), ], ) ], ).toWhiteContainer( width: double.infinity, pading: const EdgeInsets.all(12), margin: const EdgeInsets.all(21), ); } }