Compare commits

...

11 Commits

Author SHA1 Message Date
Faiz Hashmi 6245aa9ef4 fixed messages bug 2 years ago
Faiz Hashmi 98b35fbc61 Chat Module almost finished! 2 years ago
Faiz Hashmi c5cefa2309 models refinement 2 years ago
Faiz Hashmi 76fd46c654 models refinement 2 years ago
Faiz Hashmi 08fd442a36 Adding Chat Repo 2 years ago
Faiz Hashmi 95fec1e62d added setting screens 2 years ago
Faiz Hashmi 8168e5a81d Added Special Service Appointment Module 2 years ago
Faiz Hashmi fd6b7c2803 Request Module added to common 2 years ago
Faiz Hashmi b9a5429de5 Request Module iAP 2 years ago
Faiz Hashmi 8a8efa37f2 Added Appoinment Module and Ads Filter 2 years ago
Faiz Hashmi 057a202ed9 Appointment Module's payment final changes! 2 years ago

@ -10,8 +10,8 @@ import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/exceptions/api_exception.dart';
import 'package:mc_common_app/main.dart';
import 'package:mc_common_app/models/user/refresh_token.dart';
import 'package:mc_common_app/models/user/user.dart';
import 'package:mc_common_app/models/user_models/refresh_token.dart';
import 'package:mc_common_app/models/user_models/user.dart';
import 'package:mc_common_app/utils/shared_prefrence.dart';
typedef FactoryConstructor<U> = U Function(dynamic);

