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/extensions/string_extensions.dart'; import 'package:mc_common_app/generated/locale_keys.g.dart'; import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart'; import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/utils/utils.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:easy_localization/easy_localization.dart'; class GeneralAppointmentWidget extends StatelessWidget { final AppointmentListModel appointmentListModel; final bool isNeedTotalPayment; final bool isNeedToShowItems; final bool isNeedToShowToMoreText; final bool isSelectable; final bool isFromUpdateAppointmentPage; final bool isNeedToShowAppointmentStatus; final bool isNeedToShowMergeStatus; final Function()? onTap; const GeneralAppointmentWidget({ required this.appointmentListModel, required this.onTap, this.isNeedTotalPayment = false, this.isNeedToShowItems = false, this.isNeedToShowToMoreText = true, this.isSelectable = false, this.isNeedToShowAppointmentStatus = false, this.isFromUpdateAppointmentPage = false, this.isNeedToShowMergeStatus = false, super.key, }); List buildServicesFromAppointment({required AppointmentListModel appointmentListModel}) { if (appointmentListModel.appointmentServicesList == null || appointmentListModel.appointmentServicesList!.isEmpty) { return [const SizedBox()]; } if (appointmentListModel.appointmentServicesList!.length == 1) { List itemsList = []; if (isNeedToShowItems) { itemsList = List.generate( appointmentListModel.appointmentServicesList?.first.serviceItems?.length ?? 0, (mIndex) => showItems((appointmentListModel.appointmentServicesList?.first.serviceItems?[mIndex].name ?? "").toString(), MyAssets.modificationsIcon), ); } return [ Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: [ showServices( "${appointmentListModel.appointmentServicesList!.first.providerServiceName} ${appointmentListModel.appointmentServicesList!.first.serviceId != 0 ? '- ${appointmentListModel.appointmentServicesList!.first.serviceId}' : ""}", MyAssets.modificationsIcon, ), if (isNeedToShowItems) ...itemsList, ], ) ]; } List servicesList = List.generate( isNeedToShowToMoreText ? 2 : appointmentListModel.appointmentServicesList?.length ?? 0, (index) { List itemsList = []; if (isNeedToShowItems) { itemsList = List.generate( appointmentListModel.appointmentServicesList?[index].serviceItems?.length ?? 0, (mIndex) => showItems((appointmentListModel.appointmentServicesList?[index].serviceItems?[mIndex].name ?? "").toString(), MyAssets.modificationsIcon), ); } return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ showServices( "${appointmentListModel.appointmentServicesList![index].providerServiceName} ${appointmentListModel.appointmentServicesList![index].serviceId != 0 ? '- ${appointmentListModel.appointmentServicesList![index].serviceId}' : ""}", MyAssets.modificationsIcon, ), if (isNeedToShowItems) ...itemsList, ], ).paddingOnly(bottom: 6); }, ); if (isNeedToShowToMoreText && appointmentListModel.appointmentServicesList!.length > 2) { servicesList.add( showServices( "+ ${appointmentListModel.appointmentServicesList!.length - 2} More", "", isMoreText: true, ), ); } return servicesList; } @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (isSelectable) SizedBox( child: const SizedBox( width: 14, height: 14, ).toContainer( borderRadius: 24, marginAll: 4, paddingAll: 0, backgroundColor: (appointmentListModel.isSelected ?? false) ? MyColors.primaryColor : MyColors.greyButtonColor, ), ).toContainer( borderRadius: 24, isEnabledBorder: true, paddingAll: 0, borderWidget: 3, borderColor: MyColors.primaryColor, ), if (isSelectable) 12.width, Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (isNeedToShowMergeStatus) LocaleKeys.merged.tr().toText(color: MyColors.white).toContainer( padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 3), borderRadius: 12, backgroundColor: MyColors.greenColor, ), Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ (appointmentListModel.branchName ?? "").toText( fontSize: 12, color: MyColors.darkTextColor, isBold: true, ), (appointmentListModel.customerName ?? "").toText(color: MyColors.black, isBold: true, fontSize: 16), Row( children: [ "${LocaleKeys.phone.tr()}:".toText( color: MyColors.lightTextColor, ), 2.width, Expanded( child: appointmentListModel.customerMobileNum.toString().toText( fontSize: 12, ), ), ], ), Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ "${LocaleKeys.time.tr()}:".toText( color: MyColors.lightTextColor, ), 4.width, Expanded(child: (appointmentListModel.duration ?? "").toText(fontSize: 8)) ], ), Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ "${LocaleKeys.date.tr()}:".toText( color: MyColors.lightTextColor, ), 4.width, // Expanded(child: appointmentListModel.appointmentDate!.toFormattedDateWithoutTime().toText(fontSize: 8)) Expanded( child: appointmentListModel.appointmentDate! .toLocalizedFormattedDateWithoutTime(context) .toText(fontSize: 8), ) ], ), Row( children: [ "${LocaleKeys.delivery.tr()}: ".toText(color: MyColors.lightTextColor), 2.width, Expanded( child: (appointmentListModel.appointmentTypeEnum == AppointmentTypeEnum.home ? LocaleKeys.home.tr() : LocaleKeys.workshop.tr()).toText( fontSize: 12, ), ), ], ), Row( children: [ "${LocaleKeys.createdOn.tr()}: ".toText(color: MyColors.lightTextColor), 2.width, // Expanded(child: appointmentListModel.appointmentCreatedOn!.toFormattedDateWithoutTime().toText(fontSize: 8)) Expanded( child: appointmentListModel.appointmentCreatedOn! .toLocalizedFormattedDateWithoutTime(context) .toText(fontSize: 8), ) ], ), if (isFromUpdateAppointmentPage) ...[ if (appointmentListModel.appointmentAddress != null && appointmentListModel.appointmentAddress!.isNotEmpty) ...[ Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ "${LocaleKeys.address.tr()}: ".toText(color: MyColors.lightTextColor), 2.width, Expanded(child: (appointmentListModel.appointmentAddress ?? "").toText(fontSize: 8)) ], ), ], Row( children: [ "${LocaleKeys.paymentType.tr()}: ".toText(color: MyColors.lightTextColor), 2.width, Expanded(child: (appointmentListModel.paymentType ?? "").toText(fontSize: 8)), ], ), LocaleKeys.openMapLocation .tr() .toText( isUnderLine: true, color: MyColors.darkPrimaryColor, fontSize: 10, ) .onPress(() async { double latitude, longitude = 0.0; latitude = double.parse(appointmentListModel.appointmentLatitude!); longitude = double.parse(appointmentListModel.appointmentLongitude!); await Utils.openLocationInMaps(latitude: latitude, longitude: longitude); }), ] ], ), ), if (!isNeedTotalPayment) if (appointmentListModel.customerAppointmentList != null && appointmentListModel.customerAppointmentList!.length > 1) "${appointmentListModel.customerAppointmentList!.length - 1}+ appts".toText(fontSize: 8).toContainer( borderRadius: 15, backgroundColor: MyColors.lightGreyEAColor, padding: const EdgeInsets.symmetric( vertical: 4, horizontal: 8, ), ), if (isNeedToShowAppointmentStatus) (appointmentListModel.appointmentStatusEnum!.getAppointmentNameFromEnum()).toText(color: MyColors.white).toContainer( padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 3), borderRadius: 12, backgroundColor: MyColors.primaryColor, ), ], ), ], ), ), ], ), 8.height, Row( crossAxisAlignment: CrossAxisAlignment.end, children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ ...buildServicesFromAppointment(appointmentListModel: appointmentListModel), if (isNeedTotalPayment) Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ 18.height, LocaleKeys.totalAmount.tr().toText( fontSize: 12, color: MyColors.lightTextColor, ), Row( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.end, children: [ appointmentListModel.totalAmount.toString().toText(fontSize: 16, isBold: true), 2.width, LocaleKeys.sar.tr().toText(color: MyColors.lightTextColor), ], ), 2.height, LocaleKeys.remainingAmount.tr().toText( fontSize: 12, color: MyColors.lightTextColor, ), Row( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.end, children: [ appointmentListModel.remainingAmount.toString().toText(fontSize: 16, isBold: true), 2.width, LocaleKeys.sar.tr().toText(color: MyColors.lightTextColor), ], ), ], ) ], ), ), if (!isNeedToShowItems) const Icon(Icons.arrow_forward), ], ), ], ).toWhiteContainer(width: double.infinity, allPading: 12, onTap: onTap); } double calculateTotalPrice() { double totalServiceListPrice = 0; for (var servicesElement in appointmentListModel.appointmentServicesList!) { for (var itemsElement in servicesElement.serviceItems!) { totalServiceListPrice += double.parse(itemsElement.price ?? "0"); } } return totalServiceListPrice; } Widget showServices(String title, String icon, {bool isMoreText = false}) { return Row( children: [ if (icon != "") ...[ SvgPicture.asset(icon), 8.width, ], Flexible( child: title.toText( fontSize: 12, isBold: true, color: isMoreText ? MyColors.primaryColor : MyColors.black, ), ), ], ); } Widget showItems(String title, String icon) { return Row( children: [ SvgPicture.asset( icon, color: Colors.transparent, ), 8.width, Flexible( child: title.toText( fontSize: 10, color: MyColors.lightTextColor, ), ), ], ); } } // https://ms.hmg.com/api/ServiceProviders/ServiceProviderBranchDetail_Get?ID=1061&ServiceCategoryIDs=4 // {ID: 1061, ServiceCategoryIDs: [4]} // { // "messageStatus": 1, // "totalItemsCount": 1, // "data": [ // { // "id": 1061, // "serviceProviderID": 14, // "serviceProviderName": "James Bond", // "branchName": "Sawaidi Branch", // "branchDescription": "This is Swaidi Branch", // "cityID": 1, // "cityName": "Riyadh", // "address": "Riyadh, KSA", // "latitude": "37.541014800226456", // "longitude": "-122.36278831958771", // "distanceKM": 12811.22, // "openTime": "12:00", // "closeTime": "22:45", // "branchStatus": 3, // "branchStatusText": "ApprovedOrActive", // "branchRateAvg": 0.0, // "serviceProviderServices": [ // { // "serviceProviderServiceID": 1212, // "providerServiceDescription": null, // "categoryID": 4, // "categoryName": "Care and Protection", // "serviceID": 16, // "serviceDescription": "film body protection", // "serviceDescriptionN": "فلم حماية الدهان", // "serviceStatus": 1, // "statusText": null, // "isAllowAppointment": true, // "isAllowAppointmentHome": true, // "customerLocationRange": 10, // "rangePricePerKm": 15.0, // "itemsCount": 1 // } // ], // "serviceProviderBranchImage": [ // { // "id": 136, // "imageName": "image_picker_929CDE1A-800C-4EFE-AC48-7060BB338D77-69034-00003ADB833C597D.jpg", // "imageUrl": "https://ms.hmg.com/api/serviceProviders/ServiceProviderBranchImage?imageName=61aa8beb-99b0-4876-b47a-08dce8674a2c_50243415.png&sp=Provider_14&serviceProviderBranch=ServiceProviderBranch_1061", // "imageStr": null, // "serviceProviderBranchID": 1061, // "serviceProviderBranch": null, // "isActive": true, // "createdBy": 101, // "createdOn": "2024-12-16T14:47:48.6633333", // "modifiedBy": null, // "modifiedOn": null // }, // { // "id": 137, // "imageName": "image_picker_EBF6BA32-3E4E-4AAE-BC2C-1B136A1C32B3-69034-00003ADB7C82E00F.jpg", // "imageUrl": "https://ms.hmg.com/api/serviceProviders/ServiceProviderBranchImage?imageName=61aa8beb-99b0-4876-b47a-08dce8674a2c_51856527.png&sp=Provider_14&serviceProviderBranch=ServiceProviderBranch_1061", // "imageStr": null, // "serviceProviderBranchID": 1061, // "serviceProviderBranch": null, // "isActive": true, // "createdBy": 101, // "createdOn": "2024-12-16T14:47:48.6866667", // "modifiedBy": null, // "modifiedOn": null // }, // { // "id": 138, // "imageName": "image_picker_168879D6-4707-4D0E-ACDA-0C956BD2AC4A-69034-00003AE6922D39CF.jpg", // "imageUrl": "https://ms.hmg.com/api/serviceProviders/ServiceProviderBranchImage?imageName=61aa8beb-99b0-4876-b47a-08dce8674a2c_61115226.png&sp=Provider_14&serviceProviderBranch=ServiceProviderBranch_1061", // "imageStr": null, // "serviceProviderBranchID": 1061, // "serviceProviderBranch": null, // "isActive": true, // "createdBy": 101, // "createdOn": "2024-12-16T14:47:48.7066667", // "modifiedBy": null, // "modifiedOn": null // } // ] // } // ], // "message": "Success" // }