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.
car_common_app/lib/views/appointments/review_appointment_view.dart

418 lines
20 KiB
Dart

import 'dart:developer';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/app_state.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/service_schedule_model.dart';
import 'package:mc_common_app/models/provider_branches_models/provider_contact_info_model.dart';
import 'package:mc_common_app/models/services_models/item_model.dart';
import 'package:mc_common_app/models/services_models/service_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/view_models/appointments_view_model.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart';
class ReviewAppointment extends StatelessWidget {
const ReviewAppointment({super.key});
Widget showItem(String title, String value) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"$title: ".toText(color: MyColors.lightTextColor, letterSpacing: -0.48),
3.width,
Flexible(child: value.toText(isBold: true, overflow: TextOverflow.ellipsis)),
],
);
}
Widget buildPersonalInformationCard({required BuildContext context}) {
return Padding(
padding: const EdgeInsets.only(
bottom: 0,
left: 21,
right: 21,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
(LocaleKeys.personalInformation.tr()).toText(fontSize: 16, isBold: true),
showItem(LocaleKeys.name.tr(), "${AppState().getUser.data!.userInfo!.firstName ?? ""} ${AppState().getUser.data!.userInfo!.lastName ?? ""}"),
showItem(LocaleKeys.phoneNumber.tr(), AppState().getUser.data!.userInfo!.mobileNo ?? ""),
showItem(LocaleKeys.email.tr(), AppState().getUser.data!.userInfo!.email ?? ""),
],
).toWhiteContainer(width: double.infinity, allPading: 12),
);
}
Widget buildBranchInfoCard({required BuildContext context}) {
AppointmentsVM appointmentsVM = context.read<AppointmentsVM>();
return Padding(
padding: const EdgeInsets.only(
bottom: 0,
left: 21,
right: 21,
),
child: Row(
children: [
appointmentsVM.selectedBranchModel!.branchProfileImage.buildNetworkImage(
width: 80,
height: 60,
fit: BoxFit.cover,
),
12.width,
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
(appointmentsVM.selectedBranchModel!.branchName ?? "").toText(fontSize: 16, isBold: true),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Flexible(
child: (appointmentsVM.selectedBranchModel!.branchDescription ?? "").toText(fontSize: 12, color: MyColors.lightTextColor),
),
],
),
if ((appointmentsVM.selectedBranchModel!.latitude != null && appointmentsVM.selectedBranchModel!.latitude!.isNotEmpty) &&
(appointmentsVM.selectedBranchModel!.longitude != null && appointmentsVM.selectedBranchModel!.longitude!.isNotEmpty)) ...[
Row(
children: [
LocaleKeys.openMapLocation.tr().toText(
fontSize: 12,
isBold: true,
color: MyColors.primaryColor,
isUnderLine: true,
),
4.width,
Image.asset(
MyAssets.icRightUpPng,
height: 6,
width: 6,
color: MyColors.primaryColor,
),
],
).onPress(() async {
double latitude, longitude = 0.0;
latitude = double.parse(appointmentsVM.selectedBranchModel!.latitude!);
longitude = double.parse(appointmentsVM.selectedBranchModel!.longitude!);
await Utils.openLocationInMaps(latitude: latitude, longitude: longitude);
}),
] else ...[
const SizedBox(),
],
],
),
),
if (appointmentsVM.selectedBranchModel!.branchRateAvg != null && appointmentsVM.selectedBranchModel!.branchRateAvg != 0.0) ...[
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
"${appointmentsVM.selectedBranchModel!.branchRateAvg}".toText(
isUnderLine: true,
isBold: true,
fontSize: 12,
),
2.width,
MyAssets.starIcon.buildSvg(width: 12),
],
),
]
],
),
],
),
),
],
).toWhiteContainer(width: double.infinity, allPading: 12));
}
Widget buildServicesInfoCard({required BuildContext context}) {
AppointmentsVM appointmentsVM = context.read<AppointmentsVM>();
return ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: appointmentsVM.serviceAppointmentScheduleList.length,
itemBuilder: (BuildContext context, int scheduleIndex) {
ServiceAppointmentScheduleModel scheduleData = appointmentsVM.serviceAppointmentScheduleList[scheduleIndex];
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: LocaleKeys.services.tr().toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
),
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ListView.separated(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: scheduleData.servicesListInAppointment!.length,
itemBuilder: (BuildContext context, int serviceIndex) {
String selectedTimeSlot = "";
if (scheduleData.selectedCustomTimeDateSlotModel!.availableSlots != null) {
selectedTimeSlot = scheduleData.selectedCustomTimeDateSlotModel!.availableSlots!.firstWhere((element) => element.isSelected).slot;
}
return Column(
children: [
if (scheduleData.servicesListInAppointment!.isNotEmpty) ...[
Column(
children: List.generate(scheduleData.servicesListInAppointment!.length, (serviceIndex) {
ServiceModel serviceData = scheduleData.servicesListInAppointment![serviceIndex];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"${serviceData.providerServiceDescription}".toText(fontSize: 16, isBold: true),
if (scheduleData.appointmentTypeEnum == AppointmentTypeEnum.home) ...[
"${LocaleKeys.chargesPerKM.tr()}: ${serviceData.servicelocationInfo.homeChargesInCurrentService.toStringAsFixed(2)} ${LocaleKeys.sar.tr()}/km".toText(
fontSize: 12,
color: MyColors.lightTextColor,
),
],
],
),
Column(
children: List.generate(serviceData.serviceItems!.length, (itemIndex) {
ItemData itemData = serviceData.serviceItems![itemIndex];
return Column(
children: [
// Item Name and Price
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
("${itemData.name}: ${itemData.price} ${LocaleKeys.sar.tr()}").toText(fontSize: 13, color: MyColors.lightTextColor),
],
),
//Description
// Row(
// crossAxisAlignment: CrossAxisAlignment.start,
// mainAxisAlignment: MainAxisAlignment.start,
// children: [
// ("${itemData.description}").toText(fontSize: 11, color: MyColors.lightTextColor),
// ],
// ),
],
);
}),
).paddingOnly(bottom: 10),
],
);
}),
).paddingOnly(bottom: 10),
],
5.height,
SizedBox(
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.timeLocation.tr().toText(fontSize: 16, isBold: true),
3.height,
Row(children: [
"${LocaleKeys.dateAndTime.tr()}: ".toText(fontSize: 12, color: MyColors.lightTextColor),
"${scheduleData.selectedCustomTimeDateSlotModel!.date!.date} at $selectedTimeSlot".toText(fontSize: 12),
]),
Row(
children: [
("${LocaleKeys.location.tr()}: ").toText(fontSize: 12, color: MyColors.lightTextColor),
(scheduleData.appointmentTypeEnum == AppointmentTypeEnum.home ? LocaleKeys.homeLocation.tr() : LocaleKeys.companyLocation.tr()).toText(fontSize: 12),
if (appointmentsVM.currentLocationInfoModel != null && scheduleData.appointmentTypeEnum == AppointmentTypeEnum.home) ...[
" , ${appointmentsVM.currentLocationInfoModel!.distanceToBranch.toStringAsFixed(2)} KM".toText(fontSize: 12),
],
],
),
if (appointmentsVM.currentLocationInfoModel != null && scheduleData.appointmentTypeEnum == AppointmentTypeEnum.home) ...[
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
("${LocaleKeys.address.tr()}: ").toText(fontSize: 12, color: MyColors.lightTextColor),
Flexible(child: appointmentsVM.currentLocationInfoModel!.address.toText(fontSize: 12)),
],
),
],
],
),
),
10.height,
const Divider(thickness: 0.7),
Builder(builder: (BuildContext context) {
double totalServicePrice = scheduleData.totalLocationCharges ?? 0.0;
double totalKms = scheduleData.locationInfoModel!.distanceToBranch;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.amountVAR.tr().toText(fontSize: 16, isBold: true),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.serviceCharges.tr().toText(fontSize: 14, color: MyColors.lightTextColor),
"${scheduleData.amountTotal.toString()} ${LocaleKeys.sar.tr()}".toText(fontSize: 16, isBold: true),
],
),
if (scheduleData.appointmentTypeEnum == AppointmentTypeEnum.home) ...[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(child: ("${LocaleKeys.locationCharges.tr()} (${totalKms.toStringAsFixed(2)}km away)").toText(fontSize: 14, color: MyColors.lightTextColor)),
("${totalServicePrice.toStringAsFixed(2)} ${LocaleKeys.sar.tr()}").toText(fontSize: 16, isBold: true),
],
),
],
10.height,
],
);
}),
],
);
},
separatorBuilder: (BuildContext context, int index) => const Divider(thickness: 2),
).paddingOnly(bottom: 10),
],
),
],
).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.fromLTRB(21, 0, 21, 12));
},
);
}
Widget buildNextButtonFooter({required BuildContext context}) {
AppointmentsVM appointmentsVM = context.read<AppointmentsVM>();
return Container(
color: MyColors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Divider(thickness: 0.8, height: 2),
8.height,
if (appointmentsVM.amountToPayForAppointment > 0) ...[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.payableNow.tr().toText(fontSize: 14),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
appointmentsVM.amountToPayForAppointment.toString().toText(fontSize: 16, isBold: true),
2.width,
LocaleKeys.sar.tr().toText(color: MyColors.lightTextColor, fontSize: 12, isBold: true).paddingOnly(bottom: 2),
],
)
],
).paddingOnly(left: 21, right: 21),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.remainingAmount.tr().toText(fontSize: 14),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
(appointmentsVM.totalAmount - appointmentsVM.amountToPayForAppointment).toStringAsFixed(2).toText(fontSize: 16, isBold: true),
2.width,
LocaleKeys.sar.tr().toText(color: MyColors.lightTextColor, fontSize: 12, isBold: true).paddingOnly(bottom: 2),
],
)
],
).paddingOnly(left: 21, right: 21),
],
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.totalAmount.tr().toText(fontSize: 18, isBold: true),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
appointmentsVM.totalAmount.toStringAsFixed(2).toText(fontSize: 29, isBold: true),
2.width,
LocaleKeys.sar.tr().toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5),
],
)
],
).paddingOnly(left: 21, right: 21),
5.height,
SizedBox(
width: double.infinity,
child: ShowFillButton(
maxHeight: 55,
backgroundColor: MyColors.darkPrimaryColor,
title: LocaleKeys.bookAppointment.tr(),
onPressed: () {
appointmentsVM.onBookAppointmentPressed(context);
},
).paddingOnly(bottom: 12, left: 21, right: 21),
),
],
),
);
}
@override
Widget build(BuildContext context) {
log("state: ${AppState().getUser.data!.userInfo!.customerId}");
return Scaffold(
appBar: CustomAppBar(
title: LocaleKeys.reviewAppointment.tr(),
isRemoveBackButton: false,
isDrawerEnabled: false,
onBackButtonTapped: () => Navigator.pop(context),
actions: [
IconButton(
onPressed: () async {
final appointmentsVM = context.read<AppointmentsVM>();
ProviderContactInfoModel? contact = await appointmentsVM.getProvidersContactInfo(providerId: appointmentsVM.selectedBranchModel!.serviceProviderId ?? 0, context: context);
if (contact != null) {
Utils.buildProviderContactInfoBottomSheet(context: context, email: contact.email, mobileNo: contact.mobile);
}
},
icon: const Icon(Icons.help_outline_outlined).paddingOnly(right: 21),
),
],
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ListView(
children: [
10.height,
buildBranchInfoCard(context: context),
10.height,
buildServicesInfoCard(context: context),
10.height,
buildPersonalInformationCard(context: context),
20.height,
],
).expand(),
buildNextButtonFooter(context: context),
],
),
);
}
}