@ -1,6 +1,6 @@
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:mc_common_app/models/post_params_model.dart';
import 'package:mc_common_app/models/user/user.dart';
import 'package:mc_common_app/models/general_models/post_params_model.dart';
import 'package:mc_common_app/models/user_models/user.dart';
import 'package:mc_common_app/utils/enums.dart';
class AppState {

@ -50,13 +50,14 @@ class ApiConsts {
static String ServiceProviderService_Get = "${baseUrlServices}api/ServiceProviders/ServiceProviderService_Get";
static String BranchesAndServices = "${baseUrlServices}api/ServiceProviders/ServiceProviderDetail_Get";
static String GetAllNearBranches = "${baseUrlServices}api/ServiceProviders/ServiceProviderBranchDetail_Get";
static String GetServiceItemAppointmentScheduleSlots = "${baseUrlServices}api/ServiceProviders/ServiceItemAppointmentScheduleSlots_Get";
static String ServiceProvidersAppointmentCreate = "${baseUrlServices}api/ServiceProviders/ServiceProvidersAppointment_Create";
//Appointment APIs
static String serviceProvidersAppointmentGet = "${baseUrlServices}api/ServiceProviders/ServiceProvidersAppointment_Get";
static String serviceCategoryGet = "${baseUrlServices}api/Master/ServiceCategory_Get";
static String serviceItemsGet = "${baseUrlServices}api/ServiceProviders/ServiceItem_Get";
static String GetServiceItemAppointmentScheduleSlots = "${baseUrlServices}api/ServiceProviders/ServiceItemAppointmentScheduleSlots_GetByAppointmentType";
static String ServiceProvidersAppointmentCreate = "${baseUrlServices}api/ServiceProviders/ServiceProvidersAppointmentList_Create";
static String ServiceProviderAppointmentRescheduleCancelAppointment = "${baseUrlServices}api/ServiceProviders/ServiceProviderAppointment_RescheduleCancelAppointment";
//ServiceProvidersServiceID as params
// static String servicesGet = "${baseUrlServices}api/ServiceProviders/Services_Get";
@ -100,6 +101,8 @@ 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";
@ -128,6 +131,10 @@ class ApiConsts {
//Requests
static String createRequest = "${baseUrlServices}api/RequestManagement/Request_Create";
static String getRequest = "${baseUrlServices}api/RequestManagement/Request_Get";
static String getRequestOffers = "${baseUrlServices}api/RequestManagement/ReqOffer_Get";
//Chat
static String chatHubUrl = "$baseUrlServices/McHub";
static List<String> closingUrls = ["PayFortResponse"];
}
@ -140,7 +147,8 @@ class GlobalConsts {
static String fontZoomSize = "font_zoom_size";
static String welcomeVideoUrl = "welcomeVideoUrl";
static String doNotShowWelcomeVideo = "doNotShowWelcomeVideo";
static String demandAmountError = "Demand Amount Cannot be Empty";
static String demandAmountError = "Amount Cannot be Empty";
static String descriptionError = "Description Cannot be Empty";
static String vehicleVinError = "Vehicle VIN Cannot be Empty";
static String vehicleTitleError = "Vehicle Title Cannot be Empty";
static String warrantyError = "Warranty Duration Cannot be Empty";

@ -5,8 +5,11 @@ import 'package:injector/injector.dart';
import 'package:mc_common_app/api/api_client.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/repositories/ads_repo.dart';
import 'package:mc_common_app/repositories/appointment_repo.dart';
import 'package:mc_common_app/repositories/chat_repo.dart';
import 'package:mc_common_app/repositories/common_repo.dart';
import 'package:mc_common_app/repositories/payments_repo.dart';
import 'package:mc_common_app/repositories/provider_repo.dart';
import 'package:mc_common_app/repositories/user_repo.dart';
import 'package:mc_common_app/services/common_services.dart';
import 'package:mc_common_app/services/payments_service.dart';
@ -29,5 +32,8 @@ class AppDependencies {
injector.registerSingleton<AdsRepo>(() => AdsRepoImp());
injector.registerSingleton<PaymentsRepo>(() => PaymentsRepoImp());
injector.registerSingleton<RequestRepo>(() => RequestRepoImp());
injector.registerSingleton<ProviderRepo>(() => ProviderRepoImp());
injector.registerSingleton<AppointmentRepo>(() => AppointmentRepoImp());
injector.registerSingleton<ChatRepo>(() => ChatRepoImp());
}
}

@ -1,4 +1,7 @@
import 'package:mc_common_app/models/user/register_user.dart';
import 'package:mc_common_app/models/requests_models/offers_model.dart';
import 'package:mc_common_app/models/requests_models/request_model.dart';
import 'package:mc_common_app/models/user_models/register_user.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/views/user/change_email_page.dart';
import 'package:mc_common_app/views/user/change_mobile_page.dart';
@ -46,6 +49,7 @@ class AppRoutes {
static const String bookProviderAppView = "/bookProviderAppView";
static const String appointmentDetailView = "/appointmentDetailView";
static const String bookAppointmenServicesView = "/bookAppointmenServicesView";
static const String bookAppointmenSchedulesView = "/bookAppointmenSchedulesView";
static const String bookAppointmentsItemView = "/bookAppointmentsItemView";
static const String reviewAppointmentView = "/reviewAppointmentView";
@ -53,7 +57,7 @@ class AppRoutes {
static const String selectAdTypeView = "/selectAdTypeView";
static const String adsDetailView = "/adsDetailView";
static const String createAdView = "/createAdView";
static const String adsSearchFilterScreen = "/adsSearchFilterScreen";
static const String adsFilterView = "/adsFilterView";
// Payments
static const String paymentMethodsView = "/paymentMethodsView";
@ -67,9 +71,19 @@ class AppRoutes {
static const String subscriptionsPage = "/subscriptionsPage";
//Requests
static const String myRequestsPage = "/myRequestsPage";
static const String createRequestPage = "/createRequestPage";
static const String offersListPage = "/offersListPage";
static const String requestsDetailPage = "/requestsDetailPage";
static const String sendOfferPage = "/sendOfferPage";
//Setting Options
static const String settingOptionsFaqs = "/settingOptionsFaqs";
static const String settingOptionsLanguages = "/settingOptionsLanguages";
static const String settingOptionsInviteFriends = "/settingOptionsInviteFriends";
//Chat
static const String chatView = "/chatView";
static const String initialRoute = splash;
@ -94,3 +108,19 @@ class AppRoutes {
editAccountPage: (context) => const EditAccountPage(),
};
}
class ChatViewArguments {
final RequestModel? requestModel;
final ChatTypeEnum chatTypeEnum;
final String senderId;
final String receiverId;
ChatViewArguments({required this.chatTypeEnum, this.requestModel, required this.senderId, required this.receiverId});
}
class OfferListPageArguments {
final List<OffersModel> offersList;
final RequestModel? requestModel;
OfferListPageArguments({required this.offersList, this.requestModel});
}

@ -198,7 +198,7 @@ extension AdPostEnum on int {
return AdPostStatus.buyingService;
} else if (this == 11) {
return AdPostStatus.reserveCancel;
} else if (this == -1) {
} else if (this == 0) {
return AdPostStatus.allAds;
} else {
return AdPostStatus.pendingForPost;
@ -206,6 +206,50 @@ extension AdPostEnum on int {
}
}
extension AppointmentEnum on int {
AppointmentStatusEnum toAppointmentStatusEnum() {
if (this == 1) {
return AppointmentStatusEnum.booked;
} else if (this == 2) {
return AppointmentStatusEnum.confirmed;
} else if (this == 3) {
return AppointmentStatusEnum.arrived;
} else if (this == 4) {
return AppointmentStatusEnum.cancelled;
} else if (this == 5) {
return AppointmentStatusEnum.rescheduled;
} else {
return AppointmentStatusEnum.allAppointments;
}
}
}
extension RequestTypeTypeEnum on int {
RequestsTypeEnum toRequestTypeStatusEnum() {
if (this == 1) {
return RequestsTypeEnum.specialCarRequest;
} else if (this == 2) {
return RequestsTypeEnum.serviceRequest;
}
return RequestsTypeEnum.specialCarRequest;
}
}
extension RequestTypeStatusToInt on RequestsTypeEnum {
int getIdFromRequestTypeStatusEnum() {
switch (this) {
case RequestsTypeEnum.specialCarRequest:
return 1;
case RequestsTypeEnum.serviceRequest:
return 2;
default:
return 0;
}
}
}
extension AdPostStatusToInt on AdPostStatus {
int getIdFromAdPostStatusEnum() {
switch (this) {
@ -241,7 +285,55 @@ extension AdPostStatusToInt on AdPostStatus {
case AdPostStatus.reserveCancel:
return 11;
default:
return -1;
return 0;
}
}
}
extension PaymentTypesToInt on PaymentTypes {
int getIdFromPaymentTypesEnum() {
switch (this) {
case PaymentTypes.subscription:
return 1;
case PaymentTypes.appointment:
return 2;
case PaymentTypes.adReserve:
return 4;
case PaymentTypes.ads:
return 3;
case PaymentTypes.request:
return 5;
default:
return 0;
}
}
}
extension AppointmentStatusToInt on AppointmentStatusEnum {
int getIdFromAppointmentStatusEnum() {
switch (this) {
case AppointmentStatusEnum.booked:
return 1;
case AppointmentStatusEnum.confirmed:
return 2;
case AppointmentStatusEnum.arrived:
return 3;
case AppointmentStatusEnum.cancelled:
return 4;
case AppointmentStatusEnum.rescheduled:
return 5;
default:
return 0;
}
}
}
@ -256,7 +348,7 @@ extension CreatedByRoleEnumToInt on CreatedByRoleEnum {
case CreatedByRoleEnum.provider:
return 3;
case CreatedByRoleEnum.allAds:
return -1;
return 0;
default:
return 1;
}
@ -281,7 +373,7 @@ extension AdReserveStatusEnum on int {
extension AdOwnerEnum on int {
CreatedByRoleEnum toCreatedByRoleEnum() {
if (this == -1) {
if (this == 0) {
return CreatedByRoleEnum.allAds;
} else if (this == 1) {
return CreatedByRoleEnum.admin;
@ -390,3 +482,177 @@ extension VehicleAdTypeEnum on int {
}
}
}
extension FormatMonthByName on int {
String getMonthNameByNumber() {
switch (this) {
case 1:
return "January";
case 2:
return "February";
case 3:
return "March";
case 4:
return "April";
case 5:
return "May";
case 6:
return "June";
case 7:
return "July";
case 8:
return "August";
case 9:
return "September";
case 10:
return "October";
case 11:
return "November";
case 12:
return "December";
default:
return "";
}
}
}
extension FormatMonthByNumber on String {
int getMonthNumberByName() {
switch (this) {
case "January":
return 1;
case "February":
return 2;
case "March":
return 3;
case "April":
return 4;
case "May":
return 5;
case "June":
return 6;
case "July":
return 7;
case "August":
return 8;
case "September":
return 9;
case "October":
return 10;
case "November":
return 11;
case "December":
return 12;
default:
return 1;
}
}
}
extension ChatMessageTypeEnumExt on int {
//FreeText = 1,
// Image = 2,
// Audio = 3,
// Video = 4,
// Offer = 5
ChatMessageTypeEnum toChatMessageTypeEnum() {
if (this == 1) {
return ChatMessageTypeEnum.freeText;
} else if (this == 2) {
return ChatMessageTypeEnum.image;
} else if (this == 3) {
return ChatMessageTypeEnum.audio;
} else if (this == 4) {
return ChatMessageTypeEnum.video;
} else if (this == 5) {
return ChatMessageTypeEnum.offer;
}
return ChatMessageTypeEnum.freeText;
}
}
extension ChatMessageTypeToInt on ChatMessageTypeEnum {
int getIdFromChatMessageTypeEnum() {
switch (this) {
case ChatMessageTypeEnum.freeText:
return 1;
case ChatMessageTypeEnum.image:
return 2;
case ChatMessageTypeEnum.audio:
return 3;
case ChatMessageTypeEnum.video:
return 4;
case ChatMessageTypeEnum.offer:
return 5;
default:
return 1;
}
}
}
extension RequestOfferStatusEnumExt on int {
RequestOfferStatusEnum toRequestOfferStatusEnum() {
if (this == 1) {
return RequestOfferStatusEnum.offer;
} else if (this == 2) {
return RequestOfferStatusEnum.negotiate;
} else if (this == 3) {
return RequestOfferStatusEnum.accepted;
} else if (this == 4) {
return RequestOfferStatusEnum.rejected;
} else if (this == 5) {
return RequestOfferStatusEnum.cancel;
}
return RequestOfferStatusEnum.cancel;
}
}
extension RequestOfferStatusEnumToInt on RequestOfferStatusEnum {
int getIdFromRequestOfferStatusEnum() {
switch (this) {
case RequestOfferStatusEnum.offer:
return 1;
case RequestOfferStatusEnum.negotiate:
return 2;
case RequestOfferStatusEnum.accepted:
return 3;
case RequestOfferStatusEnum.rejected:
return 4;
case RequestOfferStatusEnum.cancel:
return 5;
default:
return 0;
}
}
}
extension ChatTypeEnumExt on int {
ChatTypeEnum toChatTypeEnum() {
if (this == 1) {
return ChatTypeEnum.general;
} else if (this == 2) {
return ChatTypeEnum.ads;
} else if (this == 3) {
return ChatTypeEnum.requestOffer;
}
return ChatTypeEnum.general;
}
}
extension ChatTypeEnumToInt on ChatTypeEnum {
int getIdFromChatTypeEnum() {
switch (this) {
case ChatTypeEnum.general:
return 1;
case ChatTypeEnum.ads:
return 2;
case ChatTypeEnum.requestOffer:
return 3;
default:
return 1;
}
}
}

@ -1,44 +0,0 @@
// To parse this JSON data, do
//
// final account = accountFromJson(jsonString);
import 'dart:convert';
import 'package:mc_common_app/models/parent_list.dart';
Account accountFromJson(String str) => Account.fromJson(json.decode(str));
String accountToJson(Account data) => json.encode(data.toJson());
class Account {
Account({
required this.parentList,
required this.selectedItem,
});
List<ParentList>? parentList;
int selectedItem;
factory Account.fromJson(Map<String, dynamic> json) => Account(
parentList: json["parentList"] == null
? null
: List<ParentList>.from(
json["parentList"].map((x) => ParentList.fromJson(x))),
selectedItem:
json["selectedItem"] == null ? null : json["selectedItem"],
);
Map<String, dynamic> toJson() => {
"parentList": parentList == null
? null
: List<dynamic>.from(parentList!.map((x) => x.toJson())),
"selectedItem": selectedItem == null ? null : selectedItem,
};
Map<String, dynamic> toJsonData() => {
"selectedItem": selectedItem == null ? null : selectedItem,
};
}

@ -9,7 +9,7 @@ class AdDetailsModel {
String? startdate;
String? enddate;
Vehicle? vehicle;
List<SpecialServiceModel>? specialservice;
List<SpecialServiceModelForAds>? specialservice;
// List<Null>? reserved;
int? statusID;
@ -97,9 +97,9 @@ class AdDetailsModel {
enddate = json['enddate'];
vehicle = json['vehicle'] != null ? Vehicle.fromJson(json['vehicle']) : null;
if (json['specialservice'] != null) {
specialservice = <SpecialServiceModel>[];
specialservice = <SpecialServiceModelForAds>[];
json['specialservice'].forEach((v) {
specialservice!.add(SpecialServiceModel.fromJson(v));
specialservice!.add(SpecialServiceModelForAds.fromJson(v));
});
}
statusID = json['statusID'];
@ -138,48 +138,6 @@ class AdDetailsModel {
isMyAd = isMyAds;
isReservedByMe = false;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
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<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
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 {

@ -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<String, dynamic> json) {
id = json['id'];
mcBankAccountID = json['mcBankAccountID'];
adsID = json['adsID'];
isActive = json['isActive'];
bankName = json['bankName'];
iban = json['iban'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['mcBankAccountID'] = mcBankAccountID;
data['adsID'] = adsID;
data['isActive'] = isActive;
data['bankName'] = bankName;
data['iban'] = iban;
return data;
}
}

@ -0,0 +1,92 @@
class PhotoSpecialServiceScheduleModel {
int? photoOfficeID;
String? fromDate;
String? toDate;
int? photoOfficeAppointmentScheduleID;
String? photoOfficeName;
String? description;
String? areaName;
String? latitude;
String? longitude;
int? distanceKM;
int? totalItemsCount;
List<PhotoOfficeScheduleSlots>? photoOfficeScheduleSlots;
PhotoSpecialServiceScheduleModel(
{this.photoOfficeID,
this.fromDate,
this.toDate,
this.photoOfficeAppointmentScheduleID,
this.photoOfficeName,
this.description,
this.areaName,
this.latitude,
this.longitude,
this.distanceKM,
this.totalItemsCount,
this.photoOfficeScheduleSlots});
PhotoSpecialServiceScheduleModel.fromJson(Map<String, dynamic> json) {
photoOfficeID = json['photoOfficeID'];
fromDate = json['fromDate'];
toDate = json['toDate'];
photoOfficeAppointmentScheduleID = json['photoOfficeAppointmentScheduleID'];
photoOfficeName = json['photoOfficeName'];
description = json['description'];
areaName = json['areaName'];
latitude = json['latitude'];
longitude = json['longitude'];
distanceKM = json['distanceKM'];
totalItemsCount = json['totalItemsCount'];
if (json['photoOfficeScheduleSlots'] != null) {
photoOfficeScheduleSlots = <PhotoOfficeScheduleSlots>[];
json['photoOfficeScheduleSlots'].forEach((v) {
photoOfficeScheduleSlots!.add(PhotoOfficeScheduleSlots.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
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();
}
return data;
}
}
class PhotoOfficeScheduleSlots {
int? id;
String? slotDate;
String? startTime;
String? endTime;
PhotoOfficeScheduleSlots({this.id, this.slotDate, this.startTime, this.endTime});
PhotoOfficeScheduleSlots.fromJson(Map<String, dynamic> json) {
id = json['id'];
slotDate = json['slotDate'];
startTime = json['startTime'];
endTime = json['endTime'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['slotDate'] = slotDate;
data['startTime'] = startTime;
data['endTime'] = endTime;
return data;
}
}

@ -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;
@ -15,18 +18,18 @@ class SpecialServiceModel {
SpecialServiceModel(
{this.id,
this.name,
this.description,
this.price,
this.specialServiceType,
this.specialServiceTypeName,
this.isActive,
this.startDate,
this.endDate,
this.details,
this.office,
this.isSelected,
this.isDelivery});
this.name,
this.description,
this.price,
this.specialServiceType,
this.specialServiceTypeName,
this.isActive,
this.startDate,
this.endDate,
this.details,
this.office,
this.isSelected,
this.isDelivery});
SpecialServiceModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
@ -53,27 +56,6 @@ class SpecialServiceModel {
isDelivery = json['isDelivery'];
isSelected = false;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
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 {
@ -83,8 +65,7 @@ class Details {
int? tocity;
int? price;
Details(
{this.id, this.specialServiceID, this.fromcity, this.tocity, this.price});
Details({this.id, this.specialServiceID, this.fromcity, this.tocity, this.price});
Details.fromJson(Map<String, dynamic> json) {
id = json['id'];
@ -93,16 +74,6 @@ class Details {
tocity = json['tocity'];
price = json['price'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['specialServiceID'] = specialServiceID;
data['fromcity'] = fromcity;
data['tocity'] = tocity;
data['price'] = price;
return data;
}
}
class Office {
@ -113,13 +84,7 @@ class Office {
String? city;
int? specialServiceID;
Office(
{this.id,
this.officeAreaName,
this.officeAreaNameN,
this.cityID,
this.city,
this.specialServiceID});
Office({this.id, this.officeAreaName, this.officeAreaNameN, this.cityID, this.city, this.specialServiceID});
Office.fromJson(Map<String, dynamic> json) {
id = json['id'];
@ -129,15 +94,43 @@ class Office {
city = json['city'];
specialServiceID = json['specialServiceID'];
}
}
class SpecialServiceModelForAds {
int? adsID;
int? specialServiceID;
String? name;
String? description;
double? price;
AppointmentStatusEnum? appointmentStatusEnum;
int? appointmentStatusId;
String? appointmentDate;
SpecialServiceModelForAds({
this.adsID,
this.specialServiceID,
this.name,
this.description,
this.price,
this.appointmentStatusEnum,
this.appointmentDate,
this.appointmentStatusId,
});
SpecialServiceModelForAds.fromJson(Map<String, dynamic> json) {
adsID = json['adsID'];
specialServiceID = json['specialServiceID'];
name = json['name'];
description = json['description'];
price = json['price'];
appointmentStatusEnum = (json['appointmentStatus'] as int).toAppointmentStatusEnum();
appointmentDate = json['appointmentDate'];
appointmentStatusId = json['appointmentStatus'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['officeAreaName'] = officeAreaName;
data['officeAreaNameN'] = officeAreaNameN;
data['cityID'] = cityID;
data['city'] = city;
data['specialServiceID'] = specialServiceID;
return data;
@override
String toString() {
return 'SpecialServiceModelForAds{adsID: $adsID, specialServiceID: $specialServiceID, name: $name, description: $description, price: $price, appointmentStatusEnum: $appointmentStatusEnum, appointmentStatusId: $appointmentStatusId, appointmentDate: $appointmentDate}';
}
}

@ -1,3 +1,6 @@
import 'package:mc_common_app/models/appointments_models/service_schedule_model.dart';
import 'package:mc_common_app/models/general_models/widgets_models.dart';
class SSCarCheckScheduleModel {
int? serviceProviderID;
int? serviceProviderBranchID;
@ -7,22 +10,27 @@ class SSCarCheckScheduleModel {
String? latitude;
String? longitude;
List<ScheduleServices>? scheduleServices;
List<BranchScheduleSlots>? branchScheduleSlots;
List<CarCheckOfficeScheduleSlots>? branchScheduleSlots;
int? totalItemsCount;
int? distanceKM;
List<CustomTimeDateSlotModel>? 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<String, dynamic> json) {
serviceProviderID = json['serviceProviderID'];
@ -39,36 +47,51 @@ class SSCarCheckScheduleModel {
});
}
if (json['branchScheduleSlots'] != null) {
branchScheduleSlots = <BranchScheduleSlots>[];
branchScheduleSlots = <CarCheckOfficeScheduleSlots>[];
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<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
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<CustomTimeDateSlotModel> getFormattedDateTimeSlotPackage() {
List<CustomTimeDateSlotModel> 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<TimeSlotModel>? getAvailableSlotsByDate(String date) {
List<TimeSlotModel> 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<CustomTimeDateSlotModel> 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<String, dynamic> json) {
CarCheckOfficeScheduleSlots.fromJson(Map<String, dynamic> json) {
id = json['id'];
slotDate = json['slotDate'];
startTime = json['startTime'];
endTime = json['endTime'];
bookAppointment = json['bookAppointment'];
allowAppointment = json['allowAppointment'];
slotDurationMinute = json['slotDurationMinute'];
}
Map<String, dynamic> 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;
}
}

@ -1,4 +1,8 @@
class SSPhotoScheduleModel {
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/appointments_models/service_schedule_model.dart';
import 'package:mc_common_app/models/general_models/widgets_models.dart';
class SSPhotoOfficeScheduleModel {
int? photoOfficeID;
String? fromDate;
String? toDate;
@ -11,22 +15,29 @@ class SSPhotoScheduleModel {
int? distanceKM;
int? totalItemsCount;
List<PhotoOfficeScheduleSlots>? photoOfficeScheduleSlots;
List<CustomTimeDateSlotModel>? 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<String, dynamic> json) {
SSPhotoOfficeScheduleModel.fromJson(Map<String, dynamic> 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<CustomTimeDateSlotModel> getFormattedDateTimeSlotPackage() {
List<CustomTimeDateSlotModel> 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;
}
List<TimeSlotModel>? getAvailableSlotsByDate(String date) {
List<TimeSlotModel> 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;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
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();
bool isAlreadyThere(String dateToFind, List<CustomTimeDateSlotModel> slots) {
int index = slots.indexWhere((element) {
return element.date!.date == dateToFind;
});
if (index == -1) {
return false;
} else {
return true;
}
return data;
}
}
@ -73,23 +100,19 @@ class PhotoOfficeScheduleSlots {
String? slotDate;
String? startTime;
String? endTime;
int? bookAppointment;
int? allowAppointment;
int? slotDurationMinute;
PhotoOfficeScheduleSlots(
{this.id, this.slotDate, this.startTime, this.endTime});
PhotoOfficeScheduleSlots({this.id, this.slotDate, this.startTime, this.endTime, this.bookAppointment, this.allowAppointment, this.slotDurationMinute});
PhotoOfficeScheduleSlots.fromJson(Map<String, dynamic> json) {
id = json['id'];
slotDate = json['slotDate'];
slotDate = (json['slotDate'] as String).toFormattedDateWithoutTime();
startTime = json['startTime'];
endTime = json['endTime'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['slotDate'] = slotDate;
data['startTime'] = startTime;
data['endTime'] = endTime;
return data;
bookAppointment = json['bookAppointment'];
allowAppointment = json['allowAppointment'];
slotDurationMinute = json['slotDurationMinute'];
}
}

@ -1,3 +1,7 @@
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/services_models/service_model.dart';
import 'package:mc_common_app/utils/enums.dart';
class AppointmentListModel {
int? id;
int? serviceSlotID;
@ -9,28 +13,34 @@ class AppointmentListModel {
bool? isPaymentRequired;
int? paymentStatus;
String? paymentStatusText;
String? customerName;
String? customerName;
String? providerName;
String? duration;
String? appointmentDate;
List<ServiceAppointmentItems>? serviceAppointmentItems;
AppointmentStatusEnum? appointmentStatusEnum;
List<ServiceModel>? appointmentServicesList;
AppointmentListModel(
{this.id,
this.serviceSlotID,
this.appointmentStatusID,
this.appointmentStatusText,
this.serviceProviderID,
this.customerID,
this.isActive,
this.isPaymentRequired,
this.paymentStatus,
this.paymentStatusText,
this.customerName,
this.providerName,
this.duration,
this.appointmentDate,
this.serviceAppointmentItems});
this.serviceSlotID,
this.appointmentStatusID,
this.appointmentStatusText,
this.serviceProviderID,
this.customerID,
this.isActive,
this.isPaymentRequired,
this.paymentStatus,
this.paymentStatusText,
this.customerName,
this.providerName,
this.duration,
this.appointmentDate,
this.appointmentServicesList});
@override
String toString() {
return 'AppointmentListModel{id: $id, serviceSlotID: $serviceSlotID, appointmentStatusID: $appointmentStatusID, appointmentStatusText: $appointmentStatusText, serviceProviderID: $serviceProviderID, customerID: $customerID, isActive: $isActive, isPaymentRequired: $isPaymentRequired, paymentStatus: $paymentStatus, paymentStatusText: $paymentStatusText, customerName: $customerName, providerName: $providerName, duration: $duration, appointmentDate: $appointmentDate, appointmentStatusEnum: $appointmentStatusEnum, appointmentServicesList: $appointmentServicesList}';
}
AppointmentListModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
@ -47,35 +57,14 @@ class AppointmentListModel {
providerName = json['providerName'];
duration = json['duration'];
appointmentDate = json['appointmentDate'];
if (json['serviceAppointmentItems'] != null) {
serviceAppointmentItems = <ServiceAppointmentItems>[];
json['serviceAppointmentItems'].forEach((v) {
serviceAppointmentItems!.add(ServiceAppointmentItems.fromJson(v));
});
}
}
appointmentStatusEnum = (json['appointmentStatusID'] as int).toAppointmentStatusEnum();
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['serviceSlotID'] = serviceSlotID;
data['appointmentStatusID'] = appointmentStatusID;
data['appointmentStatusText'] = appointmentStatusText;
data['serviceProviderID'] = serviceProviderID;
data['customerID'] = customerID;
data['isActive'] = isActive;
data['isPaymentRequired'] = isPaymentRequired;
data['paymentStatus'] = paymentStatus;
data['paymentStatusText'] = paymentStatusText;
data['customerName'] = customerName;
data['providerName'] = providerName;
data['duration'] = duration;
data['appointmentDate'] = appointmentDate;
if (serviceAppointmentItems != null) {
data['serviceAppointmentItems'] =
serviceAppointmentItems!.map((v) => v.toJson()).toList();
if (json['serviceList'] != null) {
appointmentServicesList = <ServiceModel>[];
json['serviceList'].forEach((v) {
appointmentServicesList!.add(ServiceModel.fromJson(v, isForAppointment: true));
});
}
return data;
}
}
@ -85,11 +74,7 @@ class ServiceAppointmentItems {
String? serviceItemName;
String? serviceItemDescription;
ServiceAppointmentItems(
{this.id,
this.serviceItemID,
this.serviceItemName,
this.serviceItemDescription});
ServiceAppointmentItems({this.id, this.serviceItemID, this.serviceItemName, this.serviceItemDescription});
ServiceAppointmentItems.fromJson(Map<String, dynamic> json) {
id = json['id'];

@ -4,7 +4,7 @@
import 'dart:convert';
import 'package:mc_common_app/models/services/service_model.dart';
import 'package:mc_common_app/models/services_models/service_model.dart';
Schedule scheduleFromJson(String str) => Schedule.fromJson(json.decode(str));

@ -1,6 +1,6 @@
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/widgets_models.dart';
import 'package:mc_common_app/models/services_models/service_model.dart';
import 'package:mc_common_app/models/general_models/widgets_models.dart';
class CustomTimeDateSlotModel {
TimeSlotModel? date;
@ -11,30 +11,25 @@ class CustomTimeDateSlotModel {
class ServiceAppointmentScheduleModel {
List<ServiceSlotList>? serviceSlotList;
List<ItemData>? serviceItemList;
List<ServiceModel>? servicesListInAppointment;
int? selectedDateIndex;
// String? selectedTimeSlot;
// List<TimeSlotModel>? availableDates;
// List<TimeSlotModel>? availableTimeSlots;
List<CustomTimeDateSlotModel>? customTimeDateSlotList;
CustomTimeDateSlotModel? selectedCustomTimeDateSlotModel;
double? amountToPay;
double? amountTotal;
double? amountRem;
int? appointmentType;
ServiceAppointmentScheduleModel({
this.serviceSlotList,
this.serviceItemList,
this.servicesListInAppointment,
this.selectedDateIndex,
// this.selectedTimeSlot,
// this.availableDates,
// this.availableTimeSlots,
this.customTimeDateSlotList,
this.selectedCustomTimeDateSlotModel,
this.amountToPay,
this.amountTotal,
this.amountRem,
this.appointmentType,
});
List<CustomTimeDateSlotModel> getFormattedDateTimeSlotPackage() {
@ -42,7 +37,7 @@ class ServiceAppointmentScheduleModel {
for (var element in serviceSlotList!) {
if (!isAlreadyThere(element.slotDate!, customTimeDateSlotList)) {
customTimeDateSlotList.add(CustomTimeDateSlotModel(
date: TimeSlotModel(slotId: element.id!, isSelected: false, date: element.slotDate!, allowAppointment: true),
date: TimeSlotModel(slotId: element.id!, isSelected: false, date: element.slotDate!, allowAppointment: (element.allowAppointment ?? 0) > (element.bookAppointment ?? 0)),
availableSlots: getAvailableSlotsByDate(element.slotDate!),
));
}
@ -91,25 +86,17 @@ class ServiceAppointmentScheduleModel {
}
}
List<TimeSlotModel> getFormattedSlotDates() {
List<TimeSlotModel> slotDates = [];
return slotDates;
}
//TODO: I WILL START FROM HERE; I NEED TO ONLY PICK THE DISTINCT DATES FROM THE RESPONSE AND THEN BASED ON THE DATE SELECTION I WILL PICK THEIR SLOTS.
//TODO: AFTER THAT, I WILL
ServiceAppointmentScheduleModel.fromJson(Map<String, dynamic> json) {
ServiceAppointmentScheduleModel.fromJson(Map<String, dynamic> json, {bool isForAppointment = false}) {
if (json['serviceSlotList'] != null) {
serviceSlotList = <ServiceSlotList>[];
json['serviceSlotList'].forEach((v) {
serviceSlotList!.add(ServiceSlotList.fromJson(v));
});
}
if (json['serviceItemList'] != null) {
serviceItemList = <ItemData>[];
json['serviceItemList'].forEach((v) {
serviceItemList!.add(ItemData.fromJson(v));
if (json['serviceList'] != null) {
servicesListInAppointment = <ServiceModel>[];
json['serviceList'].forEach((v) {
servicesListInAppointment!.add(ServiceModel.fromJson(v, isForAppointment: isForAppointment));
});
}
customTimeDateSlotList = getFormattedDateTimeSlotPackage();
@ -117,20 +104,7 @@ class ServiceAppointmentScheduleModel {
selectedDateIndex = null;
amountTotal = json['amountTotal'];
amountRem = json['amountRem'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
if (serviceSlotList != null) {
data['serviceSlotList'] = serviceSlotList!.map((v) => v.toJson()).toList();
}
if (serviceItemList != null) {
data['serviceItemList'] = serviceItemList!.map((v) => v.toJson()).toList();
}
data['amountToPay'] = amountToPay;
data['amountTotal'] = amountTotal;
data['amountRem'] = amountRem;
return data;
appointmentType = json['appointmentType'];
}
}
@ -189,27 +163,6 @@ class ServiceSlotList {
modifiedOn = json['modifiedOn'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
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}';

@ -0,0 +1,103 @@
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/utils/enums.dart';
class ChatMessageModel {
String? senderUserID;
String? senderName;
int? messageType;
ChatMessageTypeEnum? messageTypeEnum;
String? message;
RequestOffer? requestOffer;
int? requestID;
int? requestOfferID;
bool? isMyMessage;
ChatMessageModel({
this.senderUserID,
this.senderName,
this.messageType,
this.message,
this.requestOffer,
this.requestID,
this.requestOfferID,
this.isMyMessage = true,
});
ChatMessageModel.fromJson(Map<String, dynamic> json) {
final myUserId = AppState().getUser.data!.userInfo!.userId.toString();
senderUserID = json['senderUserID'];
senderName = json['senderName'];
messageType = json['messageType'];
messageTypeEnum = (json['messageType'] as int).toChatMessageTypeEnum();
message = json['message'];
requestOffer = json['requestOffer'] != null ? RequestOffer.fromJson(json['requestOffer']) : null;
requestID = json['requestID'];
requestOfferID = json['requestOfferID'];
isMyMessage = (json['senderUserId']).toString() == myUserId;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['senderUserID'] = senderUserID;
data['senderName'] = senderName;
data['messageType'] = messageType;
data['message'] = message;
if (requestOffer != null) {
data['requestOffer'] = requestOffer!.toJson();
}
data['requestID'] = requestID;
data['requestOfferID'] = requestOfferID;
return data;
}
}
class RequestOffer {
int? id;
int? requestID;
int? serviceProviderID;
int? offerStatus;
RequestOfferStatusEnum? requestOfferStatusEnum;
String? comment;
double? price;
String? offeredItemCreatedBy;
String? offeredItemCreatedOn;
RequestOffer({
this.id,
this.requestID,
this.serviceProviderID,
this.offerStatus,
this.comment,
this.price,
this.offeredItemCreatedBy,
this.offeredItemCreatedOn,
this.requestOfferStatusEnum = RequestOfferStatusEnum.offer,
});
RequestOffer.fromJson(Map<String, dynamic> json) {
id = json['id'];
requestID = json['requestID'];
serviceProviderID = json['serviceProviderID'];
offerStatus = json['offerStatus'];
offerStatus = json['offerStatus'];
requestOfferStatusEnum = ((json['offerStatus']) as int).toRequestOfferStatusEnum();
comment = json['comment'];
price = json['price'];
offeredItemCreatedBy = json['offeredItemCreatedBy'];
offeredItemCreatedOn = json['offeredItemCreatedOn'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['requestID'] = requestID;
data['serviceProviderID'] = serviceProviderID;
data['offerStatus'] = offerStatus;
data['comment'] = comment;
data['price'] = price;
data['offeredItemCreatedBy'] = offeredItemCreatedBy;
data['offeredItemCreatedOn'] = offeredItemCreatedOn;
return data;
}
}

@ -1,12 +0,0 @@
class ConfigModel {
ConfigModel(this.endpoint, this.organizationName);
String endpoint;
String organizationName;
factory ConfigModel.fromJson(Map<String, dynamic> json) =>
ConfigModel("", "");
// Map<String, dynamic> toJson() => _$ConfigModelToJson(this);
}

@ -1,65 +0,0 @@
class ContentInfoModel {
int? totalItemsCount;
int? statusCode;
String? message;
List<ContentInfoDataModel>? data;
ContentInfoModel({this.totalItemsCount, this.statusCode, this.message, this.data});
ContentInfoModel.fromJson(Map<String, dynamic> json) {
totalItemsCount = json['totalItemsCount'];
statusCode = json['statusCode'];
message = json['message'];
if (json['data'] != null) {
data = [];
json['data'].forEach((v) {
data?.add(new ContentInfoDataModel.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['totalItemsCount'] = this.totalItemsCount;
data['statusCode'] = this.statusCode;
data['message'] = this.message;
if (this.data != null) {
data['data'] = this.data?.map((v) => v.toJson()).toList();
}
return data;
}
}
class ContentInfoDataModel {
int? contentInfoId;
int? contentTypeId;
String? content;
String? contentTypeNameEn;
String? contentTypeNameAr;
String? fileName;
String? exposeFilePath;
ContentInfoDataModel({this.contentInfoId, this.contentTypeId, this.content, this.contentTypeNameEn, this.contentTypeNameAr, this.fileName, this.exposeFilePath});
ContentInfoDataModel.fromJson(Map<String, dynamic> json) {
contentInfoId = json['contentInfoId'];
contentTypeId = json['contentTypeId'];
content = json['content'];
contentTypeNameEn = json['contentTypeNameEn'];
contentTypeNameAr = json['contentTypeNameAr'];
fileName = json['fileName'];
exposeFilePath = json['exposeFilePath'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['contentInfoId'] = this.contentInfoId;
data['contentTypeId'] = this.contentTypeId;
data['content'] = this.content;
data['contentTypeNameEn'] = this.contentTypeNameEn;
data['contentTypeNameAr'] = this.contentTypeNameAr;
data['fileName'] = this.fileName;
data['exposeFilePath'] = this.exposeFilePath;
return data;
}
}

@ -1,11 +1,11 @@
class Enums {
class EnumsModel {
int id;
int enumTypeId;
String enumValueStr;
int enumValue;
bool isActive;
Enums({
EnumsModel({
required this.id,
required this.enumTypeId,
required this.enumValueStr,
@ -13,7 +13,7 @@ class Enums {
required this.isActive,
});
factory Enums.fromJson(Map<String, dynamic> json) => Enums(
factory EnumsModel.fromJson(Map<String, dynamic> json) => EnumsModel(
id: json["id"],
enumTypeId: json["enumTypeID"],
enumValueStr: json["enumValueStr"],
@ -21,6 +21,11 @@ class Enums {
isActive: json["isActive"],
);
@override
String toString() {
return 'EnumsModel{id: $id, enumTypeId: $enumTypeId, enumValueStr: $enumValueStr, enumValue: $enumValue, isActive: $isActive}';
}
Map<String, dynamic> toJson() => {
"id": id,
"enumTypeID": enumTypeId,

@ -279,6 +279,29 @@ class VehiclePostingImages {
}
}
class RequestPostingImages {
int? id;
String? requestImage;
int? requestID;
RequestPostingImages({this.id, this.requestImage, this.requestID});
RequestPostingImages.fromJson(Map<String, dynamic> json) {
id = json['id'];
requestImage = json['requestImage'];
requestID = json['requestID'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['requestImage'] = requestImage;
data['requestID'] = requestID;
return data;
}
}
class VehiclePostingDamageParts {
int? id;
String? comment;

@ -1,62 +0,0 @@
class MemberModel {
int? totalItemsCount;
int? statusCode;
String? message;
List<MemberDataModel>? data;
MemberModel({this.totalItemsCount, this.statusCode, this.message, this.data});
MemberModel.fromJson(Map<String, dynamic> json) {
totalItemsCount = json['totalItemsCount'];
statusCode = json['statusCode'];
message = json['message'];
if (json['data'] != null) {
data = [];
json['data'].forEach((v) {
data?.add(new MemberDataModel.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['totalItemsCount'] = this.totalItemsCount;
data['statusCode'] = this.statusCode;
data['message'] = this.message;
if (this.data != null) {
data['data'] = this.data?.map((v) => v.toJson()).toList();
}
return data;
}
}
class MemberDataModel {
int? committeeId;
String? firstName;
String? lastName;
String? description;
String? picture;
int? orderNo;
MemberDataModel({this.committeeId, this.firstName, this.lastName, this.description, this.picture, this.orderNo});
MemberDataModel.fromJson(Map<String, dynamic> json) {
committeeId = json['committeeId'];
firstName = json['firstName'];
lastName = json['lastName'];
description = json['description'];
picture = json['picture'];
orderNo = json['orderNo'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['committeeId'] = this.committeeId;
data['firstName'] = this.firstName;
data['lastName'] = this.lastName;
data['description'] = this.description;
data['picture'] = this.picture;
data['orderNo'] = this.orderNo;
return data;
}
}

@ -1,26 +0,0 @@
class ParentList {
ParentList({
required this.dbId,
required this.text,
required this.path,
required this.isSelected,
});
int dbId;
String text;
String path;
bool isSelected;
factory ParentList.fromJson(Map<String, dynamic> json) => ParentList(
dbId: json["dbId"] == null ? null : json["dbId"],
text: json["text"] == null ? null : json["text"],
path: json["path"] == null ? null : json["path"],
isSelected: false,
);
Map<String, dynamic> toJson() => {
"dbId": dbId == null ? null : dbId,
"text": text == null ? null : text,
"path": path == null ? null : path,
};
}

@ -1,6 +1,6 @@
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/provider_branches_models/profile/categroy.dart';
import 'package:mc_common_app/models/services/service_model.dart';
import 'package:mc_common_app/models/services_models/service_model.dart';
import 'package:mc_common_app/utils/enums.dart';
class BranchDetailModel {

@ -6,7 +6,7 @@ import 'dart:convert';
import 'package:equatable/equatable.dart';
import 'package:mc_common_app/models/provider_branches_models/provider_profile_model.dart';
import 'package:mc_common_app/models/services/service_model.dart';
import 'package:mc_common_app/models/services_models/service_model.dart';
Category categoryFromJson(String str) => Category.fromJson(json.decode(str));

@ -0,0 +1,169 @@
class OffersModel {
int? id;
int? requestID;
int? serviceProviderID;
ServiceProvider? serviceProvider;
int? offerStatus;
String? offerStatusText;
String? comment;
double? price;
OffersModel(
{this.id,
this.requestID,
this.serviceProviderID,
this.serviceProvider,
this.offerStatus,
this.offerStatusText,
this.comment,
this.price});
OffersModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
requestID = json['requestID'];
serviceProviderID = json['serviceProviderID'];
serviceProvider = json['serviceProvider'] != null
? ServiceProvider.fromJson(json['serviceProvider'])
: null;
offerStatus = json['offerStatus'];
offerStatusText = json['offerStatusText'];
comment = json['comment'];
price = json['price'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['requestID'] = requestID;
data['serviceProviderID'] = serviceProviderID;
if (serviceProvider != null) {
data['serviceProvider'] = serviceProvider!.toJson();
}
data['offerStatus'] = offerStatus;
data['offerStatusText'] = offerStatusText;
data['comment'] = comment;
data['price'] = price;
return data;
}
}
class ServiceProvider {
int? providerId;
String? providerGUID;
String? firstName;
String? lastName;
String? name;
int? gender;
String? genderName;
String? mobileNo;
String? email;
bool? isEmailVerfied;
bool? isCompleted;
int? city;
String? cityName;
int? country;
String? countryName;
int? accountStatus;
String? accountStatusText;
int? activityStatus;
String? activityStatusText;
String? bankName;
String? iBanNo;
bool? isActive;
String? subscriptionDate;
String? companyName;
String? currency;
String? branch;
dynamic requestOffer;
ServiceProvider(
{this.providerId,
this.providerGUID,
this.firstName,
this.lastName,
this.name,
this.gender,
this.genderName,
this.mobileNo,
this.email,
this.isEmailVerfied,
this.isCompleted,
this.city,
this.cityName,
this.country,
this.countryName,
this.accountStatus,
this.accountStatusText,
this.activityStatus,
this.activityStatusText,
this.bankName,
this.iBanNo,
this.isActive,
this.subscriptionDate,
this.companyName,
this.currency,
this.branch,
this.requestOffer});
ServiceProvider.fromJson(Map<String, dynamic> json) {
providerId = json['providerId'];
providerGUID = json['providerGUID'];
firstName = json['firstName'];
lastName = json['lastName'];
name = json['name'];
gender = json['gender'];
genderName = json['genderName'];
mobileNo = json['mobileNo'];
email = json['email'];
isEmailVerfied = json['isEmailVerfied'];
isCompleted = json['isCompleted'];
city = json['city'];
cityName = json['cityName'];
country = json['country'];
countryName = json['countryName'];
accountStatus = json['accountStatus'];
accountStatusText = json['accountStatusText'];
activityStatus = json['activityStatus'];
activityStatusText = json['activityStatusText'];
bankName = json['bankName'];
iBanNo = json['iBanNo'];
isActive = json['isActive'];
subscriptionDate = json['subscriptionDate'];
companyName = json['companyName'];
currency = json['currency'];
branch = json['branch'];
requestOffer = json['requestOffer'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['providerId'] = providerId;
data['providerGUID'] = providerGUID;
data['firstName'] = firstName;
data['lastName'] = lastName;
data['name'] = name;
data['gender'] = gender;
data['genderName'] = genderName;
data['mobileNo'] = mobileNo;
data['email'] = email;
data['isEmailVerfied'] = isEmailVerfied;
data['isCompleted'] = isCompleted;
data['city'] = city;
data['cityName'] = cityName;
data['country'] = country;
data['countryName'] = countryName;
data['accountStatus'] = accountStatus;
data['accountStatusText'] = accountStatusText;
data['activityStatus'] = activityStatus;
data['activityStatusText'] = activityStatusText;
data['bankName'] = bankName;
data['iBanNo'] = iBanNo;
data['isActive'] = isActive;
data['subscriptionDate'] = subscriptionDate;
data['companyName'] = companyName;
data['currency'] = currency;
data['branch'] = branch;
data['requestOffer'] = requestOffer;
return data;
}
}

@ -10,6 +10,7 @@ class RequestModel {
String vehicleTypeName;
String countryName;
String customerName;
String customerID;
dynamic serviceProviders;
int offerCount;
int id;
@ -43,6 +44,7 @@ class RequestModel {
required this.vehicleTypeName,
required this.countryName,
required this.customerName,
required this.customerID,
required this.serviceProviders,
required this.offerCount,
required this.id,
@ -68,39 +70,42 @@ class RequestModel {
required this.modifiedOn,
});
factory RequestModel.fromJson(Map<String, dynamic> json) => RequestModel(
requestType: json["requestType"],
requestTypeName: json["requestTypeName"],
requestStatusName: json["requestStatusName"],
requestStatus: (json['requestStatus'] as int).toRequestStatusEnum(),
cityName: json["cityName"],
vehicleTypeName: json["vehicleTypeName"],
countryName: json["countryName"],
customerName: json["customerName"],
serviceProviders: json["serviceProviders"],
offerCount: json["offerCount"],
id: json["id"],
customerId: json["customerID"],
customer: json["customer"],
brand: json["brand"],
model: json["model"],
year: json["year"],
isNew: json["isNew"],
description: json["description"],
requestImages: List<dynamic>.from(json["requestImages"].map((x) => x)),
cityId: json["cityID"],
city: json["city"],
price: json["price"],
paymentStatus: json["paymentStatus"],
vehicleTypeId: json["vehicleTypeID"],
countryId: json["countryID"],
requestProviderItem: List<dynamic>.from(json["requestProviderItem"].map((x) => x)),
isActive: json["isActive"],
createdBy: json["createdBy"],
createdOn: DateTime.parse(json["createdOn"]),
modifiedBy: json["modifiedBy"],
modifiedOn: json["modifiedOn"],
);
factory RequestModel.fromJson(Map<String, dynamic> json) {
return RequestModel(
requestType: json["requestType"],
requestTypeName: json["requestTypeName"],
requestStatusName: json["requestStatusName"],
requestStatus: (json['requestStatus'] as int).toRequestStatusEnum(),
cityName: json["cityName"],
vehicleTypeName: json["vehicleTypeName"],
countryName: json["countryName"],
customerName: json["customerName"],
customerID: json["customerUserID"],
serviceProviders: json["serviceProviders"],
offerCount: json["offerCount"],
id: json["id"],
customerId: json["customerID"],
customer: json["customer"],
brand: json["brand"],
model: json["model"],
year: json["year"],
isNew: json["isNew"],
description: json["description"],
requestImages: List<dynamic>.from(json["requestImages"].map((x) => x)),
cityId: json["cityID"],
city: json["city"],
price: json["price"],
paymentStatus: json["paymentStatus"],
vehicleTypeId: json["vehicleTypeID"],
countryId: json["countryID"],
requestProviderItem: List<dynamic>.from(json["requestProviderItem"].map((x) => x)),
isActive: json["isActive"],
createdBy: json["createdBy"],
createdOn: DateTime.parse(json["createdOn"]),
modifiedBy: json["modifiedBy"],
modifiedOn: json["modifiedOn"],
);
}
Map<String, dynamic> toJson() => {
"requestType": requestType,

@ -1,34 +0,0 @@
///
/// This example was taken from
/// https://flutter.dev/docs/development/data-and-backend/json
///
/// This allows the `User` class to access private members in
/// the generated file. The value for this is *.g.dart, where
/// the star denotes the source file name.
/// An annotation for the code generator to know that this class needs the
/// JSON serialization logic to be generated.
class BackendResponse {
BackendResponse({required this.id, required this.isOk, required this.result});
int id;
bool isOk;
dynamic result;
/// A necessary factory constructor for creating a new User instance
/// from a map. Pass the map to the generated `_$UserFromJson()` constructor.
/// The constructor is named after the source class, in this case, User.
factory BackendResponse.fromJson(Map<String, dynamic> json) =>
BackendResponse(
id: 1,
isOk: false,
result: null,
);
//
// /// `toJson` is the convention for a class to declare support for serialization
// /// to JSON. The implementation simply calls the private, generated
// /// helper method `_$UserToJson`.
// Map<String, dynamic> toJson() => _$BackendResponseToJson(this);
}

@ -1,105 +0,0 @@
// To parse this JSON data, do
//
// final itemModel = itemModelFromJson(jsonString);
import 'dart:convert';
ItemModel itemModelFromJson(String str) => ItemModel.fromJson(json.decode(str));
String itemModelToJson(ItemModel data) => json.encode(data.toJson());
class ItemModel {
final int? messageStatus;
final int? totalItemsCount;
final List<ItemData>? data;
final String? message;
ItemModel({
this.messageStatus,
this.totalItemsCount,
this.data,
this.message,
});
factory ItemModel.fromJson(Map<String, dynamic> json) => ItemModel(
messageStatus: json["messageStatus"],
totalItemsCount: json["totalItemsCount"],
data: json["data"] == null ? [] : List<ItemData>.from(json["data"]!.map((x) => ItemData.fromJson(x))),
message: json["message"],
);
Map<String, dynamic> toJson() => {
"messageStatus": messageStatus,
"totalItemsCount": totalItemsCount,
"data": data == null ? [] : List<dynamic>.from(data!.map((x) => x.toJson())),
"message": message,
};
}
class ItemData {
final int? id;
final String? name;
final String? price;
final String? manufactureDate;
final String? description;
final dynamic pictureUrl;
final int? companyId;
final int? serviceProviderServiceId;
final String? serviceProviderServiceDescription;
final bool? isActive;
final bool? isAllowAppointment;
final bool? isAppointmentCompanyLoc;
final bool? isAppointmentCustomerLoc;
final double? appointmentPricePercentage;
bool? isUpdateOrSelected;
ItemData({
this.id,
this.name,
this.price,
this.manufactureDate,
this.description,
this.pictureUrl,
this.companyId,
this.serviceProviderServiceId,
this.serviceProviderServiceDescription,
this.isActive,
this.isAllowAppointment,
this.isAppointmentCompanyLoc,
this.isAppointmentCustomerLoc,
this.appointmentPricePercentage,
this.isUpdateOrSelected,
});
factory ItemData.fromJson(Map<String, dynamic> json) => ItemData(
id: json["id"],
name: json["name"],
price: json["price"].toString(),
manufactureDate: json["manufactureDate"],
description: json["description"],
pictureUrl: json["pictureUrl"],
companyId: json["companyID"],
serviceProviderServiceId: json["serviceProviderServiceID"],
serviceProviderServiceDescription: json["serviceProviderServiceDescription"],
isActive: json["isActive"],
isAllowAppointment: json["isAllowAppointment"],
isAppointmentCompanyLoc: json["isAppointmentCompanyLoc"],
isAppointmentCustomerLoc: json["isAppointmentCustomerLoc"],
isUpdateOrSelected: false,
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
"price": price,
"manufactureDate": manufactureDate,
"description": description,
"pictureUrl": pictureUrl,
"companyID": companyId,
"serviceProviderServiceID": serviceProviderServiceId,
"isActive": isActive,
"isAllowAppointment": isAllowAppointment,
"isAppointmentCompanyLoc": isAppointmentCompanyLoc,
"isAppointmentCustomerLoc": isAppointmentCustomerLoc,
};
}

@ -0,0 +1,113 @@
// To parse this JSON data, do
//
// final itemModel = itemModelFromJson(jsonString);
import 'dart:convert';
ItemModel itemModelFromJson(String str) => ItemModel.fromJson(json.decode(str));
String itemModelToJson(ItemModel data) => json.encode(data.toJson());
class ItemModel {
final int? messageStatus;
final int? totalItemsCount;
final List<ItemData>? data;
final String? message;
ItemModel({
this.messageStatus,
this.totalItemsCount,
this.data,
this.message,
});
factory ItemModel.fromJson(Map<String, dynamic> json) => ItemModel(
messageStatus: json["messageStatus"],
totalItemsCount: json["totalItemsCount"],
data: json["data"] == null ? [] : List<ItemData>.from(json["data"]!.map((x) => ItemData.fromJson(x))),
message: json["message"],
);
Map<String, dynamic> toJson() => {
"messageStatus": messageStatus,
"totalItemsCount": totalItemsCount,
"data": data == null ? [] : List<dynamic>.from(data!.map((x) => x.toJson())),
"message": message,
};
}
class ItemData {
final int? id;
final String? name;
final String? price;
final String? manufactureDate;
final String? description;
final dynamic pictureUrl;
final int? companyId;
final int? serviceProviderServiceId;
final String? serviceProviderServiceDescription;
final bool? isActive;
final bool? isAllowAppointment;
final bool? isAppointmentCompanyLoc;
final bool? isAppointmentCustomerLoc;
final double? appointmentPricePercentage;
bool? isUpdateOrSelected;
bool? isHomeSelected;
ItemData({
this.id,
this.name,
this.price,
this.manufactureDate,
this.description,
this.pictureUrl,
this.companyId,
this.serviceProviderServiceId,
this.serviceProviderServiceDescription,
this.isActive,
this.isAllowAppointment,
this.isAppointmentCompanyLoc,
this.isAppointmentCustomerLoc,
this.appointmentPricePercentage,
this.isUpdateOrSelected,
this.isHomeSelected,
});
factory ItemData.fromJson(Map<String, dynamic> json) => ItemData(
id: json["id"],
name: json["name"],
price: json["price"].toString(),
manufactureDate: json["manufactureDate"],
description: json["description"],
pictureUrl: json["pictureUrl"],
companyId: json["companyID"],
serviceProviderServiceId: json["serviceProviderServiceID"],
serviceProviderServiceDescription: json["serviceProviderServiceDescription"],
isActive: json["isActive"],
isAllowAppointment: json["isAllowAppointment"],
isAppointmentCompanyLoc: json["isAppointmentCompanyLoc"],
isAppointmentCustomerLoc: json["isAppointmentCustomerLoc"],
isUpdateOrSelected: false,
isHomeSelected: false,
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
"price": price,
"manufactureDate": manufactureDate,
"description": description,
"pictureUrl": pictureUrl,
"companyID": companyId,
"serviceProviderServiceID": serviceProviderServiceId,
"isActive": isActive,
"isAllowAppointment": isAllowAppointment,
"isAppointmentCompanyLoc": isAppointmentCompanyLoc,
"isAppointmentCustomerLoc": isAppointmentCustomerLoc,
};
@override
String toString() {
return 'ItemData{id: $id, name: $name, price: $price, manufactureDate: $manufactureDate, description: $description, pictureUrl: $pictureUrl, companyId: $companyId, serviceProviderServiceId: $serviceProviderServiceId, serviceProviderServiceDescription: $serviceProviderServiceDescription, isActive: $isActive, isAllowAppointment: $isAllowAppointment, isAppointmentCompanyLoc: $isAppointmentCompanyLoc, isAppointmentCustomerLoc: $isAppointmentCustomerLoc, appointmentPricePercentage: $appointmentPricePercentage, isUpdateOrSelected: $isUpdateOrSelected}';
}
}

@ -1,4 +1,4 @@
import 'package:mc_common_app/models/services/item_model.dart';
import 'package:mc_common_app/models/services_models/item_model.dart';
class ServiceModel {
final int? serviceProviderServiceId;
@ -19,6 +19,9 @@ class ServiceModel {
bool isExpandedOrSelected;
int providerServiceId;
String providerServiceName;
bool isHomeSelected;
String homeLocation;
double currentTotalServicePrice;
ServiceModel({
this.serviceProviderServiceId,
@ -36,13 +39,15 @@ class ServiceModel {
this.rangePricePerKm,
this.itemsCount,
this.serviceItems,
this.isHomeSelected = false,
this.homeLocation = "",
this.currentTotalServicePrice = 0.0,
required this.isExpandedOrSelected,
required this.providerServiceId,
required this.providerServiceName,
});
factory ServiceModel.fromJson(Map<String, dynamic> json) =>
ServiceModel(
factory ServiceModel.fromJson(Map<String, dynamic> json, {bool isForAppointment = false}) => ServiceModel(
serviceProviderServiceId: json["serviceProviderServiceID"],
providerServiceDescription: json["providerServiceDescription"],
categoryId: json["categoryID"],
@ -57,14 +62,21 @@ class ServiceModel {
customerLocationRange: json["customerLocationRange"],
rangePricePerKm: json["rangePricePerKm"].toString(),
itemsCount: json["itemsCount"],
serviceItems: json["branchServiceItems"] == null ? [] : List<ItemData>.from(json["branchServiceItems"]!.map((x) => ItemData.fromJson(x))),
serviceItems: isForAppointment
? json["serviceItemList"] == null
? []
: List<ItemData>.from(json["serviceItemList"]!.map((x) => ItemData.fromJson(x)))
: json["branchServiceItems"] == null
? []
: List<ItemData>.from(json["branchServiceItems"]!.map((x) => ItemData.fromJson(x))),
isExpandedOrSelected: false,
providerServiceId: 0,
providerServiceName: "",
isHomeSelected: false,
homeLocation: "",
);
Map<String, dynamic> toJson() =>
{
Map<String, dynamic> toJson() => {
"serviceProviderServiceID": serviceProviderServiceId,
"providerServiceDescription": providerServiceDescription,
"categoryID": categoryId,

@ -1,74 +0,0 @@
class SurahModel {
int? totalItemsCount;
int? statusCode;
String? message;
List<SurahModelData>? data;
SurahModel({this.totalItemsCount, this.statusCode, this.message, this.data});
SurahModel.fromJson(Map<String, dynamic> json) {
totalItemsCount = json['totalItemsCount'];
statusCode = json['statusCode'];
message = json['message'];
if (json['data'] != null) {
data = [];
json['data'].forEach((v) {
data?.add(SurahModelData.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['totalItemsCount'] = totalItemsCount;
data['statusCode'] = statusCode;
data['message'] = message;
if (this.data != null) {
data['data'] = this.data?.map((v) => v.toJson()).toList();
}
return data;
}
}
class SurahModelData {
int? id;
int? surahID;
String? nameAR;
String? nameEN;
int? numberOfAyahs;
String? englishNameTranslation;
int? revelationID;
String? revelationType;
int? startPageNo;
int? endPageNo;
SurahModelData({this.id, this.surahID, this.nameAR, this.nameEN, this.numberOfAyahs, this.englishNameTranslation, this.revelationID, this.revelationType, this.startPageNo, this.endPageNo});
SurahModelData.fromJson(Map<String, dynamic> json) {
id = json['id'];
surahID = json['surahID'];
nameAR = json['nameAR'];
nameEN = json['nameEN'];
numberOfAyahs = json['numberOfAyahs'];
englishNameTranslation = json['englishNameTranslation'];
revelationID = json['revelation_ID'];
revelationType = json['revelationType'];
startPageNo = json['startPageNo'];
endPageNo = json['endPageNo'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['surahID'] = this.surahID;
data['nameAR'] = this.nameAR;
data['nameEN'] = this.nameEN;
data['numberOfAyahs'] = this.numberOfAyahs;
data['englishNameTranslation'] = this.englishNameTranslation;
data['revelation_ID'] = this.revelationID;
data['revelationType'] = this.revelationType;
data['startPageNo'] = this.startPageNo;
data['endPageNo'] = this.endPageNo;
return data;
}
}

@ -0,0 +1,44 @@
// // To parse this JSON data, do
// //
// // final account = accountFromJson(jsonString);
//
// import 'dart:convert';
//
// import 'package:mc_common_app/models/parent_list.dart';
//
//
//
//
// Account accountFromJson(String str) => Account.fromJson(json.decode(str));
//
// String accountToJson(Account data) => json.encode(data.toJson());
//
// class Account {
// Account({
// required this.parentList,
// required this.selectedItem,
// });
//
// List<ParentList>? parentList;
// int selectedItem;
//
// factory Account.fromJson(Map<String, dynamic> json) => Account(
// parentList: json["parentList"] == null
// ? null
// : List<ParentList>.from(
// json["parentList"].map((x) => ParentList.fromJson(x))),
// selectedItem:
// json["selectedItem"] == null ? null : json["selectedItem"],
// );
//
// Map<String, dynamic> toJson() => {
// "parentList": parentList == null
// ? null
// : List<dynamic>.from(parentList!.map((x) => x.toJson())),
// "selectedItem": selectedItem == null ? null : selectedItem,
// };
//
// Map<String, dynamic> toJsonData() => {
// "selectedItem": selectedItem == null ? null : selectedItem,
// };
// }

@ -0,0 +1,12 @@
// class ConfigModel {
// ConfigModel(this.endpoint, this.organizationName);
//
// String endpoint;
//
// String organizationName;
//
// factory ConfigModel.fromJson(Map<String, dynamic> json) =>
// ConfigModel("", "");
//
// // Map<String, dynamic> toJson() => _$ConfigModelToJson(this);
// }

@ -0,0 +1,65 @@
// class ContentInfoModel {
// int? totalItemsCount;
// int? statusCode;
// String? message;
// List<ContentInfoDataModel>? data;
//
// ContentInfoModel({this.totalItemsCount, this.statusCode, this.message, this.data});
//
// ContentInfoModel.fromJson(Map<String, dynamic> json) {
// totalItemsCount = json['totalItemsCount'];
// statusCode = json['statusCode'];
// message = json['message'];
// if (json['data'] != null) {
// data = [];
// json['data'].forEach((v) {
// data?.add(new ContentInfoDataModel.fromJson(v));
// });
// }
// }
//
// Map<String, dynamic> toJson() {
// final Map<String, dynamic> data = new Map<String, dynamic>();
// data['totalItemsCount'] = this.totalItemsCount;
// data['statusCode'] = this.statusCode;
// data['message'] = this.message;
// if (this.data != null) {
// data['data'] = this.data?.map((v) => v.toJson()).toList();
// }
// return data;
// }
// }
//
// class ContentInfoDataModel {
// int? contentInfoId;
// int? contentTypeId;
// String? content;
// String? contentTypeNameEn;
// String? contentTypeNameAr;
// String? fileName;
// String? exposeFilePath;
//
// ContentInfoDataModel({this.contentInfoId, this.contentTypeId, this.content, this.contentTypeNameEn, this.contentTypeNameAr, this.fileName, this.exposeFilePath});
//
// ContentInfoDataModel.fromJson(Map<String, dynamic> json) {
// contentInfoId = json['contentInfoId'];
// contentTypeId = json['contentTypeId'];
// content = json['content'];
// contentTypeNameEn = json['contentTypeNameEn'];
// contentTypeNameAr = json['contentTypeNameAr'];
// fileName = json['fileName'];
// exposeFilePath = json['exposeFilePath'];
// }
//
// Map<String, dynamic> toJson() {
// final Map<String, dynamic> data = new Map<String, dynamic>();
// data['contentInfoId'] = this.contentInfoId;
// data['contentTypeId'] = this.contentTypeId;
// data['content'] = this.content;
// data['contentTypeNameEn'] = this.contentTypeNameEn;
// data['contentTypeNameAr'] = this.contentTypeNameAr;
// data['fileName'] = this.fileName;
// data['exposeFilePath'] = this.exposeFilePath;
// return data;
// }
// }

@ -0,0 +1,62 @@
// class MemberModel {
// int? totalItemsCount;
// int? statusCode;
// String? message;
// List<MemberDataModel>? data;
//
// MemberModel({this.totalItemsCount, this.statusCode, this.message, this.data});
//
// MemberModel.fromJson(Map<String, dynamic> json) {
// totalItemsCount = json['totalItemsCount'];
// statusCode = json['statusCode'];
// message = json['message'];
// if (json['data'] != null) {
// data = [];
// json['data'].forEach((v) {
// data?.add(new MemberDataModel.fromJson(v));
// });
// }
// }
//
// Map<String, dynamic> toJson() {
// final Map<String, dynamic> data = new Map<String, dynamic>();
// data['totalItemsCount'] = this.totalItemsCount;
// data['statusCode'] = this.statusCode;
// data['message'] = this.message;
// if (this.data != null) {
// data['data'] = this.data?.map((v) => v.toJson()).toList();
// }
// return data;
// }
// }
//
// class MemberDataModel {
// int? committeeId;
// String? firstName;
// String? lastName;
// String? description;
// String? picture;
// int? orderNo;
//
// MemberDataModel({this.committeeId, this.firstName, this.lastName, this.description, this.picture, this.orderNo});
//
// MemberDataModel.fromJson(Map<String, dynamic> json) {
// committeeId = json['committeeId'];
// firstName = json['firstName'];
// lastName = json['lastName'];
// description = json['description'];
// picture = json['picture'];
// orderNo = json['orderNo'];
// }
//
// Map<String, dynamic> toJson() {
// final Map<String, dynamic> data = new Map<String, dynamic>();
// data['committeeId'] = this.committeeId;
// data['firstName'] = this.firstName;
// data['lastName'] = this.lastName;
// data['description'] = this.description;
// data['picture'] = this.picture;
// data['orderNo'] = this.orderNo;
// return data;
// }
// }

@ -0,0 +1,26 @@
// class ParentList {
// ParentList({
// required this.dbId,
// required this.text,
// required this.path,
// required this.isSelected,
// });
//
// int dbId;
// String text;
// String path;
// bool isSelected;
//
// factory ParentList.fromJson(Map<String, dynamic> json) => ParentList(
// dbId: json["dbId"] == null ? null : json["dbId"],
// text: json["text"] == null ? null : json["text"],
// path: json["path"] == null ? null : json["path"],
// isSelected: false,
// );
//
// Map<String, dynamic> toJson() => {
// "dbId": dbId == null ? null : dbId,
// "text": text == null ? null : text,
// "path": path == null ? null : path,
// };
// }

@ -63,3 +63,5 @@
// return 'ProviderServiceModel{id: $id, description: $description, descriptionN: $descriptionN, serviceIconUrl: $serviceIconUrl, serviceImageUrl: $serviceImageUrl, serviceCategoryID: $serviceCategoryID, isActive: $isActive, categoryName: $categoryName, ispartial: $ispartial, appointmentPricePercentage: $appointmentPricePercentage, refundAmountPercentage: $refundAmountPercentage, isSelected: $isSelected}';
// }
// }
// // test

@ -0,0 +1,34 @@
// ///
// /// This example was taken from
// /// https://flutter.dev/docs/development/data-and-backend/json
// ///
//
// /// This allows the `User` class to access private members in
// /// the generated file. The value for this is *.g.dart, where
// /// the star denotes the source file name.
//
// /// An annotation for the code generator to know that this class needs the
// /// JSON serialization logic to be generated.
//
// class BackendResponse {
// BackendResponse({required this.id, required this.isOk, required this.result});
//
// int id;
// bool isOk;
// dynamic result;
//
// /// A necessary factory constructor for creating a new User instance
// /// from a map. Pass the map to the generated `_$UserFromJson()` constructor.
// /// The constructor is named after the source class, in this case, User.
// factory BackendResponse.fromJson(Map<String, dynamic> json) =>
// BackendResponse(
// id: 1,
// isOk: false,
// result: null,
// );
// //
// // /// `toJson` is the convention for a class to declare support for serialization
// // /// to JSON. The implementation simply calls the private, generated
// // /// helper method `_$UserToJson`.
// // Map<String, dynamic> toJson() => _$BackendResponseToJson(this);
// }

@ -0,0 +1,74 @@
// class SurahModel {
// int? totalItemsCount;
// int? statusCode;
// String? message;
// List<SurahModelData>? data;
//
// SurahModel({this.totalItemsCount, this.statusCode, this.message, this.data});
//
// SurahModel.fromJson(Map<String, dynamic> json) {
// totalItemsCount = json['totalItemsCount'];
// statusCode = json['statusCode'];
// message = json['message'];
// if (json['data'] != null) {
// data = [];
// json['data'].forEach((v) {
// data?.add(SurahModelData.fromJson(v));
// });
// }
// }
//
// Map<String, dynamic> toJson() {
// final Map<String, dynamic> data = new Map<String, dynamic>();
// data['totalItemsCount'] = totalItemsCount;
// data['statusCode'] = statusCode;
// data['message'] = message;
// if (this.data != null) {
// data['data'] = this.data?.map((v) => v.toJson()).toList();
// }
// return data;
// }
// }
//
// class SurahModelData {
// int? id;
// int? surahID;
// String? nameAR;
// String? nameEN;
// int? numberOfAyahs;
// String? englishNameTranslation;
// int? revelationID;
// String? revelationType;
// int? startPageNo;
// int? endPageNo;
//
// SurahModelData({this.id, this.surahID, this.nameAR, this.nameEN, this.numberOfAyahs, this.englishNameTranslation, this.revelationID, this.revelationType, this.startPageNo, this.endPageNo});
//
// SurahModelData.fromJson(Map<String, dynamic> json) {
// id = json['id'];
// surahID = json['surahID'];
// nameAR = json['nameAR'];
// nameEN = json['nameEN'];
// numberOfAyahs = json['numberOfAyahs'];
// englishNameTranslation = json['englishNameTranslation'];
// revelationID = json['revelation_ID'];
// revelationType = json['revelationType'];
// startPageNo = json['startPageNo'];
// endPageNo = json['endPageNo'];
// }
//
// Map<String, dynamic> toJson() {
// final Map<String, dynamic> data = new Map<String, dynamic>();
// data['id'] = this.id;
// data['surahID'] = this.surahID;
// data['nameAR'] = this.nameAR;
// data['nameEN'] = this.nameEN;
// data['numberOfAyahs'] = this.numberOfAyahs;
// data['englishNameTranslation'] = this.englishNameTranslation;
// data['revelation_ID'] = this.revelationID;
// data['revelationType'] = this.revelationType;
// data['startPageNo'] = this.startPageNo;
// data['endPageNo'] = this.endPageNo;
// return data;
// }
// }

@ -6,11 +6,12 @@ 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';
import 'package:mc_common_app/models/advertisment_models/vehicle_details_models.dart';
import 'package:mc_common_app/models/generic_resp_model.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/utils/enums.dart';
abstract class AdsRepo {
@ -54,9 +55,15 @@ abstract class AdsRepo {
Future<List<AdDetailsModel>> getMyAds();
Future<AdsBankDetailsModel?> getAdBankingAccountInfo({required int adId});
Future<GenericRespModel> updateAdStatus({required int adId, required AdPostStatus adStatusToUpdate});
Future<GenericRespModel> createAppointmentForAdSpecialService({required int adId, required int photoOfficeID, required int photoOfficeSlotID, required int adsSpecialServiceID});
Future<GenericRespModel> deleteAd({required int adId});
Future<GenericRespModel> cancelMyAdReservation({required int adId});
}
class AdsRepoImp implements AdsRepo {
@ -86,8 +93,8 @@ class AdsRepoImp implements AdsRepo {
var postParams = {
"CountryID": countryId.toString(),
};
GenericRespModel adsGenericModel =
await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleCityGet, queryParameters: postParams);
GenericRespModel adsGenericModel = await apiClient.getJsonForObject(
token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleCityGet, queryParameters: countryId != -1 ? postParams : null);
List<VehicleCityModel> vehicleCities = List.generate(adsGenericModel.data.length, (index) => VehicleCityModel.fromJson(adsGenericModel.data[index]));
return vehicleCities;
}
@ -141,8 +148,12 @@ class AdsRepoImp implements AdsRepo {
var postParams = {
"VehicleType": vehicleTypeId.toString(),
};
GenericRespModel adsGenericModel =
await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleModelYearGet, queryParameters: postParams);
GenericRespModel adsGenericModel = await apiClient.getJsonForObject(
token: appState.getUser.data!.accessToken,
(json) => GenericRespModel.fromJson(json),
ApiConsts.vehicleModelYearGet,
queryParameters: vehicleTypeId != -1 ? postParams : null,
);
List<VehicleYearModel> vehicleModelYears = List.generate(adsGenericModel.data.length, (index) => VehicleYearModel.fromJson(adsGenericModel.data[index]));
return vehicleModelYears;
}
@ -152,8 +163,12 @@ class AdsRepoImp implements AdsRepo {
var postParams = {
"VehicleType": vehicleTypeId.toString(),
};
GenericRespModel adsGenericModel =
await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleModelGet, queryParameters: postParams);
GenericRespModel adsGenericModel = await apiClient.getJsonForObject(
token: appState.getUser.data!.accessToken,
(json) => GenericRespModel.fromJson(json),
ApiConsts.vehicleModelGet,
queryParameters: postParams,
);
List<VehicleModel> vehicleModels = List.generate(adsGenericModel.data.length, (index) => VehicleModel.fromJson(adsGenericModel.data[index]));
return vehicleModels;
}
@ -163,8 +178,12 @@ class AdsRepoImp implements AdsRepo {
var postParams = {
"VehicleType": vehicleTypeId.toString(),
};
GenericRespModel adsGenericModel =
await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleBrandGet, queryParameters: postParams);
GenericRespModel adsGenericModel = await apiClient.getJsonForObject(
token: appState.getUser.data!.accessToken,
(json) => GenericRespModel.fromJson(json),
ApiConsts.vehicleBrandGet,
queryParameters: vehicleTypeId != -1 ? postParams : null,
);
List<VehicleBrandsModel> vehicleBrands = List.generate(adsGenericModel.data.length, (index) => VehicleBrandsModel.fromJson(adsGenericModel.data[index]));
return vehicleBrands;
}
@ -174,8 +193,12 @@ class AdsRepoImp implements AdsRepo {
var postParams = {
"VehicleType": vehicleTypeId.toString(),
};
GenericRespModel adsGenericModel =
await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleSellerTypeGet, queryParameters: postParams);
GenericRespModel adsGenericModel = await apiClient.getJsonForObject(
token: appState.getUser.data!.accessToken,
(json) => GenericRespModel.fromJson(json),
ApiConsts.vehicleSellerTypeGet,
queryParameters: postParams,
);
List<VehicleSellerTypeModel> vehicleSellerTypes = List.generate(adsGenericModel.data.length, (index) => VehicleSellerTypeModel.fromJson(adsGenericModel.data[index]));
return vehicleSellerTypes;
}
@ -185,8 +208,12 @@ class AdsRepoImp implements AdsRepo {
var postParams = {
"VehicleType": vehicleTypeId.toString(),
};
GenericRespModel adsGenericModel =
await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleTransmissionGet, queryParameters: postParams);
GenericRespModel adsGenericModel = await apiClient.getJsonForObject(
token: appState.getUser.data!.accessToken,
(json) => GenericRespModel.fromJson(json),
ApiConsts.vehicleTransmissionGet,
queryParameters: postParams,
);
List<VehicleTransmissionModel> vehicleTransmissions = List.generate(adsGenericModel.data.length, (index) => VehicleTransmissionModel.fromJson(adsGenericModel.data[index]));
return vehicleTransmissions;
}
@ -379,6 +406,26 @@ class AdsRepoImp implements AdsRepo {
return vehicleAdsDetails;
}
@override
Future<AdsBankDetailsModel?> 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<AdsBankDetailsModel> adsBankDetails = List.generate(adsGenericModel.data.length, (index) => AdsBankDetailsModel.fromJson(adsGenericModel.data[index]));
if (adsBankDetails.isNotEmpty) {
return adsBankDetails.first;
}
return null;
}
@override
Future<GenericRespModel> updateAdStatus({required int adId, required AdPostStatus adStatusToUpdate}) async {
var postParams = {
@ -414,4 +461,49 @@ class AdsRepoImp implements AdsRepo {
return Future.value(adsGenericModel);
}
@override
Future<GenericRespModel> 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<GenericRespModel> 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);
}
}

@ -0,0 +1,162 @@
import 'dart:developer';
import 'package:mc_common_app/api/api_client.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependencies.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/general_models/m_response.dart';
import 'package:mc_common_app/models/provider_branches_models/profile/services.dart';
import 'package:mc_common_app/models/appointments_models/schedule_model.dart';
import 'package:mc_common_app/models/appointments_models/service_schedule_model.dart';
import 'package:mc_common_app/utils/enums.dart';
abstract class AppointmentRepo {
Future<Services> getAllServices(String branchId);
Future<MResponse> createSchedule(Map map);
Future<MResponse> addServicesInSchedule(Map map);
Future<MResponse> updateSchedule(Map map);
Future<List<ScheduleData>> getSchedules(String branchId);
Future<MResponse> updateServicesInSchedule(Map map);
Future<List<ServiceAppointmentScheduleModel>> mergeServiceIntoAvailableSchedules({
required List<String> serviceItemIdsForHome,
required List<String> serviceItemIdsForWorkshop,
});
Future<GenericRespModel> createServiceAppointment({required List<ServiceAppointmentScheduleModel> schedules, required int serviceProviderID});
Future<GenericRespModel> cancelOrRescheduleServiceAppointment({required int serviceAppointmentID, required int serviceSlotID, required int appointmentScheduleAction});
}
class AppointmentRepoImp implements AppointmentRepo {
@override
Future<Services> getAllServices(String branchId) async {
Map<String, dynamic> map = {"ProviderBranchID": branchId};
String t = AppState().getUser.data!.accessToken ?? "";
return await injector.get<ApiClient>().getJsonForObject((json) => Services.fromJson(json), ApiConsts.getServicesOfBranch, token: t, queryParameters: map);
}
@override
Future<MResponse> createSchedule(Map map) async {
String t = AppState().getUser.data!.accessToken ?? "";
return await injector.get<ApiClient>().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.createSchedule, map, token: t);
}
@override
Future<MResponse> addServicesInSchedule(Map map) async {
String t = AppState().getUser.data!.accessToken ?? "";
return await injector.get<ApiClient>().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.createGroup, map, token: t);
}
@override
Future<List<ScheduleData>> getSchedules(String branchId) async {
Map<String, dynamic> map = {"ServiceProviderBranchID": branchId};
String t = AppState().getUser.data!.accessToken ?? "";
GenericRespModel adsGenericModel = await injector.get<ApiClient>().getJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.getSchedule,
token: t,
queryParameters: map,
);
return List.generate(adsGenericModel.data.length, (index) => ScheduleData.fromJson(adsGenericModel.data[index]));
}
@override
Future<MResponse> updateSchedule(Map map) async {
String t = AppState().getUser.data!.accessToken ?? "";
return await injector.get<ApiClient>().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.updateSchedule, map, token: t);
}
@override
Future<MResponse> updateServicesInSchedule(Map map) async {
String t = AppState().getUser.data!.accessToken ?? "";
return await injector.get<ApiClient>().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.updateGroup, map, token: t);
}
Future<List<ServiceAppointmentScheduleModel>> mergeServiceIntoAvailableSchedules({
required List<String> serviceItemIdsForHome,
required List<String> serviceItemIdsForWorkshop,
}) async {
String t = AppState().getUser.data!.accessToken ?? "";
var queryParameters = [
{
"appointmentType": 2,
"ServiceItemIDs": serviceItemIdsForHome,
},
{
"appointmentType": 1,
"ServiceItemIDs": serviceItemIdsForWorkshop,
}
];
GenericRespModel adsGenericModel = await injector.get<ApiClient>().postJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.GetServiceItemAppointmentScheduleSlots,
queryParameters,
token: t,
);
if (adsGenericModel.data == null) {
return [];
}
List<ServiceAppointmentScheduleModel> serviceAppointmentScheduleModel =
List.generate(adsGenericModel.data.length, (index) => ServiceAppointmentScheduleModel.fromJson(adsGenericModel.data[index], isForAppointment: true));
return serviceAppointmentScheduleModel;
}
Future<GenericRespModel> createServiceAppointment({required List<ServiceAppointmentScheduleModel> schedules, required int serviceProviderID}) async {
String t = AppState().getUser.data!.accessToken ?? "";
int customerId = AppState().getUser.data!.userInfo!.customerId ?? 0;
List<Map<String, dynamic>> mapList = [];
schedules.forEach((schedule) {
List<int> serviceItemIds = [];
schedule.servicesListInAppointment!.forEach((service) {
service.serviceItems!.forEach((item) {
serviceItemIds.add(item.id!);
});
});
mapList.add({
"serviceSlotID": schedule.selectedCustomTimeDateSlotModel!.date!.slotId,
"serviceProviderID": serviceProviderID,
"customerID": customerId,
"serviceItemID": serviceItemIds,
});
});
GenericRespModel adsGenericModel = await injector.get<ApiClient>().postJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.ServiceProvidersAppointmentCreate,
mapList,
token: t,
);
return adsGenericModel;
}
@override
Future<GenericRespModel> cancelOrRescheduleServiceAppointment({required int serviceAppointmentID, required int serviceSlotID, required int appointmentScheduleAction}) async {
String t = AppState().getUser.data!.accessToken ?? "";
final payload = {
"serviceAppointmentID": serviceAppointmentID,
"serviceSlotID": serviceSlotID,
"appointmentScheduleAction": appointmentScheduleAction,
};
GenericRespModel adsGenericModel = await injector.get<ApiClient>().postJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.ServiceProviderAppointmentRescheduleCancelAppointment,
payload,
token: t,
);
return adsGenericModel;
}
}

@ -0,0 +1,32 @@
import 'dart:io';
import 'package:http/io_client.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/main.dart';
import 'package:signalr_core/signalr_core.dart';
abstract class ChatRepo {
Future<HubConnection> getHubConnection();
}
class ChatRepoImp implements ChatRepo {
@override
Future<HubConnection> getHubConnection() async {
final userId = AppState().getUser.data!.userInfo!.userId ?? "";
final hubUrl = "https://ms.hmg.com/McHub?userID=$userId";
logger.i("Connecting with Hub ($hubUrl)");
HubConnection hub;
hub = HubConnectionBuilder()
.withUrl(
hubUrl,
HttpConnectionOptions(
client: IOClient(HttpClient()
..badCertificateCallback = (x, y, z) => true),
logging: (level, message) {
print(message);
},
))
.build();
return hub;
}
}

@ -4,14 +4,14 @@ import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependencies.dart';
import 'package:mc_common_app/models/advertisment_models/ss_car_check_schedule_model.dart';
import 'package:mc_common_app/models/advertisment_models/ss_photo_schedule_model.dart';
import 'package:mc_common_app/models/advertisment_models/vehicle_details_models.dart';
import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart';
import 'package:mc_common_app/models/generic_resp_model.dart';
import 'package:mc_common_app/models/user/cities.dart';
import 'package:mc_common_app/models/user/country.dart';
import 'package:mc_common_app/models/user/role.dart';
import 'package:mc_common_app/models/general_models/enums_model.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/user_models/cities.dart';
import 'package:mc_common_app/models/user_models/country.dart';
import 'package:mc_common_app/models/user_models/role.dart';
import '../models/advertisment_models/vehicle_details_models.dart';
import '../models/enums.dart';
abstract class CommonRepo {
Future<Country> getAllCountries();
@ -27,7 +27,7 @@ abstract class CommonRepo {
Future<SSCarCheckScheduleModel> getCarCheckServiceScheduleDetails({required double lat, required double long});
Future<SSPhotoScheduleModel> getPhotographyServiceScheduleDetails({required double lat, required double long});
Future<List<SSPhotoOfficeScheduleModel>> getPhotographyServiceScheduleListByOffices({required double lat, required double long});
// Future<List<ProviderCategoryModel>> getProviderServiceCategories();
@ -38,7 +38,7 @@ abstract class CommonRepo {
//TODO: Needs to remove common methods from AD's repo and delete all repeated methods.
Future<VehicleDetailsModel> getVehicleDetails({int? vehicleTypeId, int? vehicleBrandId});
Future<List<Enums>> getEnumTypeValues({int? enumTypeID, String? enumTypeName});
Future<List<EnumsModel>> getEnumTypeValues({int? enumTypeID, String? enumTypeName});
}
class CommonRepoImp implements CommonRepo {
@ -66,7 +66,7 @@ class CommonRepoImp implements CommonRepo {
@override
Future<List<AppointmentListModel>> getMyAppointments() async {
var params = {
"userID": appState.getUser.data!.userInfo!.userId ?? "",
"customerID": appState.getUser.data!.userInfo!.customerId.toString() ?? "",
};
GenericRespModel genericRespModel = await apiClient.getJsonForObject(
token: appState.getUser.data!.accessToken,
@ -95,7 +95,7 @@ class CommonRepoImp implements CommonRepo {
}
@override
Future<SSPhotoScheduleModel> getPhotographyServiceScheduleDetails({required double lat, required double long}) async {
Future<List<SSPhotoOfficeScheduleModel>> getPhotographyServiceScheduleListByOffices({required double lat, required double long}) async {
var params = {
"Latitude": lat.toString(),
"Longitude": long.toString(),
@ -106,8 +106,11 @@ class CommonRepoImp implements CommonRepo {
queryParameters: params,
ApiConsts.adsPhotoOfficeAppointmentScheduleSlotGet,
);
SSPhotoScheduleModel ssPhotoScheduleModel = SSPhotoScheduleModel.fromJson(genericRespModel.data[0]);
return ssPhotoScheduleModel;
if (genericRespModel.data == null) {
return [];
}
List<SSPhotoOfficeScheduleModel> ssPhotoScheduleModel = List.generate(genericRespModel.data.length, (index) => SSPhotoOfficeScheduleModel.fromJson(genericRespModel.data[index]));
return ssPhotoScheduleModel ?? [];
}
@override
@ -159,7 +162,7 @@ class CommonRepoImp implements CommonRepo {
}
@override
Future<List<Enums>> getEnumTypeValues({int? enumTypeID, String? enumTypeName}) async {
Future<List<EnumsModel>> getEnumTypeValues({int? enumTypeID, String? enumTypeName}) async {
var postParams = {"enumTypeID": (enumTypeID ?? 0).toString(), "enumTypeName": enumTypeName ?? ""};
GenericRespModel enumGenericModel = await apiClient.postJsonForObject(
(json) => GenericRespModel.fromJson(json),
@ -168,7 +171,7 @@ class CommonRepoImp implements CommonRepo {
token: appState.getUser.data!.accessToken,
);
List<Enums> vehicleCities = List.generate(enumGenericModel.data.length, (index) => Enums.fromJson(enumGenericModel.data[index]));
List<EnumsModel> vehicleCities = List.generate(enumGenericModel.data.length, (index) => EnumsModel.fromJson(enumGenericModel.data[index]));
return vehicleCities;
}
//

@ -2,7 +2,7 @@ import 'package:mc_common_app/api/api_client.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependencies.dart';
import 'package:mc_common_app/models/generic_resp_model.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/payment_models/pay_order_detail_resp_model.dart';
abstract class PaymentsRepo {

@ -0,0 +1,55 @@
import 'dart:async';
import 'package:mc_common_app/api/api_client.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependencies.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/provider_branches_models/branch_detail_model.dart';
import 'package:mc_common_app/models/provider_branches_models/provider_profile_model.dart';
import 'package:mc_common_app/models/services_models/item_model.dart';
abstract class ProviderRepo {
Future<List<BranchDetailModel>> getAllNearBranchAndServices();
Future<List<ItemData>> getServiceItems(int serviceId);
Future<ProviderProfileModel> getBranchAndServices(int providerId);
}
class ProviderRepoImp implements ProviderRepo {
ApiClient apiClient = injector.get<ApiClient>();
AppState appState = injector.get<AppState>();
@override
Future<List<BranchDetailModel>> getAllNearBranchAndServices() async {
GenericRespModel adsGenericModel = await apiClient.getJsonForObject((json) => GenericRespModel.fromJson(json), ApiConsts.GetAllNearBranches, token: appState.getUser.data!.accessToken);
List<BranchDetailModel> nearBranches = List.generate(adsGenericModel.data.length, (index) => BranchDetailModel.fromJson(adsGenericModel.data[index]));
return nearBranches;
}
@override
Future<List<ItemData>> getServiceItems(int serviceId) async {
var queryParameters = {
"ServiceProviderServiceID": serviceId.toString(),
};
GenericRespModel adsGenericModel = await apiClient.getJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.getServiceItems,
token: appState.getUser.data!.accessToken,
queryParameters: queryParameters,
);
List<ItemData> serviceItems = List.generate(adsGenericModel.data.length, (index) => ItemData.fromJson(adsGenericModel.data[index]));
return serviceItems;
}
@override
Future<ProviderProfileModel> getBranchAndServices(int providerId) async {
var postParams = {"serviceProviderID": providerId.toString()};
GenericRespModel adsGenericModel =
await apiClient.getJsonForObject((json) => GenericRespModel.fromJson(json), ApiConsts.BranchesAndServices, token: appState.getUser.data!.accessToken, queryParameters: postParams);
return ProviderProfileModel.fromJson(adsGenericModel.data);
}
}

@ -2,12 +2,15 @@ import 'package:mc_common_app/api/api_client.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependencies.dart';
import 'package:mc_common_app/models/generic_resp_model.dart';
import 'package:mc_common_app/models/requests/request_model.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/requests_models/offers_model.dart';
import 'package:mc_common_app/models/requests_models/request_model.dart';
abstract class RequestRepo {
Future<GenericRespModel> createRequest(Map<String, dynamic> map);
Future<List<OffersModel>> getOffersByRequest({required int requestId, int serviceProviderId = 0});
Future<List<RequestModel>> getRequests(Map<String, dynamic> postParams);
}
@ -42,4 +45,25 @@ class RequestRepoImp implements RequestRepo {
);
return requests;
}
@override
Future<List<OffersModel>> getOffersByRequest({required int requestId, int serviceProviderId = 0}) async {
var queryParameters = {
"RequestID": requestId.toString(),
"ServiceProviderID": serviceProviderId.toString(),
};
GenericRespModel genericRespModel = await apiClient.getJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.getRequestOffers,
queryParameters: queryParameters,
token: appState.getUser.data!.accessToken,
);
List<OffersModel> offersList = List.generate(
genericRespModel.data.length,
(index) => OffersModel.fromJson(
genericRespModel.data[index],
),
);
return offersList;
}
}

@ -7,23 +7,23 @@ import 'package:mc_common_app/api/api_client.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependencies.dart';
import 'package:mc_common_app/models/m_response.dart';
import 'package:mc_common_app/models/user/basic_otp.dart';
import 'package:mc_common_app/models/user/change_email.dart';
import 'package:mc_common_app/models/user/change_mobile.dart';
import 'package:mc_common_app/models/user/cities.dart';
import 'package:mc_common_app/models/user/confirm_email.dart';
import 'package:mc_common_app/models/user/confirm_mobile.dart';
import 'package:mc_common_app/models/user/confirm_password.dart';
import 'package:mc_common_app/models/user/country.dart';
import 'package:mc_common_app/models/user/forget_password_otp_compare.dart';
import 'package:mc_common_app/models/user/image_response.dart';
import 'package:mc_common_app/models/user/login_password.dart';
import 'package:mc_common_app/models/user/refresh_token.dart';
import 'package:mc_common_app/models/user/register_user.dart';
import 'package:mc_common_app/models/user/role.dart';
import 'package:mc_common_app/models/user/user.dart';
import 'package:mc_common_app/models/user/verify_email.dart';
import 'package:mc_common_app/models/general_models/m_response.dart';
import 'package:mc_common_app/models/user_models/basic_otp.dart';
import 'package:mc_common_app/models/user_models/change_email.dart';
import 'package:mc_common_app/models/user_models/change_mobile.dart';
import 'package:mc_common_app/models/user_models/cities.dart';
import 'package:mc_common_app/models/user_models/confirm_email.dart';
import 'package:mc_common_app/models/user_models/confirm_mobile.dart';
import 'package:mc_common_app/models/user_models/confirm_password.dart';
import 'package:mc_common_app/models/user_models/country.dart';
import 'package:mc_common_app/models/user_models/forget_password_otp_compare.dart';
import 'package:mc_common_app/models/user_models/image_response.dart';
import 'package:mc_common_app/models/user_models/login_password.dart';
import 'package:mc_common_app/models/user_models/refresh_token.dart';
import 'package:mc_common_app/models/user_models/register_user.dart';
import 'package:mc_common_app/models/user_models/role.dart';
import 'package:mc_common_app/models/user_models/user.dart';
import 'package:mc_common_app/models/user_models/verify_email.dart';
import 'package:mc_common_app/utils/shared_prefrence.dart';
abstract class UserRepo {
@ -81,7 +81,7 @@ class UserRepoImp implements UserRepo {
String? t;
if (isNeedToPassToken) {
t = AppState().getUser.data!.accessToken ?? "";
debugPrint("token " + t);
debugPrint("token $t");
}
return await injector.get<ApiClient>().postJsonForObject((json) => BasicOtpRespModel.fromJson(json), ApiConsts.BasicOTP, postParams, token: t);
}
@ -96,7 +96,7 @@ class UserRepoImp implements UserRepo {
String? t;
if (isNeedToPassToken) {
t = AppState().getUser.data!.accessToken ?? "";
debugPrint("token " + t);
debugPrint("token $t");
}
return await injector.get<ApiClient>().postJsonForObject((json) => RegisterUserRespModel.fromJson(json), ApiConsts.BasicVerify, postParams, token: t);
}
@ -112,7 +112,7 @@ class UserRepoImp implements UserRepo {
String? t;
if (isNeedToPassToken) {
t = AppState().getUser.data!.accessToken ?? "";
debugPrint("token " + t);
debugPrint("token $t");
}
return await injector.get<ApiClient>().postJsonForObject((json) => RegisterUserRespModel.fromJson(json), ApiConsts.BasicComplete, postParams, token: t);
}
@ -212,7 +212,7 @@ class UserRepoImp implements UserRepo {
// return await injector.get<ApiClient>().postJsonForResponse(ApiConsts.ChangePassword, postParams);
String t = AppState().getUser.data!.accessToken ?? "";
debugPrint("token " + t);
debugPrint("token $t");
return await injector.get<ApiClient>().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.ChangePassword, postParams, token: t);
}
@ -274,7 +274,7 @@ class UserRepoImp implements UserRepo {
// return await injector.get<ApiClient>().postJsonForResponse(ApiConsts.ChangePassword, postParams);
String t = AppState().getUser.data!.accessToken ?? "";
debugPrint("token " + t);
debugPrint("token $t");
return await injector.get<ApiClient>().postJsonForObject((json) => ImageResponse.fromJson(json), ApiConsts.UpdateUserImage, postParams, token: t);
}
@ -284,7 +284,7 @@ class UserRepoImp implements UserRepo {
// return await injector.get<ApiClient>().postJsonForResponse(ApiConsts.ChangePassword, postParams);
String t = AppState().getUser.data!.accessToken ?? "";
debugPrint("token " + t);
debugPrint("token $t");
return await injector.get<ApiClient>().postJsonForObject((json) => ImageResponse.fromJson(json), ApiConsts.UpdateUserImage, postParams, token: t);
}

@ -3,14 +3,18 @@ import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/services/my_in_app_browser.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/utils.dart';
abstract class PaymentService {
Future<void> placeAdPayment({
Future<void> placePayment({
required int id,
required int paymentType,
List<int>? appointmentIds,
required PaymentTypes paymentType,
required Function() onSuccess,
required Function() onFailure,
});
@ -32,25 +36,46 @@ 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<void> placeAdPayment({
Future<void> placePayment({
required int id,
required int paymentType,
List<int>? appointmentIds,
required PaymentTypes paymentType,
required Function() onSuccess,
required Function() onFailure,
}) async {
print("PaymentUrl: ${ApiConsts.paymentWebViewUrl}?PaymentType=$paymentType&AdsID=$id");
String urlRequest = "";
int customerId = AppState().getUser.data!.userInfo!.customerId ?? 0;
switch (paymentType) {
case PaymentTypes.subscription:
urlRequest = "${ApiConsts.paymentWebViewUrl}?PaymentType=${paymentType.getIdFromPaymentTypesEnum()}&OrderProviderSubscriptionID=$id";
break;
case PaymentTypes.appointment:
String appointIds = '';
for (int i = 0; i < appointmentIds!.length; i++) {
var element = appointmentIds[i];
if (i == appointmentIds.length - 1) {
appointIds = "$appointIds$element";
} else {
appointIds = "$appointIds$element:";
}
}
urlRequest = "${ApiConsts.paymentWebViewUrl}?PaymentType=${paymentType.getIdFromPaymentTypesEnum()}&CustomerID=$customerId&AppointmentIDs=$appointIds";
break;
case PaymentTypes.adReserve:
urlRequest = "${ApiConsts.paymentWebViewUrl}?PaymentType=${paymentType.getIdFromPaymentTypesEnum()}&CustomerID=$customerId&AdsID=$id";
break;
case PaymentTypes.ads:
urlRequest = "${ApiConsts.paymentWebViewUrl}?PaymentType=${paymentType.getIdFromPaymentTypesEnum()}&CustomerID=$customerId&AdsID=$id";
break;
case PaymentTypes.extendAds:
urlRequest = "${ApiConsts.paymentWebViewUrl}?PaymentType=${paymentType.getIdFromPaymentTypesEnum()}&CustomerID=$customerId&AdsID=$id";
break;
case PaymentTypes.request:
urlRequest = "${ApiConsts.paymentWebViewUrl}?PaymentType=${paymentType.getIdFromPaymentTypesEnum()}&CustomerID=$customerId&RequestID=$id";
break;
}
log("PaymentUrl: $urlRequest");
myInAppBrowser = MyInAppBrowser(onExitCallback: () {
log("Browser Exited");
}, onLoadStartCallback: (String url) {
@ -58,7 +83,7 @@ class PaymentServiceImp implements PaymentService {
onBrowserLoadStart(onFailure: onFailure, onSuccess: onSuccess, url: url);
});
await myInAppBrowser!.openUrlRequest(
urlRequest: URLRequest(url: Uri.parse("${ApiConsts.paymentWebViewUrl}?PaymentType=$paymentType&AdsID=$id")),
urlRequest: URLRequest(url: Uri.parse(urlRequest)),
options: inAppBrowserOptions,
);
}

@ -21,6 +21,7 @@ class MyColors {
static const Color grey70Color = Color(0xff707070);
static const Color greyACColor = Color(0xffACACAC);
static const Color chipColor = Color(0xffE6E6E6);
static const Color roundedCrossBgColor = Color(0xFFA3A3A3);
static const Color greyShadowColor = Color(0xFFE8E7E7);
static const Color grey98Color = Color(0xff989898);
static const Color lightGreyEFColor = Color(0xffEFEFEF);
@ -36,6 +37,7 @@ class MyColors {
static const Color green = Color(0xffffffff);
static const Color borderColor = Color(0xffE8E8E8);
static const Color greyAddBorderColor = Color(0xffEEEEEE);
static const Color lightGreyBgColor = Color(0xffFDFDFD);
//AdStatusColors:
static const Color adActiveStatusColor = Color(0xff5FC16A);

@ -78,8 +78,8 @@ enum PaymentMethods {
enum PaymentTypes {
subscription,
appointment,
ads,
adReserve,
ads,
request,
extendAds,
}
@ -141,3 +141,40 @@ enum BranchStatusEnum {
blocked, // 5
deactivated // 6
}
enum AppointmentStatusEnum {
booked,
confirmed,
arrived,
cancelled,
rescheduled,
allAppointments,
}
enum RequestsTypeEnum {
specialCarRequest,
serviceRequest,
}
enum ChatMessageTypeEnum {
freeText,
image,
audio,
video,
file,
offer,
}
enum RequestOfferStatusEnum {
offer,
negotiate,
accepted,
rejected,
cancel,
}
enum ChatTypeEnum {
general,
ads,
requestOffer,
}

@ -223,6 +223,33 @@ class Utils {
}
}
static Color getChipColorByRequestStatus(RequestStatus requestStatus) {
switch (requestStatus) {
case RequestStatus.pending:
return MyColors.adPendingStatusColor;
case RequestStatus.submitted:
return MyColors.lightTextColor;
case RequestStatus.inProgress:
return MyColors.lightTextColor;
case RequestStatus.completed:
return MyColors.greenColor;
case RequestStatus.cancelled:
return MyColors.redColor;
case RequestStatus.paid:
return MyColors.greenColor;
case RequestStatus.expired:
return MyColors.redColor;
case RequestStatus.shipping:
return MyColors.greenColor;
}
}
static statusContainerChip({required String text, EdgeInsetsGeometry padding = const EdgeInsets.symmetric(vertical: 3, horizontal: 6), Color chipColor = MyColors.greenColor}) {
return Container(
decoration: BoxDecoration(

@ -8,14 +8,17 @@ 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';
import 'package:mc_common_app/models/advertisment_models/ss_car_check_schedule_model.dart';
import 'package:mc_common_app/models/advertisment_models/ss_photo_schedule_model.dart';
import 'package:mc_common_app/models/advertisment_models/vehicle_details_models.dart';
import 'package:mc_common_app/models/generic_resp_model.dart';
import 'package:mc_common_app/models/widgets_models.dart';
import 'package:mc_common_app/models/general_models/enums_model.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/appointments_models/service_schedule_model.dart';
import 'package:mc_common_app/models/general_models/widgets_models.dart';
import 'package:mc_common_app/repositories/ads_repo.dart';
import 'package:mc_common_app/repositories/common_repo.dart';
import 'package:mc_common_app/services/common_services.dart';
@ -54,7 +57,7 @@ class AdVM extends BaseVM {
List<AdsDurationModel> vehicleAdsDurations = [];
List<SpecialServiceModel> vehicleAdsSpecialServices = [];
SSCarCheckScheduleModel? ssCarCheckScheduleModel;
SSPhotoScheduleModel? ssPhotoScheduleModel;
SSPhotoOfficeScheduleModel? ssPhotoScheduleModel;
String demandAmountError = "";
String vehicleVinError = "";
@ -142,49 +145,52 @@ 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();
// }
notifyListeners();
}
List<EnumsModel> exploreAdsEnums = [];
List<EnumsModel> myAdsEnums = [];
List<FilterListModel> exploreAdsFilterOptions = [];
List<FilterListModel> myAdsFilterOptions = [];
populateAdsFilterList() {
populateAdsFilterList() async {
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();
exploreAdsFilterOptions = [
FilterListModel(title: "All Ads", isSelected: true, id: -1),
FilterListModel(title: "Mowater Ads", isSelected: false, id: 1),
FilterListModel(title: "Customer Ads", isSelected: false, id: 2),
FilterListModel(title: "Provider Ads", isSelected: false, id: 3),
];
myAdsFilterOptions = [
FilterListModel(title: "All Ads", isSelected: true, id: -1),
FilterListModel(title: "Active", isSelected: false, id: 6),
FilterListModel(title: "Pending For Review", isSelected: false, id: 1),
FilterListModel(title: "Pending For Payment", isSelected: false, id: 2),
FilterListModel(title: "Sold", isSelected: false, id: 8),
FilterListModel(title: "Deactivated", isSelected: false, id: 4),
FilterListModel(title: "Reserved", isSelected: false, id: 9),
FilterListModel(title: "Expired", isSelected: false, id: 7),
FilterListModel(title: "Rejected", isSelected: false, id: 3),
FilterListModel(title: "Pending For Post", isSelected: false, id: 5),
];
notifyListeners();
}
applyFilterOnExploreAds({required int index, required CreatedByRoleEnum createdByRoleFilter}) {
myAdsFilterOptions.clear();
for (int i = 0; i < myAdsEnums.length; i++) {
myAdsFilterOptions.add(FilterListModel(title: myAdsEnums[i].enumValueStr, isSelected: false, id: myAdsEnums[i].enumValue));
}
myAdsFilterOptions.insert(0, FilterListModel(title: "All Ads", isSelected: true, id: 0));
for (int i = 0; i < exploreAdsEnums.length; i++) {
exploreAdsFilterOptions.add(FilterListModel(title: "${exploreAdsEnums[i].enumValueStr} Ads", isSelected: false, id: exploreAdsEnums[i].enumValue));
}
exploreAdsFilterOptions.insert(0, FilterListModel(title: "All Ads", isSelected: true, id: 0));
notifyListeners();
}
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,14 +202,16 @@ 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;
}
myAdsFilterOptions[index].isSelected = true;
if (adPostStatusEnum.getIdFromAdPostStatusEnum() == -1) {
if (adPostStatusEnum.getIdFromAdPostStatusEnum() == 0) {
myAdsFilteredList = myAds;
notifyListeners();
return;
@ -225,18 +233,15 @@ class AdVM extends BaseVM {
}
Future<void> 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<void> 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<void> 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<void> 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<void> 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);
}
@ -417,7 +451,14 @@ class AdVM extends BaseVM {
SelectionModel vehicleBrandId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
void updateSelectionVehicleBrandId(SelectionModel id) {
void updateSelectionVehicleBrandId(SelectionModel id, {bool isForSearch = false}) {
if (isForSearch) {
VehicleBrandsModel brand = vehicleBrands.firstWhere((element) => element.id == id.selectedId);
DropValue brandValue = DropValue(brand.id ?? 0, brand.vehicleBrandDescription ?? "", "");
if (!ifAlreadyExist(list: vehicleBrandsAdSearchHistory, value: brandValue)) {
addToVehicleBrandsAdSearchHistory(value: brandValue);
}
}
vehicleBrandId = id;
getVehicleDetailsByVehicleBrandId();
@ -433,7 +474,14 @@ class AdVM extends BaseVM {
SelectionModel vehicleModelYearId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
void updateSelectionVehicleModelYearId(SelectionModel id) {
void updateSelectionVehicleModelYearId(SelectionModel id, {bool isForSearch = false}) {
if (isForSearch) {
VehicleYearModel year = vehicleModelYears.firstWhere((element) => element.id == id.selectedId);
DropValue yearValue = DropValue(year.id ?? 0, year.modelYear ?? "", "");
if (!ifAlreadyExist(list: vehicleYearAdSearchHistory, value: yearValue)) {
addToVehicleYearAdSearchHistory(value: yearValue);
}
}
vehicleModelYearId = id;
notifyListeners();
}
@ -534,7 +582,14 @@ class AdVM extends BaseVM {
SelectionModel vehicleCityId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
void updateSelectionVehicleCityId(SelectionModel id) {
void updateSelectionVehicleCityId(SelectionModel id, {bool isForSearch = false}) async {
if (isForSearch) {
VehicleCityModel city = vehicleCities.firstWhere((element) => element.id == id.selectedId);
DropValue cityValue = DropValue(city.id ?? 0, city.cityName ?? "", "");
if (!ifAlreadyExist(list: vehicleLocationAdSearchHistory, value: cityValue)) {
addToVehicleLocationAdSearchHistory(value: cityValue);
}
}
vehicleCityId = id;
notifyListeners();
}
@ -930,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);
@ -974,8 +1029,8 @@ class AdVM extends BaseVM {
}
void pickMultipleImages() async {
List<File> Images = await commonServices.pickMultipleImages();
pickedVehicleImages.addAll(Images);
List<File> images = await commonServices.pickMultipleImages();
pickedVehicleImages.addAll(images);
if (pickedVehicleImages.isNotEmpty) vehicleImageError = "";
notifyListeners();
}
@ -1033,8 +1088,8 @@ class AdVM extends BaseVM {
}
void pickMultipleDamageImages() async {
List<File> Images = await commonServices.pickMultipleImages();
pickedDamageImages.addAll(Images);
List<File> images = await commonServices.pickMultipleImages();
pickedDamageImages.addAll(images);
if (pickedDamageImages.isNotEmpty) vehicleDamageImageError = "";
notifyListeners();
}
@ -1076,6 +1131,126 @@ 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();
}
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<SSPhotoOfficeScheduleModel> photoSSSchedulesByOffices = [];
SSPhotoOfficeScheduleModel selectedPhotoSSSchedulesByOffice = SSPhotoOfficeScheduleModel();
Future<void> 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) {
if (isNeedToRebuild) setState(ViewState.idle);
Utils.showToast("Error: ${e.toString()}");
}
}
// Future<void> 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<void> 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<int> createNewAd() async {
AppState appState = injector.get<AppState>();
List<int> adsSelectedServices = [];
@ -1090,9 +1265,10 @@ class AdVM extends BaseVM {
specialServiceIDs: adsSelectedServices,
);
List<VehiclePostingImages> vehicleImages = [];
pickedVehicleImages.forEach((element) async {
for (var element in pickedVehicleImages) {
vehicleImages.add(await convertFileToVehiclePostingImages(file: element));
});
}
List<VehiclePostingDamageParts> vehicleDamageImages = [];
@ -1161,6 +1337,102 @@ class AdVM extends BaseVM {
);
return vehiclePostingDamageParts;
}
// ************ ADS SEARCH VIEW ****************
Future<void> populateDataForAdFilter() async {
if (vehicleBrands.isEmpty) {
vehicleBrands = await adsRepo.getVehicleBrands(vehicleTypeId: -1);
}
if (vehicleModelYears.isEmpty) {
vehicleModelYears = await adsRepo.getVehicleModelYears(vehicleTypeId: -1);
}
vehicleCities = await adsRepo.getVehicleCities(countryId: -1); // fetch all the cities
}
ifAlreadyExist({required List<DropValue> list, required DropValue value}) {
int index = list.indexWhere((element) {
return element.id == value.id;
});
if (index != -1) {
return true;
}
return false;
}
//BRANDS
List<DropValue> vehicleBrandsAdSearchHistory = [];
void removeVehicleBrandsAdSearchHistory({bool isClear = false, required int index}) {
if (isClear) {
vehicleBrandsAdSearchHistory.clear();
notifyListeners();
return;
}
vehicleBrandsAdSearchHistory.removeAt(index);
notifyListeners();
}
void addToVehicleBrandsAdSearchHistory({required DropValue value}) {
vehicleBrandsAdSearchHistory.add(value);
notifyListeners();
}
// LOCATION
List<DropValue> vehicleLocationAdSearchHistory = [];
void removeVehicleLocationAdSearchHistory({bool isClear = false, required int index}) {
if (isClear) {
vehicleLocationAdSearchHistory.clear();
notifyListeners();
return;
}
vehicleLocationAdSearchHistory.removeAt(index);
notifyListeners();
}
void addToVehicleLocationAdSearchHistory({required DropValue value}) {
vehicleLocationAdSearchHistory.add(value);
notifyListeners();
}
// OWNER
List<DropValue> vehicleAdOwnerSearchHistory = [];
void removeVehicleAdOwnerSearchHistory({bool isClear = false, required int index}) {
if (isClear) {
vehicleAdOwnerSearchHistory.clear();
notifyListeners();
return;
}
vehicleAdOwnerSearchHistory.removeAt(index);
notifyListeners();
}
void addToVehicleAdOwnerSearchHistory({required DropValue value}) {
vehicleAdOwnerSearchHistory.add(value);
notifyListeners();
}
// YEAR
List<DropValue> vehicleYearAdSearchHistory = [];
void removeVehicleYearAdSearchHistory({bool isClear = false, required int index}) {
if (isClear) {
vehicleYearAdSearchHistory.clear();
notifyListeners();
return;
}
vehicleYearAdSearchHistory.removeAt(index);
notifyListeners();
}
void addToVehicleYearAdSearchHistory({required DropValue value}) {
vehicleYearAdSearchHistory.add(value);
notifyListeners();
}
}
class VehicleDamageCard {

@ -0,0 +1,691 @@
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart';
import 'package:mc_common_app/models/general_models/enums_model.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/provider_branches_models/branch_detail_model.dart';
import 'package:mc_common_app/models/provider_branches_models/provider_profile_model.dart';
import 'package:mc_common_app/models/appointments_models/service_schedule_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/models/general_models/widgets_models.dart';
import 'package:mc_common_app/repositories/appointment_repo.dart';
import 'package:mc_common_app/repositories/common_repo.dart';
import 'package:mc_common_app/repositories/provider_repo.dart';
import 'package:mc_common_app/services/common_services.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/view_models/base_view_model.dart';
import 'package:mc_common_app/view_models/dashboard_view_model_customer.dart';
import 'package:mc_common_app/view_models/payment_view_model.dart';
import 'package:mc_common_app/views/appointments/book_appointment_schedules_view.dart';
import 'package:mc_common_app/views/appointments/widgets/appointment_service_pick_bottom_sheet.dart';
import 'package:mc_common_app/widgets/common_widgets/info_bottom_sheet.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';
class AppointmentsVM extends BaseVM {
final CommonRepo commonRepo;
final CommonAppServices commonServices;
final ProviderRepo providerRepo;
final AppointmentRepo scheduleRepo;
AppointmentsVM({required this.commonServices, required this.scheduleRepo, required this.providerRepo, required this.commonRepo});
bool isFetchingLists = false;
List<AppointmentListModel> myAppointments = [];
List<AppointmentListModel> myUpComingAppointments = [];
List<AppointmentListModel> myFilteredAppointments = [];
List<FilterListModel> appointmentsFilterOptions = [];
// List<ScheduleData> availableSchedules = [];
bool isFetchingServices = false;
List<DropValue> branchCategories = [];
bool isHomeTapped = false;
List<ServiceAppointmentScheduleModel> serviceAppointmentScheduleList = [];
bool ifItemAlreadySelected(int id) {
int indexFound = allSelectedItemsInAppointments.indexWhere((element) => element.id == id);
if (indexFound != -1) {
return true;
}
return false;
}
List<ItemData> allSelectedItemsInAppointments = [];
Future<void> onItemsSelectedInService() async {
if (currentServiceSelection != null) {
int index = servicesInCurrentAppointment.indexWhere((element) => element.serviceId == currentServiceSelection!.serviceId!);
if (index == -1) {
double totalPrice = 0.0;
for (var element in currentServiceSelection!.serviceItems!) {
totalPrice = totalPrice + double.parse(element.price ?? "0.0");
}
currentServiceSelection!.currentTotalServicePrice = totalPrice;
servicesInCurrentAppointment.insert(0, currentServiceSelection!);
}
resetCategorySelectionBottomSheet();
notifyListeners();
}
}
Future<void> onBookAppointmentPressed(BuildContext context) async {
Utils.showLoading(context);
bool isSuccess = false;
List<int> appointmentIdsList = [];
try {
GenericRespModel genericRespModel = await scheduleRepo.createServiceAppointment(
schedules: serviceAppointmentScheduleList,
serviceProviderID: selectedBranchModel!.serviceProviderId ?? 0,
);
if (genericRespModel.messageStatus == 2 || genericRespModel.data == null) {
Utils.hideLoading(context);
Utils.showToast("${genericRespModel.message.toString()}");
return;
}
if (genericRespModel.data != null) {
genericRespModel.data.forEach((element) {
if (element['appointmentID'] != 0) {
appointmentIdsList.add(element['appointmentID']);
isSuccess = true;
} else {
isSuccess = false;
return;
}
});
}
context.read<DashboardVmCustomer>().onNavbarTapped(1);
applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.booked);
Utils.hideLoading(context);
resetAfterBookingAppointment();
if (isSuccess) {
if (amountToPayForAppointment > 0) {
context.read<PaymentVM>().updateAppointmentIdsForPayment(ids: appointmentIdsList);
navigateWithName(context, AppRoutes.paymentMethodsView, arguments: PaymentTypes.appointment);
} else {
Utils.showToast("Your appointment has been booked successfully!");
getMyAppointments();
navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard);
}
}
} catch (e) {
Utils.showToast("${e.toString()}");
}
}
Future<void> onConfirmAppointmentPressed({required BuildContext context, required appointmentId}) async {
context.read<PaymentVM>().updateAppointmentIdsForPayment(ids: [appointmentId]);
navigateWithName(context, AppRoutes.paymentMethodsView, arguments: PaymentTypes.appointment);
}
Future<void> onCancelAppointmentPressed({required BuildContext context, required AppointmentListModel appointmentListModel}) async {
Utils.showLoading(context);
try {
GenericRespModel genericRespModel = await scheduleRepo.cancelOrRescheduleServiceAppointment(
serviceAppointmentID: appointmentListModel.id ?? 0,
serviceSlotID: appointmentListModel.serviceSlotID ?? 0,
appointmentScheduleAction: 2, // 1 for Reschedule and 2 for Cancel
);
if (genericRespModel.messageStatus == 2 || genericRespModel.data == null) {
Utils.hideLoading(context);
Utils.showToast("${genericRespModel.message.toString()}");
return;
}
if (genericRespModel.data == 1) {
context.read<DashboardVmCustomer>().onNavbarTapped(1);
applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.cancelled);
Utils.showToast("${genericRespModel.message.toString()}");
await getMyAppointments();
Utils.hideLoading(context);
getMyAppointments();
navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard);
}
} catch (e) {
Utils.showToast("${e.toString()}");
}
}
void updateIsHomeTapped(bool value) {
isHomeTapped = value;
if (currentServiceSelection != null) {
currentServiceSelection!.isHomeSelected = value;
}
notifyListeners();
}
String pickedHomeLocation = "";
void updatePickedHomeLocation(String value) {
pickedHomeLocation = value;
pickHomeLocationError = "";
if (currentServiceSelection != null) {
currentServiceSelection!.homeLocation = value;
}
notifyListeners();
}
SelectionModel branchSelectedCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
void updateProviderCategoryId(SelectionModel id) {
branchSelectedCategoryId = id;
getBranchServices(categoryId: branchSelectedCategoryId.selectedId);
notifyListeners();
}
List<FilterListModel> providersFilterOptions = [];
List<BranchDetailModel> nearbyBranches = [];
BranchDetailModel? selectedBranchModel;
List<ServiceModel> branchServices = [];
List<ServiceModel> servicesInCurrentAppointment = [];
ServiceModel? currentServiceSelection;
void updateBranchServiceId(SelectionModel id) async {
branchSelectedServiceId = id;
currentServiceSelection = branchServices.firstWhere((element) => element.serviceProviderServiceId == id.selectedId);
notifyListeners();
}
void removeServiceInCurrentAppointment(int index) {
int serviceId = servicesInCurrentAppointment.elementAt(index).serviceProviderServiceId ?? -1;
allSelectedItemsInAppointments.removeWhere((element) => element.serviceProviderServiceId == serviceId);
servicesInCurrentAppointment.removeAt(index);
notifyListeners();
}
resetCategorySelectionBottomSheet() {
selectedSubServicesCounter = 0;
branchSelectedCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
isHomeTapped = false;
branchSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
currentServiceSelection = null;
}
resetAfterBookingAppointment() {
allSelectedItemsInAppointments.clear();
// servicesInCurrentAppointment.clear();
serviceAppointmentScheduleList.clear();
}
List<EnumsModel> myAppointmentsEnum = [];
populateAppointmentsFilterList() async {
appointmentsFilterOptions.clear();
myAppointmentsEnum = await commonRepo.getEnumTypeValues(enumTypeID: 13); //TODO: 13 is to get Appointments Filter Enums
for (int i = 0; i < myAppointmentsEnum.length; i++) {
appointmentsFilterOptions.add(FilterListModel(title: myAppointmentsEnum[i].enumValueStr, isSelected: false, id: myAppointmentsEnum[i].enumValue));
}
appointmentsFilterOptions.insert(0, FilterListModel(title: "All Appointments", isSelected: true, id: 0));
notifyListeners();
}
applyFilterOnAppointmentsVM({required AppointmentStatusEnum appointmentStatusEnum}) {
if (appointmentsFilterOptions.isEmpty) return;
for (var value in appointmentsFilterOptions) {
value.isSelected = false;
}
appointmentsFilterOptions[appointmentStatusEnum.getIdFromAppointmentStatusEnum()].isSelected = true;
if (appointmentStatusEnum.getIdFromAppointmentStatusEnum() == 0) {
myFilteredAppointments = myAppointments;
notifyListeners();
return;
}
myFilteredAppointments = myAppointments.where((element) => element.appointmentStatusID! == appointmentStatusEnum.getIdFromAppointmentStatusEnum()).toList();
notifyListeners();
}
Future<void> getMyAppointments({bool isNeedToRebuild = false}) async {
if (isNeedToRebuild) setState(ViewState.busy);
myAppointments = await commonRepo.getMyAppointments();
myFilteredAppointments = myAppointments;
myUpComingAppointments = myAppointments.where((element) => element.appointmentStatusEnum == AppointmentStatusEnum.booked).toList();
setState(ViewState.idle);
// applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.allAppointments);
notifyListeners();
}
updateSelectedBranch(BranchDetailModel branchDetailModel) {
selectedBranchModel = branchDetailModel;
getBranchCategories();
notifyListeners();
}
updateSelectedAppointmentDate({required int dateIndex, required int scheduleIndex}) {
for (var element in serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList!) {
element.date!.isSelected = false;
}
serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![dateIndex].date!.isSelected = true;
serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex = dateIndex;
final date = TimeSlotModel(
date: serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![dateIndex].date!.date,
slotId: serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![dateIndex].date!.slotId,
isSelected: true,
slot: "",
);
serviceAppointmentScheduleList[scheduleIndex].selectedCustomTimeDateSlotModel = CustomTimeDateSlotModel(date: date);
notifyListeners();
}
updateSelectedAppointmentSlotByDate({required int scheduleIndex, required int slotIndex}) {
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!;
notifyListeners();
}
double amountToPayForAppointment = 0.0;
double totalAmount = 0.0;
List<ItemData> serviceItemsFromApi = [];
ProviderProfileModel? providerProfileModel;
int selectedSubServicesCounter = 0;
onItemUpdateOrSelected(int index, bool selected, int itemId) {
int serviceIndex = servicesInCurrentAppointment.indexWhere((element) => element.serviceId == currentServiceSelection!.serviceId!);
// print("servicesInCurrentAppointment: ${servicesInCurrentAppointment.length}");
// if (serviceIndex == -1) {
// return;
// }
serviceItemsFromApi[index].isUpdateOrSelected = selected;
serviceItemsFromApi[index].isHomeSelected = isHomeTapped;
if (selected) {
selectedSubServicesCounter = selectedSubServicesCounter + 1;
selectSubServicesError = "";
currentServiceSelection!.serviceItems!.add(serviceItemsFromApi[index]);
allSelectedItemsInAppointments.add(serviceItemsFromApi[index]);
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;
currentServiceSelection!.serviceItems!.removeWhere((element) => element.id == itemId);
allSelectedItemsInAppointments.removeWhere((element) => element.id == itemId);
servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice =
servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice - double.parse((serviceItemsFromApi[index].price) ?? "0.0");
servicesInCurrentAppointment[serviceIndex].serviceItems!.removeWhere((element) => element.id == itemId);
}
notifyListeners();
}
populateBranchesFilterList() {
providersFilterOptions.clear();
providersFilterOptions = [
FilterListModel(title: "All Providers", isSelected: true, id: 0),
FilterListModel(title: "Maintenance", isSelected: false, id: 1),
FilterListModel(title: "Oil Service", isSelected: false, id: 2),
FilterListModel(title: "Accessories", isSelected: false, id: 3),
FilterListModel(title: "Tire Service", isSelected: false, id: 4),
FilterListModel(title: "Dent and Paint", isSelected: false, id: 5),
];
notifyListeners();
}
applyFilterOnProviders({required int index}) {
if (providersFilterOptions.isEmpty) return;
for (var value in providersFilterOptions) {
value.isSelected = false;
}
providersFilterOptions[index].isSelected = true;
notifyListeners();
}
getAllNearBranches({bool isNeedToRebuild = false}) async {
//TODO: needs to lat,long into API
nearbyBranches.clear();
if (isNeedToRebuild) setState(ViewState.busy);
nearbyBranches = await providerRepo.getAllNearBranchAndServices();
setState(ViewState.idle);
}
Future<List<ItemData>> getServiceItems(int serviceId) async {
serviceItemsFromApi.clear();
serviceItemsFromApi = await providerRepo.getServiceItems(serviceId);
for (var item in serviceItemsFromApi) {
if (ifItemAlreadySelected(item.id!)) {
item.isUpdateOrSelected = true;
}
}
setState(ViewState.idle);
return serviceItemsFromApi;
}
getBranchAndServices(int providerId) async {
providerProfileModel = null;
providerProfileModel = await providerRepo.getBranchAndServices(providerId);
setState(ViewState.idle);
}
String pickHomeLocationError = "";
String selectSubServicesError = "";
SelectionModel branchSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
bool isCategoryAlreadyPresent(int id) {
final contain = branchCategories.where((element) => element.id == id);
if (contain.isEmpty) {
return false;
}
return true;
}
void getBranchCategories() async {
for (var value in selectedBranchModel!.branchServices!) {
if (!isCategoryAlreadyPresent(value.categoryId!)) {
branchCategories.add(DropValue(value.categoryId!, value.categoryName!, ""));
}
}
notifyListeners();
}
getBranchServices({required int categoryId}) async {
branchSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
isHomeTapped = false;
pickedHomeLocation = "";
pickHomeLocationError = "";
if (categoryId != -1) {
isFetchingServices = true;
branchServices = getFilteredBranchServices(categoryId: categoryId);
isFetchingServices = false;
notifyListeners();
}
}
List<ServiceModel> getFilteredBranchServices({required int categoryId}) {
List<ServiceModel> filteredServices = selectedBranchModel!.branchServices!.where((element) => element.categoryId == categoryId).toList();
return filteredServices;
}
void updatePickHomeLocationError(String value) {
pickHomeLocationError = value;
// notifyListeners();
}
bool isServiceSelectionValidated() {
if (branchSelectedServiceId.selectedId == -1) {
return false;
}
if (isHomeTapped) {
if (pickedHomeLocation == "") {
updatePickHomeLocationError(GlobalConsts.homeLocationEmptyError);
return false;
}
}
return true;
}
bool validateItemsSelection() {
for (var value in serviceItemsFromApi) {
if (value.isUpdateOrSelected!) {
return true;
}
}
selectSubServicesError = "Please select at least one sub service";
notifyListeners();
return false;
}
String getTotalPrice(List<ServiceModel> serviceItems) {
var totalPrice = 0.0;
for (var element in serviceItems) {
totalPrice = totalPrice + (element.currentTotalServicePrice);
}
return totalPrice.toString();
}
void openTheAddServiceBottomSheet(BuildContext context, AppointmentsVM appointmentsVM) {
showModalBottomSheet(
context: context,
isScrollControlled: true,
enableDrag: true,
builder: (BuildContext context) {
return AppointmentServicePickBottomSheet();
},
);
}
void priceBreakDownClicked(BuildContext context, ServiceModel selectedService) {
showModalBottomSheet(
context: context,
isScrollControlled: true,
enableDrag: true,
builder: (BuildContext context) {
double totalKms = 15.3;
return InfoBottomSheet(
title: "Charges Breakdown".toText(fontSize: 24, isBold: true),
description: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Services".toText(fontSize: 16, isBold: true),
Column(
children: List.generate(
selectedService.serviceItems!.length,
(index) => Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"${selectedService.serviceItems![index].name}".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
"${selectedService.serviceItems![index].price} SAR".toText(fontSize: 12, isBold: true),
],
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
"${selectedService.currentTotalServicePrice} SAR".toText(fontSize: 16, isBold: true),
],
),
if (selectedService.isHomeSelected) ...[
20.height,
"Home Location".toText(fontSize: 16, isBold: true),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"${totalKms}km ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
"${selectedService.rangePricePerKm} x $totalKms".toText(fontSize: 12, isBold: true),
],
),
8.height,
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
"${selectedService.rangePricePerKm ?? 0 * totalKms} SAR".toText(fontSize: 16, isBold: true),
],
),
],
30.height,
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"Total Amount ".toText(fontSize: 16, isBold: true),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
(selectedService.isHomeSelected
? "${(selectedService.currentTotalServicePrice) + (double.parse((selectedService.rangePricePerKm ?? "0.0")) * totalKms)}"
: "${selectedService.currentTotalServicePrice}")
.toText(fontSize: 29, isBold: true),
2.width,
"SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5),
],
)
],
),
30.height,
],
));
});
}
void onReviewButtonPressed(BuildContext context) {
bool isValidated = false;
for (int i = 0; i < serviceAppointmentScheduleList.length; i++) {
final schedule = serviceAppointmentScheduleList[i];
if (schedule.selectedCustomTimeDateSlotModel == null) {
isValidated = false;
break;
}
if (schedule.selectedCustomTimeDateSlotModel!.date == null || !schedule.selectedCustomTimeDateSlotModel!.date!.isSelected) {
isValidated = false;
break;
} else {
if (schedule.selectedCustomTimeDateSlotModel!.availableSlots == null) {
isValidated = false;
break;
} else {
TimeSlotModel slot = schedule.selectedCustomTimeDateSlotModel!.availableSlots!.firstWhere((element) => element.isSelected);
if (slot.date.isNotEmpty) {
isValidated = true;
break;
}
}
}
}
if (!isValidated) {
Utils.showToast("You must select appointment time for each schedule's appointment.");
return;
}
navigateWithName(context, AppRoutes.reviewAppointmentView);
}
void onServicesNextPressed(BuildContext context) async {
Utils.showLoading(context);
List<String> serviceItemIdsForHome = [];
List<String> serviceItemIdsForWorkshop = [];
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,
serviceItemIdsForWorkshop: serviceItemIdsForWorkshop,
);
if (serviceAppointmentScheduleList.isEmpty) {
Utils.hideLoading(context);
Utils.showToast("There are no available appointments for selected Items.");
return;
}
totalAmount = 0.0;
amountToPayForAppointment = 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
notifyListeners();
}
Future<void> onRescheduleAppointmentPressed({required BuildContext context, required AppointmentListModel appointmentListModel}) async {
Utils.showLoading(context);
List<String> serviceItemIdsForHome = [];
List<String> serviceItemIdsForWorkshop = [];
for (var service in appointmentListModel.appointmentServicesList!) {
for (var serviceItem in service.serviceItems!) {
serviceItemIdsForWorkshop.add(serviceItem.id!.toString());
// if (serviceItem.isHomeSelected ?? false) {
// serviceItemIdsForHome.add(serviceItem.id!.toString());
// } else {
// serviceItemIdsForWorkshop.add(serviceItem.id!.toString());
// }
}
}
serviceAppointmentScheduleList = await scheduleRepo.mergeServiceIntoAvailableSchedules(
serviceItemIdsForHome: serviceItemIdsForHome,
serviceItemIdsForWorkshop: serviceItemIdsForWorkshop,
);
if (serviceAppointmentScheduleList.isEmpty) {
Utils.hideLoading(context);
Utils.showToast("There are no available appointments for selected Items.");
return;
}
Utils.hideLoading(context);
navigateWithName(
context,
AppRoutes.bookAppointmenSchedulesView,
arguments: ScreenArgumentsForAppointmentDetailPage(routeFlag: 2, appointmentId: appointmentListModel.id ?? 0),
); // 2 For Rescheduling an Appointment
notifyListeners();
}
Future<void> onRescheduleAppointmentConfirmPressed({required BuildContext context, required int appointmentId, required int selectedSlotId}) async {
Utils.showLoading(context);
try {
GenericRespModel genericRespModel = await scheduleRepo.cancelOrRescheduleServiceAppointment(
serviceAppointmentID: appointmentId,
serviceSlotID: selectedSlotId,
appointmentScheduleAction: 1, // 1 for Reschedule and 2 for Cancel
);
if (genericRespModel.messageStatus == 2 || genericRespModel.data == null) {
Utils.hideLoading(context);
Utils.showToast("${genericRespModel.message.toString()}");
return;
}
if (genericRespModel.data == 1) {
context.read<DashboardVmCustomer>().onNavbarTapped(1);
applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.cancelled);
Utils.showToast("${genericRespModel.message.toString()}");
getMyAppointments();
Utils.hideLoading(context);
navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard);
}
} catch (e) {
Utils.showToast("${e.toString()}");
}
}
}

@ -0,0 +1,141 @@
import 'package:flutter/cupertino.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/main.dart';
import 'package:mc_common_app/models/chat_models/cat_message_model.dart';
import 'package:mc_common_app/repositories/chat_repo.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/utils.dart';
import 'package:signalr_core/signalr_core.dart';
class ChatVM extends ChangeNotifier {
final ChatRepo chatRepo;
ChatVM({required this.chatRepo});
late HubConnection hubConnection;
List<ChatMessageModel> chatMessages = [];
String chatMessageText = "";
updateChatMessageText(String value) {
chatMessageText = value;
}
clearChatMessageText() {
chatMessageText = "";
notifyListeners();
}
Future<void> onNewMessageReceived({required List<ChatMessageModel> messages}) async {
chatMessages.addAll(messages);
notifyListeners();
}
Future<void> buildHubConnection() async {
// if (hubConnection.state != HubConnectionState.Connected) {
try {
hubConnection = await chatRepo.getHubConnection();
await hubConnection.start();
hubConnection.on("ReceiveMessageRequestOffer", (List<Object?>? arguments) {
if (arguments == null || arguments.isEmpty) return;
List<ChatMessageModel> chat = [];
for (var message in arguments) {
final chatMessage = ChatMessageModel.fromJson(message as Map<String, dynamic>);
chat.add(chatMessage);
}
onNewMessageReceived(messages: chat);
logger.i("I received ping : ${arguments.toString()}");
});
} catch (e) {
logger.i("Error: ${e.toString()}");
}
notifyListeners();
// }
}
Future<bool> onSendMessageForRequestOffer({
required String receiverId,
required ChatMessageTypeEnum chatMessageType,
required String message,
required int requestId,
required String offerPrice,
}) async {
if (hubConnection.state != HubConnectionState.connected) {
await buildHubConnection();
}
if (hubConnection.state == HubConnectionState.connected) {
final providerId = AppState().getUser.data!.userInfo!.providerId;
hubConnection.invoke(
"SendMessageRequestOffer",
args: <Object>[
<String, dynamic>{
"ReceiverUserID": receiverId,
"MessageType": chatMessageType.getIdFromChatMessageTypeEnum(),
"Message": message,
"RequestID": requestId,
"RequestOfferID": 0,
"RequestOffer": <String, dynamic>{
"RequestID": requestId,
"Price": double.parse(offerPrice),
"ServiceProviderID": providerId,
"OfferStatus": RequestOfferStatusEnum.offer.getIdFromRequestOfferStatusEnum(),
"Comment": message,
},
}
],
).catchError((e) {
logger.i("error in invoking SendMessageRequestOffer: ${e.toString()}");
Utils.showToast(e.toString());
return false;
});
}
return true;
}
Future<bool> onTextMessageSend({
required String receiverId,
required ChatMessageTypeEnum chatMessageType,
required String message,
required int requestId,
required String offerPrice,
}) async {
if (message.isEmpty) return false;
if (hubConnection.state != HubConnectionState.connected) {
await buildHubConnection();
}
if (hubConnection.state == HubConnectionState.connected) {
final userId = AppState().getUser.data!.userInfo!.userId.toString();
final name = AppState().getUser.data!.userInfo!.firstName.toString();
hubConnection.invoke(
"SendMessageRequestOffer",
args: <Object>[
<String, dynamic>{
"ReceiverUserID": receiverId,
"MessageType": chatMessageType.getIdFromChatMessageTypeEnum(),
"Message": message,
"RequestID": requestId,
}
],
).catchError((e) {
logger.i("error in invoking SendMessageRequestOffer: ${e.toString()}");
Utils.showToast(e.toString());
return false;
});
ChatMessageModel chatMessageModel = ChatMessageModel(
messageType: chatMessageType.getIdFromChatMessageTypeEnum(),
message: message,
isMyMessage: true,
requestID: requestId,
senderName: name,
senderUserID: userId,
);
onNewMessageReceived(messages: [chatMessageModel]);
}
return true;
}
}

@ -0,0 +1,55 @@
import 'dart:io';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/user_models/image_response.dart';
import 'package:mc_common_app/repositories/user_repo.dart';
import 'package:mc_common_app/services/common_services.dart';
import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/view_models/base_view_model.dart';
import 'package:flutter/cupertino.dart';
import 'package:easy_localization/easy_localization.dart';
class DashboardVmCustomer extends BaseVM {
final CommonAppServices commonServices;
final UserRepo userRepo;
DashboardVmCustomer({required this.commonServices, required this.userRepo});
String pickedImage = "";
int selectedNavbarBarIndex = 2;
void onNavbarTapped(int index) {
selectedNavbarBarIndex = index;
notifyListeners();
}
void pickImageFromPhone(BuildContext context, int sourceFlag) async {
final File? pickedImageFile = await commonServices.pickImageFromPhone(sourceFlag);
if (pickedImageFile == null) {
return;
}
int sizeInBytes = pickedImageFile.lengthSync();
if (sizeInBytes > 1000) {
Utils.showToast(LocaleKeys.fileLarger.tr());
return;
} else {
String image64 = Utils.convertFileToBase64(pickedImageFile);
Utils.showLoading(context);
ImageResponse response = await userRepo.updateUserImage(image64);
Utils.hideLoading(context);
Navigator.pop(context);
if (response.messageStatus == 1) {
Utils.showToast(LocaleKeys.imageUploaded.tr());
AppState().getUser.data!.userInfo!.userImageUrl = response.data;
} else {
Utils.showToast(response.message ?? "");
}
}
}
Future<ImageResponse> updateUserImage(String image) async {
return await userRepo.updateUserImage(image);
}
}

@ -1,5 +1,8 @@
import 'dart:developer';
import 'package:flutter/cupertino.dart';
import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/payment_models/pay_order_detail_resp_model.dart';
import 'package:mc_common_app/repositories/payments_repo.dart';
import 'package:mc_common_app/services/payments_service.dart';
@ -22,6 +25,24 @@ class PaymentVM extends ChangeNotifier {
currentAdId = id;
}
int requestId = -1;
void updateRequestId({required int id}) {
requestId = id;
}
int orderProviderSubscriptionId = -1;
void updateOrderProviderSubscriptionId({required int id}) {
orderProviderSubscriptionId = id;
}
List<int> appointmentIdsForPayment = [];
void updateAppointmentIdsForPayment({required List<int> ids}) {
appointmentIdsForPayment = ids;
}
updateSelectedPaymentMethod(PaymentMethods selectedMethod) {
selectedPaymentMethod = selectedMethod;
notifyListeners();
@ -49,29 +70,104 @@ class PaymentVM extends ChangeNotifier {
return;
}
Future<void> placeThePayment({required int adId, required int paymentTypeId, required BuildContext context}) async {
await paymentService.placeAdPayment(
id: currentAdId,
paymentType: paymentTypeId,
Future<void> onAdsPaymentSuccess({required BuildContext context, required int currentAdId, required int paymentTypeId}) async {
Utils.showLoading(context);
PayOrderDetailRespModel payOrderDetailRespModel = await paymentRepo.getPayOrderDetails(paymentId: paymentTypeId, adId: currentAdId);
await Future.delayed(const Duration(seconds: 2));
Utils.hideLoading(context);
print("payOrderDetailRespModel: ${payOrderDetailRespModel.toString()}");
if (payOrderDetailRespModel.isPaid == null || !payOrderDetailRespModel.isPaid!) {
Utils.showToast("Payment Failed!");
return;
}
if (payOrderDetailRespModel.isPaid != null && payOrderDetailRespModel.isPaid!) {
Utils.showToast("Payment Successful");
navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard);
}
}
Future<void> onAppointmentPaymentSuccess({required BuildContext context, required int currentAdId, required int paymentTypeId}) async {
Utils.showLoading(context);
//TODO: CONFIRM FROM ZAHOOR THAT WILL THIS METHOD WORK FOR APPOINTMENT
PayOrderDetailRespModel payOrderDetailRespModel = await paymentRepo.getPayOrderDetails(paymentId: paymentTypeId, adId: currentAdId);
await Future.delayed(const Duration(seconds: 2));
Utils.hideLoading(context);
print("payOrderDetailRespModel: ${payOrderDetailRespModel.toString()}");
if (payOrderDetailRespModel.isPaid == null || !payOrderDetailRespModel.isPaid!) {
Utils.showToast("Payment Failed!");
return;
}
if (payOrderDetailRespModel.isPaid != null && payOrderDetailRespModel.isPaid!) {
Utils.showToast("Payment Successful");
navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard);
}
}
int getIdTypeByPaymentType(PaymentTypes paymentTypes) {
switch (paymentTypes) {
case PaymentTypes.subscription:
return orderProviderSubscriptionId;
case PaymentTypes.appointment:
return -1;
case PaymentTypes.request:
return requestId;
case PaymentTypes.adReserve:
case PaymentTypes.ads:
case PaymentTypes.extendAds:
return currentAdId;
}
}
Future<void> placeThePayment({required PaymentTypes paymentTypeEnum, required BuildContext context}) async {
await paymentService.placePayment(
// This will be request ID for request payment || ad ID for Ad Related Payment || OrderProviderSubscriptionID for SubscriptionPayment
id: getIdTypeByPaymentType(paymentTypeEnum),
appointmentIds: appointmentIdsForPayment,
paymentType: paymentTypeEnum,
onFailure: () {
Utils.showToast("Payment Failed!");
switch (paymentTypeEnum) {
case PaymentTypes.subscription:
// TODO: Handle this case.
break;
case PaymentTypes.appointment:
// TODO: Handle this case.
log("Appointment Payment has been Failed!!");
break;
case PaymentTypes.adReserve:
// TODO: Handle this case.
break;
case PaymentTypes.ads:
// TODO: Handle this case.
break;
case PaymentTypes.request:
// TODO: Handle this case.
break;
case PaymentTypes.extendAds:
// TODO: Handle this case.
break;
}
},
onSuccess: () async {
Utils.showLoading(context);
PayOrderDetailRespModel payOrderDetailRespModel = await paymentRepo.getPayOrderDetails(paymentId: paymentTypeId, adId: currentAdId);
await Future.delayed(const Duration(seconds: 2));
Utils.hideLoading(context);
print("payOrderDetailRespModel: ${payOrderDetailRespModel.toString()}");
if (payOrderDetailRespModel.isPaid == null || !payOrderDetailRespModel.isPaid!) {
Utils.showToast("Payment Failed!");
return;
}
if (payOrderDetailRespModel.isPaid != null && payOrderDetailRespModel.isPaid!) {
Utils.showToast("Payment Successful");
navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard);
switch (paymentTypeEnum) {
case PaymentTypes.subscription:
break;
case PaymentTypes.appointment:
log("Appointment Payment has been Succeeded");
break;
case PaymentTypes.request:
break;
case PaymentTypes.adReserve:
case PaymentTypes.ads:
case PaymentTypes.extendAds:
await onAdsPaymentSuccess(context: context, paymentTypeId: paymentTypeEnum.getIdFromPaymentTypesEnum(), currentAdId: currentAdId);
break;
}
},
);
@ -80,34 +176,21 @@ class PaymentVM extends ChangeNotifier {
Future<void> onVisaCardSelected(BuildContext context, PaymentTypes paymentType) async {
currentPaymentType = paymentType;
switch (currentPaymentType) {
case PaymentTypes.ads:
if (currentAdId == -1) return;
int paymentType = 3;
await placeThePayment(adId: currentAdId, context: context, paymentTypeId: paymentType);
break;
case PaymentTypes.adReserve:
if (currentAdId == -1) return;
int paymentType = 4;
await placeThePayment(adId: currentAdId, context: context, paymentTypeId: paymentType);
break;
case PaymentTypes.extendAds:
if (currentAdId == -1) return;
int paymentType = 6;
await placeThePayment(adId: currentAdId, context: context, paymentTypeId: paymentType);
case PaymentTypes.appointment:
if (appointmentIdsForPayment.isEmpty) return;
await placeThePayment(context: context, paymentTypeEnum: paymentType);
break;
case PaymentTypes.request:
// TODO: Handle this case.
break;
case PaymentTypes.subscription:
// TODO: Handle this case.
break;
case PaymentTypes.appointment:
// TODO: Handle this case.
case PaymentTypes.ads:
case PaymentTypes.adReserve:
case PaymentTypes.extendAds:
if (currentAdId == -1) return;
await placeThePayment(context: context, paymentTypeEnum: paymentType);
break;
}
}

@ -1,17 +1,29 @@
import 'dart:io';
// ignore_for_file: use_build_context_synchronously, avoid_function_literals_in_foreach_calls
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.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/vehicle_details_models.dart';
import 'package:mc_common_app/models/enums.dart';
import 'package:mc_common_app/models/generic_resp_model.dart';
import 'package:mc_common_app/models/requests/request_model.dart';
import 'package:mc_common_app/models/widgets_models.dart';
import 'package:mc_common_app/models/chat_models/cat_message_model.dart';
import 'package:mc_common_app/models/general_models/enums_model.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/requests_models/offers_model.dart';
import 'package:mc_common_app/models/requests_models/request_model.dart';
import 'package:mc_common_app/models/general_models/widgets_models.dart';
import 'package:mc_common_app/repositories/common_repo.dart';
import 'package:mc_common_app/repositories/request_repo.dart';
import 'package:mc_common_app/services/common_services.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/view_models/base_view_model.dart';
import '../repositories/request_repo.dart';
import 'package:mc_common_app/view_models/chat_view_model.dart';
import 'package:provider/provider.dart';
class RequestsVM extends BaseVM {
final CommonAppServices commonServices;
@ -20,23 +32,69 @@ class RequestsVM extends BaseVM {
RequestsVM({required this.commonServices, required this.commonRepo, required this.requestRepo});
List<FilterListModel> requestsFilterOptions = [];
List<RequestModel> myRequests = [];
List<RequestModel> myFilteredRequests = [];
List<FilterListModel> requestsTypeFilterOptions = [];
List<EnumsModel> myRequestsTypeEnum = [];
populateRequestsFilterList() async {
requestsTypeFilterOptions.clear();
if (myRequestsTypeEnum.isEmpty) {
myRequestsTypeEnum = await commonRepo.getEnumTypeValues(enumTypeID: 16); //TODO: 16 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));
}
log("requestsTypeFilterOptions: ${requestsTypeFilterOptions.toString()}");
populateRequestsFilterList() {
requestsFilterOptions.clear();
requestsFilterOptions = [
FilterListModel(title: "Cars", isSelected: true, id: 1),
FilterListModel(title: "Spare Parts", isSelected: false, id: 2),
];
notifyListeners();
}
applyFilterOnRequestsVM({required int index}) {
if (requestsFilterOptions.isEmpty) return;
for (var value in requestsFilterOptions) {
Future<void> getRequests({bool isNeedToRebuild = false, required AppType appType}) async {
if (isNeedToRebuild) setState(ViewState.busy);
var paramsForGetRequests = <String, dynamic>{};
paramsForGetRequests = {
"pageSize": 100,
"pageIndex": 0,
"requestType": 0,
};
if (appType == AppType.provider) {
paramsForGetRequests.addEntries([MapEntry("providerID", AppState().getUser.data!.userInfo!.providerId)]);
// paramsForGetRequests = {
// "providerID": AppState().getUser.data!.userInfo!.providerId,
// "pageSize": 100,
// "pageIndex": 0,
// "requestType": 0,
// };
} else {
paramsForGetRequests.addEntries([MapEntry("customerID", AppState().getUser.data!.userInfo!.customerId)]);
// paramsForGetRequests = {
// "customerID": AppState().getUser.data!.userInfo!.customerId,
// "pageSize": 100,
// "pageIndex": 0,
// "requestType": 0,
// };
}
myRequests = await requestRepo.getRequests(paramsForGetRequests);
applyFilterOnRequestsVM(requestsTypeEnum: RequestsTypeEnum.specialCarRequest);
setState(ViewState.idle);
notifyListeners();
}
applyFilterOnRequestsVM({required RequestsTypeEnum requestsTypeEnum}) {
if (requestsTypeFilterOptions.isEmpty) return;
for (var value in requestsTypeFilterOptions) {
value.isSelected = false;
}
requestsFilterOptions[index].isSelected = true;
requestsTypeFilterOptions[requestsTypeEnum.getIdFromRequestTypeStatusEnum() - 1].isSelected = true; // -1 to match with the index
myFilteredRequests = myRequests.where((element) => element.requestType == requestsTypeEnum.getIdFromRequestTypeStatusEnum()).toList();
notifyListeners();
}
@ -53,8 +111,8 @@ class RequestsVM extends BaseVM {
}
void pickMultipleImages() async {
List<File> Images = await commonServices.pickMultipleImages();
pickedVehicleImages.addAll(Images);
List<File> images = await commonServices.pickMultipleImages();
pickedVehicleImages.addAll(images);
if (pickedVehicleImages.isNotEmpty) vehicleImageError = "";
notifyListeners();
}
@ -62,7 +120,6 @@ class RequestsVM extends BaseVM {
bool isFetchingRequestType = false;
bool isFetchingVehicleType = true;
bool isFetchingVehicleDetail = false;
List<Enums> requestTypes = [];
List<VehicleTypeModel> vehicleTypes = [];
VehicleDetailsModel? vehicleDetails;
List<VehicleBrandsModel> vehicleBrands = [];
@ -73,14 +130,6 @@ class RequestsVM extends BaseVM {
SelectionModel requestTypeId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
getRequestTypes() async {
requestTypeId.selectedId = -1;
isFetchingRequestType = true;
requestTypes = await commonRepo.getEnumTypeValues(enumTypeID: 16); //TODO: 16 is to get Request types
isFetchingRequestType = false;
notifyListeners();
}
void updateSelectionRequestTypeId(SelectionModel id) async {
requestTypeId = id;
getVehicleTypes();
@ -90,14 +139,14 @@ class RequestsVM extends BaseVM {
SelectionModel vehicleTypeId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
Future<void> getVehicleTypes() async {
reset();
resetRequestCreationForm();
isFetchingVehicleType = true;
vehicleTypes = await commonRepo.getVehicleTypes();
isFetchingVehicleType = false;
notifyListeners();
}
reset() {
resetRequestCreationForm() {
vehicleTypeId.selectedId = -1;
vehicleBrandId.selectedId = -1;
vehicleModelId.selectedId = -1;
@ -191,9 +240,27 @@ class RequestsVM extends BaseVM {
description = v;
}
Future<GenericRespModel?> createRequest() async {
if (validate()) {
Map<String, dynamic> m = {
Future<VehiclePostingImages> convertFileToRequestPostingImages({required File file}) async {
List<int> imageBytes = await file.readAsBytes();
String image = base64Encode(imageBytes);
String fileName = file.path.split('/').last;
VehiclePostingImages vehiclePostingImages = VehiclePostingImages(
imageName: fileName,
imageStr: image,
imageUrl: file.path,
);
return vehiclePostingImages;
}
Future<void> onCreateRequestTapped(BuildContext context) async {
if (validateCreateRequestForm()) {
Utils.showLoading(context);
List<VehiclePostingImages> vehicleImages = [];
pickedVehicleImages.forEach((element) async {
vehicleImages.add(await convertFileToRequestPostingImages(file: element));
});
Map<String, dynamic> body = {
"customerID": AppState().getUser.data!.userInfo!.customerId ?? 0,
"requestType": requestTypeId.selectedId,
"vehicleTypeID": vehicleTypeId.selectedId,
@ -206,16 +273,26 @@ class RequestsVM extends BaseVM {
"price": price,
"description": description,
"isSpecialServiceNeeded": false,
"requestImages": []
"requestImages": vehicleImages,
};
GenericRespModel respModel = await requestRepo.createRequest(m);
return respModel;
} else {
return null;
try {
GenericRespModel respModel = await requestRepo.createRequest(body);
Utils.hideLoading(context);
if (respModel.messageStatus == 1) {
Utils.showToast("Request Successfully Created");
Navigator.pop(context);
await getRequests(appType: AppType.customer);
} else {
Utils.showToast(respModel.message.toString());
}
} catch (e, s) {
Utils.hideLoading(context);
log(s.toString());
}
}
}
bool validate() {
bool validateCreateRequestForm() {
bool isValid = true;
if (requestTypeId.selectedId == -1) {
Utils.showToast("Please select valid Request Type");
@ -248,25 +325,109 @@ class RequestsVM extends BaseVM {
return isValid;
}
bool isRequestLoading = true;
List<RequestModel> requests = [];
Future<List<OffersModel>> getOffersByRequest({required int requestId, required BuildContext context}) async {
try {
Utils.showLoading(context);
List<OffersModel> respModel = await requestRepo.getOffersByRequest(requestId: requestId);
Utils.hideLoading(context);
return respModel;
} catch (e) {
Utils.showToast(e.toString());
Utils.hideLoading(context);
return [];
}
}
String offerPriceError = "";
String offerDescriptionError = "";
String offerPrice = "";
void updateOfferPrice(String value) {
offerPrice = value;
if (value.isNotEmpty) {
offerPriceError = "";
}
}
String offerDescription = "";
getRequests() async {
isRequestLoading = true;
void updateOfferDescription(String value) {
offerDescription = value;
if (value.isNotEmpty) {
offerDescriptionError = "";
}
}
//SENDING OFFER
bool isSendOfferValidated() {
bool isValidated = true;
if (offerPrice.isEmpty) {
offerPriceError = GlobalConsts.demandAmountError;
isValidated = false;
notifyListeners();
} else {
offerPriceError = "";
}
if (offerDescription.isEmpty) {
offerDescriptionError = GlobalConsts.descriptionError;
isValidated = false;
notifyListeners();
} else {
offerDescriptionError = "";
}
notifyListeners();
int selectedRequestType;
// Find the FilterListModel with isSelected equal to true
return isValidated;
}
requests = await requestRepo.getRequests(
{
"customerID": AppState().getUser.data!.userInfo!.customerId,
"pageSize": 100,
"pageIndex": 0,
"requestType": requestsFilterOptions.firstWhere((element) => element.isSelected).id,
},
);
isRequestLoading = false;
void resetSendOfferBottomSheet() {
offerPrice = "";
offerDescription = "";
offerDescriptionError = "";
offerDescription = "";
notifyListeners();
}
Future<void> onSendOfferPressed({
required BuildContext context,
required String receiverId,
required String message,
required int requestId,
required String offerPrice,
required RequestModel requestModel,
}) async {
if (isSendOfferValidated()) {
bool status = await context.read<ChatVM>().onSendMessageForRequestOffer(
receiverId: receiverId,
chatMessageType: ChatMessageTypeEnum.offer,
message: message,
requestId: requestId,
offerPrice: offerPrice,
);
if (status) {
final senderName = AppState().getUser.data!.userInfo!.firstName;
final senderId = AppState().getUser.data!.userInfo!.userId;
// resetSendOfferBottomSheet();
Navigator.pop(context);
ChatMessageModel chatMessageModel = ChatMessageModel(
isMyMessage: true,
message: message,
messageType: ChatMessageTypeEnum.freeText.getIdFromChatMessageTypeEnum(),
senderName: senderName,
senderUserID: senderId,
);
context.read<ChatVM>().onNewMessageReceived(messages: [chatMessageModel]);
ChatViewArguments chatViewArguments = ChatViewArguments(
chatTypeEnum: ChatTypeEnum.requestOffer,
requestModel: requestModel,
receiverId: requestModel.customerID,
senderId: senderId ?? "",
);
navigateWithName(context, AppRoutes.chatView, arguments: chatViewArguments);
}
}
}
}

@ -8,20 +8,20 @@ import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/m_response.dart';
import 'package:mc_common_app/models/user/basic_otp.dart';
import 'package:mc_common_app/models/user/change_email.dart';
import 'package:mc_common_app/models/user/change_mobile.dart';
import 'package:mc_common_app/models/user/confirm_email.dart';
import 'package:mc_common_app/models/user/confirm_mobile.dart';
import 'package:mc_common_app/models/user/confirm_password.dart';
import 'package:mc_common_app/models/user/country.dart';
import 'package:mc_common_app/models/user/forget_password_otp_compare.dart';
import 'package:mc_common_app/models/user/forget_password_otp_request.dart';
import 'package:mc_common_app/models/user/login_password.dart';
import 'package:mc_common_app/models/user/register_user.dart';
import 'package:mc_common_app/models/user/user.dart';
import 'package:mc_common_app/models/user/verify_email.dart';
import 'package:mc_common_app/models/general_models/m_response.dart';
import 'package:mc_common_app/models/user_models/basic_otp.dart';
import 'package:mc_common_app/models/user_models/change_email.dart';
import 'package:mc_common_app/models/user_models/change_mobile.dart';
import 'package:mc_common_app/models/user_models/confirm_email.dart';
import 'package:mc_common_app/models/user_models/confirm_mobile.dart';
import 'package:mc_common_app/models/user_models/confirm_password.dart';
import 'package:mc_common_app/models/user_models/country.dart';
import 'package:mc_common_app/models/user_models/forget_password_otp_compare.dart';
import 'package:mc_common_app/models/user_models/forget_password_otp_request.dart';
import 'package:mc_common_app/models/user_models/login_password.dart';
import 'package:mc_common_app/models/user_models/register_user.dart';
import 'package:mc_common_app/models/user_models/user.dart';
import 'package:mc_common_app/models/user_models/verify_email.dart';
import 'package:mc_common_app/repositories/user_repo.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart';
@ -77,7 +77,7 @@ class UserVM extends BaseVM {
title: LocaleKeys.emailChangedSuccessfully.tr(),
//"Email is Changed Successfully",
onClick: () {
Navigator.of(context).pushNamedAndRemoveUntil(AppRoutes.loginWithPassword, (Route<dynamic> route) => false);
Navigator.of(context).pushNamedAndRemoveUntil(AppRoutes.loginWithPassword, (Route<dynamic> route) => true);
},
),
);
@ -109,7 +109,7 @@ class UserVM extends BaseVM {
title: LocaleKeys.phoneNumberVerified.tr(),
//"Phone Number Verified",
onClick: () {
Navigator.of(context).pushNamedAndRemoveUntil(AppRoutes.loginWithPassword, (Route<dynamic> route) => false);
Navigator.of(context).pushNamedAndRemoveUntil(AppRoutes.loginWithPassword, (Route<dynamic> route) => true);
},
),
);
@ -132,7 +132,7 @@ class UserVM extends BaseVM {
Utils.showToast(LocaleKeys.passwordIsUpdated.tr());
//("Password is Updated");
// navigateWithName(context, AppRoutes.loginWithPassword);
Navigator.of(context).pushNamedAndRemoveUntil(AppRoutes.loginWithPassword, (Route<dynamic> route) => false);
Navigator.of(context).pushNamedAndRemoveUntil(AppRoutes.loginWithPassword, (Route<dynamic> route) => true);
} else {
Utils.showToast(res.message ?? "");
}

@ -4,7 +4,7 @@ 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/models/widgets_models.dart';
import 'package:mc_common_app/models/general_models/widgets_models.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/view_models/ad_view_model.dart';

@ -3,7 +3,7 @@ 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/models/widgets_models.dart';
import 'package:mc_common_app/models/general_models/widgets_models.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/view_models/ad_view_model.dart';
import 'package:mc_common_app/views/advertisement/ad_creation_steps/ad_creation_steps_containers.dart';
@ -141,6 +141,7 @@ class VehicleDetails extends StatelessWidget {
(DropValue value) => adVM.updateSelectionVehicleTransmissionId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleTransmissionsDrop,
hint: "Vehicle Transmission",
dropdownValue: adVM.vehicleTransmissionId.selectedId != -1 ? DropValue(adVM.vehicleTransmissionId.selectedId, adVM.vehicleTransmissionId.selectedOption, "") : null,
errorValue: adVM.vehicleTransmissionId.errorValue,
);
}),

@ -3,7 +3,7 @@ import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/advertisment_models/ads_duration_model.dart';
import 'package:mc_common_app/models/widgets_models.dart';
import 'package:mc_common_app/models/general_models/widgets_models.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.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';
@ -6,7 +8,8 @@ import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/int_extensions.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/widgets_models.dart';
import 'package:mc_common_app/models/advertisment_models/special_service_model.dart';
import 'package:mc_common_app/models/general_models/widgets_models.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/dialogs_and_bottomsheets.dart';
import 'package:mc_common_app/utils/enums.dart';
@ -16,18 +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:mc_common_app/widgets/txt_field.dart';
import 'package:provider/provider.dart';
class AdsDetailView extends StatelessWidget {
class AdsDetailView extends StatefulWidget {
final AdDetailsModel adDetails;
const AdsDetailView({Key? key, required this.adDetails}) : super(key: key);
@override
State<AdsDetailView> createState() => _AdsDetailViewState();
}
class _AdsDetailViewState extends State<AdsDetailView> {
@override
void initState() {
scheduleMicrotask(() {
onAdDetailsLoaded();
});
super.initState();
}
Future<void> onAdDetailsLoaded() async {
context.read<PaymentVM>().updateCurrentAdId(id: widget.adDetails.id!);
if ((widget.adDetails.isMyAd ?? false) && (widget.adDetails.adPostStatus == AdPostStatus.reserved)) {
await context.read<AdVM>().getAdBankingAccountInfo(adId: widget.adDetails.id!);
}
}
void deleteAdBottomSheet(BuildContext context) {
AdVM adVM = context.read<AdVM>();
return actionConfirmationBottomSheet(
@ -41,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!);
},
),
),
@ -63,8 +90,6 @@ class AdsDetailView extends StatelessWidget {
@override
Widget build(BuildContext context) {
print("adId: ${adDetails.id}");
print("statusID: ${adDetails.statusID}");
return Scaffold(
appBar: CustomAppBar(
title: "Ads",
@ -72,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: () {
@ -107,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(
@ -121,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(
@ -136,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,
),
@ -156,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,
@ -183,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),
],
),
)
@ -259,20 +326,6 @@ class BuildAdDetailsActionButtonForExploreAds extends StatelessWidget {
)
],
),
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// "Tax".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
// Row(
// crossAxisAlignment: CrossAxisAlignment.end,
// children: [
// "${adDetailsModel.taxPrice}".toText(fontSize: 16, isBold: true),
// 2.width,
// "SAR".toText(color: MyColors.lightTextColor, fontSize: 10, isBold: true).paddingOnly(bottom: 0),
// ],
// )
// ],
// ),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end,
@ -368,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: [
@ -467,27 +502,6 @@ class BuildAdDetailsActionButtonForExploreAds extends StatelessWidget {
@override
Widget build(BuildContext context) {
context.read<PaymentVM>().updateCurrentAdId(id: adDetailsModel.id!);
// 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:
@ -505,6 +519,93 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget {
const BuildAdDetailsActionButtonForMyAds({Key? key, required this.adDetailsModel}) : super(key: key);
void onBookPhotographyServiceClicked(BuildContext context, {required AdDetailsModel adDetailsModel}) async {
AdVM adVM = context.read<AdVM>();
if (adVM.photoOfficeSelectedId.selectedId == -1) {
adVM.getPhotographyServiceScheduleListByOffices(latitude: 46.703430, longitude: 24.625720, isNeedToRebuild: true); // TODO: These Lat Long need to be dynamic
}
return showModalBottomSheet(
context: context,
isScrollControlled: true,
enableDrag: true,
builder: (BuildContext 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<DropValue> 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,
],
));
});
},
);
}
void reserveAdPriceBreakDownClicked(BuildContext context) {
showModalBottomSheet(
context: context,
@ -649,7 +750,7 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget {
});
}
Widget pendingForReviewAction(BuildContext context, {required bool isPendingPost}) {
Widget pendingForReviewAction({required String pendingText}) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
@ -660,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: () {},
),
@ -671,18 +772,49 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget {
);
}
Widget pendingForPaymentAction(BuildContext context, {required int adID}) {
Widget pendingForPaymentAction(BuildContext context, {required AdDetailsModel ad}) {
SpecialServiceModelForAds? photoSpecialServiceModel;
for (var element in ad.specialservice!) {
if (element.specialServiceID == 1) {
photoSpecialServiceModel = element;
}
}
bool payButtonStatus = photoSpecialServiceModel != null && photoSpecialServiceModel.appointmentStatusId == 0;
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
if (photoSpecialServiceModel != null && photoSpecialServiceModel.appointmentStatusId == 0) ...[
Row(
children: [
Expanded(
child: ShowFillButton(
isFilled: false,
borderColor: MyColors.darkPrimaryColor,
maxHeight: 55,
title: "Book ${photoSpecialServiceModel.name}",
txtColor: MyColors.darkPrimaryColor,
onPressed: () {
onBookPhotographyServiceClicked(context, adDetailsModel: adDetailsModel);
},
),
),
],
),
8.height,
],
Row(
children: [
Expanded(
child: ShowFillButton(
maxHeight: 55,
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);
}
},
),
),
@ -760,19 +892,93 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget {
);
}
Widget cancelReservationAction(BuildContext context) {
Future buildCancelReservationBottomSheet(BuildContext context, {required AdDetailsModel adDetails}) {
return showModalBottomSheet(
context: context,
isScrollControlled: true,
enableDrag: true,
builder: (BuildContext context) {
return InfoBottomSheet(
title: "Cancel Reservation".toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
description: Padding(
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
12.height,
TxtField(
maxLines: 5,
value: "",
errorValue: "",
keyboardType: TextInputType.text,
hint: "Reason for cancellation",
onChanged: (v) => () {},
),
],
),
25.height,
ShowFillButton(
title: "Submit",
onPressed: () {
Navigator.pop(context);
AdVM adVM = context.read<AdVM>();
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);
},
),
),
);
},
maxWidth: double.infinity,
),
19.height,
],
),
));
},
);
}
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: () {
buildCancelReservationBottomSheet(context, adDetails: adDetails);
}),
),
],
);
@ -802,7 +1008,6 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget {
adVM.updateSelectionVehicleTypeId(
SelectionModel(selectedId: adDetailsModel.vehicle!.vehicleType!, selectedOption: (adDetailsModel.vehicle!.vehicleType!).toVehicleTypeString(), errorValue: ""),
);
showMyBottomSheet(context, child: const AdDurationSelectionSheetContent(isFromExtendAd: true, isUpdateAdSelected: true));
},
),
@ -832,59 +1037,24 @@ 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) {
context.read<PaymentVM>().updateCurrentAdId(id: adDetailsModel.id!);
switch (adDetailsModel.adPostStatus!) {
case AdPostStatus.pendingForPayment:
return pendingForPaymentAction(context, adID: adDetailsModel.id!);
return pendingForPaymentAction(context, ad: adDetailsModel);
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(context, isPendingPost: true);
return pendingForReviewAction(pendingText: "Waiting for admin to post");
case AdPostStatus.pendingForReview:
return pendingForReviewAction(context, isPendingPost: false);
return pendingForReviewAction(pendingText: "Waiting for Admins Approval");
case AdPostStatus.sold:
case AdPostStatus.expired:

@ -0,0 +1,135 @@
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/models/general_models/widgets_models.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/view_models/ad_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/common_widgets/search_entity_widget.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';
class AdsFilterView extends StatelessWidget {
const AdsFilterView({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
title: "Ads Filter",
profileImageUrl: MyAssets.bnCar,
isRemoveBackButton: false,
isDrawerEnabled: false,
onBackButtonTapped: () {
context.read<AdVM>().resetValues();
Navigator.pop(context);
},
),
body: Consumer<AdVM>(
builder: (BuildContext context, AdVM adVM, Widget? child) {
return WillPopScope(
onWillPop: () async {
context.read<AdVM>().resetValues();
return true;
},
child: Column(
children: [
ListView(
children: [
20.height,
SearchEntityWidget(
title: "Search By Location",
actionWidget: Builder(builder: (context) {
List<DropValue> vehicleBrandsDrop = [];
for (var element in adVM.vehicleCities) {
vehicleBrandsDrop.add(DropValue(element.id?.toInt() ?? 0, element.cityName ?? "", ""));
}
return DropdownField(
(DropValue value) => adVM.updateSelectionVehicleCityId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true),
list: vehicleBrandsDrop,
dropdownValue: adVM.vehicleCityId.selectedId != -1 ? DropValue(adVM.vehicleCityId.selectedId, adVM.vehicleCityId.selectedOption, "") : null,
hint: "Select Location",
errorValue: adVM.vehicleCityId.errorValue,
);
}),
historyContent: adVM.vehicleLocationAdSearchHistory,
onHistoryItemDeleted: (index) {
adVM.removeVehicleLocationAdSearchHistory(index: index);
},
onHistoryItemTapped: (DropValue value) => adVM.updateSelectionVehicleCityId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true),
),
const Divider(thickness: 1.2).paddingOnly(top: 7, bottom: 7),
SearchEntityWidget(
title: "Search By Brand Name",
actionWidget: Builder(builder: (context) {
List<DropValue> vehicleBrandsDrop = [];
for (var element in adVM.vehicleBrands) {
vehicleBrandsDrop.add(DropValue(element.id?.toInt() ?? 0, element.vehicleBrandDescription ?? "", ""));
}
return DropdownField(
(DropValue value) => adVM.updateSelectionVehicleBrandId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true),
list: vehicleBrandsDrop,
dropdownValue: adVM.vehicleBrandId.selectedId != -1 ? DropValue(adVM.vehicleBrandId.selectedId, adVM.vehicleBrandId.selectedOption, "") : null,
hint: "Select Vehicle Brand",
errorValue: adVM.vehicleBrandId.errorValue,
);
}),
historyContent: adVM.vehicleBrandsAdSearchHistory,
onHistoryItemDeleted: (index) => adVM.removeVehicleBrandsAdSearchHistory(index: index),
onHistoryItemTapped: (DropValue value) => adVM.updateSelectionVehicleBrandId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true),
),
const Divider(thickness: 1.2).paddingOnly(top: 7, bottom: 7),
SearchEntityWidget(
title: "Search By Year",
actionWidget: Builder(builder: (context) {
List<DropValue> vehicleBrandsDrop = [];
for (var element in adVM.vehicleModelYears) {
vehicleBrandsDrop.add(DropValue(element.id?.toInt() ?? 0, element.modelYear ?? "", ""));
}
return DropdownField(
(DropValue value) => adVM.updateSelectionVehicleModelYearId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true),
list: vehicleBrandsDrop,
dropdownValue: adVM.vehicleModelYearId.selectedId != -1 ? DropValue(adVM.vehicleModelYearId.selectedId, adVM.vehicleModelYearId.selectedOption, "") : null,
hint: "Select Year",
errorValue: adVM.vehicleModelYearId.errorValue,
);
}),
historyContent: adVM.vehicleYearAdSearchHistory,
onHistoryItemDeleted: (index) => adVM.removeVehicleYearAdSearchHistory(index: index),
onHistoryItemTapped: (DropValue value) => adVM.updateSelectionVehicleModelYearId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true),
)
],
).expand(),
Container(
color: MyColors.white,
child: Column(
children: [
5.height,
Row(
children: [
Expanded(
child: ShowFillButton(
maxHeight: 55,
title: "Search",
onPressed: () {},
backgroundColor: MyColors.darkPrimaryColor,
txtColor: MyColors.white,
fontSize: 18,
),
)
],
),
10.height,
],
),
),
],
).horPaddingMain(),
);
},
),
);
}
}

@ -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;

@ -1,19 +0,0 @@
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
class AdsSearchFilterView extends StatelessWidget {
const AdsSearchFilterView({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
title: "Filter Ads",
profileImageUrl: MyAssets.bnCar,
isRemoveBackButton: false,
isDrawerEnabled: false,
),
);
}
}

@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/advertisment_models/vehicle_details_models.dart';
import 'package:mc_common_app/models/widgets_models.dart';
import 'package:mc_common_app/models/general_models/widgets_models.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/view_models/ad_view_model.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart';

@ -4,7 +4,7 @@ import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/advertisment_models/vehicle_details_models.dart';
import 'package:mc_common_app/models/widgets_models.dart';
import 'package:mc_common_app/models/general_models/widgets_models.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/view_models/ad_view_model.dart';

@ -0,0 +1,245 @@
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/models/appointments_models/appointment_list_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/dialogs_and_bottomsheets.dart';
import 'package:mc_common_app/utils/enums.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/common_widgets/card_button_with_icon.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart';
class AppointmentDetailView extends StatelessWidget {
final AppointmentListModel appointmentListModel;
AppointmentDetailView({Key? key, required this.appointmentListModel}) : super(key: key);
Widget getBaseActionButtonWidget({required Color color, required String text, Color textColor = MyColors.white, required Function() onPressed}) {
return Expanded(
child: ShowFillButton(
maxHeight: 55,
title: text,
onPressed: onPressed,
backgroundColor: color,
txtColor: textColor,
fontSize: 18,
),
);
}
Widget buildBottomActionButton({required AppointmentStatusEnum appointmentStatusEnum, required BuildContext context}) {
switch (appointmentStatusEnum) {
case AppointmentStatusEnum.booked:
return Align(
alignment: Alignment.bottomCenter,
child: Row(
children: [
getBaseActionButtonWidget(color: MyColors.redColor, onPressed: () => appointmentCancelConfirmationSheet(context), text: "Cancel"),
12.width,
getBaseActionButtonWidget(
color: MyColors.greenColor,
onPressed: () {
context.read<AppointmentsVM>().onConfirmAppointmentPressed(context: context, appointmentId: appointmentListModel.id);
},
text: "Confirm"),
],
),
);
case AppointmentStatusEnum.confirmed:
return Align(
alignment: Alignment.bottomCenter,
child: Row(
children: [
getBaseActionButtonWidget(color: MyColors.redColor, onPressed: () => appointmentCancelConfirmationSheet(context), text: "Cancel"),
],
),
);
case AppointmentStatusEnum.arrived:
return Align(
alignment: Alignment.bottomCenter,
child: Row(
children: [
getBaseActionButtonWidget(color: MyColors.grey98Color.withOpacity(0.3), textColor: MyColors.lightTextColor, onPressed: () {}, text: "In Progress"),
],
),
);
case AppointmentStatusEnum.cancelled:
return Align(
alignment: Alignment.bottomCenter,
child: Row(
children: [
getBaseActionButtonWidget(color: MyColors.grey98Color.withOpacity(0.3), textColor: MyColors.lightTextColor, onPressed: () {}, text: "Cancelled"),
],
),
);
case AppointmentStatusEnum.allAppointments:
return SizedBox();
case AppointmentStatusEnum.rescheduled:
return Align(
alignment: Alignment.bottomCenter,
child: Row(
children: [
getBaseActionButtonWidget(color: MyColors.redColor, onPressed: () => appointmentCancelConfirmationSheet(context), text: "Cancel"),
12.width,
getBaseActionButtonWidget(
color: MyColors.greenColor,
onPressed: () {
context.read<AppointmentsVM>().onConfirmAppointmentPressed(context: context, appointmentId: appointmentListModel.id);
},
text: "Confirm"),
],
),
);
}
}
void appointmentCancelConfirmationSheet(BuildContext context) {
final appointmentsVm = context.read<AppointmentsVM>();
return actionConfirmationBottomSheet(
context: context,
title: "Do you want to cancel this appointment?".toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
subtitle: "Your appointment will be cancelled and you cannot undo this action.",
actionButtonYes: Expanded(
child: ShowFillButton(
maxHeight: 55,
title: "Yes",
fontSize: 15,
onPressed: () {
Navigator.pop(context);
appointmentsVm.onCancelAppointmentPressed(context: context, appointmentListModel: appointmentListModel);
},
),
),
actionButtonNo: Expanded(
child: ShowFillButton(
maxHeight: 55,
isFilled: false,
borderColor: MyColors.darkPrimaryColor,
title: "No",
txtColor: MyColors.darkPrimaryColor,
fontSize: 15,
onPressed: () {
Navigator.pop(context);
},
),
),
);
}
@override
Widget build(BuildContext context) {
AppointmentsVM appointmentsVM = context.read<AppointmentsVM>();
return Scaffold(
appBar: CustomAppBar(
title: "Appointment",
profileImageUrl: MyAssets.bnCar,
isRemoveBackButton: false,
isDrawerEnabled: false,
),
body: Container(
padding: const EdgeInsets.only(bottom: 10, left: 21, right: 21),
child: Stack(
children: [
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
appointmentListModel.providerName!.toText(fontSize: 16, isBold: true),
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
MyAssets.miniClockDark.buildSvg(
height: 12,
width: 12,
fit: BoxFit.fill,
),
5.width,
"${appointmentListModel.duration ?? ""} ${appointmentListModel.appointmentDate!.toFormattedDateWithoutTime()}".toText(fontSize: 12, isBold: true, color: MyColors.lightTextColor),
],
),
13.height,
if (appointmentListModel.appointmentServicesList != null && appointmentListModel.appointmentServicesList!.isNotEmpty) ...[
Column(
children: List.generate(appointmentListModel.appointmentServicesList!.length, (index) {
ServiceModel service = appointmentListModel.appointmentServicesList![index];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
// MyAssets.maintenanceIcon.buildSvg(
// height: 10,
// width: 10,
// fit: BoxFit.fill,
// ),
// 10.width,
"${index + 1}. ${service.providerServiceDescription}".toText(fontSize: 14, isBold: true),
],
),
if (service.serviceItems != null && service.serviceItems!.isNotEmpty) ...[
Column(
children: List.generate(
service.serviceItems!.length,
(index) => "${service.serviceItems![index].name}".toText(
textAlign: TextAlign.start,
fontSize: 12,
color: MyColors.lightTextColor,
),
),
).paddingOnly(left: 15),
],
5.height,
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
((service.currentTotalServicePrice).toString()).toText(fontSize: 25, isBold: true),
2.width,
"SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5),
Icon(
Icons.arrow_drop_down,
size: 30,
)
],
).onPress(() => appointmentsVM.priceBreakDownClicked(context, service)),
],
);
}),
),
],
15.height,
Row(
children: [
CardButtonWithIcon(
title: "Reschedule Appointment",
onCardTapped: () {
context.read<AppointmentsVM>().onRescheduleAppointmentPressed(context: context, appointmentListModel: appointmentListModel);
},
icon: MyAssets.scheduleAppointmentIcon.buildSvg(),
),
if (appointmentListModel.appointmentStatusEnum == AppointmentStatusEnum.booked) ...[
10.width,
CardButtonWithIcon(
title: "Pay for Appointment",
onCardTapped: () {
context.read<AppointmentsVM>().onConfirmAppointmentPressed(context: context, appointmentId: appointmentListModel.id);
},
icon: MyAssets.creditCardIcon.buildSvg(),
),
],
],
),
15.height,
],
).toWhiteContainer(width: double.infinity, allPading: 12),
buildBottomActionButton(appointmentStatusEnum: appointmentListModel.appointmentStatusEnum!, context: context),
],
),
),
);
}
}

@ -0,0 +1,162 @@
import 'package:flutter/material.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/appointments_models/service_schedule_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/view_models/appointments_view_model.dart';
import 'package:mc_common_app/views/appointments/widgets/custom_calender_widget.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/time_slots.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart';
class ScreenArgumentsForAppointmentDetailPage {
final int routeFlag; // 1 = coming from create appointment || 2 = coming from reschedule appointment
final int appointmentId; // 1 = coming from create appointment || 2 = coming from reschedule appointment
ScreenArgumentsForAppointmentDetailPage({required this.routeFlag, required this.appointmentId});
}
class BookAppointmentSchedulesView extends StatelessWidget {
final ScreenArgumentsForAppointmentDetailPage screenArgumentsForAppointmentDetailPage;
BookAppointmentSchedulesView({Key? key, required this.screenArgumentsForAppointmentDetailPage}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
title: "Book Appointment",
isRemoveBackButton: false,
isDrawerEnabled: false,
onBackButtonTapped: () => Navigator.pop(context),
),
body: Consumer(
builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
21.height,
ListView.builder(
shrinkWrap: true,
itemCount: appointmentsVM.serviceAppointmentScheduleList.length,
itemBuilder: (BuildContext context, int scheduleIndex) {
ServiceAppointmentScheduleModel scheduleData = appointmentsVM.serviceAppointmentScheduleList[scheduleIndex];
return ExpansionTile(
tilePadding: EdgeInsets.symmetric(horizontal: 21, vertical: 10),
childrenPadding: EdgeInsets.only(left: 16, bottom: 10, right: 16),
title: Column(
children: [
Row(
children: [
Expanded(
child: "Schedule ${scheduleIndex + 1}".toText(fontSize: 20, isBold: true),
),
],
),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Service Location: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
("${scheduleData.appointmentType == 2 ? "Home" : "Workshop"}").toText(fontSize: 12, isBold: true).expand(),
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
5.height,
ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: appointmentsVM.serviceAppointmentScheduleList[scheduleIndex].servicesListInAppointment!.length,
itemBuilder: (BuildContext context, int serviceIndex) {
ServiceModel selectedService = appointmentsVM.serviceAppointmentScheduleList[scheduleIndex].servicesListInAppointment![serviceIndex];
return Row(
children: [
Expanded(
child: ("${serviceIndex + 1}. ${selectedService.providerServiceDescription}").toText(fontSize: 15, isBold: true, color: MyColors.lightTextColor),
),
],
);
},
),
],
),
],
),
children: [
Column(
children: [
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(
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);
},
),
),
],
],
),
],
).toWhiteContainer(width: double.infinity, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10));
},
).expand(),
Row(
children: [
Expanded(
child: ShowFillButton(
txtColor: MyColors.black,
maxHeight: 55,
title: "Cancel",
onPressed: () => Navigator.pop(context),
backgroundColor: MyColors.greyButtonColor,
),
),
12.width,
Expanded(
child: ShowFillButton(
maxHeight: 55,
title: screenArgumentsForAppointmentDetailPage.routeFlag == 1 ? "Review" : "Confirm",
onPressed: () {
if (screenArgumentsForAppointmentDetailPage.routeFlag == 1) {
appointmentsVM.onReviewButtonPressed(context);
} else {
appointmentsVM.onRescheduleAppointmentConfirmPressed(
context: context,
appointmentId: screenArgumentsForAppointmentDetailPage.appointmentId,
selectedSlotId: appointmentsVM.serviceAppointmentScheduleList.first.selectedCustomTimeDateSlotModel!.date!.slotId,
);
}
},
backgroundColor: MyColors.darkPrimaryColor,
),
)
],
).paddingAll(21)
],
);
},
));
}
}

@ -0,0 +1,138 @@
import 'package:flutter/material.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.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/view_models/appointments_view_model.dart';
import 'package:mc_common_app/views/advertisement/custom_add_button.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 BookAppointmentServicesView extends StatelessWidget {
BookAppointmentServicesView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
title: "Book Appointment",
isRemoveBackButton: false,
isDrawerEnabled: false,
onBackButtonTapped: () {
context.read<AppointmentsVM>().resetAfterBookingAppointment();
Navigator.pop(context);
},
),
body: Consumer(
builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
21.height,
CustomAddButton(
needsBorder: true,
bgColor: MyColors.white,
onTap: () => appointmentsVM.openTheAddServiceBottomSheet(context, appointmentsVM),
text: "Add Services",
icon: Container(
height: 24,
width: 24,
decoration: const BoxDecoration(shape: BoxShape.circle, color: MyColors.darkTextColor),
child: const Icon(Icons.add, color: MyColors.white),
),
).horPaddingMain(),
10.height,
ListView.builder(
shrinkWrap: true,
itemCount: appointmentsVM.servicesInCurrentAppointment.length,
itemBuilder: (BuildContext context, int serviceIndex) {
ServiceModel serviceData = appointmentsVM.servicesInCurrentAppointment[serviceIndex];
return Column(
children: [
Row(
children: [
Expanded(
child: (serviceData.serviceDescription ?? "").toText(fontSize: 15, isBold: true),
),
IconButton(
onPressed: () => appointmentsVM.removeServiceInCurrentAppointment(serviceIndex),
icon: Icon(Icons.delete_outline, color: MyColors.redColor),
)
],
),
if (true) ...[
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Service Location: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
(serviceData.isHomeSelected ? serviceData.homeLocation : "Workshop").toText(fontSize: 12, isBold: true).expand(),
],
),
5.height,
Column(
children: List.generate(serviceData.serviceItems!.length, (itemIndex) {
ItemData itemData = serviceData.serviceItems![itemIndex];
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"${itemData.name}: ".toText(fontSize: 13, color: MyColors.lightTextColor, isBold: true),
("${itemData.price}").toText(fontSize: 13, isBold: true).expand(),
],
);
}),
),
8.height,
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
((appointmentsVM.servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice).toString()).toText(fontSize: 32, isBold: true),
2.width,
"SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5),
Icon(
Icons.arrow_drop_down,
size: 30,
)
],
).onPress(() => appointmentsVM.priceBreakDownClicked(context, appointmentsVM.servicesInCurrentAppointment[serviceIndex])),
],
],
).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10));
},
).expand(),
Row(
children: [
Expanded(
child: ShowFillButton(
txtColor: MyColors.black,
maxHeight: 55,
title: "Cancel",
onPressed: () {
appointmentsVM.servicesInCurrentAppointment.clear();
appointmentsVM.allSelectedItemsInAppointments.clear();
Navigator.pop(context);
},
backgroundColor: MyColors.greyButtonColor,
),
),
12.width,
Expanded(
child: ShowFillButton(
maxHeight: 55,
title: "Next",
onPressed: () {
appointmentsVM.onServicesNextPressed(context);
},
backgroundColor: MyColors.darkPrimaryColor,
),
)
],
).paddingAll(21)
],
);
},
));
}
}

@ -0,0 +1,151 @@
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/models/services_models/item_model.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/view_models/appointments_view_model.dart';
import 'package:mc_common_app/views/appointments/widgets/service_item_with_price_checkbox.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 BookAppointmentsItemView extends StatelessWidget {
const BookAppointmentsItemView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
title: "Select Items",
isRemoveBackButton: false,
isDrawerEnabled: false,
actions: [MyAssets.searchIcon.buildSvg().paddingOnly(right: 21)],
onBackButtonTapped: () => Navigator.pop(context),
),
body: Consumer(
builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: 40,
width: double.infinity,
color: MyColors.darkTextColor,
alignment: Alignment.centerLeft,
child: "${appointmentsVM.selectedSubServicesCounter} Item(s) Selected".toText(fontSize: 16, color: MyColors.white).horPaddingMain(),
),
16.height,
Column(
children: [
"Few services are not available on home location. Change the location to workshop to full access the services".toText(fontSize: 12, isItalic: true, color: MyColors.lightTextColor),
8.height,
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Change location or service: ".toText(fontSize: 14, isBold: true),
"Edit".toText(fontSize: 14, isBold: true, isUnderLine: true, color: MyColors.adPendingStatusColor),
5.width,
MyAssets.icEdit.buildSvg(width: 17),
],
).onPress(() {}),
16.height,
Divider(),
],
).horPaddingMain(),
appointmentsVM.serviceItemsFromApi.isEmpty
? Expanded(child: Center(child: "No Items to show.".toText(fontSize: 16, color: MyColors.lightTextColor)))
: ListView.separated(
separatorBuilder: (BuildContext context, int index) => Divider(),
itemCount: appointmentsVM.serviceItemsFromApi.length,
itemBuilder: (BuildContext context, int index) {
ItemData itemData = appointmentsVM.serviceItemsFromApi[index];
return ServiceItemWithPriceCheckBox(
description: itemData.description ?? "Some description about the sub-services",
title: itemData.name!,
isSelected: itemData.isUpdateOrSelected!,
onSelection: (bool value) {
print("itemId: ${itemData.id}");
appointmentsVM.onItemUpdateOrSelected(index, !itemData.isUpdateOrSelected!, itemData.id!);
},
priceWidget: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
// TODO: This Price will be decided according to the service selected
itemData.price!.split(".").first.toText(fontSize: 30, isBold: true),
" SAR".toText(fontSize: 15, isBold: true, color: MyColors.lightTextColor).paddingOnly(bottom: 5),
],
),
);
},
).expand(),
Column(
children: [
Divider(
height: 1,
thickness: 0.7,
),
8.height,
if (appointmentsVM.selectSubServicesError != "")
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
appointmentsVM.selectSubServicesError.toText(fontSize: 14, color: Colors.red),
],
).paddingOnly(right: 10),
8.height,
Row(
children: [
Expanded(
child: ShowFillButton(
txtColor: MyColors.black,
maxHeight: 55,
title: "Cancel",
onPressed: () {
appointmentsVM.resetCategorySelectionBottomSheet();
pop(context);
},
backgroundColor: MyColors.greyButtonColor,
),
),
12.width,
Expanded(
child: Builder(
builder: (BuildContext context) {
return ShowFillButton(
maxHeight: 55,
title: "Next",
onPressed: () async {
bool resp = appointmentsVM.validateItemsSelection();
if (resp) {
appointmentsVM.onItemsSelectedInService();
Navigator.pop(context);
}
// bool resp = appointmentsVM.validateItemsSelection();
// if (resp) {
// Utils.showLoading(context);
// await appointmentsVM.mergeServiceIntoAvailableSchedules();
// appointmentsVM.resetCategorySelectionBottomSheet();
// Utils.hideLoading(context);
// Navigator.of(context).pushReplacementNamed(AppRoutes.bookAppointmenServicesView);
// }
},
backgroundColor: !appointmentsVM.isServiceSelectionValidated() ? MyColors.lightTextColor.withOpacity(0.6) : MyColors.darkPrimaryColor,
);
},
),
),
],
).horPaddingMain(),
16.height,
],
),
],
);
},
));
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save