diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 6b4b846..9d6e575 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -101,6 +101,9 @@ class ApiConsts { static String deleteAd = "${baseUrlServices}api/Advertisement/Ads_Delete"; static String adsCarCheckupSPBranchScheduleSlotGet = "${baseUrlServices}api/Advertisement/AdsCarCheckupSPBranchScheduleSlot_Get"; static String adsPhotoOfficeAppointmentScheduleSlotGet = "${baseUrlServices}api/Advertisement/PhotoOfficeAppointmentScheduleSlot_Get"; + static String adsPhotoOfficeAppointmentCreate = "${baseUrlServices}api/Advertisement/PhotoOfficeAppointment_Create"; + static String adsMCBankAccountAdGet = "${baseUrlServices}api/Advertisement/MCBankAccountAd_Get"; + //Subscription static String getAllSubscriptions = "${baseUrlServices}api/Common/Subscription_Get"; diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index b000882..000ed6a 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -285,10 +285,10 @@ extension PaymentTypesToInt on PaymentTypes { return 2; case PaymentTypes.adReserve: - return 3; + return 4; case PaymentTypes.ads: - return 4; + return 3; case PaymentTypes.request: return 5; diff --git a/lib/models/advertisment_models/ad_details_model.dart b/lib/models/advertisment_models/ad_details_model.dart index 37dcc42..dc0c4d6 100644 --- a/lib/models/advertisment_models/ad_details_model.dart +++ b/lib/models/advertisment_models/ad_details_model.dart @@ -138,48 +138,6 @@ class AdDetailsModel { isMyAd = isMyAds; isReservedByMe = false; } - - Map toJson() { - final Map data = {}; - data['id'] = id; - data['startdate'] = startdate; - data['enddate'] = enddate; - if (vehicle != null) { - data['vehicle'] = vehicle!.toJson(); - } - if (specialservice != null) { - data['specialservice'] = specialservice!.map((v) => v.toJson()).toList(); - } - // if (reserved != null) { - // data['reserved'] = reserved!.map((v) => v.toJson()).toList(); - // } - data['statusID'] = statusID; - data['statuslabel'] = statuslabel; - data['adsDurationPrice'] = adsDurationPrice; - data['adsDurationDiscount'] = adsDurationDiscount; - data['adsDurationDiscountPrice'] = adsDurationDiscountPrice; - data['comment'] = comment; - data['active'] = active; - data['isPaid'] = isPaid; - data['isSubscription'] = isSubscription; - data['isVerified'] = isVerified; - data['netPrice'] = netPrice; - data['specialServiceTotalPrice'] = specialServiceTotalPrice; - data['taxPrice'] = taxPrice; - data['totalPrice'] = totalPrice; - data['userID'] = userID; - data['vehiclePostingID'] = vehiclePostingID; - data['qrCodePath'] = qrCodePath; - data['isCustomerAcknowledged'] = isCustomerAcknowledged; - data['createdByRole'] = createdByRole; - data['totalViews'] = totalViews; - data['createdOn'] = createdOn; - data['priceExcludingDiscount'] = priceExcludingDiscount; - data['reservePrice'] = reservePrice; - data['isMCHandled'] = isMCHandled; - data['modifiedOn'] = modifiedOn; - return data; - } } class Vehicle { @@ -273,58 +231,6 @@ class Vehicle { countryID = json['countryID']; currency = json['currency']; } - - Map toJson() { - final Map data = {}; - data['id'] = id; - data['cityID'] = cityID; - data['cityName'] = cityName; - data['demandAmount'] = demandAmount; - data['isActive'] = isActive; - data['isFinanceAvailable'] = isFinanceAvailable; - data['status'] = status; - data['statustext'] = statustext; - if (category != null) { - data['category'] = category!.toJson(); - } - if (color != null) { - data['color'] = color!.toJson(); - } - if (condition != null) { - data['condition'] = condition!.toJson(); - } - if (mileage != null) { - data['mileage'] = mileage!.toJson(); - } - if (model != null) { - data['model'] = model!.toJson(); - } - if (modelyear != null) { - data['modelyear'] = modelyear!.toJson(); - } - if (sellertype != null) { - data['sellertype'] = sellertype!.toJson(); - } - if (transmission != null) { - data['transmission'] = transmission!.toJson(); - } - if (duration != null) { - data['duration'] = duration!.toJson(); - } - if (image != null) { - data['image'] = image!.map((v) => v.toJson()).toList(); - } - if (damagereport != null) { - data['damagereport'] = damagereport!.map((v) => v.toJson()).toList(); - } - data['vehicleDescription'] = vehicleDescription; - data['vehicleTitle'] = vehicleTitle; - data['vehicleType'] = vehicleType; - data['vehicleVIN'] = vehicleVIN; - data['countryID'] = countryID; - data['currency'] = currency; - return data; - } } class Category { diff --git a/lib/models/advertisment_models/ads_bank_details_model.dart b/lib/models/advertisment_models/ads_bank_details_model.dart new file mode 100644 index 0000000..47fb8cc --- /dev/null +++ b/lib/models/advertisment_models/ads_bank_details_model.dart @@ -0,0 +1,30 @@ +class AdsBankDetailsModel { + int? id; + int? mcBankAccountID; + int? adsID; + bool? isActive; + String? bankName; + String? iban; + + AdsBankDetailsModel({this.id, this.mcBankAccountID, this.adsID, this.isActive, this.bankName, this.iban}); + + AdsBankDetailsModel.fromJson(Map json) { + id = json['id']; + mcBankAccountID = json['mcBankAccountID']; + adsID = json['adsID']; + isActive = json['isActive']; + bankName = json['bankName']; + iban = json['iban']; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['mcBankAccountID'] = mcBankAccountID; + data['adsID'] = adsID; + data['isActive'] = isActive; + data['bankName'] = bankName; + data['iban'] = iban; + return data; + } +} diff --git a/lib/models/advertisment_models/special_service_model.dart b/lib/models/advertisment_models/special_service_model.dart index 33e21c5..73204b5 100644 --- a/lib/models/advertisment_models/special_service_model.dart +++ b/lib/models/advertisment_models/special_service_model.dart @@ -1,3 +1,6 @@ +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/utils/enums.dart'; + class SpecialServiceModel { int? id; String? name; @@ -53,27 +56,6 @@ class SpecialServiceModel { isDelivery = json['isDelivery']; isSelected = false; } - - Map toJson() { - final Map data = {}; - data['id'] = id; - data['name'] = name; - data['description'] = description; - data['price'] = price; - data['specialServiceType'] = specialServiceType; - data['specialServiceTypeName'] = specialServiceTypeName; - data['isActive'] = isActive; - data['startDate'] = startDate; - data['endDate'] = endDate; - if (details != null) { - data['details'] = details!.map((v) => v.toJson()).toList(); - } - if (office != null) { - data['office'] = office!.map((v) => v.toJson()).toList(); - } - data['isDelivery'] = isDelivery; - return data; - } } class Details { @@ -92,16 +74,6 @@ class Details { tocity = json['tocity']; price = json['price']; } - - Map toJson() { - final Map data = {}; - data['id'] = id; - data['specialServiceID'] = specialServiceID; - data['fromcity'] = fromcity; - data['tocity'] = tocity; - data['price'] = price; - return data; - } } class Office { @@ -122,17 +94,6 @@ class Office { city = json['city']; specialServiceID = json['specialServiceID']; } - - Map toJson() { - final Map data = {}; - data['id'] = id; - data['officeAreaName'] = officeAreaName; - data['officeAreaNameN'] = officeAreaNameN; - data['cityID'] = cityID; - data['city'] = city; - data['specialServiceID'] = specialServiceID; - return data; - } } class SpecialServiceModelForAds { @@ -141,6 +102,9 @@ class SpecialServiceModelForAds { String? name; String? description; double? price; + AppointmentStatusEnum? appointmentStatusEnum; + int? appointmentStatusId; + String? appointmentDate; SpecialServiceModelForAds({ this.adsID, @@ -148,6 +112,9 @@ class SpecialServiceModelForAds { this.name, this.description, this.price, + this.appointmentStatusEnum, + this.appointmentDate, + this.appointmentStatusId, }); SpecialServiceModelForAds.fromJson(Map json) { @@ -156,15 +123,14 @@ class SpecialServiceModelForAds { name = json['name']; description = json['description']; price = json['price']; + appointmentStatusEnum = (json['appointmentStatus'] as int).toAppointmentStatusEnum(); + appointmentDate = json['appointmentDate']; + appointmentStatusId = json['appointmentStatus']; + } - Map toJson() { - final Map data = {}; - data['adsID'] = adsID; - data['specialServiceID'] = specialServiceID; - data['name'] = name; - data['description'] = description; - data['price'] = price; - return data; + @override + String toString() { + return 'SpecialServiceModelForAds{adsID: $adsID, specialServiceID: $specialServiceID, name: $name, description: $description, price: $price, appointmentStatusEnum: $appointmentStatusEnum, appointmentStatusId: $appointmentStatusId, appointmentDate: $appointmentDate}'; } } diff --git a/lib/models/advertisment_models/ss_car_check_schedule_model.dart b/lib/models/advertisment_models/ss_car_check_schedule_model.dart index 8c538bc..0c0e22d 100644 --- a/lib/models/advertisment_models/ss_car_check_schedule_model.dart +++ b/lib/models/advertisment_models/ss_car_check_schedule_model.dart @@ -1,3 +1,6 @@ +import 'package:mc_common_app/models/service_schedule_model.dart'; +import 'package:mc_common_app/models/widgets_models.dart'; + class SSCarCheckScheduleModel { int? serviceProviderID; int? serviceProviderBranchID; @@ -7,22 +10,27 @@ class SSCarCheckScheduleModel { String? latitude; String? longitude; List? scheduleServices; - List? branchScheduleSlots; + List? branchScheduleSlots; int? totalItemsCount; int? distanceKM; + List? customTimeDateSlotList; + CustomTimeDateSlotModel? selectedCustomTimeDateSlotModel; - SSCarCheckScheduleModel( - {this.serviceProviderID, - this.serviceProviderBranchID, - this.branchAppointmentScheduleID, - this.branchName, - this.address, - this.latitude, - this.longitude, - this.scheduleServices, - this.branchScheduleSlots, - this.distanceKM, - this.totalItemsCount}); + SSCarCheckScheduleModel({ + this.serviceProviderID, + this.serviceProviderBranchID, + this.branchAppointmentScheduleID, + this.branchName, + this.address, + this.latitude, + this.longitude, + this.scheduleServices, + this.branchScheduleSlots, + this.distanceKM, + this.totalItemsCount, + this.selectedCustomTimeDateSlotModel, + this.customTimeDateSlotList, + }); SSCarCheckScheduleModel.fromJson(Map json) { serviceProviderID = json['serviceProviderID']; @@ -39,36 +47,51 @@ class SSCarCheckScheduleModel { }); } if (json['branchScheduleSlots'] != null) { - branchScheduleSlots = []; + branchScheduleSlots = []; json['branchScheduleSlots'].forEach((v) { - branchScheduleSlots!.add(BranchScheduleSlots.fromJson(v)); + branchScheduleSlots!.add(CarCheckOfficeScheduleSlots.fromJson(v)); }); } totalItemsCount = json['totalItemsCount']; //TODO: We will update this when Backend team will add this value distanceKM = 0; + customTimeDateSlotList = getFormattedDateTimeSlotPackage(); } - Map toJson() { - final Map data = {}; - data['serviceProviderID'] = serviceProviderID; - data['serviceProviderBranchID'] = serviceProviderBranchID; - data['branchAppointmentScheduleID'] = branchAppointmentScheduleID; - data['branchName'] = branchName; - data['address'] = address; - data['latitude'] = latitude; - data['longitude'] = longitude; - if (scheduleServices != null) { - data['scheduleServices'] = scheduleServices!.map((v) => v.toJson()).toList(); + List getFormattedDateTimeSlotPackage() { + List customTimeDateSlotList = []; + for (var element in branchScheduleSlots!) { + if (!isAlreadyThere(element.slotDate!, customTimeDateSlotList)) { + customTimeDateSlotList.add(CustomTimeDateSlotModel( + date: TimeSlotModel(slotId: element.id!, isSelected: false, date: element.slotDate!, allowAppointment: (element.allowAppointment ?? 0) > (element.bookAppointment ?? 0)), + availableSlots: getAvailableSlotsByDate(element.slotDate!), + )); + } } - if (branchScheduleSlots != null) { - data['branchScheduleSlots'] = branchScheduleSlots!.map((v) => v.toJson()).toList(); + + return customTimeDateSlotList; + } + + List? getAvailableSlotsByDate(String date) { + List timeslots = []; + for (var element in branchScheduleSlots!) { + if (element.slotDate == date) { + timeslots.add(TimeSlotModel(slotId: element.id!, slot: element.startTime!, date: element.slotDate!, isSelected: false, allowAppointment: element.bookAppointment! < element.allowAppointment!)); + } } - data['totalItemsCount'] = totalItemsCount; - data['distanceKM'] = distanceKM; + return timeslots; + } - return data; + bool isAlreadyThere(String dateToFind, List slots) { + int index = slots.indexWhere((element) { + return element.date!.date == dateToFind; + }); + if (index == -1) { + return false; + } else { + return true; + } } } @@ -91,19 +114,25 @@ class ScheduleServices { } } -class BranchScheduleSlots { +class CarCheckOfficeScheduleSlots { int? id; String? slotDate; String? startTime; String? endTime; + int? bookAppointment; + int? allowAppointment; + int? slotDurationMinute; - BranchScheduleSlots({this.id, this.slotDate, this.startTime, this.endTime}); + CarCheckOfficeScheduleSlots({this.id, this.slotDate, this.startTime, this.endTime, this.bookAppointment, this.allowAppointment, this.slotDurationMinute}); - BranchScheduleSlots.fromJson(Map json) { + CarCheckOfficeScheduleSlots.fromJson(Map json) { id = json['id']; slotDate = json['slotDate']; startTime = json['startTime']; endTime = json['endTime']; + bookAppointment = json['bookAppointment']; + allowAppointment = json['allowAppointment']; + slotDurationMinute = json['slotDurationMinute']; } Map toJson() { @@ -112,6 +141,9 @@ class BranchScheduleSlots { data['slotDate'] = slotDate; data['startTime'] = startTime; data['endTime'] = endTime; + data['bookAppointment'] = bookAppointment; + data['allowAppointment'] = allowAppointment; + data['slotDurationMinute'] = slotDurationMinute; return data; } } diff --git a/lib/models/advertisment_models/ss_photo_schedule_model.dart b/lib/models/advertisment_models/ss_photo_schedule_model.dart index d863f41..fdef0fa 100644 --- a/lib/models/advertisment_models/ss_photo_schedule_model.dart +++ b/lib/models/advertisment_models/ss_photo_schedule_model.dart @@ -1,4 +1,8 @@ -class SSPhotoScheduleModel { +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/models/service_schedule_model.dart'; +import 'package:mc_common_app/models/widgets_models.dart'; + +class SSPhotoOfficeScheduleModel { int? photoOfficeID; String? fromDate; String? toDate; @@ -11,22 +15,29 @@ class SSPhotoScheduleModel { int? distanceKM; int? totalItemsCount; List? photoOfficeScheduleSlots; + List? customTimeDateSlotList; + CustomTimeDateSlotModel? selectedCustomTimeDateSlotModel; + int? selectedDateIndex; - SSPhotoScheduleModel( - {this.photoOfficeID, - this.fromDate, - this.toDate, - this.photoOfficeAppointmentScheduleID, - this.photoOfficeName, - this.description, - this.areaName, - this.latitude, - this.longitude, - this.distanceKM, - this.totalItemsCount, - this.photoOfficeScheduleSlots}); + SSPhotoOfficeScheduleModel({ + this.photoOfficeID, + this.fromDate, + this.toDate, + this.photoOfficeAppointmentScheduleID, + this.photoOfficeName, + this.description, + this.areaName, + this.latitude, + this.longitude, + this.distanceKM, + this.totalItemsCount, + this.photoOfficeScheduleSlots, + this.customTimeDateSlotList, + this.selectedCustomTimeDateSlotModel, + this.selectedDateIndex, + }); - SSPhotoScheduleModel.fromJson(Map json) { + SSPhotoOfficeScheduleModel.fromJson(Map json) { photoOfficeID = json['photoOfficeID']; fromDate = json['fromDate']; toDate = json['toDate']; @@ -44,27 +55,43 @@ class SSPhotoScheduleModel { photoOfficeScheduleSlots!.add(PhotoOfficeScheduleSlots.fromJson(v)); }); } + customTimeDateSlotList = getFormattedDateTimeSlotPackage(); + selectedDateIndex = null; + } + + List getFormattedDateTimeSlotPackage() { + List customTimeDateSlotList = []; + for (var element in photoOfficeScheduleSlots!) { + if (!isAlreadyThere(element.slotDate!, customTimeDateSlotList)) { + customTimeDateSlotList.add(CustomTimeDateSlotModel( + date: TimeSlotModel(slotId: element.id!, isSelected: false, date: element.slotDate!, allowAppointment: (element.allowAppointment ?? 0) > (element.bookAppointment ?? 0)), + availableSlots: getAvailableSlotsByDate(element.slotDate!), + )); + } + } + + return customTimeDateSlotList; } - Map toJson() { - final Map data = {}; - data['photoOfficeID'] = photoOfficeID; - data['fromDate'] = fromDate; - data['toDate'] = toDate; - data['photoOfficeAppointmentScheduleID'] = - photoOfficeAppointmentScheduleID; - data['photoOfficeName'] = photoOfficeName; - data['description'] = description; - data['areaName'] = areaName; - data['latitude'] = latitude; - data['longitude'] = longitude; - data['distanceKM'] = distanceKM; - data['totalItemsCount'] = totalItemsCount; - if (photoOfficeScheduleSlots != null) { - data['photoOfficeScheduleSlots'] = - photoOfficeScheduleSlots!.map((v) => v.toJson()).toList(); + List? getAvailableSlotsByDate(String date) { + List timeslots = []; + for (var element in photoOfficeScheduleSlots!) { + if (element.slotDate == date) { + timeslots.add(TimeSlotModel(slotId: element.id!, slot: element.startTime!, date: element.slotDate!, isSelected: false, allowAppointment: element.bookAppointment! < element.allowAppointment!)); + } + } + return timeslots; + } + + bool isAlreadyThere(String dateToFind, List slots) { + int index = slots.indexWhere((element) { + return element.date!.date == dateToFind; + }); + if (index == -1) { + return false; + } else { + return true; } - return data; } } @@ -77,35 +104,15 @@ class PhotoOfficeScheduleSlots { int? allowAppointment; int? slotDurationMinute; - PhotoOfficeScheduleSlots( - {this.id, - this.slotDate, - this.startTime, - this.endTime, - this.bookAppointment, - this.allowAppointment, - this.slotDurationMinute}); + PhotoOfficeScheduleSlots({this.id, this.slotDate, this.startTime, this.endTime, this.bookAppointment, this.allowAppointment, this.slotDurationMinute}); PhotoOfficeScheduleSlots.fromJson(Map json) { id = json['id']; - slotDate = json['slotDate']; + slotDate = (json['slotDate'] as String).toFormattedDateWithoutTime(); startTime = json['startTime']; endTime = json['endTime']; bookAppointment = json['bookAppointment']; allowAppointment = json['allowAppointment']; slotDurationMinute = json['slotDurationMinute']; } - - Map toJson() { - final Map data = {}; - data['id'] = id; - data['slotDate'] = slotDate; - data['startTime'] = startTime; - data['endTime'] = endTime; - data['bookAppointment'] = bookAppointment; - data['allowAppointment'] = allowAppointment; - data['slotDurationMinute'] = slotDurationMinute; - return data; - } } - diff --git a/lib/models/service_schedule_model.dart b/lib/models/service_schedule_model.dart index 071d1ff..5df14a7 100644 --- a/lib/models/service_schedule_model.dart +++ b/lib/models/service_schedule_model.dart @@ -1,5 +1,4 @@ import 'package:mc_common_app/extensions/string_extensions.dart'; -import 'package:mc_common_app/models/services/item_model.dart'; import 'package:mc_common_app/models/services/service_model.dart'; import 'package:mc_common_app/models/widgets_models.dart'; @@ -51,11 +50,7 @@ class ServiceAppointmentScheduleModel { List timeslots = []; for (var element in serviceSlotList!) { if (element.slotDate == date) { - timeslots.add(TimeSlotModel(slotId: element.id!, - slot: element.startTime!, - date: element.slotDate!, - isSelected: false, - allowAppointment: element.bookAppointment! < element.allowAppointment!)); + timeslots.add(TimeSlotModel(slotId: element.id!, slot: element.startTime!, date: element.slotDate!, isSelected: false, allowAppointment: element.bookAppointment! < element.allowAppointment!)); } } return timeslots; @@ -65,13 +60,12 @@ class ServiceAppointmentScheduleModel { var seenSlots = {}; var slotTimeData = serviceSlotList! - .where((slot) => - seenSlots.add(TimeSlotModel( - slot: slot.startTime!, - slotId: slot.id!, - isSelected: false, - date: slot.slotDate!.toFormattedDateWithoutTime(), - ))) + .where((slot) => seenSlots.add(TimeSlotModel( + slot: slot.startTime!, + slotId: slot.id!, + isSelected: false, + date: slot.slotDate!.toFormattedDateWithoutTime(), + ))) .toList(); List slotTime = []; for (var element in slotTimeData) { @@ -92,13 +86,6 @@ class ServiceAppointmentScheduleModel { } } - List getFormattedSlotDates() { - List slotDates = []; - return slotDates; - } - - //comprehensive checkup and body checkup - ServiceAppointmentScheduleModel.fromJson(Map json, {bool isForAppointment = false}) { if (json['serviceSlotList'] != null) { serviceSlotList = []; @@ -139,22 +126,23 @@ class ServiceSlotList { int? modifiedBy; String? modifiedOn; - ServiceSlotList({this.id, - this.branchAppointmentScheduleID, - this.branchAppointmentSchedule, - this.serviceProviderID, - this.slotDate, - this.startTime, - this.endTime, - this.bookAppointment, - this.allowAppointment, - this.slotDurationMinute, - this.appointmentType, - this.isActive, - this.createdBy, - this.createdOn, - this.modifiedBy, - this.modifiedOn}); + ServiceSlotList( + {this.id, + this.branchAppointmentScheduleID, + this.branchAppointmentSchedule, + this.serviceProviderID, + this.slotDate, + this.startTime, + this.endTime, + this.bookAppointment, + this.allowAppointment, + this.slotDurationMinute, + this.appointmentType, + this.isActive, + this.createdBy, + this.createdOn, + this.modifiedBy, + this.modifiedOn}); ServiceSlotList.fromJson(Map json) { id = json['id']; @@ -175,27 +163,6 @@ class ServiceSlotList { modifiedOn = json['modifiedOn']; } - Map toJson() { - final Map data = {}; - data['id'] = id; - data['branchAppointmentScheduleID'] = branchAppointmentScheduleID; - data['branchAppointmentSchedule'] = branchAppointmentSchedule; - data['serviceProviderID'] = serviceProviderID; - data['slotDate'] = slotDate; - data['startTime'] = startTime; - data['endTime'] = endTime; - data['bookAppointment'] = bookAppointment; - data['allowAppointment'] = allowAppointment; - data['slotDurationMinute'] = slotDurationMinute; - data['appointmentType'] = appointmentType; - data['isActive'] = isActive; - data['createdBy'] = createdBy; - data['createdOn'] = createdOn; - data['modifiedBy'] = modifiedBy; - data['modifiedOn'] = modifiedOn; - return data; - } - @override String toString() { return 'ServiceSlotList{id: $id, branchAppointmentScheduleID: $branchAppointmentScheduleID, branchAppointmentSchedule: $branchAppointmentSchedule, serviceProviderID: $serviceProviderID, slotDate: $slotDate, startTime: $startTime, endTime: $endTime, bookAppointment: $bookAppointment, allowAppointment: $allowAppointment, slotDurationMinute: $slotDurationMinute, appointmentType: $appointmentType, isActive: $isActive, createdBy: $createdBy, createdOn: $createdOn, modifiedBy: $modifiedBy, modifiedOn: $modifiedOn}'; diff --git a/lib/repositories/ads_repo.dart b/lib/repositories/ads_repo.dart index 9507097..7f2f8e9 100644 --- a/lib/repositories/ads_repo.dart +++ b/lib/repositories/ads_repo.dart @@ -6,6 +6,7 @@ import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/config/dependencies.dart'; import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/models/advertisment_models/ad_details_model.dart'; +import 'package:mc_common_app/models/advertisment_models/ads_bank_details_model.dart'; import 'package:mc_common_app/models/advertisment_models/ads_duration_model.dart'; import 'package:mc_common_app/models/advertisment_models/reserved_ads_models.dart'; import 'package:mc_common_app/models/advertisment_models/special_service_model.dart'; @@ -54,9 +55,15 @@ abstract class AdsRepo { Future> getMyAds(); + Future getAdBankingAccountInfo({required int adId}); + Future updateAdStatus({required int adId, required AdPostStatus adStatusToUpdate}); + Future createAppointmentForAdSpecialService({required int adId, required int photoOfficeID, required int photoOfficeSlotID, required int adsSpecialServiceID}); + Future deleteAd({required int adId}); + + Future cancelMyAdReservation({required int adId}); } class AdsRepoImp implements AdsRepo { @@ -399,6 +406,26 @@ class AdsRepoImp implements AdsRepo { return vehicleAdsDetails; } + @override + Future getAdBankingAccountInfo({required int adId}) async { + var params = { + "userID": appState.getUser.data!.userInfo!.userId ?? "", + "AdsID": "$adId", + }; + GenericRespModel adsGenericModel = await apiClient.getJsonForObject( + token: appState.getUser.data!.accessToken, + (json) => GenericRespModel.fromJson(json), + queryParameters: params, + ApiConsts.adsMCBankAccountAdGet, + ); + + List adsBankDetails = List.generate(adsGenericModel.data.length, (index) => AdsBankDetailsModel.fromJson(adsGenericModel.data[index])); + if (adsBankDetails.isNotEmpty) { + return adsBankDetails.first; + } + return null; + } + @override Future updateAdStatus({required int adId, required AdPostStatus adStatusToUpdate}) async { var postParams = { @@ -434,4 +461,49 @@ class AdsRepoImp implements AdsRepo { return Future.value(adsGenericModel); } + + @override + Future cancelMyAdReservation({required int adId}) async { + var postParams = { + "adID": adId, + }; + + String token = appState.getUser.data!.accessToken ?? ""; + GenericRespModel adsGenericModel = await apiClient.postJsonForObject( + (json) => GenericRespModel.fromJson(json), + ApiConsts.deleteAd, + postParams, + token: token, + ); + + return Future.value(adsGenericModel); + } + + @override + Future createAppointmentForAdSpecialService({ + required int adId, + required int photoOfficeID, + required int photoOfficeSlotID, + required int adsSpecialServiceID, + }) async { + int customerId = AppState().getUser.data!.userInfo!.customerId ?? 0; + + var postParams = { + "adsID": adId, + "photoOfficeID": photoOfficeID, + "photoOfficeSlotID": photoOfficeSlotID, + "adsSpecialServiceID": adsSpecialServiceID, + "customerID": customerId, + }; + + String token = appState.getUser.data!.accessToken ?? ""; + GenericRespModel adsGenericModel = await apiClient.postJsonForObject( + (json) => GenericRespModel.fromJson(json), + ApiConsts.adsPhotoOfficeAppointmentCreate, + postParams, + token: token, + ); + + return Future.value(adsGenericModel); + } } diff --git a/lib/repositories/common_repo.dart b/lib/repositories/common_repo.dart index e4e24d7..f4dd9d9 100644 --- a/lib/repositories/common_repo.dart +++ b/lib/repositories/common_repo.dart @@ -27,7 +27,7 @@ abstract class CommonRepo { Future getCarCheckServiceScheduleDetails({required double lat, required double long}); - Future> getPhotographyServiceScheduleListByOffices({required double lat, required double long}); + Future> getPhotographyServiceScheduleListByOffices({required double lat, required double long}); // Future> getProviderServiceCategories(); @@ -95,7 +95,7 @@ class CommonRepoImp implements CommonRepo { } @override - Future> getPhotographyServiceScheduleListByOffices({required double lat, required double long}) async { + Future> getPhotographyServiceScheduleListByOffices({required double lat, required double long}) async { var params = { "Latitude": lat.toString(), "Longitude": long.toString(), @@ -109,7 +109,7 @@ class CommonRepoImp implements CommonRepo { if (genericRespModel.data == null) { return []; } - List ssPhotoScheduleModel = List.generate(genericRespModel.data.length, (index) => SSPhotoScheduleModel.fromJson(genericRespModel.data[index])); + List ssPhotoScheduleModel = List.generate(genericRespModel.data.length, (index) => SSPhotoOfficeScheduleModel.fromJson(genericRespModel.data[index])); return ssPhotoScheduleModel ?? []; } diff --git a/lib/services/payments_service.dart b/lib/services/payments_service.dart index a82ddb9..917a7cf 100644 --- a/lib/services/payments_service.dart +++ b/lib/services/payments_service.dart @@ -36,17 +36,6 @@ class PaymentServiceImp implements PaymentService { ios: IOSInAppBrowserOptions(hideToolbarBottom: true, toolbarBottomBackgroundColor: Colors.white, closeButtonColor: Colors.white, presentationStyle: IOSUIModalPresentationStyle.OVER_FULL_SCREEN)); - String generateBrowserUrl(int id) { - String form = Utils.getAdsPaymentBrowserForm(paymentId: 3, adId: id); - // form.replaceFirst("SERVICE_URL_VALUE", ApiConsts.paymentWebViewUrl); - // form.replaceFirst("PaymentType_Value", 4.toString()); - // form.replaceFirst("AdID_Value", id.toString()); - - var bytes = utf8.encode(form); - var base64Str = base64.encode(bytes); - return 'data:text/html;base64,$base64Str'; - } - @override Future placePayment({ required int id, @@ -60,7 +49,6 @@ class PaymentServiceImp implements PaymentService { switch (paymentType) { case PaymentTypes.subscription: urlRequest = "${ApiConsts.paymentWebViewUrl}?PaymentType=${paymentType.getIdFromPaymentTypesEnum()}&OrderProviderSubscriptionID=$id"; - break; case PaymentTypes.appointment: String appointIds = ''; diff --git a/lib/view_models/ad_view_model.dart b/lib/view_models/ad_view_model.dart index 76aa86f..2a61780 100644 --- a/lib/view_models/ad_view_model.dart +++ b/lib/view_models/ad_view_model.dart @@ -8,6 +8,7 @@ import 'package:mc_common_app/config/dependencies.dart'; import 'package:mc_common_app/config/routes.dart'; import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/models/advertisment_models/ad_details_model.dart'; +import 'package:mc_common_app/models/advertisment_models/ads_bank_details_model.dart'; import 'package:mc_common_app/models/advertisment_models/ads_duration_model.dart'; import 'package:mc_common_app/models/advertisment_models/reserved_ads_models.dart'; import 'package:mc_common_app/models/advertisment_models/special_service_model.dart'; @@ -16,6 +17,7 @@ import 'package:mc_common_app/models/advertisment_models/ss_photo_schedule_model import 'package:mc_common_app/models/advertisment_models/vehicle_details_models.dart'; import 'package:mc_common_app/models/enums_model.dart'; import 'package:mc_common_app/models/generic_resp_model.dart'; +import 'package:mc_common_app/models/service_schedule_model.dart'; import 'package:mc_common_app/models/widgets_models.dart'; import 'package:mc_common_app/repositories/ads_repo.dart'; import 'package:mc_common_app/repositories/common_repo.dart'; @@ -55,7 +57,7 @@ class AdVM extends BaseVM { List vehicleAdsDurations = []; List vehicleAdsSpecialServices = []; SSCarCheckScheduleModel? ssCarCheckScheduleModel; - SSPhotoScheduleModel? ssPhotoScheduleModel; + SSPhotoOfficeScheduleModel? ssPhotoScheduleModel; String demandAmountError = ""; String vehicleVinError = ""; @@ -143,8 +145,8 @@ class AdVM extends BaseVM { isExploreAdsTapped = value; //To show the Active Ads - applyFilterOnMyAds(index: 0, adPostStatusEnum: AdPostStatus.allAds); - applyFilterOnExploreAds(index: 0, createdByRoleFilter: CreatedByRoleEnum.allAds); + applyFilterOnMyAds(adPostStatusEnum: AdPostStatus.allAds); + applyFilterOnExploreAds(createdByRoleFilter: CreatedByRoleEnum.allAds); // if (value) { // await getExploreAds(); // } @@ -159,8 +161,12 @@ class AdVM extends BaseVM { List myAdsFilterOptions = []; populateAdsFilterList() async { - myAdsEnums = await commonRepo.getEnumTypeValues(enumTypeID: 18); //TODO: 18 is to get My Ad Filter Enums - exploreAdsEnums = await commonRepo.getEnumTypeValues(enumTypeID: 23); //TODO: 23 is to get Explore Ad Filter Enums + if (myAdsEnums.isEmpty) { + myAdsEnums = await commonRepo.getEnumTypeValues(enumTypeID: 18); //TODO: 18 is to get My Ad Filter Enums + } + if (exploreAdsEnums.isEmpty) { + exploreAdsEnums = await commonRepo.getEnumTypeValues(enumTypeID: 23); //TODO: 23 is to get Explore Ad Filter Enums + } exploreAdsFilterOptions.clear(); myAdsFilterOptions.clear(); @@ -177,14 +183,14 @@ class AdVM extends BaseVM { notifyListeners(); } - applyFilterOnExploreAds({required int index, required CreatedByRoleEnum createdByRoleFilter}) { + applyFilterOnExploreAds({required CreatedByRoleEnum createdByRoleFilter}) { if (exploreAdsFilterOptions.isEmpty) return; + int index = exploreAdsFilterOptions.indexWhere((element) => element.id.toCreatedByRoleEnum() == createdByRoleFilter); + for (var value in exploreAdsFilterOptions) { value.isSelected = false; } exploreAdsFilterOptions[index].isSelected = true; - // TODO: --> here we will filter the allAds list - // TODO: --> and get the updated list into this new list everytime filter changes if (createdByRoleFilter == CreatedByRoleEnum.allAds) { exploreAdsFilteredList = exploreAds; notifyListeners(); @@ -196,8 +202,10 @@ class AdVM extends BaseVM { notifyListeners(); } - applyFilterOnMyAds({required int index, required AdPostStatus adPostStatusEnum}) { + applyFilterOnMyAds({required AdPostStatus adPostStatusEnum}) { if (myAdsFilterOptions.isEmpty) return; + int index = myAdsFilterOptions.indexWhere((element) => element.id.toAdPostEnum() == adPostStatusEnum); + for (var value in myAdsFilterOptions) { value.isSelected = false; } @@ -225,18 +233,15 @@ class AdVM extends BaseVM { } Future getMyAds() async { - isFetchingLists = true; setState(ViewState.busy); myAds = await adsRepo.getAllAds(isMyAds: true); final myActiveAds = myAds.where((element) => element.adPostStatus == AdPostStatus.active).toList(); myActiveAdsForHome = myActiveAds.length >= 3 ? myActiveAds.take(3).toList() : myActiveAds; await getMyReservedAds(); - isFetchingLists = true; setState(ViewState.idle); } Future getMyReservedAds() async { - isFetchingLists = true; setState(ViewState.busy); //TODO: BREAKING // myReservedAdsRespModel = await adsRepo.getMyReservedAds(); @@ -266,6 +271,19 @@ class AdVM extends BaseVM { notifyListeners(); } + AdsBankDetailsModel? adsBankDetailsModel; + + Future getAdBankingAccountInfo({required int adId}) async { + setState(ViewState.busy); + try { + adsBankDetailsModel = await adsRepo.getAdBankingAccountInfo(adId: 21); + setState(ViewState.idle); + } catch (e) { + setState(ViewState.idle); + Utils.showToast(e.toString()); + } + } + Future markAdAsSold(BuildContext context, {required int adId}) async { Utils.showLoading(context); GenericRespModel respModel = await adsRepo.updateAdStatus(adId: adId, adStatusToUpdate: AdPostStatus.sold); @@ -278,7 +296,7 @@ class AdVM extends BaseVM { Utils.hideLoading(context); Utils.showToast("A has been marked as sold successfully!"); updateIsExploreAds(false); - applyFilterOnMyAds(index: 1, adPostStatusEnum: AdPostStatus.sold); //pending for review + applyFilterOnMyAds(adPostStatusEnum: AdPostStatus.sold); //pending for review navigateReplaceWithName(context, AppRoutes.dashboard); } @@ -294,7 +312,23 @@ class AdVM extends BaseVM { Utils.hideLoading(context); Utils.showToast("A has been deleted successfully!"); updateIsExploreAds(false); - applyFilterOnMyAds(index: 1, adPostStatusEnum: AdPostStatus.active); //pending for review + applyFilterOnMyAds(adPostStatusEnum: AdPostStatus.active); //pending for review + navigateReplaceWithName(context, AppRoutes.dashboard); + } + + Future cancelMyAdReservation(BuildContext context, {required int adId}) async { + Utils.showLoading(context); + GenericRespModel respModel = await adsRepo.cancelMyAdReservation(adId: adId); + + if (respModel.messageStatus != 1) { + Utils.hideLoading(context); + Utils.showToast(respModel.message ?? "Something went wrong!"); + return; + } + Utils.hideLoading(context); + Utils.showToast("Your reservation has been cancelled."); + updateIsExploreAds(false); + applyFilterOnMyAds(adPostStatusEnum: AdPostStatus.active); //pending for review navigateReplaceWithName(context, AppRoutes.dashboard); } @@ -310,7 +344,7 @@ class AdVM extends BaseVM { Utils.hideLoading(context); Utils.showToast("A has been deactivated successfully!"); updateIsExploreAds(false); - applyFilterOnMyAds(index: 1, adPostStatusEnum: AdPostStatus.cancelled); //pending for review + applyFilterOnMyAds(adPostStatusEnum: AdPostStatus.cancelled); //pending for review navigateReplaceWithName(context, AppRoutes.dashboard); } @@ -951,7 +985,7 @@ class AdVM extends BaseVM { currentProgressStep = AdCreationSteps.vehicleDetails; resetValues(); updateIsExploreAds(false); - applyFilterOnMyAds(index: 1, adPostStatusEnum: AdPostStatus.pendingForReview); //pending for review + applyFilterOnMyAds(adPostStatusEnum: AdPostStatus.pendingForReview); //pending for review navigateReplaceWithName(context, AppRoutes.dashboard); } catch (e) { Utils.hideLoading(context); @@ -1097,27 +1131,125 @@ class AdVM extends BaseVM { notifyListeners(); } + resetSpecialServiceBottomSheet() { + photoOfficeSelectedId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); + selectedPhotoSSSchedulesByOffice = SSPhotoOfficeScheduleModel(); + selectedPhotoOfficeSlotDateTime = null; + photoSSSchedulesByOffices = []; + } + SelectionModel photoOfficeSelectedId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); void updatePhotoOfficeSelectedId(SelectionModel id) { photoOfficeSelectedId = id; + selectedPhotoSSSchedulesByOffice = photoSSSchedulesByOffices.elementAt(int.parse(id.itemPrice)); notifyListeners(); } - List photoSSSchedulesByOffices = []; + updateSelectedPhotoOfficeAppointmentDate({required int dateIndex}) { + for (var element in selectedPhotoSSSchedulesByOffice.customTimeDateSlotList!) { + element.date!.isSelected = false; + for (var element in element.availableSlots!) { + element.isSelected = false; + } + } + + selectedPhotoSSSchedulesByOffice.customTimeDateSlotList![dateIndex].date!.isSelected = true; + selectedPhotoSSSchedulesByOffice.selectedDateIndex = dateIndex; + final date = TimeSlotModel( + date: selectedPhotoSSSchedulesByOffice.customTimeDateSlotList![dateIndex].date!.date, + slotId: selectedPhotoSSSchedulesByOffice.customTimeDateSlotList![dateIndex].date!.slotId, + isSelected: true, + slot: "", + ); + selectedPhotoSSSchedulesByOffice.selectedCustomTimeDateSlotModel = CustomTimeDateSlotModel(date: date); + notifyListeners(); + } + + int? selectedPhotoOfficeSlotDateTime; + + updateSelectedAppointmentSlotByDate({required int slotIndex}) { + for (var element in selectedPhotoSSSchedulesByOffice.customTimeDateSlotList!) { + for (var element in element.availableSlots!) { + element.isSelected = false; + } + } + int index = selectedPhotoSSSchedulesByOffice.selectedDateIndex!; + selectedPhotoSSSchedulesByOffice.customTimeDateSlotList![index].availableSlots![slotIndex].isSelected = true; + selectedPhotoOfficeSlotDateTime = selectedPhotoSSSchedulesByOffice.customTimeDateSlotList![index].availableSlots![slotIndex].slotId; + selectedPhotoSSSchedulesByOffice.selectedCustomTimeDateSlotModel!.availableSlots = selectedPhotoSSSchedulesByOffice.customTimeDateSlotList![index].availableSlots!; + notifyListeners(); + } + + List photoSSSchedulesByOffices = []; + SSPhotoOfficeScheduleModel selectedPhotoSSSchedulesByOffice = SSPhotoOfficeScheduleModel(); Future getPhotographyServiceScheduleListByOffices({required double latitude, required double longitude, bool isNeedToRebuild = false}) async { if (isNeedToRebuild) setState(ViewState.busy); try { photoSSSchedulesByOffices = await commonRepo.getPhotographyServiceScheduleListByOffices(lat: latitude, long: longitude); + if (isNeedToRebuild) setState(ViewState.idle); } catch (e) { - setState(ViewState.busy); + if (isNeedToRebuild) setState(ViewState.idle); Utils.showToast("Error: ${e.toString()}"); } } + // Future getCarCheckServiceScheduleListByOffices({required double latitude, required double longitude, bool isNeedToRebuild = false}) async { + // if (isNeedToRebuild) setState(ViewState.busy); + // + // try { + // photoSSSchedulesByOffices = await commonRepo.getCarCheckServiceScheduleDetails(lat: latitude, long: longitude); + // if (isNeedToRebuild) setState(ViewState.idle); + // } catch (e) { + // if (isNeedToRebuild) setState(ViewState.idle); + // Utils.showToast("Error: ${e.toString()}"); + // } + // } + + Future onAdSSBookAppointmentPressed(BuildContext context, {required AdDetailsModel adDetailsModel, required int adsSpecialServiceID}) async { + bool isValidated = false; + + if (selectedPhotoSSSchedulesByOffice.photoOfficeID == null) { + isValidated = false; + } else if (selectedPhotoSSSchedulesByOffice.selectedCustomTimeDateSlotModel == null || !selectedPhotoSSSchedulesByOffice.selectedCustomTimeDateSlotModel!.date!.isSelected) { + isValidated = false; + } else { + if (selectedPhotoSSSchedulesByOffice.selectedCustomTimeDateSlotModel!.availableSlots == null) { + isValidated = false; + } else { + TimeSlotModel slot = selectedPhotoSSSchedulesByOffice.selectedCustomTimeDateSlotModel!.availableSlots!.firstWhere((element) => element.isSelected); + if (slot.date.isNotEmpty) { + isValidated = true; + } + } + } + if (!isValidated) { + Utils.showToast("You must select appointment time the service."); + return; + } + Utils.showLoading(context); + try { + GenericRespModel genericRespModel = await adsRepo.createAppointmentForAdSpecialService( + adId: adDetailsModel.id ?? 0, + photoOfficeID: photoOfficeSelectedId.selectedId, + photoOfficeSlotID: selectedPhotoOfficeSlotDateTime ?? 0, + adsSpecialServiceID: adsSpecialServiceID, + ); + Utils.hideLoading(context); + if (genericRespModel.messageStatus != 1) { + Utils.showToast("Error: ${genericRespModel.message}"); + } else { + resetSpecialServiceBottomSheet(); + navigateWithName(context, AppRoutes.paymentMethodsView, arguments: PaymentTypes.ads); + } + } catch (e) { + Utils.hideLoading(context); + Utils.showToast("Error: ${e.toString()}"); + } + } Future createNewAd() async { AppState appState = injector.get(); diff --git a/lib/view_models/appointments_view_model.dart b/lib/view_models/appointments_view_model.dart index 1031175..a09b00e 100644 --- a/lib/view_models/appointments_view_model.dart +++ b/lib/view_models/appointments_view_model.dart @@ -71,9 +71,9 @@ class AppointmentsVM extends BaseVM { if (index == -1) { double totalPrice = 0.0; - currentServiceSelection!.serviceItems!.forEach((element) { + for (var element in currentServiceSelection!.serviceItems!) { totalPrice = totalPrice + double.parse(element.price ?? "0.0"); - }); + } currentServiceSelection!.currentTotalServicePrice = totalPrice; servicesInCurrentAppointment.insert(0, currentServiceSelection!); } @@ -222,7 +222,7 @@ class AppointmentsVM extends BaseVM { resetAfterBookingAppointment() { allSelectedItemsInAppointments.clear(); - servicesInCurrentAppointment.clear(); + // servicesInCurrentAppointment.clear(); serviceAppointmentScheduleList.clear(); } @@ -276,9 +276,9 @@ class AppointmentsVM extends BaseVM { } updateSelectedAppointmentDate({required int dateIndex, required int scheduleIndex}) { - serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList!.forEach((element) { + for (var element in serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList!) { element.date!.isSelected = false; - }); + } serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![dateIndex].date!.isSelected = true; serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex = dateIndex; @@ -293,9 +293,11 @@ class AppointmentsVM extends BaseVM { } updateSelectedAppointmentSlotByDate({required int scheduleIndex, required int slotIndex}) { - serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList!.forEach((element) { - element.availableSlots!.forEach((element) => element.isSelected = false); - }); + for (var element in serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList!) { + for (var element in element.availableSlots!) { + element.isSelected = false; + } + } int index = serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex!; serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![index].availableSlots![slotIndex].isSelected = true; serviceAppointmentScheduleList[scheduleIndex].selectedCustomTimeDateSlotModel!.availableSlots = serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![index].availableSlots!; @@ -313,9 +315,10 @@ class AppointmentsVM extends BaseVM { onItemUpdateOrSelected(int index, bool selected, int itemId) { int serviceIndex = servicesInCurrentAppointment.indexWhere((element) => element.serviceId == currentServiceSelection!.serviceId!); - if (serviceIndex == -1) { - return; - } + // print("servicesInCurrentAppointment: ${servicesInCurrentAppointment.length}"); + // if (serviceIndex == -1) { + // return; + // } serviceItemsFromApi[index].isUpdateOrSelected = selected; serviceItemsFromApi[index].isHomeSelected = isHomeTapped; @@ -324,13 +327,13 @@ class AppointmentsVM extends BaseVM { selectSubServicesError = ""; currentServiceSelection!.serviceItems!.add(serviceItemsFromApi[index]); allSelectedItemsInAppointments.add(serviceItemsFromApi[index]); - allSelectedItemsInAppointments.forEach((element) { + for (var element in allSelectedItemsInAppointments) { if (!ifItemAlreadySelected(element.id!)) { servicesInCurrentAppointment[serviceIndex].serviceItems!.add(serviceItemsFromApi[index]); servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice = servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice + double.parse((serviceItemsFromApi[index].price) ?? "0.0"); } - }); + } } if (!selected) { selectedSubServicesCounter = selectedSubServicesCounter - 1; @@ -376,11 +379,11 @@ class AppointmentsVM extends BaseVM { Future> getServiceItems(int serviceId) async { serviceItemsFromApi.clear(); serviceItemsFromApi = await providerRepo.getServiceItems(serviceId); - serviceItemsFromApi.forEach((item) { + for (var item in serviceItemsFromApi) { if (ifItemAlreadySelected(item.id!)) { item.isUpdateOrSelected = true; } - }); + } setState(ViewState.idle); return serviceItemsFromApi; } @@ -463,9 +466,9 @@ class AppointmentsVM extends BaseVM { String getTotalPrice(List serviceItems) { var totalPrice = 0.0; - serviceItems.forEach((element) { + for (var element in serviceItems) { totalPrice = totalPrice + (element.currentTotalServicePrice); - }); + } return totalPrice.toString(); } @@ -567,7 +570,7 @@ class AppointmentsVM extends BaseVM { break; } else { if (schedule.selectedCustomTimeDateSlotModel!.availableSlots == null) { - isValidated = true; + isValidated = false; break; } else { TimeSlotModel slot = schedule.selectedCustomTimeDateSlotModel!.availableSlots!.firstWhere((element) => element.isSelected); @@ -590,13 +593,13 @@ class AppointmentsVM extends BaseVM { List serviceItemIdsForHome = []; List serviceItemIdsForWorkshop = []; - allSelectedItemsInAppointments.forEach((serviceItem) { + for (var serviceItem in allSelectedItemsInAppointments) { if (serviceItem.isHomeSelected!) { serviceItemIdsForHome.add(serviceItem.id!.toString()); } else { serviceItemIdsForWorkshop.add(serviceItem.id!.toString()); } - }); + } serviceAppointmentScheduleList = await scheduleRepo.mergeServiceIntoAvailableSchedules( serviceItemIdsForHome: serviceItemIdsForHome, @@ -610,12 +613,10 @@ class AppointmentsVM extends BaseVM { } totalAmount = 0.0; amountToPayForAppointment = 0.0; - serviceAppointmentScheduleList.forEach( - (schedule) { - amountToPayForAppointment = amountToPayForAppointment + (schedule.amountToPay ?? 0.0); - totalAmount = totalAmount + (schedule.amountTotal ?? 0.0); - }, - ); + for (var schedule in serviceAppointmentScheduleList) { + amountToPayForAppointment = amountToPayForAppointment + (schedule.amountToPay ?? 0.0); + totalAmount = totalAmount + (schedule.amountTotal ?? 0.0); + } Utils.hideLoading(context); navigateWithName(context, AppRoutes.bookAppointmenSchedulesView, arguments: ScreenArgumentsForAppointmentDetailPage(routeFlag: 1, appointmentId: 0)); // 1 For Creating an Appointment @@ -628,8 +629,8 @@ class AppointmentsVM extends BaseVM { List serviceItemIdsForHome = []; List serviceItemIdsForWorkshop = []; - appointmentListModel.appointmentServicesList!.forEach((service) { - service.serviceItems!.forEach((serviceItem) { + for (var service in appointmentListModel.appointmentServicesList!) { + for (var serviceItem in service.serviceItems!) { serviceItemIdsForWorkshop.add(serviceItem.id!.toString()); // if (serviceItem.isHomeSelected ?? false) { @@ -637,8 +638,8 @@ class AppointmentsVM extends BaseVM { // } else { // serviceItemIdsForWorkshop.add(serviceItem.id!.toString()); // } - }); - }); + } + } serviceAppointmentScheduleList = await scheduleRepo.mergeServiceIntoAvailableSchedules( serviceItemIdsForHome: serviceItemIdsForHome, diff --git a/lib/view_models/payment_view_model.dart b/lib/view_models/payment_view_model.dart index 4d742a4..539731b 100644 --- a/lib/view_models/payment_view_model.dart +++ b/lib/view_models/payment_view_model.dart @@ -40,7 +40,6 @@ class PaymentVM extends ChangeNotifier { List appointmentIdsForPayment = []; void updateAppointmentIdsForPayment({required List ids}) { - log("appointmetList: $ids"); appointmentIdsForPayment = ids; } diff --git a/lib/view_models/requests_view_model.dart b/lib/view_models/requests_view_model.dart index 32bce7b..8652d5d 100644 --- a/lib/view_models/requests_view_model.dart +++ b/lib/view_models/requests_view_model.dart @@ -32,9 +32,9 @@ class RequestsVM extends BaseVM { populateRequestsFilterList() async { requestsTypeFilterOptions.clear(); - - myRequestsTypeEnum = await commonRepo.getEnumTypeValues(enumTypeID: 16); //TODO: 13 is to get Requests Filter Enums - + if (myRequestsTypeEnum.isEmpty) { + myRequestsTypeEnum = await commonRepo.getEnumTypeValues(enumTypeID: 16); //TODO: 13 is to get Requests Filter Enums + } for (int i = 0; i < myRequestsTypeEnum.length; i++) { requestsTypeFilterOptions.add(FilterListModel(title: myRequestsTypeEnum[i].enumValueStr, isSelected: false, id: myRequestsTypeEnum[i].enumValue)); } diff --git a/lib/views/advertisement/ads_detail_view.dart b/lib/views/advertisement/ads_detail_view.dart index dc4145b..dbc5c01 100644 --- a/lib/views/advertisement/ads_detail_view.dart +++ b/lib/views/advertisement/ads_detail_view.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/classes/consts.dart'; @@ -17,20 +19,42 @@ import 'package:mc_common_app/view_models/ad_view_model.dart'; import 'package:mc_common_app/view_models/payment_view_model.dart'; import 'package:mc_common_app/views/advertisement/ad_duration_selection_sheet_content.dart'; import 'package:mc_common_app/views/advertisement/ads_images_slider.dart'; +import 'package:mc_common_app/views/appointments/widgets/custom_calender_widget.dart'; import 'package:mc_common_app/widgets/bottom_sheet.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/common_widgets/info_bottom_sheet.dart'; +import 'package:mc_common_app/widgets/common_widgets/time_slots.dart'; import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:provider/provider.dart'; import 'package:sizer/sizer.dart'; -class AdsDetailView extends StatelessWidget { +class AdsDetailView extends StatefulWidget { final AdDetailsModel adDetails; const AdsDetailView({Key? key, required this.adDetails}) : super(key: key); + @override + State createState() => _AdsDetailViewState(); +} + +class _AdsDetailViewState extends State { + @override + void initState() { + scheduleMicrotask(() { + onAdDetailsLoaded(); + }); + super.initState(); + } + + Future onAdDetailsLoaded() async { + context.read().updateCurrentAdId(id: widget.adDetails.id!); + if ((widget.adDetails.isMyAd ?? false) && (widget.adDetails.adPostStatus == AdPostStatus.reserved)) { + await context.read().getAdBankingAccountInfo(adId: widget.adDetails.id!); + } + } + void deleteAdBottomSheet(BuildContext context) { AdVM adVM = context.read(); return actionConfirmationBottomSheet( @@ -44,7 +68,7 @@ class AdsDetailView extends StatelessWidget { fontSize: 15, onPressed: () { Navigator.pop(context); - adVM.deleteMyAd(context, adId: adDetails.id!); + adVM.deleteMyAd(context, adId: widget.adDetails.id!); }, ), ), @@ -66,9 +90,6 @@ class AdsDetailView extends StatelessWidget { @override Widget build(BuildContext context) { - print("adId: ${adDetails.id}"); - print("statusID: ${adDetails.specialservice!.first.name}"); - context.read().updateCurrentAdId(id: adDetails.id!); return Scaffold( appBar: CustomAppBar( title: "Ads", @@ -76,7 +97,7 @@ class AdsDetailView extends StatelessWidget { isRemoveBackButton: false, isDrawerEnabled: false, actions: [ - (adDetails.isMyAd ?? false + ((widget.adDetails.isMyAd ?? false) && (widget.adDetails.adPostStatus != AdPostStatus.reserved) ? IconButton( icon: const Icon(Icons.delete_outline, color: MyColors.redColor), onPressed: () { @@ -111,12 +132,12 @@ class AdsDetailView extends StatelessWidget { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - CarouselWithIndicatorDemo(vehicleImages: adDetails.vehicle!.image!), + CarouselWithIndicatorDemo(vehicleImages: widget.adDetails.vehicle!.image!), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - "${adDetails.vehicle!.vehicleTitle} | ${adDetails.vehicle!.color!.label}".toText(fontSize: 18, isBold: true), - (adDetails.vehicle!.cityName ?? "").toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor), + "${widget.adDetails.vehicle!.vehicleTitle} | ${widget.adDetails.vehicle!.color!.label}".toText(fontSize: 18, isBold: true), + (widget.adDetails.vehicle!.cityName ?? "").toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor), ], ), Row( @@ -125,13 +146,13 @@ class AdsDetailView extends StatelessWidget { Row( children: [ "Model: ".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), - "${adDetails.vehicle!.modelyear!.label}".toText( + "${widget.adDetails.vehicle!.modelyear!.label}".toText( fontSize: 14, isBold: true, ), ], ), - "${adDetails.vehicle!.countryID}".toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor), + "${widget.adDetails.vehicle!.countryID}".toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor), ], ), Row( @@ -140,19 +161,21 @@ class AdsDetailView extends StatelessWidget { Row( children: [ "Mileage: ".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), - "${adDetails.vehicle!.mileage!.mileageEnd}Km".toText( + "${widget.adDetails.vehicle!.mileage!.mileageEnd}Km".toText( fontSize: 14, isBold: true, ), ], ), - adDetails.createdOn != null ? DateTime.parse(adDetails.createdOn!).getTimeAgo().toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor) : const SizedBox(), + widget.adDetails.createdOn != null + ? DateTime.parse(widget.adDetails.createdOn!).getTimeAgo().toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor) + : const SizedBox(), ], ), Row( children: [ "Transmission: ".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), - "${adDetails.vehicle!.transmission!.label}".toText( + "${widget.adDetails.vehicle!.transmission!.label}".toText( fontSize: 14, isBold: true, ), @@ -160,21 +183,21 @@ class AdsDetailView extends StatelessWidget { ), 8.height, "Description: ".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), - "${adDetails.vehicle!.vehicleDescription}".toText( + "${widget.adDetails.vehicle!.vehicleDescription}".toText( fontSize: 14, isBold: true, ), - if (adDetails.isMyAd ?? false) ...[ + if (widget.adDetails.isMyAd ?? false) ...[ 8.height, "Demand: ".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), Row( crossAxisAlignment: CrossAxisAlignment.end, children: [ - adDetails.vehicle!.demandAmount!.toInt().toString().toText(fontSize: 30, height: 1.2, isBold: true), + widget.adDetails.vehicle!.demandAmount!.toInt().toString().toText(fontSize: 30, height: 1.2, isBold: true), " SAR".toText(fontSize: 15, isBold: true, color: MyColors.lightTextColor).paddingOnly(bottom: 5), ], ), - if (adDetails.adPostStatus == AdPostStatus.expired) ...[ + if (widget.adDetails.adPostStatus == AdPostStatus.expired) ...[ 8.height, const Divider(thickness: 1, height: 1), 8.height, @@ -187,25 +210,65 @@ class AdsDetailView extends StatelessWidget { ] ], ).toWhiteContainer(width: double.infinity, allPading: 12), + 12.height, + Consumer(builder: (BuildContext context, AdVM adVM, Widget? child) { + if (adVM.adsBankDetailsModel != null) { + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Bank Details".toText(fontSize: 18, isBold: true), + // Row( + // children: [ + // "Full Name: ".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), + // "${widget.adDetails.vehicle!.vehicleDescription}".toText( + // fontSize: 14, + // isBold: true, + // ), + // ], + // ), + Row( + children: [ + "Bank Name: ".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), + (adVM.adsBankDetailsModel!.bankName ?? "").toText( + fontSize: 14, + isBold: true, + ), + ], + ), + Row( + children: [ + "IBAN: ".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), + (adVM.adsBankDetailsModel!.iban ?? "").toText( + fontSize: 14, + isBold: true, + ), + ], + ), + ], + ).toWhiteContainer(width: double.infinity, allPading: 12); + } + return const SizedBox.shrink(); + }) ], ), ), SizedBox( child: Column( children: [ - if (!(adDetails.isMyAd ?? false)) ...[ + if (!(widget.adDetails.isMyAd ?? false)) ...[ const Divider(thickness: 1, height: 1), 18.height, Row( crossAxisAlignment: CrossAxisAlignment.end, children: [ - adDetails.vehicle!.demandAmount!.toInt().toString().toText(fontSize: 30, isBold: true), + widget.adDetails.vehicle!.demandAmount!.toInt().toString().toText(fontSize: 30, isBold: true), " SAR".toText(fontSize: 15, isBold: true, color: MyColors.lightTextColor).paddingOnly(bottom: 5), ], ), 14.height, ], - adDetails.isMyAd ?? false ? BuildAdDetailsActionButtonForMyAds(adDetailsModel: adDetails) : BuildAdDetailsActionButtonForExploreAds(adDetailsModel: adDetails), + widget.adDetails.isMyAd ?? false ? BuildAdDetailsActionButtonForMyAds(adDetailsModel: widget.adDetails) : BuildAdDetailsActionButtonForExploreAds(adDetailsModel: widget.adDetails), ], ), ) @@ -358,24 +421,6 @@ class BuildAdDetailsActionButtonForExploreAds extends StatelessWidget { }); } - Widget cancelReservationAction(BuildContext context) { - return Row( - children: [ - Expanded( - child: ShowFillButton( - borderColor: MyColors.redColor, - txtColor: MyColors.redColor, - isFilled: false, - fontSize: 16, - maxHeight: 55, - title: "Cancel Reservation", - onPressed: () {}, - ), - ), - ], - ); - } - Widget reserveAdAction(BuildContext context, AdDetailsModel adDetailsModel) { return Row( children: [ @@ -457,26 +502,6 @@ class BuildAdDetailsActionButtonForExploreAds extends StatelessWidget { @override Widget build(BuildContext context) { - // switch (adPostStatus) { - // case AdPostStatus.pendingForPayment: - // break; - // case AdPostStatus.active: - // break; - // case AdPostStatus.reserved: - // return cancelReservationAction(context); - // - // case AdPostStatus.buyingService: - // case AdPostStatus.reserveCancel: - // case AdPostStatus.rejected: - // case AdPostStatus.cancelled: - // case AdPostStatus.pendingForPost: - // case AdPostStatus.pendingForReview: - // case AdPostStatus.sold: - // case AdPostStatus.expired: - // break; - // } - // return defaultAction(context); - switch (adDetailsModel.createdByRoleEnum!) { case CreatedByRoleEnum.customer: case CreatedByRoleEnum.provider: @@ -494,10 +519,10 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget { const BuildAdDetailsActionButtonForMyAds({Key? key, required this.adDetailsModel}) : super(key: key); - void onBookPhotographyServiceClicked(BuildContext context) async { + void onBookPhotographyServiceClicked(BuildContext context, {required AdDetailsModel adDetailsModel}) async { AdVM adVM = context.read(); if (adVM.photoOfficeSelectedId.selectedId == -1) { - adVM.getPhotographyServiceScheduleListByOffices(latitude: 46.703430, longitude: 24.625720); + adVM.getPhotographyServiceScheduleListByOffices(latitude: 46.703430, longitude: 24.625720, isNeedToRebuild: true); // TODO: These Lat Long need to be dynamic } return showModalBottomSheet( @@ -505,70 +530,78 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget { isScrollControlled: true, enableDrag: true, builder: (BuildContext context) { - return InfoBottomSheet( - title: "Set Date and Time".toText(fontSize: 28, isBold: true, letterSpacing: -1.44, height: 1.2), - description: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - 25.height, - Builder( - builder: (context) { - List vehicleCitiesDrop = []; - for (var element in adVM.photoSSSchedulesByOffices) { - vehicleCitiesDrop.add(DropValue(element.photoOfficeID?.toInt() ?? 0, element.photoOfficeName ?? "", "")); - } - return DropdownField( - (DropValue value) => adVM.updatePhotoOfficeSelectedId(SelectionModel(selectedId: value.id, selectedOption: value.value)), - list: vehicleCitiesDrop, - dropdownValue: adVM.photoOfficeSelectedId.selectedId != -1 ? DropValue(adVM.photoOfficeSelectedId.selectedId, adVM.photoOfficeSelectedId.selectedOption, "") : null, - hint: "Select Office", - errorValue: adVM.photoOfficeSelectedId.errorValue, - ); - }, - ), - if (adVM.photoOfficeSelectedId.selectedId != -1) ...[ - 9.height, - // CustomCalenderWidget(customTimeDateSlotList: [], scheduleIndex: scheduleIndex), - // if (appointmentsVM.serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex != null) ...[ - // 5.height, - // Row( - // mainAxisAlignment: MainAxisAlignment.start, - // children: [ - // ("Available Slots").toText(fontSize: 14, isBold: true), - // ], - // ), - // 5.height, - // SizedBox( - // width: double.infinity, - // child: BuildTimeSlots( - // timeSlots: appointmentsVM.serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![appointmentsVM.serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex!] - // .availableSlots ?? - // [], - // onPressed: (slotIndex) { - // appointmentsVM.updateSelectedAppointmentSlotByDate(scheduleIndex: scheduleIndex, slotIndex: slotIndex); - // }, - // ), - // ), - // ], - 5.height, - Row( - children: [ - Expanded( - child: ShowFillButton( - maxHeight: 55, - title: "Book and Pay", - fontSize: 15, - onPressed: () { - Navigator.pop(context); + return Consumer(builder: (BuildContext context, AdVM adVM, Widget? child) { + return InfoBottomSheet( + title: "Set Date and Time".toText(fontSize: 28, isBold: true, letterSpacing: -1.44, height: 1.2), + description: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + 25.height, + adVM.state == ViewState.busy + ? const Center(child: CircularProgressIndicator()) + : Builder( + builder: (context) { + List vehicleCitiesDrop = []; + for (int i = 0; i < adVM.photoSSSchedulesByOffices.length; i++) { + var element = adVM.photoSSSchedulesByOffices[i]; + vehicleCitiesDrop.add(DropValue(element.photoOfficeID?.toInt() ?? 0, element.photoOfficeName ?? "", i.toString())); + } + + return DropdownField( + (DropValue value) => adVM.updatePhotoOfficeSelectedId(SelectionModel(selectedId: value.id, selectedOption: value.value, itemPrice: value.subValue)), + // here the item price is the index of the selected option + list: vehicleCitiesDrop, + dropdownValue: adVM.photoOfficeSelectedId.selectedId != -1 ? DropValue(adVM.photoOfficeSelectedId.selectedId, adVM.photoOfficeSelectedId.selectedOption, "") : null, + hint: "Select Office", + errorValue: adVM.photoOfficeSelectedId.errorValue, + ); }, ), + if (adVM.photoOfficeSelectedId.selectedId != -1) ...[ + 9.height, + CustomCalenderAppointmentWidget( + customTimeDateSlotList: adVM.selectedPhotoSSSchedulesByOffice.customTimeDateSlotList ?? [], + onDateSelected: (dateIndex) => adVM.updateSelectedPhotoOfficeAppointmentDate(dateIndex: dateIndex), + selectedCustomTimeDateSlotModel: adVM.selectedPhotoSSSchedulesByOffice.selectedCustomTimeDateSlotModel, + ), + if (adVM.selectedPhotoSSSchedulesByOffice.selectedCustomTimeDateSlotModel != null && adVM.selectedPhotoSSSchedulesByOffice.selectedCustomTimeDateSlotModel!.date != null) ...[ + 5.height, + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + ("Available Slots").toText(fontSize: 14, isBold: true), + ], + ), + 5.height, + SizedBox( + width: double.infinity, + child: BuildTimeSlots( + timeSlots: adVM.selectedPhotoSSSchedulesByOffice.customTimeDateSlotList![adVM.selectedPhotoSSSchedulesByOffice.selectedDateIndex!].availableSlots ?? [], + onPressed: (slotIndex) => adVM.updateSelectedAppointmentSlotByDate(slotIndex: slotIndex), + ), ), + 20.height, ], - ), + 5.height, + Row( + children: [ + Expanded( + child: ShowFillButton( + maxHeight: 55, + title: "Book and Pay", + fontSize: 15, + onPressed: () { + adVM.onAdSSBookAppointmentPressed(context, adDetailsModel: adDetailsModel, adsSpecialServiceID: 1); //1 for photography Service + }, + ), + ), + ], + ), + ], + 19.height, ], - 19.height, - ], - )); + )); + }); }, ); } @@ -717,7 +750,7 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget { }); } - Widget pendingForReviewAction({required bool isPendingPost}) { + Widget pendingForReviewAction({required String pendingText}) { return Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ @@ -728,7 +761,7 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget { backgroundColor: MyColors.grey98Color.withOpacity(0.3), txtColor: MyColors.lightTextColor, maxHeight: 55, - title: isPendingPost ? "Waiting for admin to post" : "Waiting for Admins Approval", + title: pendingText, isBold: false, onPressed: () {}, ), @@ -746,10 +779,11 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget { photoSpecialServiceModel = element; } } + bool payButtonStatus = photoSpecialServiceModel != null && photoSpecialServiceModel.appointmentStatusId == 0; return Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ - if (photoSpecialServiceModel != null) ...[ + if (photoSpecialServiceModel != null && photoSpecialServiceModel.appointmentStatusId == 0) ...[ Row( children: [ Expanded( @@ -760,7 +794,7 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget { title: "Book ${photoSpecialServiceModel.name}", txtColor: MyColors.darkPrimaryColor, onPressed: () { - onBookPhotographyServiceClicked(context); + onBookPhotographyServiceClicked(context, adDetailsModel: adDetailsModel); }, ), ), @@ -773,12 +807,14 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget { Expanded( child: ShowFillButton( maxHeight: 55, - backgroundColor: MyColors.grey98Color.withOpacity(0.3), - txtColor: MyColors.lightTextColor, + backgroundColor: payButtonStatus ? MyColors.grey98Color.withOpacity(0.3) : MyColors.darkPrimaryColor, + txtColor: payButtonStatus ? MyColors.lightTextColor : MyColors.white, isBold: false, title: "Pay Now", onPressed: () { - navigateWithName(context, AppRoutes.paymentMethodsView, arguments: PaymentTypes.ads); + if (photoSpecialServiceModel == null) { + navigateWithName(context, AppRoutes.paymentMethodsView, arguments: PaymentTypes.ads); + } }, ), ), @@ -856,19 +892,49 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget { ); } - Widget cancelReservationAction(BuildContext context) { + Widget cancelReservationAction(BuildContext context, {required AdDetailsModel adDetails}) { return Row( children: [ Expanded( child: ShowFillButton( - borderColor: MyColors.redColor, - txtColor: MyColors.redColor, - isFilled: false, - fontSize: 16, - maxHeight: 55, - title: "Cancel Reservation", - onPressed: () {}, - ), + borderColor: MyColors.redColor, + txtColor: MyColors.redColor, + isFilled: false, + fontSize: 16, + maxHeight: 55, + title: "Cancel Reservation", + onPressed: () { + AdVM adVM = context.read(); + return actionConfirmationBottomSheet( + context: context, + title: "Do you want to cancel the reservation?".toText(fontSize: 28, isBold: true, letterSpacing: -1.44), + subtitle: "Your ad reservation will be cancelled and this ad will be again visible to everyone to buy.", + actionButtonYes: Expanded( + child: ShowFillButton( + maxHeight: 55, + title: "Yes", + fontSize: 15, + onPressed: () { + Navigator.pop(context); + adVM.cancelMyAdReservation(context, adId: adDetails.id!); + }, + ), + ), + actionButtonNo: Expanded( + child: ShowFillButton( + maxHeight: 55, + isFilled: false, + borderColor: MyColors.darkPrimaryColor, + title: "No", + txtColor: MyColors.darkPrimaryColor, + fontSize: 15, + onPressed: () { + Navigator.pop(context); + }, + ), + ), + ); + }), ), ], ); @@ -927,40 +993,6 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget { ); } - Widget defaultAction(BuildContext context) { - return Row( - children: [ - Expanded( - child: ShowFillButton( - maxHeight: 55, - title: "Reserve Ad", - onPressed: () { - reserveAdPriceBreakDownClicked(context); - // navigateWithName(context, AppRoutes.paymentMethodsView); - }, - ), - ), - 8.width, - Container( - height: 55, - width: 55, - alignment: Alignment.center, - decoration: BoxDecoration(border: Border.all(color: MyColors.black, width: 2)), - //TODO: It Will be replaced by a WhatsApp Icon - child: const Icon(Icons.message, color: MyColors.black), - ).onPress(() {}), - 8.width, - Container( - height: 55, - width: 55, - alignment: Alignment.center, - decoration: BoxDecoration(border: Border.all(color: MyColors.black, width: 2)), - child: const Icon(Icons.phone, color: MyColors.black), - ).onPress(() {}), - ], - ); - } - @override Widget build(BuildContext context) { switch (adDetailsModel.adPostStatus!) { @@ -969,16 +1001,16 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget { case AdPostStatus.active: return markAsSoldAction(context); case AdPostStatus.reserved: - break; + return cancelReservationAction(context, adDetails: adDetailsModel); case AdPostStatus.buyingService: case AdPostStatus.reserveCancel: case AdPostStatus.rejected: case AdPostStatus.cancelled: case AdPostStatus.pendingForPost: - return pendingForReviewAction(isPendingPost: true); + return pendingForReviewAction(pendingText: "Waiting for admin to post"); case AdPostStatus.pendingForReview: - return pendingForReviewAction(isPendingPost: false); + return pendingForReviewAction(pendingText: "Waiting for Admins Approval"); case AdPostStatus.sold: case AdPostStatus.expired: diff --git a/lib/views/advertisement/ads_list.dart b/lib/views/advertisement/ads_list.dart index afdaa3f..9e8e0a6 100644 --- a/lib/views/advertisement/ads_list.dart +++ b/lib/views/advertisement/ads_list.dart @@ -44,11 +44,7 @@ class BuildAdsList extends StatelessWidget { adDetails: adsList[index], isAdsFragment: isAdsFragment, shouldShowAdStatus: shouldShowAdStatus, - ).onPress( - () { - navigateWithName(context, AppRoutes.adsDetailView, arguments: adsList[index]); - }, - ); + ).onPress(() => navigateWithName(context, AppRoutes.adsDetailView, arguments: adsList[index])); }, separatorBuilder: (BuildContext context, int index) { return 12.height; diff --git a/lib/views/appointments/book_appointment_schedules_view.dart b/lib/views/appointments/book_appointment_schedules_view.dart index da6204d..4b27e26 100644 --- a/lib/views/appointments/book_appointment_schedules_view.dart +++ b/lib/views/appointments/book_appointment_schedules_view.dart @@ -1,4 +1,3 @@ - import 'package:flutter/material.dart'; import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; @@ -91,7 +90,12 @@ class BookAppointmentSchedulesView extends StatelessWidget { children: [ Column( children: [ - CustomCalenderWidget(customTimeDateSlotList: scheduleData.customTimeDateSlotList ?? [], scheduleIndex: scheduleIndex), + CustomCalenderAppointmentWidget( + customTimeDateSlotList: scheduleData.customTimeDateSlotList ?? [], + onDateSelected: (int dateIndex) { + appointmentsVM.updateSelectedAppointmentDate(scheduleIndex: scheduleIndex, dateIndex: dateIndex); + }, + selectedCustomTimeDateSlotModel: scheduleData.selectedCustomTimeDateSlotModel), if (appointmentsVM.serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex != null) ...[ 5.height, Row( diff --git a/lib/views/appointments/book_appointments_item_view.dart b/lib/views/appointments/book_appointments_item_view.dart index 3063fbd..07a5f37 100644 --- a/lib/views/appointments/book_appointments_item_view.dart +++ b/lib/views/appointments/book_appointments_item_view.dart @@ -20,7 +20,7 @@ class BookAppointmentsItemView extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: CustomAppBar( - title: "Select Services", + title: "Select Items", isRemoveBackButton: false, isDrawerEnabled: false, actions: [MyAssets.searchIcon.buildSvg().paddingOnly(right: 21)], diff --git a/lib/views/appointments/widgets/appointment_service_pick_bottom_sheet.dart b/lib/views/appointments/widgets/appointment_service_pick_bottom_sheet.dart index 979df51..1c723b2 100644 --- a/lib/views/appointments/widgets/appointment_service_pick_bottom_sheet.dart +++ b/lib/views/appointments/widgets/appointment_service_pick_bottom_sheet.dart @@ -12,6 +12,7 @@ import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:mc_common_app/widgets/txt_field.dart'; import 'package:provider/provider.dart'; + class AppointmentServicePickBottomSheet extends StatelessWidget { const AppointmentServicePickBottomSheet({Key? key}) : super(key: key); diff --git a/lib/views/appointments/widgets/custom_calender_widget.dart b/lib/views/appointments/widgets/custom_calender_widget.dart index 4be5587..3f91f27 100644 --- a/lib/views/appointments/widgets/custom_calender_widget.dart +++ b/lib/views/appointments/widgets/custom_calender_widget.dart @@ -1,4 +1,3 @@ - import 'package:flutter/material.dart'; import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/models/service_schedule_model.dart'; @@ -10,17 +9,23 @@ import 'package:provider/provider.dart'; import 'package:intl/intl.dart'; import 'package:table_calendar/table_calendar.dart'; -class CustomCalenderWidget extends StatefulWidget { +class CustomCalenderAppointmentWidget extends StatefulWidget { final List customTimeDateSlotList; - final int scheduleIndex; + final CustomTimeDateSlotModel? selectedCustomTimeDateSlotModel; + final Function(int) onDateSelected; - const CustomCalenderWidget({super.key, required this.customTimeDateSlotList, required this.scheduleIndex}); + const CustomCalenderAppointmentWidget({ + super.key, + required this.customTimeDateSlotList, + required this.selectedCustomTimeDateSlotModel, + required this.onDateSelected, + }); @override - State createState() => _CustomCalenderWidgetState(); + State createState() => _CustomCalenderAppointmentWidgetState(); } -class _CustomCalenderWidgetState extends State { +class _CustomCalenderAppointmentWidgetState extends State { List allDates = []; List allMonths = []; List datesInSelectedMonth = []; @@ -41,7 +46,7 @@ class _CustomCalenderWidgetState extends State { populateDateList() { for (var value in widget.customTimeDateSlotList) { - DateTime dt = DateFormat('dd MMMM, yyyy').parse(value.date!.date); + DateTime dt = DateFormat('dd MMMM, yyyy').parse(value.date!.date.trim()); DropValue dv = DropValue(dt.month, "${dt.month.getMonthNameByNumber()}, ${dt.year}", "${dt.year}"); allDates.add(dt); @@ -51,9 +56,8 @@ class _CustomCalenderWidgetState extends State { } selectedMonth = allDates.first.month; selectedYear = allDates.first.year; - final appointmentsVM = context.read(); - if (appointmentsVM.serviceAppointmentScheduleList[widget.scheduleIndex].selectedCustomTimeDateSlotModel != null) { - DateTime alreadySelectedDate = DateFormat('dd MMMM, yyyy').parse(appointmentsVM.serviceAppointmentScheduleList[widget.scheduleIndex].selectedCustomTimeDateSlotModel!.date!.date); + if (widget.selectedCustomTimeDateSlotModel != null) { + DateTime alreadySelectedDate = DateFormat('dd MMMM, yyyy').parse(widget.selectedCustomTimeDateSlotModel!.date!.date); _selectedDay = alreadySelectedDate; _focusedDay = alreadySelectedDate; selectedMonth = alreadySelectedDate.month; @@ -61,7 +65,7 @@ class _CustomCalenderWidgetState extends State { } datesInSelectedMonth = allDates.where((element) => element.month == selectedMonth).toList(); - if (appointmentsVM.serviceAppointmentScheduleList[widget.scheduleIndex].selectedCustomTimeDateSlotModel == null) { + if (widget.selectedCustomTimeDateSlotModel == null) { _focusedDay = datesInSelectedMonth.first; } } @@ -225,7 +229,7 @@ class _CustomCalenderWidgetState extends State { }); if (dateIndex != -1) { - appointmentsVM.updateSelectedAppointmentDate(scheduleIndex: widget.scheduleIndex, dateIndex: dateIndex); + widget.onDateSelected(dateIndex); } } }, diff --git a/pubspec.lock b/pubspec.lock index efad35d..e131506 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -510,7 +510,7 @@ packages: source: hosted version: "2.0.0" intl: - dependency: transitive + dependency: "direct main" description: name: intl sha256: a3715e3bc90294e971cb7dc063fbf3cd9ee0ebf8604ffeafabd9e6f16abbdbe6 diff --git a/pubspec.yaml b/pubspec.yaml index e6788f3..2ffccc7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ dependencies: path_provider: ^2.0.4 injector: ^2.0.0 provider: ^6.0.0 - easy_localization: ^3.0.1 + easy_localization: ^3.0.3 http: ^0.13.3 permission_handler: any flutter_svg: ^1.0.3 @@ -38,6 +38,7 @@ dependencies: flutter_inappwebview: ^5.7.2+3 country_code_picker: ^3.0.0 table_calendar: ^3.0.9 + intl: any # google