Minor Fixes

aamir_dev
Faiz Hashmi 1 year ago
parent 0ada291516
commit 4b350dbeb6

@ -785,6 +785,10 @@
"tapToView": "انقر لعرض",
"noServicesAvailableToCopy": "لا توجد خدمات متاحة في هذا الفرع لنسخها.",
"copySelectedItems": "نسخ العناصر المحددة",
"companyNameMandatory": "اسم الشركة إلزامي"
"companyNameMandatory": "اسم الشركة إلزامي",
"noOfInvites": "عدد الدعوات",
"noSpecialServicesAvailable": "لا توجد خدمات خاصة متاحة للمنطقة المحددة.",
"customService": "الخدمة المخصصة",
"selectServiceDetails": "اختر تفاصيل الخدمة",
"addServiceDetails": "أضف تفاصيل الخدمة"
}

@ -783,5 +783,10 @@
"tapToView": "Tap to view",
"noServicesAvailableToCopy": "There are no services available in this branch to copy.",
"copySelectedItems": "Copy Selected Items",
"companyNameMandatory": "Company Name is mandatory"
"companyNameMandatory": "Company Name is mandatory",
"noOfInvites": "No of invites",
"noSpecialServicesAvailable": "There are no special services available for the selected region.",
"customService": "Custom Service",
"selectServiceDetails": "Select service details",
"addServiceDetails": "Add service details"
}

