You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
462 lines
20 KiB
Dart
462 lines
20 KiB
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/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<Widget> buildServicesFromAppointment({required AppointmentListModel appointmentListModel}) {
|
|
if (appointmentListModel.appointmentServicesList == null || appointmentListModel.appointmentServicesList!.isEmpty) {
|
|
return [const SizedBox()];
|
|
}
|
|
|
|
if (appointmentListModel.appointmentServicesList!.length == 1) {
|
|
List<Widget> 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<Widget> servicesList = List.generate(
|
|
isNeedToShowToMoreText ? 2 : appointmentListModel.appointmentServicesList?.length ?? 0,
|
|
(index) {
|
|
List<Widget> 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"
|
|
// }
|