@ -41,6 +41,7 @@ class ApiConsts {
static String getUserImage = "${baseUrlServices}api/ProfileImage";
static String userUpdate = "${baseUrlServices}api/User_Update";
static String providerComplaintCreate = "${baseUrlServices}api/ServiceProviders/ProviderComplaint_Create";
static String provideContactInfoGet = "${baseUrlServices}api/ServiceProviders/ServiceProviderContact_Get";
//Profile
static String fetProviderDocument = "${baseUrlServices}api/ServiceProviders/ServiceProviderDocument_Get";
@ -191,6 +192,7 @@ class ApiConsts {
static String getContactInfo = "${baseUrlServices}api/Master/ContactInfo_Get";
static String getAppInfo = "${baseUrlServices}api/Master/AppInfo_Get";
static String getTermsAndConditions = "${baseUrlServices}api/Master/TermAndCondition_Get";
static String getAppInvitationHistory = "${baseUrlServices}api/Common/AppInvitation_Get";
static List<String> closingUrls = ["PayFortResponse"];
}
@ -234,6 +236,9 @@ class GlobalConsts {
static String homeLocationEmptyError = "Home location cannot be empty";
static String fillAllFields = "Please fill out all the fields.";
static String requestTypeCannotBeEmpty = "Request type cannot be empty.";
static String serviceNameError = "Service name cannot be empty.";
static String priceError = "Price cannot be empty.";
static String taxError = "Tax cannot be empty.";
static String reserveAdPriceInfo =
"Some dummy description to explain the following concept. This price will be for 24 hours and if a user cancels the reservations before 24 hours then the amount will be automatically refunded to the buyer.";
static String appInvitationMessageEn = "🚗 Hey , check out MOWATER to book car services, buy/sell vehicles, and more—join here! [Invite Link]";
@ -261,8 +266,8 @@ class GlobalConsts {
static int maxFileCount = 7;
static int maxFileSizeInBytes = 2 * 1024 * 1024;
static String allowedFileExtensions = "jpg,png - 2MB";
static String allowedFileExtensionsPDF = "PDF 2MB";
static String allowedFileExtensions = "jpg,jpeg,png - 2MB/file";
static String allowedFileExtensionsPDF = "PDF 2MB/file";
static int providerDealerRoleTypeId = 6;
static int providerIndividualRoleTypeId = 5;

@ -736,7 +736,7 @@ class CodegenLoader extends AssetLoader{
"ownerInformation": "معلومات المالك",
"acceptedRequests": "الطلبات المقبولة",
"specialRequestChat": "دردشة الطلب الخاص",
"companyName": "اسم الشركة *",
"companyName": "اسم الشركة",
"noAvailableItems": "لا توجد عناصر متاحة.",
"serviceDeliveryType": "نوع تقديم الخدمة",
"noImagesToShow": "لا توجد صور للعرض",
@ -801,7 +801,12 @@ class CodegenLoader extends AssetLoader{
"tapToView": "انقر لعرض",
"noServicesAvailableToCopy": "لا توجد خدمات متاحة في هذا الفرع لنسخها.",
"copySelectedItems": "نسخ العناصر المحددة",
"companyNameMandatory": "اسم الشركة إلزامي"
"companyNameMandatory": "اسم الشركة إلزامي",
"noOfInvites": "عدد الدعوات",
"noSpecialServicesAvailable": "لا توجد خدمات خاصة متاحة للمنطقة المحددة.",
"customService": "الخدمة المخصصة",
"selectServiceDetails": "اختر تفاصيل الخدمة",
"addServiceDetails": "أضف تفاصيل الخدمة"
};
static const Map<String,dynamic> en_US = {
"firstTimeLogIn": "First Time Log In",
@ -1519,7 +1524,7 @@ static const Map<String,dynamic> en_US = {
"noItemsToShow": "There are no Items no show.",
"acceptedRequests": "Accepted Requests",
"specialRequestChat": "Special Request Chat",
"companyName": "Company Name *",
"companyName": "Company Name",
"noAvailableItems": "There are no available items.",
"serviceDeliveryType": "Service Delivery Type",
"noImagesToShow": "No Images to Show",
@ -1588,7 +1593,12 @@ static const Map<String,dynamic> en_US = {
"tapToView": "Tap to view",
"noServicesAvailableToCopy": "There are no services available in this branch to copy.",
"copySelectedItems": "Copy Selected Items",
"companyNameMandatory": "Company Name is mandatory"
"companyNameMandatory": "Company Name is mandatory",
"noOfInvites": "No of invites",
"noSpecialServicesAvailable": "There are no special services available for the selected region.",
"customService": "Custom Service",
"selectServiceDetails": "Select service details",
"addServiceDetails": "Add service details"
};
static const Map<String, Map<String,dynamic>> mapLocales = {"ar_SA": ar_SA, "en_US": en_US};
}

@ -1,6 +1,6 @@
// DO NOT EDIT. This is code generated via package:easy_localization/generate.dart
abstract class LocaleKeys {
abstract class LocaleKeys {
static const firstTimeLogIn = 'firstTimeLogIn';
static const signUp = 'signUp';
static const changeMobile = 'changeMobile';
@ -47,7 +47,7 @@ abstract class LocaleKeys {
static const emailChangedSuccessfully = 'emailChangedSuccessfully';
static const passwordIsUpdated = 'passwordIsUpdated';
static const passwordShouldContains = 'passwordShouldContains';
static const successfullyRegistered = ' successfullyRegistered';
static const successfullyRegistered = ' successfullyRegistered';
static const pleaseEnterSamePassword = 'pleaseEnterSamePassword';
static const firstNameMandatory = 'firstNameMandatory';
static const surnameNameMandatory = 'surnameNameMandatory';
@ -765,5 +765,10 @@ abstract class LocaleKeys {
static const noServicesAvailableToCopy = 'noServicesAvailableToCopy';
static const copySelectedItems = 'copySelectedItems';
static const companyNameMandatory = 'companyNameMandatory';
static const noOfInvites = 'noOfInvites';
static const noSpecialServicesAvailable = 'noSpecialServicesAvailable';
static const customService = 'customService';
static const selectServiceDetails = 'selectServiceDetails';
static const addServiceDetails = 'addServiceDetails';
}

@ -0,0 +1,47 @@
class ProviderContactInfoModel {
int? id;
int? providerID;
String? name;
int? allDocStatus;
String? companyName;
String? companyDescription;
int? countryID;
String? countryName;
String? userID;
String? memberSince;
String? mobile;
String? whatsApp;
String? email;
ProviderContactInfoModel({
this.id,
this.providerID,
this.name,
this.allDocStatus,
this.companyName,
this.companyDescription,
this.countryID,
this.countryName,
this.userID,
this.memberSince,
this.mobile,
this.whatsApp,
this.email,
});
ProviderContactInfoModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
providerID = json['providerID'];
name = json['name'];
allDocStatus = json['allDocStatus'];
companyName = json['companyName'];
companyDescription = json['companyDescription'];
countryID = json['countryID'];
countryName = json['countryName'];
userID = json['userID'];
memberSince = json['memberSince'];
mobile = json['mobile'];
whatsApp = json['whatsApp'];
email = json['email'];
}
}

@ -4,6 +4,7 @@ class ProviderProfileModel {
ProviderProfileModel({
this.id,
this.companyName,
this.profileImage,
this.name,
this.countryName,
this.companyDescription,
@ -20,6 +21,7 @@ class ProviderProfileModel {
});
final int? id;
final String? profileImage;
final String? companyName;
final String? companyDescription;
int? countryID;
@ -38,6 +40,7 @@ class ProviderProfileModel {
factory ProviderProfileModel.fromJson(Map<String, dynamic> json) => ProviderProfileModel(
id: json["id"],
companyName: json["companyName"],
profileImage: json["profileImage"] ?? "",
name: json["name"],
countryName: json["countryName"],
countryID: json["countryID"],

@ -0,0 +1,26 @@
class AppInvitationHistoryModel {
int? id;
int? customerID;
int? channelID;
int? appInvitationEnumID;
int? noOfInvites;
String? comments;
AppInvitationHistoryModel({
this.id,
this.customerID,
this.channelID,
this.appInvitationEnumID,
this.noOfInvites,
this.comments,
});
AppInvitationHistoryModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
customerID = json['customerID'];
channelID = json['channelID'];
appInvitationEnumID = json['appInvitationEnumID'];
noOfInvites = json['noofInvites'];
comments = json['comments'];
}
}

@ -22,17 +22,17 @@ class Role {
String? message;
factory Role.fromJson(Map<String, dynamic> json) => Role(
totalItemsCount: json["totalItemsCount"] == null ? null : json["totalItemsCount"],
totalItemsCount: json["totalItemsCount"],
data: json["data"] == null ? null : List<RoleData>.from(json["data"].map((x) => RoleData.fromJson(x))),
messageStatus: json["messageStatus"] == null ? null : json["messageStatus"],
message: json["message"] == null ? null : json["message"],
messageStatus: json["messageStatus"],
message: json["message"],
);
Map<String, dynamic> toJson() => {
"totalItemsCount": totalItemsCount == null ? null : totalItemsCount,
"totalItemsCount": totalItemsCount,
"data": data == null ? null : List<dynamic>.from(data!.map((x) => x.toJson())),
"messageStatus": messageStatus == null ? null : messageStatus,
"message": message == null ? null : message,
"messageStatus": messageStatus,
"message": message,
};
}
@ -50,16 +50,16 @@ class RoleData {
bool? isActive;
factory RoleData.fromJson(Map<String, dynamic> json) => RoleData(
id: json["id"] == null ? null : json["id"],
roleName: json["roleName"] == null ? null : json["roleName"],
roleNameN: json["roleNameN"] == null ? null : json["roleNameN"],
isActive: json["isActive"] == null ? null : json["isActive"],
id: json["id"],
roleName: json["roleName"],
roleNameN: json["roleNameN"],
isActive: json["isActive"],
);
Map<String, dynamic> toJson() => {
"id": id == null ? null : id,
"roleName": roleName == null ? null : roleName,
"roleNameN": roleNameN == null ? null : roleNameN,
"isActive": isActive == null ? null : isActive,
"id": id,
"roleName": roleName,
"roleNameN": roleNameN,
"isActive": isActive,
};
}

@ -137,6 +137,9 @@ class AdsRepoImp implements AdsRepo {
});
List vehiclePostingDamageParts = [];
int sellerTypeID = AppState().getUser.data!.userInfo!.roleId ?? 0;
adsCreationPayloadModel.vehiclePosting!.vehiclePostingDamageParts?.forEach((element) {
log("comment: ${element.comment}");
var imageMap = {
@ -169,7 +172,7 @@ class AdsRepoImp implements AdsRepo {
"vehicleConditionID": adsCreationPayloadModel.vehiclePosting!.vehicleConditionID,
"vehicleMileageID": adsCreationPayloadModel.vehiclePosting!.vehicleMileageID,
"vehicleTransmissionID": adsCreationPayloadModel.vehiclePosting!.vehicleTransmissionID,
"vehicleSellerTypeID": adsCreationPayloadModel.vehiclePosting!.vehicleSellerTypeID,
"vehicleSellerTypeID": sellerTypeID,
"cityID": adsCreationPayloadModel.vehiclePosting!.cityID,
"price": adsCreationPayloadModel.vehiclePosting!.price,
"vehicleVIN": adsCreationPayloadModel.vehiclePosting!.vehicleVIN,
@ -534,7 +537,7 @@ class AdsRepoImp implements AdsRepo {
String token = appState.getUser.data!.accessToken ?? "";
GenericRespModel adsGenericModel = await apiClient.postJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.adsPhotoOfficeAppointmentCreate,
"",
postParams,
token: token,
);

@ -21,6 +21,7 @@ abstract class AppointmentRepo {
List<String>? customerNamesList,
List<String>? customerPhonesList,
List<String>? deliveryTypeIdsList,
AppointmentStatusEnum? appointmentStatusEnum,
String? fromDate,
String? toDate,
});
@ -31,6 +32,7 @@ abstract class AppointmentRepo {
List<String>? serviceIdsList,
List<String>? itemIdsList,
List<String>? branchIdsList,
AppointmentStatusEnum? appointmentStatusEnum,
});
Future<GenericRespModel> updateAppointmentStatus({required int appointmentId, required AppointmentStatusEnum appointmentStatusEnum});
@ -170,7 +172,6 @@ class AppointmentRepoImp implements AppointmentRepo {
index = 0;
}
slotId = schedule.selectedCustomTimeDateSlotModel!.availableSlots![index].slotId;
mapList.add({
@ -237,6 +238,7 @@ class AppointmentRepoImp implements AppointmentRepo {
List<String>? customerNamesList,
List<String>? customerPhonesList,
List<String>? deliveryTypeIdsList,
AppointmentStatusEnum? appointmentStatusEnum,
String? fromDate,
String? toDate,
}) async {
@ -254,6 +256,9 @@ class AppointmentRepoImp implements AppointmentRepo {
"DateTo": toDate ?? "",
};
if (appointmentStatusEnum != null) {
params.addAll({"AppointmentStatusID": appointmentStatusEnum.getIdFromAppointmentStatusEnum().toString()});
}
GenericRespModel genericRespModel = await apiClient.getJsonForObject(
token: t,
(json) => GenericRespModel.fromJson(json),
@ -271,6 +276,7 @@ class AppointmentRepoImp implements AppointmentRepo {
List<String>? serviceIdsList,
List<String>? itemIdsList,
List<String>? branchIdsList,
AppointmentStatusEnum? appointmentStatusEnum,
}) async {
var params = {
"customerID": appState.getUser.data!.userInfo!.customerId.toString(),
@ -280,6 +286,10 @@ class AppointmentRepoImp implements AppointmentRepo {
"ServiceItemIDs": itemIdsList ?? [],
"CategoryIDs": categoryIdsList ?? [],
};
if (appointmentStatusEnum != null) {
params.addAll({"AppointmentStatusID": appointmentStatusEnum.getIdFromAppointmentStatusEnum().toString()});
}
GenericRespModel genericRespModel = await apiClient.getJsonForObject(
token: appState.getUser.data!.accessToken,
(json) => GenericRespModel.fromJson(json),

@ -77,7 +77,7 @@ abstract class BranchRepo {
Future<GenericRespModel> updateCategoryStatus({required int branchId, required int categoryId, required ServiceStatusEnum serviceStatusEnum});
Future<List<AppointmentBasicDetailsModel>> getAppointmentsByCategoryOrService({required int branchId, required int serviceId});
Future<List<AppointmentBasicDetailsModel>> getAppointmentsByCategoryOrService({required int branchId, required int categoryId, required int serviceId});
Future<GenericRespModel> getMatchedServices(int oldBranchId, int newBranchId, int categoryId);
@ -217,7 +217,7 @@ class BranchRepoImp implements BranchRepo {
"documentExt": documents[i].fileExt,
"documentImage": documents[i].document,
"isActive": true,
"dateExpire":documents[i].dateExpire,
"dateExpire": documents[i].dateExpire,
};
map.add(postParams);
}
@ -348,12 +348,22 @@ class BranchRepoImp implements BranchRepo {
}
@override
Future<List<AppointmentBasicDetailsModel>> getAppointmentsByCategoryOrService({required int branchId, required int serviceId}) async {
Future<List<AppointmentBasicDetailsModel>> getAppointmentsByCategoryOrService({required int branchId, required int categoryId, required int serviceId}) async {
var map = {
"ProviderBranchID": branchId.toString(),
"ServiceProviderServiceID": serviceId.toString(),
};
if (serviceId != -1) {
map.addAll({
"ServiceProviderServiceID": serviceId.toString(),
});
}
if (categoryId != -1) {
map.addAll({
"ServiceProviderServiceID": serviceId.toString(),
});
}
String t = AppState().getUser.data!.accessToken ?? "";
GenericRespModel genericRespModel = await apiClient.getJsonForObject(
(json) => GenericRespModel.fromJson(json),

@ -8,6 +8,7 @@ import 'package:mc_common_app/models/advertisment_models/vehicle_details_models.
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/provider_contact_info_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';
@ -56,6 +57,8 @@ abstract class CommonRepo {
Future<List<EnumsModel>> getEnumTypeValues({int? enumTypeID, String? enumTypeName});
Future<GenericRespModel> createComplainFromProvider({required int customerId, required String comment, required int complainType});
Future<ProviderContactInfoModel> getProvidersContactInfo({required int providerId});
}
class CommonRepoImp implements CommonRepo {
@ -363,4 +366,19 @@ class CommonRepoImp implements CommonRepo {
);
return adsGenericModel;
}
@override
Future<ProviderContactInfoModel> getProvidersContactInfo({required int providerId}) async {
final parameters = {
"ProviderID": providerId.toString(),
};
GenericRespModel adsGenericModel = await apiClient.getJsonForObject(
token: appState.getUser.data!.accessToken,
(json) => GenericRespModel.fromJson(json),
ApiConsts.provideContactInfoGet,
queryParameters: parameters,
);
ProviderContactInfoModel contactInfoModel = ProviderContactInfoModel.fromJson(adsGenericModel.data);
return contactInfoModel;
}
}

@ -6,6 +6,7 @@ import 'package:mc_common_app/config/dependency_injection.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/setting_utils_models/app_info_model.dart';
import 'package:mc_common_app/models/setting_utils_models/app_invitation_history_model.dart';
import 'package:mc_common_app/models/setting_utils_models/contact_infos_model.dart';
import 'package:mc_common_app/models/setting_utils_models/faqs_model.dart';
import 'package:mc_common_app/utils/enums.dart';
@ -21,6 +22,8 @@ abstract class SettingOptionsRepo {
Future<List<AppInfoModel>> getTermsAndConditions();
Future<GenericRespModel> appInvitationCreate({required int channelId, required String message});
Future<List<AppInvitationHistoryModel>> getAppInvitationsHistory();
}
class SettingOptionsRepoImp extends SettingOptionsRepo {
@ -158,17 +161,19 @@ class SettingOptionsRepoImp extends SettingOptionsRepo {
String token = appState.getUser.data!.accessToken ?? "";
final params = {
"channelID": channelId.toString(),
"appInvitationEnumID": channelId.toString(),
"comments": message,
};
if (AppState().currentAppType == AppType.customer) {
params.addAll({
"customerID": (appState.getUser.data!.userInfo!.customerId ?? "0").toString(),
"channelID": "3",
});
} else {
params.addAll({
"providerID": (appState.getUser.data!.userInfo!.providerId ?? "0").toString(),
"channelID": "2",
});
}
@ -180,4 +185,30 @@ class SettingOptionsRepoImp extends SettingOptionsRepo {
);
return genericRespModel;
}
@override
Future<List<AppInvitationHistoryModel>> getAppInvitationsHistory() async {
final params = {
"CustomerID": (appState.getUser.data!.userInfo!.customerId ?? "0").toString(),
"ChannelID": "3",
};
String token = appState.getUser.data!.accessToken ?? "";
GenericRespModel genericRespModel = await injector.get<ApiClient>().getJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.getAppInvitationHistory,
queryParameters: params,
token: token,
);
if (genericRespModel.messageStatus != 1 || genericRespModel.data == null) {
Utils.showToast(genericRespModel.message ?? LocaleKeys.somethingWrong.tr());
return [];
}
List<AppInvitationHistoryModel> list = List.generate(genericRespModel.data.length, (index) => AppInvitationHistoryModel.fromJson(genericRespModel.data[index]));
return list;
}
}

@ -379,7 +379,14 @@ class AdVM extends BaseVM {
}
Future<void> getVehicleAdsSpecialServices({required int cityId, required int countryId, required int specialServiceType}) async {
log("cityId: $cityId");
vehicleAdsSpecialServices = await adsRepo.getSpecialServices(specialServiceType: specialServiceType, countryId: countryId, cityId: cityId);
vehicleAdsSpecialServices = vehicleAdsSpecialServices.where((ad) {
bool matchesCityInDetails = ad.details?.any((detail) => detail.fromcity == cityId || detail.tocity == cityId) ?? false;
bool matchesCityInOffice = ad.office?.any((office) => office.cityID == cityId) ?? false;
return matchesCityInDetails || matchesCityInOffice;
}).toList();
notifyListeners();
}
@ -1472,12 +1479,11 @@ class AdVM extends BaseVM {
List<SSPhotoOfficeScheduleModel> photoSSSchedulesByOffices = [];
SSPhotoOfficeScheduleModel selectedPhotoSSSchedulesByOffice = SSPhotoOfficeScheduleModel();
Future<void> getPhotographyServiceScheduleListByOffices({required double latitude, required double longitude, bool isNeedToRebuild = false}) async {
Future<void> getPhotographyServiceScheduleListByOffices({required int cityId, required double latitude, required double longitude, bool isNeedToRebuild = false}) async {
if (isNeedToRebuild) setState(ViewState.busy);
int cityID = AppState().getUser.data!.userInfo!.cityId ?? 1;
try {
photoSSSchedulesByOffices = await commonRepo.getPhotographyServiceScheduleListByOffices(lat: latitude, long: longitude, cityID: cityID);
photoSSSchedulesByOffices = await commonRepo.getPhotographyServiceScheduleListByOffices(lat: latitude, long: longitude, cityID: cityId);
if (isNeedToRebuild) setState(ViewState.idle);
} catch (e) {
if (isNeedToRebuild) setState(ViewState.idle);
@ -2118,7 +2124,8 @@ class AdVM extends BaseVM {
}
}
selectionDurationStartDate = DateHelper.formatDateT(previousAdDetails!.startdate ?? "");
// selectionDurationStartDate = DateHelper.formatDateT(previousAdDetails!.startdate ?? "");
selectionDurationStartDate = "";
isPhoneNumberShown = previousAdDetails!.phoneNo != null;
if (isPhoneNumberShown) {
adPhoneNumber = previousAdDetails!.phoneNo ?? "";

@ -20,6 +20,7 @@ import 'package:mc_common_app/models/provider_branches_models/branch_detail_mode
import 'package:mc_common_app/models/provider_branches_models/branch_review_model.dart';
import 'package:mc_common_app/models/provider_branches_models/profile/categroy.dart';
import 'package:mc_common_app/models/provider_branches_models/profile/services.dart';
import 'package:mc_common_app/models/provider_branches_models/provider_contact_info_model.dart';
import 'package:mc_common_app/models/provider_branches_models/provider_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';
@ -62,9 +63,9 @@ class AppointmentsVM extends BaseVM {
List<AppointmentListModel> myAppointments = [];
List<AppointmentListModel> myUpComingAppointments = [];
List<AppointmentListModel> myFilteredAppointments = [];
List<AppointmentListModel> myFilteredAppointmentsForCustomers = [];
List<FilterListModel> appointmentsFilterOptions = [];
List<AppointmentListModel> myFilteredAppointments2 = [];
List<AppointmentListModel> myFilteredAppointmentsForProvider = [];
bool isFetchingServices = false;
@ -140,7 +141,7 @@ class AppointmentsVM extends BaseVM {
}
context.read<DashboardVmCustomer>().onNavbarTapped(1);
applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.booked);
applyFilterOnAppointmentsVMForCustomers(appointmentStatusEnum: AppointmentStatusEnum.booked);
Utils.hideLoading(context);
resetAfterBookingAppointment();
if (isSuccess) {
@ -149,7 +150,6 @@ class AppointmentsVM extends BaseVM {
navigateWithName(context, AppRoutes.paymentMethodsView, arguments: PaymentTypes.appointment);
} else {
Utils.showToast(LocaleKeys.appointmentBookedSuccessfully.tr());
getMyAppointmentsForCustomer();
navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard);
}
}
@ -227,9 +227,8 @@ class AppointmentsVM extends BaseVM {
}
if (genericRespModel.messageStatus == 1 && AppState().currentAppType == AppType.customer) {
context.read<DashboardVmCustomer>().onNavbarTapped(1);
applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.cancelled);
applyFilterOnAppointmentsVMForCustomers(appointmentStatusEnum: AppointmentStatusEnum.cancelled);
Utils.showToast(genericRespModel.message.toString());
await getMyAppointmentsForCustomer();
Utils.hideLoading(context);
navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard);
}
@ -353,46 +352,69 @@ class AppointmentsVM extends BaseVM {
notifyListeners();
}
applyFilterOnAppointmentsVM({required AppointmentStatusEnum appointmentStatusEnum, bool isNeedCustomerFilter = false}) {
log("appointmentStatusEnum: $appointmentStatusEnum");
// isNeedCustomerFilter IS ONLY FOR THE PROVIDER APP
bool isAppointmentLoading = false;
applyFilterOnAppointmentsVMForProviders({int? branchID, required AppointmentStatusEnum appointmentStatusEnum, bool isNeedCustomerFilter = false, bool shouldPopulateUpcoming = false}) async {
if (appointmentsFilterOptions.isEmpty) return;
for (var value in appointmentsFilterOptions) {
value.isSelected = false;
}
int index = appointmentsFilterOptions.indexWhere((element) => element.id == appointmentStatusEnum.getIdFromAppointmentStatusEnum());
appointmentsFilterOptions[index].isSelected = true;
for (var element in appointmentsFilterOptions) {
if (element.id == appointmentStatusEnum.getIdFromAppointmentStatusEnum()) {
element.isSelected = true;
}
isAppointmentLoading = true;
notifyListeners();
myFilteredAppointmentsForProvider = await getAppointmentsBasedOnFiltersForProviders(branchID: branchID ?? selectedBranchIdForAppointments, appointmentStatus: appointmentStatusEnum);
isAppointmentLoading = false;
if (shouldPopulateUpcoming) {
myUpComingAppointments = myFilteredAppointmentsForProvider
.where((element) =>
(element.appointmentStatusEnum == AppointmentStatusEnum.booked || element.appointmentStatusEnum == AppointmentStatusEnum.confirmed) &&
(DateHelper.parseStringToDate(element.appointmentDate!).isAfter(DateTime.now())))
.toList();
}
// appointmentsFilterOptions[
// appointmentStatusEnum.getIdFromAppointmentStatusEnum()]
// .isSelected = true;
if (appointmentStatusEnum == AppointmentStatusEnum.allAppointments) {
myFilteredAppointments = myAppointments;
if (isNeedCustomerFilter) findAppointmentsBasedOnCustomers(myFilteredAppointments);
notifyListeners();
return;
log("myUpComingAppointments: ${myUpComingAppointments.length}");
if (isNeedCustomerFilter) {
myFilteredAppointmentsForProvider = findAppointmentsBasedOnCustomers(myFilteredAppointmentsForProvider);
}
notifyListeners();
}
applyFilterOnAppointmentsVMForCustomers({required AppointmentStatusEnum appointmentStatusEnum, bool shouldPopulateUpcoming = false}) async {
log("appointmentsFilterOptions: ${appointmentsFilterOptions.isEmpty}");
if (appointmentsFilterOptions.isEmpty) return;
for (var value in appointmentsFilterOptions) {
value.isSelected = false;
}
int index = appointmentsFilterOptions.indexWhere((element) => element.id == appointmentStatusEnum.getIdFromAppointmentStatusEnum());
appointmentsFilterOptions[index].isSelected = true;
isAppointmentLoading = true;
notifyListeners();
myFilteredAppointmentsForCustomers = await getAppointmentsBasedOnFiltersForCustomer();
isAppointmentLoading = false;
if (shouldPopulateUpcoming) {
myUpComingAppointments = myFilteredAppointmentsForCustomers
.where((element) =>
(element.appointmentStatusEnum == AppointmentStatusEnum.booked || element.appointmentStatusEnum == AppointmentStatusEnum.confirmed) &&
(DateHelper.parseStringToDate(element.appointmentDate!).isAfter(DateTime.now())))
.toList();
}
myFilteredAppointments = myAppointments.where((element) => element.appointmentStatusID! == appointmentStatusEnum.getIdFromAppointmentStatusEnum()).toList();
if (isNeedCustomerFilter) findAppointmentsBasedOnCustomers(myFilteredAppointments);
notifyListeners();
}
findAppointmentsBasedOnCustomers(List<AppointmentListModel> appointments) {
// Use a Set to ensure uniqueness of customerIDs
List<AppointmentListModel> findAppointmentsBasedOnCustomers(List<AppointmentListModel> appointments) {
Set<int> uniqueCustomerIDs = <int>{};
// Extract unique customerIDs
for (var item in appointments) {
uniqueCustomerIDs.add(item.customerID ?? 0);
}
// Create a list of CustomerData instances
myFilteredAppointments2 = uniqueCustomerIDs.map((id) {
List<AppointmentListModel> groupedList = uniqueCustomerIDs.map((id) {
List<AppointmentListModel> list = appointments.where((item) => item.customerID == id).toList();
list.sort((a, b) => DateHelper.parseStringToDate(DateHelper.formatDateT(b.appointmentDate!))
.millisecondsSinceEpoch
@ -402,61 +424,16 @@ class AppointmentsVM extends BaseVM {
return model;
}).toList();
// customersAppointments = uniqueCustomerIDs.map((id) {
// List<AppointmentListModel> list = myFilteredAppointments
// .where((item) => item.customerID == id)
// .toList();
// var customerItem =
// myFilteredAppointments.firstWhere((item) => item.customerID == id);
//
// return CustomerData(
// customerID: id,
// customerName: customerItem.customerName ?? "",
// appointmentList: list,
// );
// }).toList();
}
// Future<void> getMyAppointments() async {
// setState(ViewState.busy);
//
// myAppointments =
// await appointmentRepo.getMyAppointmentsForCustomersByFilters();
// myFilteredAppointments = myAppointments;
// myUpComingAppointments = myAppointments
// .where((element) =>
// element.appointmentStatusEnum == AppointmentStatusEnum.booked)
// .toList();
// applyFilterOnAppointmentsVM(
// appointmentStatusEnum: AppointmentStatusEnum.allAppointments);
// if (myUpComingAppointments.isEmpty) {
// isShowEmptyMessage = true;
// }
// setState(ViewState.idle);
// notifyListeners();
// }
Future<void> getMyAppointmentsForCustomer({bool isNeedToRebuild = false}) async {
if (isNeedToRebuild) setState(ViewState.busy);
myAppointments = await appointmentRepo.getMyAppointmentsForCustomersByFilters();
// myFilteredAppointments = myAppointments;
setState(ViewState.idle);
applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.allAppointments);
myUpComingAppointments = myAppointments
.where((element) =>
(element.appointmentStatusEnum == AppointmentStatusEnum.booked || element.appointmentStatusEnum == AppointmentStatusEnum.confirmed) &&
(DateHelper.parseStringToDate(element.appointmentDate!).isAfter(DateTime.now())))
.toList();
notifyListeners();
return groupedList;
}
AppointmentSlots? appointmentSlots;
Future<void> getAppointmentSlotsInfo({required int branchID, required BuildContext context, bool isNeedToRebuild = false}) async {
if (isNeedToRebuild) setState(ViewState.busy);
bool isSlotsLoading = true;
Future<void> getAppointmentSlotsInfo({required int branchID}) async {
isSlotsLoading = true;
notifyListeners();
try {
GenericRespModel genericRespModel = await appointmentRepo.getAppointmentSlots(branchID: branchID, fromDate: selectedDateForAppointments, toDate: selectedDateForAppointments);
if (genericRespModel.messageStatus == 1) {
@ -464,25 +441,15 @@ class AppointmentsVM extends BaseVM {
} else {
Utils.showToast(genericRespModel.message.toString());
}
isSlotsLoading = false;
notifyListeners();
} catch (e) {
isSlotsLoading = false;
notifyListeners();
Utils.showToast(e.toString());
}
}
Future<void> getMyAppointmentsForProvider({required int branchID}) async {
setState(ViewState.busy);
myAppointments = await appointmentRepo.getMyAppointmentsForProvidersByFilters(branchID: branchID);
myFilteredAppointments = myAppointments;
myUpComingAppointments = myAppointments
.where((element) =>
(element.appointmentStatusEnum == AppointmentStatusEnum.confirmed || element.appointmentStatusEnum == AppointmentStatusEnum.booked) &&
(DateHelper.parseStringToDate(element.appointmentDate!).isAfter(DateTime.now())))
.toList();
notifyListeners();
applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.allAppointments, isNeedCustomerFilter: true);
setState(ViewState.idle);
}
Future<bool> updateAppointmentStatus({required int appointmentId, required AppointmentStatusEnum appointmentStatusEnum, bool isNeedToRebuild = false}) async {
if (isNeedToRebuild) setState(ViewState.busy);
try {
@ -520,8 +487,8 @@ class AppointmentsVM extends BaseVM {
}
bool isShowMergeButton() {
return myFilteredAppointments2[selectedAppointmentIndex].customerAppointmentList!.every((appointment) => appointment.appointmentStatusEnum == AppointmentStatusEnum.confirmed) &&
myFilteredAppointments2[selectedAppointmentIndex].customerAppointmentList!.length > 1;
return myFilteredAppointmentsForProvider[selectedAppointmentIndex].customerAppointmentList!.every((appointment) => appointment.appointmentStatusEnum == AppointmentStatusEnum.confirmed) &&
myFilteredAppointmentsForProvider[selectedAppointmentIndex].customerAppointmentList!.length > 1;
}
Future<GenericRespModel> createMergeAppointment(Map<String, dynamic> map, {bool isNeedToRebuild = false}) async {
@ -534,10 +501,10 @@ class AppointmentsVM extends BaseVM {
bool inNeedToEnableMergeButton = false;
void updateCheckBoxInMergeRequest(int currentIndex) {
myFilteredAppointments2[selectedAppointmentIndex].customerAppointmentList![currentIndex].isSelected =
!(myFilteredAppointments2[selectedAppointmentIndex].customerAppointmentList?[currentIndex].isSelected ?? false);
myFilteredAppointmentsForProvider[selectedAppointmentIndex].customerAppointmentList![currentIndex].isSelected =
!(myFilteredAppointmentsForProvider[selectedAppointmentIndex].customerAppointmentList?[currentIndex].isSelected ?? false);
int count = countSelected(myFilteredAppointments2[selectedAppointmentIndex].customerAppointmentList ?? []);
int count = countSelected(myFilteredAppointmentsForProvider[selectedAppointmentIndex].customerAppointmentList ?? []);
if (count > 1) {
inNeedToEnableMergeButton = true;
} else {
@ -917,9 +884,8 @@ class AppointmentsVM extends BaseVM {
}
if (genericRespModel.messageStatus == 1) {
context.read<DashboardVmCustomer>().onNavbarTapped(1);
applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.cancelled);
Utils.showToast(genericRespModel.message.toString());
getMyAppointmentsForCustomer();
applyFilterOnAppointmentsVMForCustomers(appointmentStatusEnum: AppointmentStatusEnum.cancelled);
Utils.hideLoading(context);
navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard);
}
@ -1011,6 +977,20 @@ class AppointmentsVM extends BaseVM {
}
}
Future<ProviderContactInfoModel?> getProvidersContactInfo({required int providerId, required BuildContext context}) async {
Utils.showLoading(context);
try {
ProviderContactInfoModel contactInfoModel = await commonRepo.getProvidersContactInfo(providerId: providerId);
Utils.hideLoading(context);
return contactInfoModel;
} catch (e, s) {
logger.e(s);
Utils.hideLoading(context);
Utils.showToast(e.toString());
return null;
}
}
// BRANCHES RELATED
List<BranchDetailModel> nearbyBranches = [];
@ -1827,105 +1807,120 @@ class AppointmentsVM extends BaseVM {
clearAppointmentFilterSelections();
if (AppState().currentAppType == AppType.provider) {
getMyAppointmentsForProvider(branchID: selectedBranchIdForAppointments);
applyFilterOnAppointmentsVMForProviders(appointmentStatusEnum: AppointmentStatusEnum.allAppointments, isNeedCustomerFilter: true);
} else {
getMyAppointmentsForCustomer();
applyFilterOnAppointmentsVMForCustomers(appointmentStatusEnum: AppointmentStatusEnum.allAppointments);
}
notifyListeners();
}
Future<void> getAppointmentsBasedOnFiltersForCustomer() async {
setState(ViewState.busy);
List<String> providersIdsList = [];
if (appointmentFilterProviderSearchHistory.isNotEmpty) {
for (var element in appointmentFilterProviderSearchHistory) {
providersIdsList.add(element.id.toString());
Future<List<AppointmentListModel>> getAppointmentsBasedOnFiltersForCustomer() async {
try {
setState(ViewState.busy);
List<String> providersIdsList = [];
if (appointmentFilterProviderSearchHistory.isNotEmpty) {
for (var element in appointmentFilterProviderSearchHistory) {
providersIdsList.add(element.id.toString());
}
}
}
List<String> categoryIdsList = [];
if (appointmentFilterCategorySearchHistory.isNotEmpty) {
for (var element in appointmentFilterCategorySearchHistory) {
categoryIdsList.add(element.id.toString());
List<String> categoryIdsList = [];
if (appointmentFilterCategorySearchHistory.isNotEmpty) {
for (var element in appointmentFilterCategorySearchHistory) {
categoryIdsList.add(element.id.toString());
}
}
}
List<String> servicesIdsList = [];
if (appointmentFilterServicesSearchHistory.isNotEmpty) {
for (var element in appointmentFilterServicesSearchHistory) {
servicesIdsList.add(element.id.toString());
List<String> servicesIdsList = [];
if (appointmentFilterServicesSearchHistory.isNotEmpty) {
for (var element in appointmentFilterServicesSearchHistory) {
servicesIdsList.add(element.id.toString());
}
}
}
List<String> itemIdsList = [];
if (appointmentFilterItemsSearchHistory.isNotEmpty) {
for (var element in appointmentFilterItemsSearchHistory) {
itemIdsList.add(element.id.toString());
List<String> itemIdsList = [];
if (appointmentFilterItemsSearchHistory.isNotEmpty) {
for (var element in appointmentFilterItemsSearchHistory) {
itemIdsList.add(element.id.toString());
}
}
}
List<String> branchesIdsList = [];
if (appointmentFilterBranchSearchHistory.isNotEmpty) {
for (var element in appointmentFilterBranchSearchHistory) {
branchesIdsList.add(element.id.toString());
List<String> branchesIdsList = [];
if (appointmentFilterBranchSearchHistory.isNotEmpty) {
for (var element in appointmentFilterBranchSearchHistory) {
branchesIdsList.add(element.id.toString());
}
}
}
myAppointments = await appointmentRepo.getMyAppointmentsForCustomersByFilters(
providerIdsList: providersIdsList,
categoryIdsList: categoryIdsList,
serviceIdsList: servicesIdsList,
itemIdsList: itemIdsList,
branchIdsList: branchesIdsList,
);
applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.allAppointments);
setState(ViewState.idle);
List<AppointmentListModel> myAppointments = await appointmentRepo.getMyAppointmentsForCustomersByFilters(
providerIdsList: providersIdsList,
categoryIdsList: categoryIdsList,
serviceIdsList: servicesIdsList,
itemIdsList: itemIdsList,
branchIdsList: branchesIdsList,
);
setState(ViewState.idle);
return myAppointments;
} catch (e) {
logger.e(e);
setState(ViewState.idle);
Utils.showToast(e.toString());
return [];
}
}
String selectedDateForAppointments = "";
Future<void> getAppointmentsBasedOnFiltersForProviders({required int branchID}) async {
setState(ViewState.busy);
List<String> servicesIdsList = [];
if (appointmentFilterServicesSearchHistory.isNotEmpty) {
for (var element in appointmentFilterServicesSearchHistory) {
servicesIdsList.add(element.id.toString());
Future<List<AppointmentListModel>> getAppointmentsBasedOnFiltersForProviders({required int branchID, AppointmentStatusEnum? appointmentStatus}) async {
try {
setState(ViewState.busy);
List<String> servicesIdsList = [];
if (appointmentFilterServicesSearchHistory.isNotEmpty) {
for (var element in appointmentFilterServicesSearchHistory) {
servicesIdsList.add(element.id.toString());
}
}
}
List<String> customerNamesList = [];
if (appointmentFilterCustomerNameSearchHistory.isNotEmpty) {
for (var element in appointmentFilterCustomerNameSearchHistory) {
customerNamesList.add(element.toString());
List<String> customerNamesList = [];
if (appointmentFilterCustomerNameSearchHistory.isNotEmpty) {
for (var element in appointmentFilterCustomerNameSearchHistory) {
customerNamesList.add(element.toString());
}
}
}
List<String> customerPhonesList = [];
if (appointmentFilterMobilePhoneSearchHistory.isNotEmpty) {
for (var element in appointmentFilterMobilePhoneSearchHistory) {
customerPhonesList.add(element.toString());
List<String> customerPhonesList = [];
if (appointmentFilterMobilePhoneSearchHistory.isNotEmpty) {
for (var element in appointmentFilterMobilePhoneSearchHistory) {
customerPhonesList.add(element.toString());
}
}
}
List<String> customerDeliveryTypesList = [];
if (appointmentFilterServiceDeliverySearchHistory.isNotEmpty) {
for (var element in appointmentFilterServiceDeliverySearchHistory) {
customerDeliveryTypesList.add(element.id.toString());
List<String> customerDeliveryTypesList = [];
if (appointmentFilterServiceDeliverySearchHistory.isNotEmpty) {
for (var element in appointmentFilterServiceDeliverySearchHistory) {
customerDeliveryTypesList.add(element.id.toString());
}
}
}
log("customerNamesList: $customerNamesList");
log("customerPhonesList: $customerPhonesList");
log("customerDeliveryTypesList: $customerDeliveryTypesList");
log("servicesIdsList: $servicesIdsList");
myAppointments = await appointmentRepo.getMyAppointmentsForProvidersByFilters(
branchID: branchID,
customerNamesList: customerNamesList,
customerPhonesList: customerPhonesList,
deliveryTypeIdsList: customerDeliveryTypesList,
serviceProviderServiceIdsList: servicesIdsList,
fromDate: '',
toDate: '');
log(" myFilteredAppointments : ${myFilteredAppointments.length}");
applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.allAppointments, isNeedCustomerFilter: true);
setState(ViewState.idle);
log("customerNamesList: $customerNamesList");
log("customerPhonesList: $customerPhonesList");
log("customerDeliveryTypesList: $customerDeliveryTypesList");
log("servicesIdsList: $servicesIdsList");
List<AppointmentListModel> myAppointments = await appointmentRepo.getMyAppointmentsForProvidersByFilters(
branchID: branchID,
customerNamesList: customerNamesList,
customerPhonesList: customerPhonesList,
deliveryTypeIdsList: customerDeliveryTypesList,
serviceProviderServiceIdsList: servicesIdsList,
appointmentStatusEnum: appointmentStatus,
fromDate: '',
toDate: '');
setState(ViewState.idle);
return myAppointments ?? [];
} catch (e) {
logger.e(e);
setState(ViewState.idle);
Utils.showToast(e.toString());
return [];
}
}
Future<bool> addProviderToFavorite({required int serviceProviderID, required BuildContext context}) async {

@ -67,7 +67,7 @@ class DashboardVmCustomer extends BaseVM {
appointmentsVM.populateAppointmentsFilterList();
adVM.populateAdsFilterList();
requestsVM.populateDataForRequestsFilter();
await appointmentsVM.getMyAppointmentsForCustomer();
await appointmentsVM.applyFilterOnAppointmentsVMForCustomers(appointmentStatusEnum: AppointmentStatusEnum.allAppointments, shouldPopulateUpcoming: true);
await appointmentsVM.applyFilterOnBranches(index: 0); // to get all branches!
await appointmentsVM.getMyRecentBranches(); // to get my recent branches

@ -82,14 +82,13 @@ class DashboardVMProvider extends BaseVM {
appointmentVM.populateAppointmentsFilterList();
shippingManagementVM.populateShippingRequestFilterList();
await serviceVM.populateBranchServiceFilters();
await serviceVM.getBranchAndServices();
if (dashboardRouteEnum != DashboardRouteEnum.fromAdsPayment && dashboardRouteEnum != DashboardRouteEnum.fromAdsSubmit) {
await adVM.getMyAds();
await adVM.getExploreAds();
}
await appointmentVM.getMyAppointmentsForProvider(branchID: appointmentVM.selectedBranchIdForAppointments);
await appointmentVM.applyFilterOnAppointmentsVMForProviders(appointmentStatusEnum: AppointmentStatusEnum.allAppointments, shouldPopulateUpcoming: true);
adVM.populateAdsFilterList();
await requestsVM.getRequests();
await subscriptionsVM.getSubscriptionBySP(AppState().getUser.data?.userInfo?.providerId.toString() ?? "", true);
@ -130,7 +129,7 @@ class DashboardVMProvider extends BaseVM {
void performCheckOnUsers(BuildContext context, Function() callBack) async {
if (AppState().getproviderSubscription.isNotEmpty && AppState().getproviderSubscription.first.subUsersRemaining! > 0) {
showMyBottomSheet(context, isDismissible: false, isScrollControlled: true, child: AddPhoneNumWidget(), callBackFunc: callBack);
showMyBottomSheet(context, isDismissible: false, isScrollControlled: true, child: AddPhoneNumWidget(), callBackFunc: callBack);
} else {
Utils.showToast(LocaleKeys.upgradeSubUsers.tr());
}

@ -275,7 +275,11 @@ class ServiceVM extends BaseVM {
context,
allowMultiple: false,
);
if (files != null && files.any((element) => element.path.split('.').last.toLowerCase() != 'pdf')) {
if (files != null && files.any((element) =>
element.path
.split('.')
.last
.toLowerCase() != 'pdf')) {
Utils.showToast("Only PDF Files are allowed");
return;
}
@ -339,6 +343,67 @@ class ServiceVM extends BaseVM {
return await branchRepo.serviceProviderDocumentsUpdate(data);
}
bool customServiceEnabledStatus = false;
void updateCustomServiceEnabledStatus(bool status) {
customServiceEnabledStatus = status;
notifyListeners();
}
String customServiceTitle = "";
void updateCustomServiceTitle(String title) {
customServiceTitle = title;
}
String customServicePrice = "";
void updateCustomServicePrice(String title) {
customServicePrice = title;
}
String customerServiceTax = "15";
void updateCustomerServiceTax(String title) {
customerServiceTax = title;
}
resetCustomServiceForm() {
customServiceTitle = "";
customServicePrice = "";
customerServiceTax = "15";
}
String customServiceTitleError = "";
String customServicePriceError = "";
String customerServiceTaxError = "";
bool isCustomServiceDetailValidated() {
bool isValidated = true;
if (customServiceTitle.isEmpty) {
customServiceTitleError = GlobalConsts.serviceNameError;
isValidated = false;
notifyListeners();
return isValidated;
} else {
customServiceTitleError = "";
}
if (customServicePrice.isEmpty) {
customServicePriceError = GlobalConsts.priceError;
isValidated = false;
} else {
customServicePriceError = "";
}
if (customerServiceTax.isEmpty) {
customerServiceTaxError = GlobalConsts.taxError;
isValidated = false;
} else {
customerServiceTaxError = "";
}
notifyListeners();
return isValidated;
}
// Create new branch
Future<void> getBranchAndServices() async {
setState(ViewState.busy);
@ -466,10 +531,10 @@ class ServiceVM extends BaseVM {
DropValue(
element.id ?? 0,
((element.categoryName!.isEmpty
? "N/A"
: countryCode == "SA"
? element.categoryNameN
: element.categoryName) ??
? "N/A"
: countryCode == "SA"
? element.categoryNameN
: element.categoryName) ??
"N/A"),
"",
),
@ -527,18 +592,23 @@ class ServiceVM extends BaseVM {
Future<GenericRespModel> createService(List<Map<String, dynamic>> map) async {
setState(ViewState.busy);
return await branchRepo.createService(map);
GenericRespModel response = await branchRepo.createService(map);
setState(ViewState.idle);
return response;
}
Future<GenericRespModel> updateServices(List<Map<String, dynamic>> map) async {
return await branchRepo.updateService(map);
}
Future<List<AppointmentBasicDetailsModel>> getAppointmentsByServiceID({required BuildContext context, required int branchId, required int serviceId}) async {
Future<List<AppointmentBasicDetailsModel>> getAppointmentsByCategoryOrService({required BuildContext context, required int branchId, required int categoryId, required int serviceId}) async {
try {
Utils.showLoading(context);
List<AppointmentBasicDetailsModel> appointmentList = await branchRepo.getAppointmentsByCategoryOrService(branchId: branchId, serviceId: serviceId);
List<AppointmentBasicDetailsModel> appointmentList = await branchRepo.getAppointmentsByCategoryOrService(
branchId: branchId,
serviceId: serviceId,
categoryId: categoryId,
);
// log("list: ${mResponse.}");
Utils.hideLoading(context);
@ -585,7 +655,8 @@ class ServiceVM extends BaseVM {
}
}
Future buildDealNotCompletedBottomSheetOptions({required BuildContext mainContext, required List<AppointmentBasicDetailsModel> appointments, required String branchName}) async {
Future cannotDeactivateServiceOrCategoryBottomSheet(
{required BuildContext mainContext, required List<AppointmentBasicDetailsModel> appointments, required String branchName, required bool isService}) async {
return actionConfirmationBottomSheet(
isOnlyOneButton: true,
context: mainContext,
@ -770,7 +841,9 @@ class ServiceVM extends BaseVM {
File file = File(imageModel.filePath!);
List<int> imageBytes = await file.readAsBytes();
String image = base64Encode(imageBytes);
String fileName = file.path.split('/').last;
String fileName = file.path
.split('/')
.last;
branchPostingImages = BranchPostingImages(
imageName: fileName,
imageStr: image,

@ -4,6 +4,7 @@ import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/main.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/setting_utils_models/app_info_model.dart';
import 'package:mc_common_app/models/setting_utils_models/app_invitation_history_model.dart';
import 'package:mc_common_app/models/setting_utils_models/contact_infos_model.dart';
import 'package:mc_common_app/models/setting_utils_models/faqs_model.dart';
import 'package:mc_common_app/repositories/setting_options_repo.dart';
@ -82,11 +83,20 @@ class SettingOptionsVM extends BaseVM {
try {
GenericRespModel respModel = await settingOptionsRepo.appInvitationCreate(channelId: inviteTypeEnum.toIntFromEnum(), message: GlobalConsts.getAppInvitationLink());
await Utils.inviteFriend(inviteTypeEnum: inviteTypeEnum, message: GlobalConsts.getAppInvitationLink());
Utils.hideLoading(context);
} catch (e) {
logger.i(e.toString());
Utils.hideLoading(context);
}
}
List<AppInvitationHistoryModel> appInvitationHistoryList = [];
Future<void> getAppInvitationHistoryList() async {
try {
appInvitationHistoryList = await settingOptionsRepo.getAppInvitationsHistory();
} catch (e) {
logger.i(e.toString());
}
}
}

@ -10,7 +10,7 @@ class DottedRoundedCard extends StatelessWidget {
final String text;
final Widget icon;
const DottedRoundedCard({Key? key, required this.onTap, required this.text, required this.icon}) : super(key: key);
const DottedRoundedCard({super.key, required this.onTap, required this.text, required this.icon});
@override
Widget build(BuildContext context) {
@ -48,44 +48,47 @@ class DottedRectContainer extends StatelessWidget {
final Widget icon;
final String extensions;
const DottedRectContainer({Key? key, required this.onTap, required this.text, required this.icon, required this.extensions}) : super(key: key);
const DottedRectContainer({super.key, required this.onTap, required this.text, required this.icon, required this.extensions});
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onTap,
child: Column(
children: [
DashedRect(
color: MyColors.lightIconColor,
strokeWidth: 2.0,
gap: 4.0,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
child: Container(
constraints: const BoxConstraints(minHeight: 60),
child: Column(
children: [
DashedRect(
color: MyColors.lightIconColor,
strokeWidth: 2.0,
gap: 4.0,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
icon,
const SizedBox(width: 8),
text
.toText(
fontSize: 15,
isBold: true,
color: MyColors.darkPrimaryColor,
)
.paddingAll(10),
],
),
),
8.height,
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
icon,
const SizedBox(width: 8),
text
.toText(
fontSize: 15,
isBold: true,
color: MyColors.darkPrimaryColor,
)
.paddingAll(6),
"( $extensions )".toText(
fontSize: 8,
color: MyColors.lightTextColor,
),
],
),
),
8.height,
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
"( $extensions )".toText(
fontSize: 8,
color: MyColors.lightTextColor,
),
],
)
],
)
],
),
),
);
}

@ -6,6 +6,7 @@ import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/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/utils.dart';
@ -22,6 +23,7 @@ class AdDuration extends StatelessWidget {
const AdDuration({super.key});
void onAddSpecialServiceButtonTapped(BuildContext context, AdVM adVM) {
adVM.updateSelectedVehicleAdsSpecialServicesId(SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""));
showModalBottomSheet(
context: context,
isScrollControlled: true,
@ -72,10 +74,7 @@ class AdDuration extends StatelessWidget {
value: adVM.vehicleAdDurationId.selectedOption,
isNeedClickAll: true,
postFixDataColor: MyColors.darkTextColor,
onTap: () async {
final formattedDate = await Utils.pickDateFromDatePicker(context);
adVM.updateSelectionDurationStartDate(formattedDate);
},
onTap: () {},
),
],
// Builder(builder: (context) {

@ -26,10 +26,31 @@ class VehicleDetails extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Consumer(builder: (BuildContext context, AdVM adVM, Widget? child) {
String roleAppState = "";
String roleName = "";
if (AppState().getUser.data!.userInfo != null) {
roleAppState = AppState().getUser.data!.userInfo!.roleName ?? "";
List list = roleAppState.split('_');
if (list.length > 1) {
roleName = list[1];
}
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.vehicleDetail.tr().toText(fontSize: 18, isBold: true),
if (AppState().currentAppType == AppType.provider && roleName.isNotEmpty) ...[
8.height,
TxtField(
value: roleName,
isBackgroundEnabled: true,
isNeedClickAll: true,
hint: '',
onTap: () {},
),
],
8.height,
Builder(
builder: (context) {
@ -56,40 +77,32 @@ class VehicleDetails extends StatelessWidget {
).paddingAll(10),
] else ...[
8.height,
if (AppState().currentAppType == AppType.provider) ...[
Builder(builder: (context) {
List<DropValue> vehicleSellerTypesDrop = [];
for (var element in adVM.vehicleSellerTypes) {
log("${element.id} : ${element.sellerType}");
vehicleSellerTypesDrop.add(DropValue(element.id?.toInt() ?? 0, element.sellerType ?? "", ""));
}
DropValue? model;
int index = -1;
if (AppState().userType == UserType.providerDealer) {
index = vehicleSellerTypesDrop.indexWhere((element) => element.id == GlobalConsts.providerDealerRoleTypeId);
} else {
index = vehicleSellerTypesDrop.indexWhere((element) => element.id == GlobalConsts.providerIndividualRoleTypeId);
}
if (index == -1) {
model = vehicleSellerTypesDrop.first;
} else {
model = vehicleSellerTypesDrop[index];
}
adVM.updateSelectionVehicleSellerTypeId(SelectionModel(selectedId: model.id, selectedOption: model.value), needRefresh: false);
return DropdownField(
(DropValue value) => adVM.updateSelectionVehicleSellerTypeId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
isSelectAble: false,
list: vehicleSellerTypesDrop,
dropdownValue: adVM.vehicleSellerTypeId.selectedId != -1 ? DropValue(adVM.vehicleSellerTypeId.selectedId, adVM.vehicleSellerTypeId.selectedOption, "") : null,
hint: LocaleKeys.vehicleSellerType.tr(),
errorValue: adVM.vehicleSellerTypeId.errorValue,
);
}),
8.height,
],
// if (AppState().currentAppType == AppType.provider) ...[
// Builder(builder: (context) {
// List<DropValue> vehicleSellerTypesDrop = [];
// for (var element in adVM.vehicleSellerTypes) {
// log("${element.id} : ${element.sellerType}");
// vehicleSellerTypesDrop.add(DropValue(element.id?.toInt() ?? 0, element.sellerType ?? "", ""));
// }
//
// adVM.updateSelectionVehicleSellerTypeId(
// SelectionModel(
// selectedId: AppState().getUser.data!.userInfo!.roleId ?? GlobalConsts.providerIndividualRoleTypeId,
// selectedOption: AppState().getUser.data!.userInfo!.roleName ?? "",
// ),
// needRefresh: false);
//
// return DropdownField(
// (DropValue value) => adVM.updateSelectionVehicleSellerTypeId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
// isSelectAble: false,
// list: vehicleSellerTypesDrop,
// dropdownValue: adVM.vehicleSellerTypeId.selectedId != -1 ? DropValue(adVM.vehicleSellerTypeId.selectedId, adVM.vehicleSellerTypeId.selectedOption, "") : null,
// hint: LocaleKeys.vehicleSellerType.tr(),
// errorValue: adVM.vehicleSellerTypeId.errorValue,
// );
// }),
// 8.height,
// ],
Builder(builder: (context) {
List<DropValue> vehicleModelsDrop = [];
for (var element in adVM.vehicleModels) {

@ -364,7 +364,9 @@ class _AdsDetailViewState extends State<AdsDetailView> {
endDate.isNotEmpty ? endDate.toText(fontSize: 10) : const SizedBox(),
],
),
(LocaleKeys.extendAd.tr()).toText(fontSize: 12, color: MyColors.darkPrimaryColor, isUnderLine: true).onPress(() async => await onExtendAdPressed()),
if (widget.adDetails.adPostStatus == AdPostStatus.active || widget.adDetails.adPostStatus == AdPostStatus.expired) ...[
(LocaleKeys.extendAd.tr()).toText(fontSize: 12, color: MyColors.darkPrimaryColor, isUnderLine: true).onPress(() async => await onExtendAdPressed()),
],
],
),
],

@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
@ -275,8 +276,13 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget {
void onBookPhotographyServiceClicked(BuildContext context, {required AdDetailsModel adDetailsModel}) async {
AdVM adVM = context.read<AdVM>();
log("adDetailsModel.vehicle!.cityID: ${adDetailsModel.vehicle!.cityID}");
if (adVM.photoOfficeSelectedId.selectedId == -1) {
adVM.getPhotographyServiceScheduleListByOffices(latitude: AppState().currentLocation.latitude, longitude: AppState().currentLocation.longitude, isNeedToRebuild: true);
adVM.getPhotographyServiceScheduleListByOffices(
cityId: adDetailsModel.vehicle!.cityID ?? AppState().getUser.data!.userInfo!.cityId ?? 0,
latitude: AppState().currentLocation.latitude,
longitude: AppState().currentLocation.longitude,
isNeedToRebuild: true);
}
return showModalBottomSheet(
@ -716,7 +722,11 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget {
title: LocaleKeys.yes.tr(),
fontSize: 15,
onPressed: () {
adVM.deactivateTheAd(context, adId: adDetailsModel.id!, comment: comments);
if (adVM.selectedDeActivateAdCommentModel.index == 0) {
adVM.markAdAsSold(context, adId: adDetailsModel.id!);
} else {
adVM.deactivateTheAd(context, adId: adDetailsModel.id!, comment: comments);
}
},
),
),

@ -1,4 +1,7 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
@ -10,6 +13,7 @@ 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/time_slots.dart';
import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart';
import 'package:mc_common_app/widgets/empty_widget.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';
@ -177,170 +181,186 @@ class BottomSheetAdSpecialServiceContent extends StatelessWidget {
builder: (BuildContext context, AdVM adVM, Widget? child) {
return SizedBox(
height: MediaQuery.of(context).size.height * 0.7,
child: Column(
children: [
Container(
margin: const EdgeInsets.all(8),
height: 8,
width: 60,
decoration: const BoxDecoration(color: MyColors.lightTextColor, borderRadius: BorderRadius.all(Radius.circular(20))),
),
12.height,
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
child: adVM.vehicleAdsSpecialServices.isEmpty
? Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.addSpecialService.tr().toText(fontSize: 24, isBold: true),
8.height,
Builder(
builder: (context) {
List<DropValue> vehicleAdsSpecialServices = [];
for (var element in adVM.vehicleAdsSpecialServices) {
if (!element.isSelected!) {
vehicleAdsSpecialServices.add(DropValue(element.id?.toInt() ?? 0, element.name ?? "", element.price == null ? "" : element.price!.toInt().toString()));
}
}
return DropdownField(
(DropValue value) => adVM.updateSelectedVehicleAdsSpecialServicesId(SelectionModel(selectedId: value.id, selectedOption: value.value, itemPrice: value.subValue)),
list: vehicleAdsSpecialServices,
hint: LocaleKeys.selectService.tr(),
dropdownValue: adVM.selectedVehicleAdsSpecialServicesId.selectedId != -1 ? DropValue(adVM.selectedVehicleAdsSpecialServicesId.selectedId, adVM.selectedVehicleAdsSpecialServicesId.selectedOption, "") : null,
);
},
Container(
margin: const EdgeInsets.all(8),
height: 8,
width: 60,
decoration: const BoxDecoration(color: MyColors.lightTextColor, borderRadius: BorderRadius.all(Radius.circular(20))),
),
if (adVM.selectedVehicleAdsSpecialServicesId.selectedId != -1) ...[
if (adVM.isFetchingLists) ...[
Center(child: const CircularProgressIndicator().paddingAll(20)),
] else ...[
8.height,
if ((adVM.selectedVehicleAdsSpecialServicesId.selectedId == 1 && adVM.ssPhotoScheduleModel != null)) ...[
// Builder(
// builder: (context) {
// List<DropValue> vehicleAdsSpecialServiceDates = adVM.populateScheduleDatesForAdPhotoService();
//
// return DropdownField(
// (DropValue value) => adVM.updateVehicleVehicleAdsPhotoServiceDate(SelectionModel(
// selectedId: value.id,
// selectedOption: value.value,
// )),
// list: vehicleAdsSpecialServiceDates,
// hint: "Select Date",
// dropdownValue: adVM.vehicleAdsPhotoServiceDate.selectedId != -1
// ? DropValue(
// adVM.vehicleAdsPhotoServiceDate.selectedId,
// adVM.vehicleAdsPhotoServiceDate.selectedOption,
// "",
// )
// : null,
// );
// },
// ),
// 22.height,
] else if ((adVM.selectedVehicleAdsSpecialServicesId.selectedId == 3 && adVM.ssCarCheckScheduleModel != null)) ...[
// Builder(
// builder: (context) {
// List<DropValue> vehicleAdsSpecialServiceDates = adVM.populateScheduleDatesForAdCarCheckService();
//
// return DropdownField(
// (DropValue value) => adVM.updateVehicleAdsCarCheckServicesDate(SelectionModel(
// selectedId: value.id,
// selectedOption: value.value,
// )),
// list: vehicleAdsSpecialServiceDates,
// hint: "Select Date",
// dropdownValue: adVM.vehicleAdsCarCheckServicesDate.selectedId != -1
// ? DropValue(
// adVM.vehicleAdsCarCheckServicesDate.selectedId,
// adVM.vehicleAdsCarCheckServicesDate.selectedOption,
// "",
// )
// : null,
// );
// },
// ),
// 22.height,
],
if (adVM.selectedVehicleAdsSpecialServicesId.selectedId != 3 && adVM.selectedVehicleAdsSpecialServicesId.selectedId != 1) ...[
descriptionCard(
description: adVM.vehicleAdsSpecialServices.firstWhere((element) => element.id == adVM.selectedVehicleAdsSpecialServicesId.selectedId).description ?? "",
),
],
if (adVM.adSSTimeSlots.isNotEmpty) ...[
LocaleKeys.availableSlots.tr().toText(fontSize: 15, isBold: true),
Center(child: LocaleKeys.noSpecialServicesAvailable.tr().toText(fontSize: 18, color: MyColors.lightTextColor, fontWeight: MyFonts.Medium)).paddingAll(30),
const SizedBox(),
],
)
: Column(
children: [
Container(
margin: const EdgeInsets.all(8),
height: 8,
width: 60,
decoration: const BoxDecoration(color: MyColors.lightTextColor, borderRadius: BorderRadius.all(Radius.circular(20))),
),
12.height,
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.addSpecialService.tr().toText(fontSize: 24, isBold: true),
8.height,
BuildTimeSlots(
timeSlots: adVM.adSSTimeSlots,
onPressed: (index) => adVM.updateIsSelectedInSlots(index),
Builder(
builder: (context) {
List<DropValue> vehicleAdsSpecialServices = [];
for (var element in adVM.vehicleAdsSpecialServices) {
if (!element.isSelected!) {
vehicleAdsSpecialServices.add(DropValue(element.id?.toInt() ?? 0, element.name ?? "", element.price == null ? "" : element.price!.toInt().toString()));
}
}
return DropdownField(
(DropValue value) => adVM.updateSelectedVehicleAdsSpecialServicesId(SelectionModel(selectedId: value.id, selectedOption: value.value, itemPrice: value.subValue)),
list: vehicleAdsSpecialServices,
hint: LocaleKeys.selectService.tr(),
dropdownValue: adVM.selectedVehicleAdsSpecialServicesId.selectedId != -1
? DropValue(adVM.selectedVehicleAdsSpecialServicesId.selectedId, adVM.selectedVehicleAdsSpecialServicesId.selectedOption, "")
: null,
);
},
),
],
22.height,
LocaleKeys.serviceAmount.tr().toText(fontSize: 16, isBold: true, color: MyColors.lightTextColor),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
adVM.selectedVehicleAdsSpecialServicesId.itemPrice.toText(fontSize: 20, isBold: true),
SizedBox(width: 1.w),
LocaleKeys.sar.tr().toText(fontSize: 12, isBold: true, color: MyColors.lightTextColor).paddingOnly(bottom: 2),
if (adVM.selectedVehicleAdsSpecialServicesId.selectedId != -1) ...[
if (adVM.isFetchingLists) ...[
Center(child: const CircularProgressIndicator().paddingAll(20)),
] else ...[
8.height,
if ((adVM.selectedVehicleAdsSpecialServicesId.selectedId == 1 && adVM.ssPhotoScheduleModel != null)) ...[
// Builder(
// builder: (context) {
// List<DropValue> vehicleAdsSpecialServiceDates = adVM.populateScheduleDatesForAdPhotoService();
//
// return DropdownField(
// (DropValue value) => adVM.updateVehicleVehicleAdsPhotoServiceDate(SelectionModel(
// selectedId: value.id,
// selectedOption: value.value,
// )),
// list: vehicleAdsSpecialServiceDates,
// hint: "Select Date",
// dropdownValue: adVM.vehicleAdsPhotoServiceDate.selectedId != -1
// ? DropValue(
// adVM.vehicleAdsPhotoServiceDate.selectedId,
// adVM.vehicleAdsPhotoServiceDate.selectedOption,
// "",
// )
// : null,
// );
// },
// ),
// 22.height,
] else if ((adVM.selectedVehicleAdsSpecialServicesId.selectedId == 3 && adVM.ssCarCheckScheduleModel != null)) ...[
// Builder(
// builder: (context) {
// List<DropValue> vehicleAdsSpecialServiceDates = adVM.populateScheduleDatesForAdCarCheckService();
//
// return DropdownField(
// (DropValue value) => adVM.updateVehicleAdsCarCheckServicesDate(SelectionModel(
// selectedId: value.id,
// selectedOption: value.value,
// )),
// list: vehicleAdsSpecialServiceDates,
// hint: "Select Date",
// dropdownValue: adVM.vehicleAdsCarCheckServicesDate.selectedId != -1
// ? DropValue(
// adVM.vehicleAdsCarCheckServicesDate.selectedId,
// adVM.vehicleAdsCarCheckServicesDate.selectedOption,
// "",
// )
// : null,
// );
// },
// ),
// 22.height,
],
if (adVM.selectedVehicleAdsSpecialServicesId.selectedId != 3 && adVM.selectedVehicleAdsSpecialServicesId.selectedId != 1) ...[
descriptionCard(
description: adVM.vehicleAdsSpecialServices.firstWhere((element) => element.id == adVM.selectedVehicleAdsSpecialServicesId.selectedId).description ?? "",
),
],
if (adVM.adSSTimeSlots.isNotEmpty) ...[
LocaleKeys.availableSlots.tr().toText(fontSize: 15, isBold: true),
8.height,
BuildTimeSlots(
timeSlots: adVM.adSSTimeSlots,
onPressed: (index) => adVM.updateIsSelectedInSlots(index),
),
],
22.height,
LocaleKeys.serviceAmount.tr().toText(fontSize: 16, isBold: true, color: MyColors.lightTextColor),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
adVM.selectedVehicleAdsSpecialServicesId.itemPrice.toText(fontSize: 20, isBold: true),
SizedBox(width: 1.w),
LocaleKeys.sar.tr().toText(fontSize: 12, isBold: true, color: MyColors.lightTextColor).paddingOnly(bottom: 2),
],
),
],
],
),
],
],
],
),
),
SizedBox(
width: double.infinity,
child: ShowFillButton(
backgroundColor: !isButtonTappable(adVM) ? MyColors.lightTextColor.withOpacity(0.6) : MyColors.darkPrimaryColor,
title: LocaleKeys.addService.tr(),
onPressed: () {
if (!isButtonTappable(adVM)) {
return;
}
Navigator.pop(context);
adVM.addNewSpecialServiceCard(
specialServiceCard: SpecialServiceCard(
serviceSelectedId: adVM.selectedVehicleAdsSpecialServicesId,
description: adVM.vehicleAdsSpecialServices.firstWhere((element) => element.id == adVM.selectedVehicleAdsSpecialServicesId.selectedId).description ?? "",
duration: "",
serviceDate: "",
serviceDateError: "",
serviceTimeError: "",
address: "",
serviceTime: "",
],
),
);
),
SizedBox(
width: double.infinity,
child: ShowFillButton(
backgroundColor: !isButtonTappable(adVM) ? MyColors.lightTextColor.withOpacity(0.6) : MyColors.darkPrimaryColor,
title: LocaleKeys.addService.tr(),
onPressed: () {
if (!isButtonTappable(adVM)) {
return;
}
Navigator.pop(context);
// adVM.addNewSpecialServiceCard(
// specialServiceCard: SpecialServiceCard(
// serviceDate: adVM.vehicleAdsSpecialServicesId.selectedId == 1
// ? adVM.vehicleAdsPhotoServiceDate.selectedOption
// : adVM.vehicleAdsSpecialServicesId.selectedId == 3
// ? adVM.vehicleAdsCarCheckServicesDate.selectedOption
// : "",
// serviceDateError: "",
// serviceSelectedId: adVM.vehicleAdsSpecialServicesId,
// serviceTimeError: "",
// description: adVM.vehicleAdsSpecialServices.firstWhere((element) => element.id == adVM.vehicleAdsSpecialServicesId.selectedId).description ?? "",
// duration: adVM.vehicleAdsSpecialServicesId.selectedId == 1
// ? adVM.ssPhotoScheduleModel!.distanceKM.toString()
// : adVM.vehicleAdsSpecialServicesId.selectedId == 3
// ? adVM.ssCarCheckScheduleModel!.distanceKM.toString()
// : "",
// address: adVM.vehicleAdsSpecialServicesId.selectedId == 1
// ? "${adVM.ssPhotoScheduleModel!.photoOfficeName} - ${adVM.ssPhotoScheduleModel!.areaName}"
// : adVM.vehicleAdsSpecialServicesId.selectedId == 3
// ? adVM.ssCarCheckScheduleModel!.address
// : "",
// serviceTime: adVM.slotSelectedIndex == null || adVM.adSSTimeSlots.isEmpty ? "" : adVM.adSSTimeSlots[adVM.slotSelectedIndex!].slot,
// ),
// );
},
).paddingOnly(bottom: 10),
),
],
).horPaddingMain(),
adVM.addNewSpecialServiceCard(
specialServiceCard: SpecialServiceCard(
serviceSelectedId: adVM.selectedVehicleAdsSpecialServicesId,
description: adVM.vehicleAdsSpecialServices.firstWhere((element) => element.id == adVM.selectedVehicleAdsSpecialServicesId.selectedId).description ?? "",
duration: "",
serviceDate: "",
serviceDateError: "",
serviceTimeError: "",
address: "",
serviceTime: "",
),
);
// adVM.addNewSpecialServiceCard(
// specialServiceCard: SpecialServiceCard(
// serviceDate: adVM.vehicleAdsSpecialServicesId.selectedId == 1
// ? adVM.vehicleAdsPhotoServiceDate.selectedOption
// : adVM.vehicleAdsSpecialServicesId.selectedId == 3
// ? adVM.vehicleAdsCarCheckServicesDate.selectedOption
// : "",
// serviceDateError: "",
// serviceSelectedId: adVM.vehicleAdsSpecialServicesId,
// serviceTimeError: "",
// description: adVM.vehicleAdsSpecialServices.firstWhere((element) => element.id == adVM.vehicleAdsSpecialServicesId.selectedId).description ?? "",
// duration: adVM.vehicleAdsSpecialServicesId.selectedId == 1
// ? adVM.ssPhotoScheduleModel!.distanceKM.toString()
// : adVM.vehicleAdsSpecialServicesId.selectedId == 3
// ? adVM.ssCarCheckScheduleModel!.distanceKM.toString()
// : "",
// address: adVM.vehicleAdsSpecialServicesId.selectedId == 1
// ? "${adVM.ssPhotoScheduleModel!.photoOfficeName} - ${adVM.ssPhotoScheduleModel!.areaName}"
// : adVM.vehicleAdsSpecialServicesId.selectedId == 3
// ? adVM.ssCarCheckScheduleModel!.address
// : "",
// serviceTime: adVM.slotSelectedIndex == null || adVM.adSSTimeSlots.isEmpty ? "" : adVM.adSSTimeSlots[adVM.slotSelectedIndex!].slot,
// ),
// );
},
).paddingOnly(bottom: 10),
),
],
).horPaddingMain(),
);
},
);

@ -37,7 +37,6 @@ class _AdDamagePartPicturesSheetState extends State<AdDamagePartPicturesSheet> {
void populateDamagePartPictures() {
for (var element in widget.adDamageReportList) {
ImageModel imageModel = ImageModel(id: element.id!, filePath: element.imageUrl!, isFromNetwork: true);
VehicleDamageCard vehicleDamageCard = VehicleDamageCard(
partSelectedId: SelectionModel(
selectedId: element.vehicleDamagePartID!,
@ -46,7 +45,16 @@ class _AdDamagePartPicturesSheetState extends State<AdDamagePartPicturesSheet> {
damagePartDescription: element.comment ?? "",
partImages: [imageModel],
);
vehicleDamageCards.add(vehicleDamageCard);
int index = vehicleDamageCards.indexWhere((card) => card.partSelectedId!.selectedId == element.vehicleDamagePartID!);
if (index == -1) {
vehicleDamageCards.add(vehicleDamageCard);
} else {
if (vehicleDamageCards[index].partImages != null) {
vehicleDamageCards[index].partImages!.add(imageModel);
}
}
}
setState(() {});
}
@ -56,7 +64,6 @@ class _AdDamagePartPicturesSheetState extends State<AdDamagePartPicturesSheet> {
return SizedBox(
height: MediaQuery.of(context).size.height / 1.2,
child: ListView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: vehicleDamageCards.length,
itemBuilder: (BuildContext context, int index) {

@ -80,7 +80,7 @@ class SelectAdTypeView extends StatelessWidget {
if (adVM.isAdEditEnabled) {
adVM.autoFillSelectedVehicleAdsDetails();
}
if (AppState().currentAppType == AppType.provider && AppState().userType == UserType.providerDealer) {
if (AppState().currentAppType == AppType.provider) {
if (isFromExtendAd && !adVM.isAdEditEnabled) {
bool status = await adVM.createAdExtensionOrder(context, adId: adsId, adsDurationId: adVM.vehicleAdDurationId.selectedId);
log("hereStatus: $status");

@ -293,11 +293,10 @@ class _AppointmentsFilterViewState extends State<AppointmentsFilterView> {
title: LocaleKeys.search.tr(),
onPressed: () {
Navigator.pop(context);
if (AppState().currentAppType == AppType.provider) {
appointmentsVM.getAppointmentsBasedOnFiltersForProviders(branchID: appointmentsVM.selectedBranchIdForAppointments);
appointmentsVM.applyFilterOnAppointmentsVMForProviders(appointmentStatusEnum: AppointmentStatusEnum.allAppointments, isNeedCustomerFilter: true);
} else {
appointmentsVM.getAppointmentsBasedOnFiltersForCustomer();
appointmentsVM.applyFilterOnAppointmentsVMForCustomers(appointmentStatusEnum: AppointmentStatusEnum.allAppointments);
}
},
backgroundColor: MyColors.darkPrimaryColor,

@ -1,3 +1,5 @@
import 'dart:developer';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/app_state.dart';
@ -6,6 +8,7 @@ import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/appointments_models/service_schedule_model.dart';
import 'package:mc_common_app/models/provider_branches_models/provider_contact_info_model.dart';
import 'package:mc_common_app/models/services_models/item_model.dart';
import 'package:mc_common_app/models/services_models/service_model.dart';
import 'package:mc_common_app/theme/colors.dart';
@ -372,6 +375,7 @@ class ReviewAppointment extends StatelessWidget {
@override
Widget build(BuildContext context) {
log("state: ${AppState().getUser.data!.userInfo!.customerId}");
return Scaffold(
appBar: CustomAppBar(
title: LocaleKeys.reviewAppointment.tr(),
@ -380,8 +384,12 @@ class ReviewAppointment extends StatelessWidget {
onBackButtonTapped: () => Navigator.pop(context),
actions: [
IconButton(
onPressed: () {
// Utils.buildProviderContactInfoBottomSheet(context: context, email:, mobileNo:);
onPressed: () async {
final appointmentsVM = context.read<AppointmentsVM>();
ProviderContactInfoModel? contact = await appointmentsVM.getProvidersContactInfo(providerId: appointmentsVM.selectedBranchModel!.serviceProviderId ?? 0, context: context);
if (contact != null) {
Utils.buildProviderContactInfoBottomSheet(context: context, email: contact.email, mobileNo: contact.mobile);
}
},
icon: const Icon(Icons.help_outline_outlined).paddingOnly(right: 21),
),

@ -287,6 +287,7 @@ class _ReviewRequestOfferState extends State<ReviewRequestOffer> {
IconButton(
onPressed: () {
final requestVM = context.read<RequestsVM>();
Utils.buildProviderContactInfoBottomSheet(
context: context,
email: requestVM.currentSelectedOffer!.email,

@ -5,6 +5,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/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/setting_utils_models/app_invitation_history_model.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';
@ -25,52 +26,82 @@ class SettingOptionsInviteFriends extends StatelessWidget {
isScrollControlled: true,
enableDrag: true,
builder: (BuildContext context) {
return InfoBottomSheet(
title: LocaleKeys.inviteFriends.tr().toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
description: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CustomSettingOptionsTile(
leadingWidget: MyAssets.whatsAppIcon.buildSvg(
height: 20,
width: 20,
color: MyColors.greyColor,
),
titleText: LocaleKeys.inviteFriendsByWhatsApp.tr(),
needBorderBelow: true,
showTrailingArrow: false,
onTap: () async {
await context.read<SettingOptionsVM>().appInvitationCreate(context: context, inviteTypeEnum: InviteTypeEnum.whatsapp);
},
),
CustomSettingOptionsTile(
leadingWidget: const Icon(
Icons.sms_outlined,
size: 20,
color: MyColors.greyColor,
return Consumer(
builder: (BuildContext context, SettingOptionsVM settingsOptionsVM, Widget? child) {
List<AppInvitationHistoryModel> list = settingsOptionsVM.appInvitationHistoryList;
int whatsAppInvites = 0;
int smsAppInvites = 0;
int emailAppInvites = 0;
for (var invite in list) {
switch (invite.appInvitationEnumID) {
case 1: // Assume 1 is WhatsApp channel
whatsAppInvites += invite.noOfInvites ?? 0;
break;
case 2: // Assume 2 is SMS channel
smsAppInvites += invite.noOfInvites ?? 0;
break;
case 3: // Assume 3 is Email channel
emailAppInvites += invite.noOfInvites ?? 0;
break;
default:
break;
}
}
return InfoBottomSheet(
title: LocaleKeys.inviteFriends.tr().toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
description: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CustomSettingOptionsTile(
leadingWidget: MyAssets.whatsAppIcon.buildSvg(
height: 20,
width: 20,
color: MyColors.greyColor,
),
titleText: LocaleKeys.inviteFriendsByWhatsApp.tr(),
subTitle: " ${LocaleKeys.noOfInvites.tr()}: $whatsAppInvites",
subtitleTextColor: MyColors.lightTextColor,
needBorderBelow: true,
showTrailingArrow: false,
onTap: () async {
await settingsOptionsVM.appInvitationCreate(context: context, inviteTypeEnum: InviteTypeEnum.whatsapp);
},
),
titleText: LocaleKeys.inviteFriendsBySMS.tr(),
needBorderBelow: true,
showTrailingArrow: false,
onTap: () async {
await context.read<SettingOptionsVM>().appInvitationCreate(context: context, inviteTypeEnum: InviteTypeEnum.sms);
}),
CustomSettingOptionsTile(
leadingWidget: const Icon(
Icons.email_outlined,
size: 20,
color: MyColors.greyColor,
),
titleText: LocaleKeys.inviteFriendsByEmail.tr(),
needBorderBelow: false,
showTrailingArrow: false,
onTap: () async {
await context.read<SettingOptionsVM>().appInvitationCreate(context: context, inviteTypeEnum: InviteTypeEnum.email);
},
CustomSettingOptionsTile(
leadingWidget: const Icon(
Icons.sms_outlined,
size: 20,
color: MyColors.greyColor,
),
titleText: LocaleKeys.inviteFriendsBySMS.tr(),
subTitle: " ${LocaleKeys.noOfInvites.tr()}: $smsAppInvites",
subtitleTextColor: MyColors.lightTextColor,
needBorderBelow: true,
showTrailingArrow: false,
onTap: () async {
await settingsOptionsVM.appInvitationCreate(context: context, inviteTypeEnum: InviteTypeEnum.sms);
}),
CustomSettingOptionsTile(
leadingWidget: const Icon(
Icons.email_outlined,
size: 20,
color: MyColors.greyColor,
),
titleText: LocaleKeys.inviteFriendsByEmail.tr(),
subTitle: " ${LocaleKeys.noOfInvites.tr()}: $emailAppInvites",
subtitleTextColor: MyColors.lightTextColor,
needBorderBelow: false,
showTrailingArrow: false,
onTap: () async {
await settingsOptionsVM.appInvitationCreate(context: context, inviteTypeEnum: InviteTypeEnum.email);
},
),
30.height,
],
),
30.height,
],
),
);
},
);
},
);

@ -12,6 +12,7 @@ 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/utils/navigator.dart';
import 'package:mc_common_app/view_models/setting_options_view_model.dart';
import 'package:mc_common_app/view_models/user_view_model.dart';
import 'package:mc_common_app/views/setting_options/widgets/custom_setting_options_tile.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
@ -110,11 +111,13 @@ class _SettingOptionsMoreState extends State<SettingOptionsMore> {
),
],
CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.settings, size: 20),
titleText: LocaleKeys.settings.tr(),
needBorderBelow: false,
onTap: () => navigateWithName(context, AppRoutes.settingOptionsInviteFriends),
),
leadingWidget: const Icon(Icons.settings, size: 20),
titleText: LocaleKeys.settings.tr(),
needBorderBelow: false,
onTap: () {
context.read<SettingOptionsVM>().getAppInvitationHistoryList();
navigateWithName(context, AppRoutes.settingOptionsInviteFriends);
}),
],
).toWhiteContainer(width: double.infinity, pading: const EdgeInsets.all(12), borderRadius: 0),
10.height,

@ -184,7 +184,7 @@ class _ShippingManagementViewState extends State<ShippingManagementView> {
text: Utils.getNameByShippingRequestStatusEnum(shippingRequest.shippingStatusEnum ?? ShippingRequestStatusEnum.initiated),
chipColor: Utils.getChipColorByShippingRequestStatusEnum(shippingRequest.shippingStatusEnum ?? ShippingRequestStatusEnum.initiated),
),
("${shippingRequest.request!.brand} ${shippingRequest.request!.model} | ${shippingRequest.id.toString()}").toText(fontSize: 16),
("${shippingRequest.request!.brand} ${shippingRequest.request!.model} | ${shippingRequest.requestID.toString()}").toText(fontSize: 16),
(shippingRequest.request!.description ?? "").toText(color: MyColors.lightTextColor, fontSize: 12, fontWeight: MyFonts.Medium),
if (shippingRequest.comment != null && shippingRequest.comment!.isNotEmpty) ...[
("${LocaleKeys.comment.tr()}: ${shippingRequest.comment ?? ""}").toText(color: MyColors.lightTextColor, fontSize: 12, fontWeight: MyFonts.Medium),

@ -33,27 +33,14 @@ class ProviderDetailCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
String nameInitials = "";
if (title.isNotEmpty) {
nameInitials = title[0];
}
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (isFromFavoriteList) ...[
CircleAvatar(
radius: 22,
backgroundColor: MyColors.darkPrimaryColor,
child: nameInitials.toText(fontSize: 25, isBold: true),
),
] else ...[
Image.asset(
providerImageUrl,
width: 80,
height: 85,
fit: BoxFit.cover,
),
],
providerImageUrl.buildNetworkImage(
width: 80,
height: 85,
fit: BoxFit.cover,
),
12.width,
Expanded(
child: Column(

@ -33,7 +33,8 @@ class DropdownField extends StatefulWidget {
final TextStyle? textStyle;
final bool isSelectAble;
const DropdownField(this.onSelect, {super.key, this.hint, this.list, this.dropdownValue, this.errorValue = "", this.showAppointmentPickerVariant = false, this.textStyle, this.isSelectAble = true});
const DropdownField(this.onSelect,
{super.key, this.hint, this.list, this.dropdownValue, this.onTap, this.errorValue = "", this.showAppointmentPickerVariant = false, this.textStyle, this.isSelectAble = true});
@override
State<DropdownField> createState() => _DropdownFieldState();
@ -51,7 +52,6 @@ class _DropdownFieldState extends State<DropdownField> {
super.initState();
}
@override
Widget build(BuildContext context) {
dropdownValue = widget.dropdownValue;
@ -72,7 +72,6 @@ class _DropdownFieldState extends State<DropdownField> {
color: !widget.isSelectAble ? Colors.transparent : null,
size: 21,
),
elevation: 16,
iconSize: widget.showAppointmentPickerVariant ? 26 : 16,
iconEnabledColor: borderColor,
@ -91,7 +90,6 @@ class _DropdownFieldState extends State<DropdownField> {
});
},
onTap: widget.onTap,
items: (widget.list ?? defaultV).map<DropdownMenuItem<DropValue>>(
(DropValue value) {
return DropdownMenuItem<DropValue>(

Loading…
Cancel
Save