aamir_dev
Faiz Hashmi 9 months ago
parent 75c46e5194
commit 021618fa6b

@ -357,7 +357,7 @@
"setupTouchID": "يرجى إعداد معرف اللمس",
"reenableTouchID": "يرجى إعادة تمكين معرف اللمس",
"scanFaceIDAuthenticate": "امسح بصمة الإصبع أو معرف الوجه للتحقق",
"AdDeletedSuccessfully": "تم حذف الإعلان بنجاح!",
"adDeletedSuccessfully": "تم حذف الإعلان بنجاح!",
"yourReservationCancelled": "تم إلغاء حجزك.",
"adDeactivatedSuccessfully": "تم إلغاء تفعيل الإعلان بنجاح!",
"vehicle": {
@ -797,5 +797,13 @@
"continueAsGuest": "الاستمرار كضيف",
"loginToViewAppointments": "الرجاء تسجيل الدخول لعرض المواعيد",
"itemType": "غرض",
"upgradeSubscription": "قم بترقية اشتراكك"
"upgradeSubscription": "قم بترقية اشتراكك",
"searchByAdID": "البحث برقم الإعلان",
"enterAdID": "أدخل رقم الإعلان",
"searchByDemandPrice": "البحث حسب سعر الطلب",
"enterStartPrice": "أدخل سعر البداية",
"enterEndPrice": "أدخل سعر النهاية",
"searchByVehicleType": "البحث حسب نوع المركبة",
"selectVehicleType": "اختر نوع المركبة",
"specialRequestsChats": "دردشات الطلبات الخاصة"
}

@ -795,5 +795,13 @@
"ok": "Ok",
"continueAsGuest": "Continue as a guest",
"loginToViewAppointments": "Please Login to View Appointments",
"itemType": "Item Type"
"itemType": "Item Type",
"searchByAdID": "Search by Ad ID",
"enterAdID": "Enter Ad ID",
"searchByDemandPrice": "Search by demand price",
"enterStartPrice": "Enter start price",
"enterEndPrice": "Enter end price",
"searchByVehicleType": "Search by vehicle type",
"selectVehicleType": "Select vehicle type",
"specialRequestsChats": "Special Requests Chats"
}

@ -125,6 +125,7 @@ class ApiConsts {
static String vehicleAdsSpecialServicesGet = "${baseUrlServices}api/Common/SpecialService_Get";
static String vehicleAdsSingleStepCreate = "${baseUrlServices}api/Advertisement/AdsSingleStep_Create";
static String vehicleAdsSingleStepUpdate = "${baseUrlServices}api/Advertisement/AdsSingleStep_Update";
static String vehicleAdsSingleStepUpdateExtend = "${baseUrlServices}api/Advertisement/AdsSingleStep_Update_Extend";
static String vehicleAdsGet = "${baseUrlServices}api/Advertisement/Ads_Get";
static String myAdsReserveGet = "${baseUrlServices}api/Advertisement/AdsReserve_Get";
static String reserveAdsBankDetailsGet = "${baseUrlServices}api/Advertisement/MCBankAccountAd_Get";
@ -137,6 +138,9 @@ class ApiConsts {
static String adsReserveCreate = "${baseUrlServices}api/Advertisement/AdsReserve_Create";
static String reserveAdPaymentOnDealDoneCreate = "${baseUrlServices}api/Advertisement/ReserveAdPaymentOnDealDone_Create";
static String adsExtendDurationCreate = "${baseUrlServices}api/Advertisement/Ads_ExtendDuration_Create";
static String adsSingleStepDraftCreate = "${baseUrlServices}api/Advertisement/AdsSingleStepDraft_Create";
static String adsSingleStepDraftUpdate = "${baseUrlServices}api/Advertisement/AdsSingleStepDraft_Update";
static String getMyDraftAds = "${baseUrlServices}api/Advertisement/AdsDraft_Get";
//Subscription
static String getMySubscriptions = "${baseUrlServices}api/ServiceProviders/ProviderSubscription_Get";
@ -415,8 +419,6 @@ class SignalrConsts {
static String receiveMessageGeneral = "ReceiveMessageGeneral";
}
class GuestConsts {
UserInfo userInfo = UserInfo.fromJson({
"id": -1,
@ -456,4 +458,4 @@ class GuestConsts {
"deviceType": "1",
"deviceToken": null,
});
}
}

@ -15,6 +15,7 @@ import 'package:mc_common_app/views/payments/payment_methods_view.dart';
import 'package:mc_common_app/views/profile/profile_view.dart';
import 'package:mc_common_app/views/requests/create_request_page.dart';
import 'package:mc_common_app/views/requests/offer_list_page.dart';
import 'package:mc_common_app/views/requests/providers_chat_list_page.dart';
import 'package:mc_common_app/views/requests/request_detail_page.dart';
import 'package:mc_common_app/views/requests/requests_filter_view.dart';
import 'package:mc_common_app/views/requests/review_request_offer.dart';
@ -151,6 +152,7 @@ class AppRoutes {
static const String offersListPage = "/offersListPage";
static const String reviewRequestOffer = "/reviewRequestOffer";
static const String providerAcceptedRequestsView = "/providerAcceptedRequestsView";
static const String providersChatListPage = "/providersChatListPage";
//Setting Options
static const String settingOptionsFaqs = "/settingOptionsFaqs";
@ -221,6 +223,7 @@ class AppRoutes {
AppRoutes.offersListPage: (context) => OfferListPage(requestId: ModalRoute.of(context)!.settings.arguments as int),
AppRoutes.reviewRequestOffer: (context) => const ReviewRequestOffer(),
AppRoutes.requestsFilterView: (context) => const RequestsFilterView(),
AppRoutes.providersChatListPage: (context) => const ProvidersChatListPage(),
//MediaViewer
AppRoutes.mediaViewerScreen: (context) => MediaViewerScreen(images: ModalRoute.of(context)!.settings.arguments as List<MessageImageModel>),

@ -373,7 +373,7 @@ class CodegenLoader extends AssetLoader{
"setupTouchID": "يرجى إعداد معرف اللمس",
"reenableTouchID": "يرجى إعادة تمكين معرف اللمس",
"scanFaceIDAuthenticate": "امسح بصمة الإصبع أو معرف الوجه للتحقق",
"AdDeletedSuccessfully": "تم حذف الإعلان بنجاح!",
"adDeletedSuccessfully": "تم حذف الإعلان بنجاح!",
"yourReservationCancelled": "تم إلغاء حجزك.",
"adDeactivatedSuccessfully": "تم إلغاء تفعيل الإعلان بنجاح!",
"vehicle": {
@ -813,7 +813,15 @@ class CodegenLoader extends AssetLoader{
"continueAsGuest": "الاستمرار كضيف",
"loginToViewAppointments": "الرجاء تسجيل الدخول لعرض المواعيد",
"itemType": "غرض",
"upgradeSubscription": "قم بترقية اشتراكك"
"upgradeSubscription": "قم بترقية اشتراكك",
"searchByAdID": "البحث برقم الإعلان",
"enterAdID": "أدخل رقم الإعلان",
"searchByDemandPrice": "البحث حسب سعر الطلب",
"enterStartPrice": "أدخل سعر البداية",
"enterEndPrice": "أدخل سعر النهاية",
"searchByVehicleType": "البحث حسب نوع المركبة",
"selectVehicleType": "اختر نوع المركبة",
"specialRequestsChats": "دردشات الطلبات الخاصة"
};
static const Map<String,dynamic> en_US = {
"firstTimeLogIn": "First Time Log In",
@ -1612,7 +1620,15 @@ static const Map<String,dynamic> en_US = {
"ok": "Ok",
"continueAsGuest": "Continue as a guest",
"loginToViewAppointments": "Please Login to View Appointments",
"itemType": "Item Type"
"itemType": "Item Type",
"searchByAdID": "Search by Ad ID",
"enterAdID": "Enter Ad ID",
"searchByDemandPrice": "Search by demand price",
"enterStartPrice": "Enter start price",
"enterEndPrice": "Enter end price",
"searchByVehicleType": "Search by vehicle type",
"selectVehicleType": "Select vehicle type",
"specialRequestsChats": "Special Requests Chats"
};
static const Map<String, Map<String,dynamic>> mapLocales = {"ar_SA": ar_SA, "en_US": en_US};
}

@ -337,7 +337,7 @@ abstract class LocaleKeys {
static const setupTouchID = 'setupTouchID';
static const reenableTouchID = 'reenableTouchID';
static const scanFaceIDAuthenticate = 'scanFaceIDAuthenticate';
static const AdDeletedSuccessfully = 'AdDeletedSuccessfully';
static const adDeletedSuccessfully = 'adDeletedSuccessfully';
static const yourReservationCancelled = 'yourReservationCancelled';
static const adDeactivatedSuccessfully = 'adDeactivatedSuccessfully';
static const vehicle_selectVehicleType = 'vehicle.selectVehicleType';
@ -777,5 +777,13 @@ abstract class LocaleKeys {
static const loginToViewAppointments = 'loginToViewAppointments';
static const itemType = 'itemType';
static const upgradeSubscription = 'upgradeSubscription';
static const searchByAdID = 'searchByAdID';
static const enterAdID = 'enterAdID';
static const searchByDemandPrice = 'searchByDemandPrice';
static const enterStartPrice = 'enterStartPrice';
static const enterEndPrice = 'enterEndPrice';
static const searchByVehicleType = 'searchByVehicleType';
static const selectVehicleType = 'selectVehicleType';
static const specialRequestsChats = 'specialRequestsChats';
}

@ -28,3 +28,17 @@ class AdsBankDetailsModel {
return data;
}
}
class AdExtensionOrderResponseModel {
final int adsID;
final bool isPaymentRequired;
AdExtensionOrderResponseModel({required this.adsID, required this.isPaymentRequired});
factory AdExtensionOrderResponseModel.fromJson(Map<String, dynamic> json) {
return AdExtensionOrderResponseModel(
adsID: json['adsID'] as int,
isPaymentRequired: json['isPaymentRequired'] as bool,
);
}
}

@ -28,6 +28,7 @@ class AppointmentListModel {
String? branchName;
int? branchId;
int? servicePaymentStatus;
bool? isPaymentRequiredAtBooking;
double? totalAmount;
double? remainingAmount;
bool? isSelected;
@ -61,6 +62,7 @@ class AppointmentListModel {
this.branchName,
this.branchId,
this.servicePaymentStatus,
this.isPaymentRequiredAtBooking,
this.totalAmount,
this.remainingAmount,
this.isSelected,
@ -102,6 +104,7 @@ class AppointmentListModel {
branchName = json['branchName'];
branchId = json['branchID'];
servicePaymentStatus = json['servicePaymentStatus'];
isPaymentRequiredAtBooking = json['isPaymentRequiredAtBooking'];
totalAmount = json['amountTotal'];
remainingAmount = json['amountRem'];
isSelected = false;

@ -1,50 +1,30 @@
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/utils/enums.dart';
class OffersModel {
int? id;
int? requestID;
int? serviceProviderID;
ServiceProvider? serviceProvider;
int? offerStatus;
RequestOfferStatusEnum? requestOfferStatusEnum;
String? offerStatusText;
String? comment;
double? price;
OffersModel(
{this.id,
this.requestID,
this.serviceProviderID,
this.serviceProvider,
this.offerStatus,
this.offerStatusText,
this.comment,
this.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;
serviceProvider = json['serviceProvider'] != null ? ServiceProvider.fromJson(json['serviceProvider']) : null;
offerStatus = json['offerStatus'];
requestOfferStatusEnum = ((json['offerStatus']) as int).toRequestOfferStatusEnum();
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 {
@ -78,32 +58,32 @@ class ServiceProvider {
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});
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'];

@ -0,0 +1,158 @@
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/utils/enums.dart';
class ProviderOffersChatsModel {
int? id;
int? requestID;
int? serviceProviderID;
ServiceProviderModel? serviceProvider;
int? offerStatus;
RequestOfferStatusEnum? requestOfferStatusEnum;
String? offerStatusText;
String? comment;
String? customerName;
double? price;
String? serviceItem;
String? offeredItemCreatedBy;
String? offeredItemCreatedByName;
String? offeredItemCreatedOn;
String? reqOfferImages;
bool? isDeliveryAvailable;
String? createdOn;
ProviderOffersChatsModel({
this.id,
this.requestID,
this.serviceProviderID,
this.serviceProvider,
this.offerStatus,
this.requestOfferStatusEnum,
this.offerStatusText,
this.comment,
this.customerName,
this.price,
this.serviceItem,
this.offeredItemCreatedBy,
this.offeredItemCreatedByName,
this.offeredItemCreatedOn,
this.reqOfferImages,
this.isDeliveryAvailable,
this.createdOn,
});
ProviderOffersChatsModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
requestID = json['requestID'];
serviceProviderID = json['serviceProviderID'];
serviceProvider = json['serviceProvider'] != null ? ServiceProviderModel.fromJson(json['serviceProvider']) : null;
offerStatus = json['offerStatus'];
requestOfferStatusEnum = ((json['offerStatus']) as int).toRequestOfferStatusEnum();
offerStatusText = json['offerStatusText'];
comment = json['comment'];
customerName = json['customerName'];
price = json['price'];
serviceItem = json['serviceItem'];
offeredItemCreatedBy = json['offeredItemCreatedBy'];
offeredItemCreatedByName = json['offeredItemCreatedByName'];
offeredItemCreatedOn = json['offeredItemCreatedOn'];
reqOfferImages = json['reqOfferImages'];
isDeliveryAvailable = json['isDeliveryAvailable'];
createdOn = json['createdOn'];
}
}
class ServiceProviderModel {
int? providerId;
String? providerGUID;
String? firstName;
String? lastName;
String? name;
int? gender;
String? genderName;
String? mobileNo;
String? email;
bool? isEmailVerified;
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? createdOn;
String? companyName;
String? currency;
String? branch;
bool? isChatted;
bool? isDealership;
ServiceProviderModel({
this.providerId,
this.providerGUID,
this.firstName,
this.lastName,
this.name,
this.gender,
this.genderName,
this.mobileNo,
this.email,
this.isEmailVerified,
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.createdOn,
this.companyName,
this.currency,
this.branch,
this.isChatted,
this.isDealership,
});
ServiceProviderModel.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'];
isEmailVerified = 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'];
createdOn = json['createdOn'];
companyName = json['companyName'];
currency = json['currency'];
branch = json['branch'];
isChatted = json['isChatted'];
isDealership = json['isDealership'];
}
}

@ -78,7 +78,7 @@ class ServiceModel {
: List<ItemData>.from(json["branchServiceItems"]!.map((x) => ItemData.fromJson(x))),
isExpandedOrSelected: false,
providerServiceId: 0,
providerServiceName: "",
providerServiceName: json['serviceName'] ?? "",
isHomeSelected: false,
isActive: json["isActive"] ?? true,
servicelocationInfo: CurrentLocationInfoModel(address: '', distanceToBranch: 0.0, homeChargesInCurrentService: 0.0, latitude: 0.0, longitude: 0.0),

@ -23,7 +23,7 @@ abstract class AdsRepo {
Future<List<SpecialServiceModel>> getSpecialServices({required int specialServiceType, required int cityId, required int countryId});
Future<GenericRespModel> createOrUpdateAd({required AdsCreationPayloadModel adsCreationPayloadModel, required bool isCreateNew});
Future<GenericRespModel> createOrUpdateAd({required AdsCreationPayloadModel adsCreationPayloadModel, required bool isCreateNew, required bool isExtendAdEditEnabled});
Future<List<AdDetailsModel>> getAllAds({
required bool isMyAds,
@ -33,13 +33,20 @@ abstract class AdsRepo {
int? page,
});
Future<List<AdDetailsModel>> getMyDraftAds({int? page});
Future<List<AdDetailsModel>> getExploreAdsBasedOnFilters({
List<String>? adIdsList,
List<String>? cityIdsList,
List<String>? vehicleModelYearIdsList,
List<String>? vehicleTypeIdsList,
List<String>? vehicleBrandIdsList,
List<String>? createdByRolesIdsList,
List<String>? vehicleAdConditionIdsList,
List<String>? vehicleAdCreatedDateList,
List<String>? mobileNumbersList,
int? startPriceDemand,
int? endPriceDemand,
int page,
bool isMyAds = false,
});
@ -120,9 +127,10 @@ class AdsRepoImp implements AdsRepo {
}
@override
Future<GenericRespModel> createOrUpdateAd({required AdsCreationPayloadModel adsCreationPayloadModel, required bool isCreateNew}) async {
Future<GenericRespModel> createOrUpdateAd({required AdsCreationPayloadModel adsCreationPayloadModel, required bool isCreateNew, required bool isExtendAdEditEnabled}) async {
List vehiclePostingImages = [];
log("isExtendAdEditEnabled: $isExtendAdEditEnabled");
log("adsCreationPayloadModel.ads!.adsDurationID,: ${adsCreationPayloadModel.ads!.adsDurationID}");
adsCreationPayloadModel.vehiclePosting!.vehiclePostingImages?.forEach((element) {
var imageMap = {
@ -195,7 +203,11 @@ class AdsRepoImp implements AdsRepo {
String token = appState.getUser.data!.accessToken ?? "";
GenericRespModel adsGenericModel = await apiClient.postJsonForObject(
(json) => GenericRespModel.fromJson(json),
isCreateNew ? ApiConsts.vehicleAdsSingleStepCreate : ApiConsts.vehicleAdsSingleStepUpdate,
isExtendAdEditEnabled
? ApiConsts.vehicleAdsSingleStepUpdateExtend
: isCreateNew
? ApiConsts.vehicleAdsSingleStepCreate
: ApiConsts.vehicleAdsSingleStepUpdate,
postParams,
token: token,
);
@ -203,6 +215,27 @@ class AdsRepoImp implements AdsRepo {
return Future.value(adsGenericModel);
}
@override
Future<List<AdDetailsModel>> getMyDraftAds({int? page}) async {
var draftAdsParams = {
"PageSize": "30",
"PageIndex": page != null ? page.toString() : "0",
"userID": appState.getUser.data!.userInfo!.userId ?? "",
};
GenericRespModel adsGenericModel = await apiClient.getJsonForObject(
token: appState.getUser.data!.accessToken,
(json) => GenericRespModel.fromJson(json),
ApiConsts.vehicleAdsGet,
queryParameters: draftAdsParams,
);
List<AdDetailsModel> vehicleAdsDetails = List.generate(
adsGenericModel.data.length,
(index) => AdDetailsModel.fromJson(adsGenericModel.data[index], true, adsGenericModel.totalItemsCount ?? 1),
);
return vehicleAdsDetails;
}
@override
Future<List<AdDetailsModel>> getAllAds({
required isMyAds,
@ -251,23 +284,33 @@ class AdsRepoImp implements AdsRepo {
@override
Future<List<AdDetailsModel>> getExploreAdsBasedOnFilters({
List<String>? adIdsList,
List<String>? cityIdsList,
List<String>? vehicleModelYearIdsList,
List<String>? vehicleTypeIdsList,
List<String>? vehicleBrandIdsList,
List<String>? createdByRolesIdsList,
List<String>? vehicleAdConditionIdsList,
List<String>? vehicleAdCreatedDateList,
List<String>? mobileNumbersList,
int? startPriceDemand,
int? endPriceDemand,
int? page,
bool isMyAds = false,
}) async {
var parameters = {
"AdsIDs": adIdsList ?? [],
"CityIDs": cityIdsList ?? [],
"VehicleTypeIDs": vehicleTypeIdsList ?? [],
"VehicleBrandIDs": vehicleBrandIdsList ?? [],
"VehicleModelYearIDs": vehicleModelYearIdsList ?? [],
"CreatedByRoles": createdByRolesIdsList ?? [],
"AdsStatuses": ["${AdPostStatus.active.getIdFromAdPostStatusEnum()}"], //only Active ADS
"VehicleNew": vehicleAdConditionIdsList ?? [],
"CreatedOn": (vehicleAdCreatedDateList != null && vehicleAdCreatedDateList.isNotEmpty) ? vehicleAdCreatedDateList.first.toString() : "",
"VehicleNew": vehicleAdConditionIdsList != null && vehicleAdConditionIdsList.isNotEmpty ? vehicleAdConditionIdsList.first.toString() : null,
"CreatedOn": (vehicleAdCreatedDateList != null && vehicleAdCreatedDateList.isNotEmpty) ? vehicleAdCreatedDateList.first.toString() : null,
"MobileNumbers": mobileNumbersList ?? [],
"StartPriceDemand": startPriceDemand?.toString(),
"EndPriceDemand": endPriceDemand?.toString(),
"isActive": "true", //only Active ADS
"isExplore": (!isMyAds).toString(),
"PageSize": "30",
@ -280,6 +323,8 @@ class AdsRepoImp implements AdsRepo {
});
}
parameters.removeWhere((key, value) => value == null);
GenericRespModel adsGenericModel = await apiClient.getJsonForObject(
token: appState.getUser.data!.accessToken,
(json) => GenericRespModel.fromJson(json),

@ -5,11 +5,9 @@ import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependency_injection.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/chat_message_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/provider_offers_model.dart';
import 'package:mc_common_app/models/requests_models/providers_offers_chat_model.dart';
import 'package:mc_common_app/models/requests_models/request_model.dart';
import 'package:mc_common_app/utils/enums.dart';
@ -30,7 +28,7 @@ abstract class RequestRepo {
required List requestImages,
});
Future<List<OffersModel>> getOffersByRequest({required int requestId, int serviceProviderId = 0});
Future<List<ProviderOffersChatsModel>> getOffersChatByProvider({int requestId = 0, required int serviceProviderId});
Future<ProviderOffersModel> getOffersFromProvidersByRequest({required int requestId});
@ -38,6 +36,7 @@ abstract class RequestRepo {
Future<List<RequestModel>> getRequestsBasedOnFilters({
required int requestTypeId,
int requestId = 0,
int requestStatusId = 0,
int reqOfferStatus = 0,
int? cityId = 0,
@ -146,6 +145,7 @@ class RequestRepoImp implements RequestRepo {
Future<List<RequestModel>> getRequestsBasedOnFilters({
required int requestTypeId,
int requestStatusId = 0,
int requestId = 0,
int reqOfferStatus = 0,
int? cityId = 0,
int? vehicleYearId = 0,
@ -275,7 +275,7 @@ class RequestRepoImp implements RequestRepo {
}
@override
Future<List<OffersModel>> getOffersByRequest({required int requestId, int serviceProviderId = 0}) async {
Future<List<ProviderOffersChatsModel>> getOffersChatByProvider({int requestId = 0, required int serviceProviderId}) async {
var queryParameters = {
"RequestID": requestId.toString(),
"ServiceProviderID": serviceProviderId.toString(),
@ -286,9 +286,9 @@ class RequestRepoImp implements RequestRepo {
queryParameters: queryParameters,
token: appState.getUser.data!.accessToken,
);
List<OffersModel> offersList = List.generate(
List<ProviderOffersChatsModel> offersList = List.generate(
genericRespModel.data.length,
(index) => OffersModel.fromJson(genericRespModel.data[index]),
(index) => ProviderOffersChatsModel.fromJson(genericRespModel.data[index]),
);
return offersList;
}

@ -80,9 +80,11 @@ class AdVM extends BaseVM {
String adPhoneNumberError = "";
// Edit Variables Amir
bool isExtendAdEditEnabled = false;
bool isAdEditEnabled = false;
AdDetailsModel? previousAdDetails;
List<AdDetailsModel> myDraftAds = [];
List<AdDetailsModel> exploreAds = [];
List<AdDetailsModel> exploreAdsFilteredList = [];
List<AdDetailsModel> myAdsFilteredList = [];
@ -179,6 +181,7 @@ class AdVM extends BaseVM {
if (myAdsStatusEnums.isEmpty) {
myAdsStatusEnums = await commonRepo.getEnumTypeValues(enumTypeID: AppEnums.myAdsFilterEnumId);
}
if (vehicleBrandsForFilters.isEmpty) {
vehicleBrandsForFilters = await commonRepo.getVehicleBrands(vehicleTypeId: -1); // to get all the brands
}
@ -340,6 +343,44 @@ class AdVM extends BaseVM {
setState(ViewState.idle);
}
bool hasMoreDataForMyDraftsAds = false;
int pageIndexForMyDrafts = 1;
Future<void> getMyDraftAds() async {
pageIndexForMyAds = 1;
hasMoreDataForMyAds = true;
setState(ViewState.busy);
myDraftAds = await adsRepo.getMyDraftAds();
notifyListeners();
setState(ViewState.idle);
}
Future<void> fetchMoreDraftAds({required AdPostStatus adsStatus}) async {
if (isLoadingMore) return;
hasMoreDataForMyDraftsAds = true;
isLoadingMore = true;
notifyListeners();
try {
final List<AdDetailsModel> newAds = await adsRepo.getMyDraftAds(page: pageIndexForMyDrafts);
if (newAds.isEmpty) {
hasMoreDataForMyDraftsAds = false;
} else {
myDraftAds.addAll(newAds);
pageIndexForMyDrafts++;
if (myDraftAds.length < myDraftAds.last.totalItemsCount!) {
hasMoreDataForMyDraftsAds = true;
} else {
hasMoreDataForMyDraftsAds = false;
}
}
} catch (error) {
isLoadingMore = false;
Utils.showToast(error.toString());
}
isLoadingMore = false;
notifyListeners();
}
Future<void> getMyAds() async {
pageIndexForMyAds = 1;
hasMoreDataForMyAds = true;
@ -418,7 +459,7 @@ class AdVM extends BaseVM {
Utils.showToast(respModel.message ?? LocaleKeys.adMarkedAsSold.tr());
updateIsExploreAds(false);
applyFilterOnMyAds(adPostStatusEnum: AdPostStatus.sold); //pending for review
navigateReplaceWithName(context, AppRoutes.dashboard);
navigateReplaceWithName(context, AppRoutes.dashboard, arguments: DashboardRouteEnum.fromAdsSubmit);
}
Future<void> deleteMyAd(BuildContext context, {required int adId}) async {
@ -431,10 +472,10 @@ class AdVM extends BaseVM {
return;
}
Utils.hideLoading(context);
Utils.showToast(LocaleKeys.AdDeletedSuccessfully.tr());
Utils.showToast(LocaleKeys.adDeletedSuccessfully.tr());
updateIsExploreAds(false);
applyFilterOnMyAds(adPostStatusEnum: AdPostStatus.active); //pending for review
navigateReplaceWithName(context, AppRoutes.dashboard);
navigateReplaceWithName(context, AppRoutes.dashboard, arguments: DashboardRouteEnum.fromAdsSubmit);
}
Future<void> cancelMyAdReservation(BuildContext context, {required int adId, required String reason}) async {
@ -450,7 +491,7 @@ class AdVM extends BaseVM {
Utils.showToast(LocaleKeys.yourReservationCancelled.tr());
updateIsExploreAds(false);
applyFilterOnMyAds(adPostStatusEnum: AdPostStatus.active); //pending for review
navigateReplaceWithName(context, AppRoutes.dashboard);
navigateReplaceWithName(context, AppRoutes.dashboard, arguments: DashboardRouteEnum.fromAdsSubmit);
}
Future<void> deactivateTheAd(BuildContext context, {required int adId, String? comment}) async {
@ -467,7 +508,7 @@ class AdVM extends BaseVM {
updateDeactivateAdReasonDescription('');
updateIsExploreAds(false);
applyFilterOnMyAds(adPostStatusEnum: AdPostStatus.cancelled); //Cacncelled
navigateReplaceWithName(context, AppRoutes.dashboard);
navigateReplaceWithName(context, AppRoutes.dashboard, arguments: DashboardRouteEnum.fromAdsSubmit);
}
bool isFetchingLists = false;
@ -570,7 +611,16 @@ class AdVM extends BaseVM {
SelectionModel vehicleTypeId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
void updateSelectionVehicleTypeId(SelectionModel id) async {
void updateSelectionVehicleTypeId(SelectionModel id, {bool isForSearch = false}) async {
if (isForSearch) {
VehicleTypeModel vehicleTypeModel = vehicleTypesForFilters.firstWhere((element) => element.id == id.selectedId);
DropValue vehicleTypeVValue = DropValue(vehicleTypeModel.id ?? 0, vehicleTypeModel.vehicleTypeName ?? "", "");
if (!ifAlreadyExist(list: vehicleTypesAdSearchHistory, value: vehicleTypeVValue)) {
addToVehicleTypesAdSearchHistory(value: vehicleTypeVValue);
}
notifyListeners();
return;
}
vehicleTypeId = id;
await getVehicleBrandsByVehicleTypeId();
notifyListeners();
@ -580,7 +630,7 @@ class AdVM extends BaseVM {
Future<void> updateSelectionVehicleBrandId(SelectionModel id, {bool isForSearch = false}) async {
if (isForSearch) {
VehicleBrandsModel brand = vehicleBrands.firstWhere((element) => element.id == id.selectedId);
VehicleBrandsModel brand = vehicleBrandsForFilters.firstWhere((element) => element.id == id.selectedId);
DropValue brandValue = DropValue(brand.id ?? 0, brand.vehicleBrandDescription ?? "", "");
if (!ifAlreadyExist(list: vehicleBrandsAdSearchHistory, value: brandValue)) {
addToVehicleBrandsAdSearchHistory(value: brandValue);
@ -1218,6 +1268,7 @@ class AdVM extends BaseVM {
return;
}
isAdEditEnabled = false;
isExtendAdEditEnabled = false;
Utils.hideLoading(context);
currentProgressStep = AdCreationSteps.vehicleDetails;
resetValues();
@ -1544,6 +1595,7 @@ class AdVM extends BaseVM {
Utils.showToast("${LocaleKeys.error.tr()}: ${genericRespModel.message}");
} else {
resetSpecialServiceBottomSheet();
pop(context);
navigateWithName(context, AppRoutes.paymentMethodsView, arguments: PaymentTypes.ads);
}
} catch (e) {
@ -1630,7 +1682,8 @@ class AdVM extends BaseVM {
);
AdsCreationPayloadModel adsCreationPayloadModel = AdsCreationPayloadModel(ads: ads, vehiclePosting: vehiclePosting);
GenericRespModel respModel = await adsRepo.createOrUpdateAd(adsCreationPayloadModel: adsCreationPayloadModel, isCreateNew: !isAdEditEnabled);
GenericRespModel respModel = await adsRepo.createOrUpdateAd(adsCreationPayloadModel: adsCreationPayloadModel, isCreateNew: !isAdEditEnabled, isExtendAdEditEnabled: isExtendAdEditEnabled);
Utils.showToast(respModel.message.toString());
@ -1686,6 +1739,8 @@ class AdVM extends BaseVM {
List<EnumsModel> vehicleConditionsEnum = [];
List<EnumsModel> adOwnerEnumsFilter = [];
List<VehicleTypeModel> vehicleTypesForFilters = [];
Future<void> populateDataForAdFilter() async {
setState(ViewState.busy);
pageIndexForExploreAds = 1;
@ -1702,6 +1757,10 @@ class AdVM extends BaseVM {
vehicleConditionsEnum = await commonRepo.getEnumTypeValues(enumTypeID: AppEnums.conditionEnumId);
}
if (vehicleTypesForFilters.isEmpty) {
vehicleTypesForFilters = await commonRepo.getVehicleTypes();
}
if (vehicleBrandsForFilters.isEmpty) {
vehicleBrandsForFilters = await commonRepo.getVehicleBrands(vehicleTypeId: -1); // to get all the brands
}
@ -1726,6 +1785,127 @@ class AdVM extends BaseVM {
return false;
}
ifAlreadyExistForStringValue({required List<String> list, required String value}) {
int index = list.indexWhere((element) {
return element == value;
});
if (index != -1) {
return true;
}
return false;
}
//Ad Demand Price
String adFilterDemandStartPrice = "";
void updateAdFilterDemandStartPrice(String title) {
adFilterDemandStartPrice = title;
}
String adFilterDemandEndPrice = "";
void updateAdFilterDemandEndPrice(String title) {
adFilterDemandEndPrice = title;
}
// Ads Mobile Number Filter
String currentAdMobilePhoneFilter = '';
void onCurrentAdMobilePhoneFilterChanged(var value) {
currentAdMobilePhoneFilter = value;
notifyListeners();
}
List<String> adFilterMobilePhoneSearchHistory = [];
void removeAdFilterMobilePhoneSearchHistory({bool isClear = false, required int index}) {
if (isClear) {
adFilterMobilePhoneSearchHistory.clear();
notifyListeners();
return;
}
adFilterMobilePhoneSearchHistory.removeAt(index);
if (adFilterMobilePhoneSearchHistory.isEmpty) {
updateAdsFiltersCounter(adsFiltersCounter - 1);
}
notifyListeners();
}
void addAdFilterMobilePhoneSearchHistory({required String value}) {
if (adFilterMobilePhoneSearchHistory.isEmpty) {
updateAdsFiltersCounter(adsFiltersCounter + 1);
}
if (!ifAlreadyExistForStringValue(list: adFilterMobilePhoneSearchHistory, value: value)) {
adFilterMobilePhoneSearchHistory.add(value);
currentAdMobilePhoneFilter = "";
}
notifyListeners();
}
// Ad ID
List<String> adsFilterAdIDSearchHistory = [];
String currentAdIDFilter = '';
void onCurrentAdIDFilterChanged(var value) {
currentAdIDFilter = value;
notifyListeners();
}
void removeAdFilterAdIDSearchHistory({bool isClear = false, required int index}) {
if (isClear) {
adsFilterAdIDSearchHistory.clear();
notifyListeners();
return;
}
adsFilterAdIDSearchHistory.removeAt(index);
if (adsFilterAdIDSearchHistory.isEmpty) {
updateAdsFiltersCounter(adsFiltersCounter - 1);
}
notifyListeners();
}
void addAdFilterAdIDSearchHistory({required String value}) {
if (adsFilterAdIDSearchHistory.isEmpty) {
updateAdsFiltersCounter(adsFiltersCounter + 1);
}
if (!ifAlreadyExistForStringValue(list: adsFilterAdIDSearchHistory, value: value)) {
adsFilterAdIDSearchHistory.add(value);
currentAdIDFilter = "";
}
notifyListeners();
}
//TYPES
List<DropValue> vehicleTypesAdSearchHistory = [];
void removeVehicleTypesAdSearchHistory({bool isClear = false, required int index}) {
if (isClear) {
vehicleTypesAdSearchHistory.clear();
notifyListeners();
return;
}
vehicleTypesAdSearchHistory.removeAt(index);
if (vehicleTypesAdSearchHistory.isEmpty) {
updateAdsFiltersCounter(adsFiltersCounter - 1);
}
notifyListeners();
}
void addToVehicleTypesAdSearchHistory({required DropValue value}) {
if (vehicleTypesAdSearchHistory.isEmpty) {
updateAdsFiltersCounter(adsFiltersCounter + 1);
}
vehicleTypesAdSearchHistory.add(value);
notifyListeners();
}
//BRANDS
List<DropValue> vehicleBrandsAdSearchHistory = [];
@ -1862,11 +2042,14 @@ class AdVM extends BaseVM {
if (vehicleAdCreatedDateSearchHistory.isEmpty) {
updateAdsFiltersCounter(adsFiltersCounter + 1);
}
if (vehicleAdCreatedDateSearchHistory.isEmpty) {
vehicleAdCreatedDateSearchHistory.add(value);
} else {
vehicleAdCreatedDateSearchHistory.first = value;
}
vehicleAdCreatedDateSearchHistory.add(value);
// if (vehicleAdCreatedDateSearchHistory.isEmpty) {
// vehicleAdCreatedDateSearchHistory.add(value);
// } else {
// vehicleAdCreatedDateSearchHistory.first = value;
// }
notifyListeners();
}
@ -1903,12 +2086,16 @@ class AdVM extends BaseVM {
}
void clearAdsFilters() {
vehicleBrandsAdSearchHistory.clear();
adsFilterAdIDSearchHistory.clear();
vehicleTypesAdSearchHistory.clear();
vehicleAdOwnerSearchHistory.clear();
vehicleLocationAdSearchHistory.clear();
vehicleYearAdSearchHistory.clear();
vehicleAdCreatedDateSearchHistory.clear();
vehicleAdConditionSearchHistory.clear();
adFilterMobilePhoneSearchHistory.clear();
adFilterDemandStartPrice = '';
adFilterDemandEndPrice = '';
adsFiltersCounter = 0;
getExploreAds();
notifyListeners();
@ -1929,12 +2116,25 @@ class AdVM extends BaseVM {
exploreAdsFilteredList.clear();
setState(ViewState.busy);
}
List<String> adIdsList = [];
if (adsFilterAdIDSearchHistory.isNotEmpty) {
for (var element in adsFilterAdIDSearchHistory) {
adIdsList.add(element.toString());
}
}
List<String> cityIdsList = [];
if (vehicleLocationAdSearchHistory.isNotEmpty) {
for (var element in vehicleLocationAdSearchHistory) {
cityIdsList.add(element.id.toString());
}
}
List<String> typesIdsList = [];
if (vehicleTypesAdSearchHistory.isNotEmpty) {
for (var element in vehicleTypesAdSearchHistory) {
typesIdsList.add(element.id.toString());
}
}
List<String> brandsIdsList = [];
if (vehicleBrandsAdSearchHistory.isNotEmpty) {
for (var element in vehicleBrandsAdSearchHistory) {
@ -1970,13 +2170,43 @@ class AdVM extends BaseVM {
}
}
List<String> phoneNumbersList = [];
if (adFilterMobilePhoneSearchHistory.isNotEmpty) {
for (var element in adFilterMobilePhoneSearchHistory) {
phoneNumbersList.add(element.toString());
}
}
int? startPriceDemand;
int? endPriceDemand;
if (adFilterDemandStartPrice.isNotEmpty) {
try {
startPriceDemand = int.parse(adFilterDemandStartPrice);
} catch (e) {
startPriceDemand = null;
}
}
if (adFilterDemandEndPrice.isNotEmpty) {
try {
endPriceDemand = int.parse(adFilterDemandEndPrice);
} catch (e) {
endPriceDemand = null;
}
}
List<AdDetailsModel> list = await adsRepo.getExploreAdsBasedOnFilters(
adIdsList: adIdsList,
cityIdsList: cityIdsList,
createdByRolesIdsList: adOwnerIdsList,
vehicleTypeIdsList: typesIdsList,
vehicleBrandIdsList: brandsIdsList,
vehicleModelYearIdsList: vehicleYearIdsList,
vehicleAdConditionIdsList: conditionsIdsList,
vehicleAdCreatedDateList: createdDatesList,
mobileNumbersList: phoneNumbersList,
startPriceDemand: startPriceDemand,
endPriceDemand: endPriceDemand,
page: pageIndex,
);
@ -1993,6 +2223,7 @@ class AdVM extends BaseVM {
void onEditUpdateAdPressed({required BuildContext context, required AdDetailsModel previousDetails, required bool isFromExtendAd}) {
isAdEditEnabled = true;
isExtendAdEditEnabled = isFromExtendAd;
previousAdDetails = previousDetails;
autoFillSelectedVehicleType();
autoFillSelectedVehicleAdsDuration();
@ -2000,22 +2231,25 @@ class AdVM extends BaseVM {
navigateWithName(context, AppRoutes.selectAdTypeView, arguments: [AppState().currentAppType == AppType.provider, isFromExtendAd, previousDetails.id]);
}
Future<bool> createAdExtensionOrder(BuildContext context, {required int adId, required int adsDurationId}) async {
Future<List<bool>> createAdExtensionOrder(BuildContext context, {required int adId, required int adsDurationId}) async {
// [0] Means API response [1] means isPaymentRequired
try {
Utils.showLoading(context);
GenericRespModel respModel = await adsRepo.createAdExtensionOrder(adID: adId, adsDurationId: adsDurationId, specialServiceIds: []);
if (respModel.messageStatus != 1) {
if (respModel.messageStatus != 1 && respModel.data == null) {
Utils.hideLoading(context);
Utils.showToast(respModel.message ?? LocaleKeys.somethingWrong.tr());
return false;
return [false, false]; // api fail response
}
Utils.hideLoading(context);
return respModel.messageStatus == 1;
final AdExtensionOrderResponseModel adExtensionOrderResponseModel = AdExtensionOrderResponseModel.fromJson(respModel.data);
return [true, adExtensionOrderResponseModel.isPaymentRequired];
} catch (e) {
Utils.hideLoading(context);
Utils.showToast(e.toString());
return false;
return [false, false]; // api fail response
}
}

@ -307,7 +307,9 @@ class AppointmentsVM extends BaseVM {
}
void removeServiceInCurrentAppointment(int index) {
int serviceId = servicesInCurrentAppointment.elementAt(index).serviceProviderServiceId ?? -1;
int serviceId = servicesInCurrentAppointment
.elementAt(index)
.serviceProviderServiceId ?? -1;
allSelectedItemsInAppointments.removeWhere((element) => element.serviceProviderServiceId == serviceId);
servicesInCurrentAppointment[index].serviceItems!.clear();
servicesInCurrentAppointment.removeAt(index);
@ -370,8 +372,8 @@ class AppointmentsVM extends BaseVM {
if (shouldPopulateUpcoming) {
myUpComingAppointments = myFilteredAppointmentsForProvider
.where((element) =>
(element.appointmentStatusEnum == AppointmentStatusEnum.booked || element.appointmentStatusEnum == AppointmentStatusEnum.confirmed) &&
(DateHelper.parseStringToDate(element.appointmentDate!).isAfter(DateTime.now())))
(element.appointmentStatusEnum == AppointmentStatusEnum.booked || element.appointmentStatusEnum == AppointmentStatusEnum.confirmed) &&
(DateHelper.parseStringToDate(element.appointmentDate!).isAfter(DateTime.now())))
.toList();
log("myUpComingAppointments: ${myUpComingAppointments.length}");
}
@ -398,8 +400,8 @@ class AppointmentsVM extends BaseVM {
if (shouldPopulateUpcoming) {
myUpComingAppointments = myFilteredAppointmentsForCustomers
.where((element) =>
(element.appointmentStatusEnum == AppointmentStatusEnum.booked || element.appointmentStatusEnum == AppointmentStatusEnum.confirmed) &&
(DateHelper.parseStringToDate(element.appointmentDate!).isAfter(DateTime.now())))
(element.appointmentStatusEnum == AppointmentStatusEnum.booked || element.appointmentStatusEnum == AppointmentStatusEnum.confirmed) &&
(DateHelper.parseStringToDate(element.appointmentDate!).isAfter(DateTime.now())))
.toList();
}
@ -414,14 +416,19 @@ class AppointmentsVM extends BaseVM {
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
.compareTo(DateHelper.parseStringToDate(DateHelper.formatDateT(a.appointmentDate!)).millisecondsSinceEpoch));
list.sort((a, b) =>
DateHelper
.parseStringToDate(DateHelper.formatDateT(b.appointmentDate!))
.millisecondsSinceEpoch
.compareTo(DateHelper
.parseStringToDate(DateHelper.formatDateT(a.appointmentDate!))
.millisecondsSinceEpoch));
AppointmentListModel model = list.first;
model.customerAppointmentList = list;
return model;
}).toList();
return groupedList;
}
@ -500,7 +507,7 @@ class AppointmentsVM extends BaseVM {
void updateCheckBoxInMergeRequest(int currentIndex) {
myFilteredAppointmentsForProvider[selectedAppointmentIndex].customerAppointmentList![currentIndex].isSelected =
!(myFilteredAppointmentsForProvider[selectedAppointmentIndex].customerAppointmentList?[currentIndex].isSelected ?? false);
!(myFilteredAppointmentsForProvider[selectedAppointmentIndex].customerAppointmentList?[currentIndex].isSelected ?? false);
int count = countSelected(myFilteredAppointmentsForProvider[selectedAppointmentIndex].customerAppointmentList ?? []);
if (count > 1) {
@ -512,7 +519,10 @@ class AppointmentsVM extends BaseVM {
}
int countSelected(List<AppointmentListModel> appointments) {
return appointments.where((appointment) => appointment.isSelected == true).toList().length;
return appointments
.where((appointment) => appointment.isSelected == true)
.toList()
.length;
}
updateSelectedAppointmentDate({required int dateIndex, required int scheduleIndex}) {
@ -688,13 +698,14 @@ class AppointmentsVM extends BaseVM {
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} ${LocaleKeys.sar.tr()}".toText(fontSize: 12, isBold: true),
],
),
(index) =>
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"${selectedService.serviceItems![index].name}".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
"${selectedService.serviceItems![index].price} ${LocaleKeys.sar.tr()}".toText(fontSize: 12, isBold: true),
],
),
),
),
Row(
@ -913,7 +924,10 @@ class AppointmentsVM extends BaseVM {
return InfoBottomSheet(
title: LocaleKeys.reportComplaint.tr().toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
description: Padding(
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
padding: EdgeInsets.only(bottom: MediaQuery
.of(context)
.viewInsets
.bottom),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -1248,9 +1262,6 @@ class AppointmentsVM extends BaseVM {
ifAlreadyExistForStringValue({required List<String> list, required String value}) {
int index = list.indexWhere((element) {
log("element: $element");
log("value: $value");
return element == value;
});

@ -19,6 +19,7 @@ import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/general_models/widgets_models.dart';
import 'package:mc_common_app/models/requests_models/offers_model.dart';
import 'package:mc_common_app/models/requests_models/provider_offers_model.dart';
import 'package:mc_common_app/models/requests_models/providers_offers_chat_model.dart';
import 'package:mc_common_app/models/requests_models/request_model.dart';
import 'package:mc_common_app/repositories/common_repo.dart';
import 'package:mc_common_app/repositories/request_repo.dart';
@ -784,32 +785,32 @@ class RequestsVM extends BaseVM {
});
try {
GenericRespModel respModel = await requestRepo.createRequest(
requestTypeId: requestTypeId.selectedId,
vehicleTypeId: vehicleTypeId.selectedId,
brand: brand,
model: model,
year: vehicleYearId.selectedOption,
isNew: vehicleConditionId.selectedId == 1,
// 1 for new, 2 for Used
countryID: vehicleCountryId.selectedId,
cityID: vehicleCityId.selectedId,
price: price.isEmpty ? "1.0" : price,
description: description,
address: address,
isSpecialServiceNeeded: false,
requestImages: requestImages,
);
Utils.hideLoading(context);
if (respModel.messageStatus == 1) {
log("requestTypeId.selectedId.toRequestTypeEnum(): ${requestTypeId.selectedId.toRequestTypeEnum()}");
Utils.showToast(LocaleKeys.requestSuccessfullyCreated.tr());
Navigator.pop(context);
await applyFilterOnRequestsVM(requestsTypeEnum: requestTypeId.selectedId.toRequestTypeEnum());
resetRequestCreationForm();
} else {
Utils.showToast(respModel.message.toString());
}
GenericRespModel respModel = await requestRepo.createRequest(
requestTypeId: requestTypeId.selectedId,
vehicleTypeId: vehicleTypeId.selectedId,
brand: brand,
model: model,
year: vehicleYearId.selectedOption,
isNew: vehicleConditionId.selectedId == 1,
// 1 for new, 2 for Used
countryID: vehicleCountryId.selectedId,
cityID: vehicleCityId.selectedId,
price: price.isEmpty ? "1.0" : price,
description: description,
address: address,
isSpecialServiceNeeded: false,
requestImages: requestImages,
);
Utils.hideLoading(context);
if (respModel.messageStatus == 1) {
log("requestTypeId.selectedId.toRequestTypeEnum(): ${requestTypeId.selectedId.toRequestTypeEnum()}");
Utils.showToast(LocaleKeys.requestSuccessfullyCreated.tr());
Navigator.pop(context);
await applyFilterOnRequestsVM(requestsTypeEnum: requestTypeId.selectedId.toRequestTypeEnum());
resetRequestCreationForm();
} else {
Utils.showToast(respModel.message.toString());
}
} catch (e, s) {
Utils.hideLoading(context);
log(e.toString());
@ -842,16 +843,20 @@ class RequestsVM extends BaseVM {
return isValid;
}
Future<List<OffersModel>> getOffersByRequest({required int requestId, required BuildContext context}) async {
List<ProviderOffersChatsModel> providerOffersChatsList = [];
Future<void> getProviderOffersChatsList({required int serviceProviderId, required BuildContext context}) async {
try {
Utils.showLoading(context);
List<OffersModel> respModel = await requestRepo.getOffersByRequest(requestId: requestId);
List<ProviderOffersChatsModel> respModel = await requestRepo.getOffersChatByProvider(serviceProviderId: serviceProviderId);
Utils.hideLoading(context);
return respModel;
providerOffersChatsList.clear();
providerOffersChatsList = respModel;
notifyListeners();
} catch (e) {
Utils.showToast(e.toString());
Utils.hideLoading(context);
return [];
return;
}
}

@ -385,9 +385,26 @@ class _AdsDetailViewState extends State<AdsDetailView> {
onPressed: () {
return deleteAdBottomSheet(context);
},
).toContainer(
margin: const EdgeInsets.fromLTRB(0, 8, 21, 8),
paddingAll: 0,
borderRadius: 100,
borderColor: MyColors.lightGreyEFColor,
isEnabledBorder: true,
height: 40,
width: 42,
);
} else if ((widget.adDetails.adPostStatus != AdPostStatus.pendingForPost)) {
actionWidget =
IconButton(icon: const Icon(Icons.chat_outlined, color: Colors.black), onPressed: () => adVM.onMessagesButtonPressed(context: context, adDetailsModel: widget.adDetails)).toContainer(
margin: const EdgeInsets.fromLTRB(0, 8, 21, 8),
paddingAll: 0,
borderRadius: 100,
borderColor: MyColors.lightGreyEFColor,
isEnabledBorder: true,
height: 40,
width: 42,
);
} else {
actionWidget = IconButton(icon: const Icon(Icons.chat_outlined, color: Colors.black), onPressed: () => adVM.onMessagesButtonPressed(context: context, adDetailsModel: widget.adDetails));
}
return Scaffold(
appBar: CustomAppBar(
@ -395,17 +412,7 @@ class _AdsDetailViewState extends State<AdsDetailView> {
profileImageUrl: MyAssets.bnCar,
isRemoveBackButton: false,
isDrawerEnabled: false,
actions: [
actionWidget.toContainer(
margin: const EdgeInsets.fromLTRB(0, 8, 21, 8),
paddingAll: 0,
borderRadius: 100,
borderColor: MyColors.lightGreyEFColor,
isEnabledBorder: true,
height: 40,
width: 42,
),
],
actions: [actionWidget],
onTap: () {},
),
body: Container(

@ -75,6 +75,33 @@ class _AdsFilterViewState extends State<AdsFilterView> {
ListView(
children: [
20.height,
SearchEntityWidget(
title: LocaleKeys.searchByAdID.tr(),
isForString: true,
actionWidget: TxtField(
value: adVM.currentAdIDFilter,
onChanged: (value) => adVM.onCurrentAdIDFilterChanged(value),
hint: LocaleKeys.enterAdID.tr(),
postfixWidget: Consumer(
builder: (BuildContext context, AdVM adVM, Widget? child) {
if (adVM.currentAdIDFilter.isEmpty) {
return const SizedBox();
}
return IconButton(
onPressed: () => adVM.addAdFilterAdIDSearchHistory(value: adVM.currentAdIDFilter),
icon: const Icon(Icons.done, color: MyColors.lightIconColor),
);
},
),
),
historyContentString: adVM.adsFilterAdIDSearchHistory,
onHistoryItemDeleted: (index) {
adVM.removeAdFilterAdIDSearchHistory(index: index);
},
onHistoryItemTapped: (DropValue value) => null,
historyContent: const [], // ignore in the case of TEXT FIELD
),
const Divider(thickness: 1.2).paddingOnly(top: 5, bottom: 5),
SearchEntityWidget(
title: LocaleKeys.searchByCity.tr(),
actionWidget: Builder(builder: (context) {
@ -95,6 +122,27 @@ class _AdsFilterViewState extends State<AdsFilterView> {
onHistoryItemTapped: (DropValue value) => null,
),
const Divider(thickness: 1.2).paddingOnly(top: 7, bottom: 7),
SearchEntityWidget(
title: LocaleKeys.searchByVehicleType.tr(),
actionWidget: Builder(builder: (context) {
List<DropValue> vehicleTypesDrop = [];
for (var element in adVM.vehicleTypesForFilters) {
vehicleTypesDrop.add(DropValue(element.id?.toInt() ?? 0, element.vehicleTypeName ?? "", ""));
}
return DropdownField(
(DropValue value) => adVM.updateSelectionVehicleTypeId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true),
list: vehicleTypesDrop,
dropdownValue: adVM.vehicleTypeId.selectedId != -1 ? DropValue(adVM.vehicleTypeId.selectedId, adVM.vehicleTypeId.selectedOption, "") : null,
hint: LocaleKeys.selectVehicleType.tr(),
errorValue: adVM.vehicleTypeId.errorValue,
);
}),
historyContent: adVM.vehicleTypesAdSearchHistory,
onHistoryItemDeleted: (index) => adVM.removeVehicleTypesAdSearchHistory(index: index),
onHistoryItemTapped: (DropValue value) => null,
),
const Divider(thickness: 1.2).paddingOnly(top: 7, bottom: 7),
SearchEntityWidget(
title: LocaleKeys.searchByBrandName.tr(),
actionWidget: Builder(builder: (context) {
@ -160,6 +208,60 @@ class _AdsFilterViewState extends State<AdsFilterView> {
onHistoryItemTapped: (DropValue value) => null,
),
const Divider(thickness: 1.2).paddingOnly(top: 7, bottom: 7),
LocaleKeys.searchByDemandPrice.tr().toText(fontSize: 16, isBold: true),
8.height,
Row(
children: [
Expanded(
child: SearchEntityWidget(
title: '',
isForString: false,
actionWidget: TxtField(
onChanged: (value) => adVM.updateAdFilterDemandStartPrice(value),
value: adVM.adFilterDemandStartPrice,
hint: LocaleKeys.enterStartPrice.tr(),
keyboardType: TextInputType.number,
numbersOnly: true,
postfixWidget: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
LocaleKeys.sar.tr().toText(fontWeight: MyFonts.Medium, fontSize: 15, color: borderColor, textAlign: TextAlign.center),
],
),
),
historyContentString: const [],
onHistoryItemDeleted: (index) {},
onHistoryItemTapped: (DropValue value) => null,
historyContent: const [], // ignore in the case of TEXT FIELD
),
),
20.width,
Expanded(
child: SearchEntityWidget(
title: '',
isForString: false,
actionWidget: TxtField(
onChanged: (value) => adVM.updateAdFilterDemandEndPrice(value),
value: adVM.adFilterDemandEndPrice,
hint: LocaleKeys.enterEndPrice.tr(),
keyboardType: TextInputType.number,
numbersOnly: true,
postfixWidget: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
LocaleKeys.sar.tr().toText(fontWeight: MyFonts.Medium, fontSize: 15, color: borderColor, textAlign: TextAlign.center),
],
),
),
historyContentString: [],
onHistoryItemDeleted: (index) {},
onHistoryItemTapped: (DropValue value) => null,
historyContent: const [], // ignore in the case of TEXT FIELD
),
),
],
),
const Divider(thickness: 1.2).paddingOnly(top: 7, bottom: 7),
SearchEntityWidget(
title: LocaleKeys.searchByAdOwner.tr(),
actionWidget: Builder(
@ -204,7 +306,34 @@ class _AdsFilterViewState extends State<AdsFilterView> {
historyContent: adVM.vehicleAdCreatedDateSearchHistory,
onHistoryItemDeleted: (index) => adVM.removeVehicleAdCreatedDateSearchHistory(index: index),
onHistoryItemTapped: (DropValue value) => null,
)
),
const Divider(thickness: 1.2).paddingOnly(top: 5, bottom: 5),
SearchEntityWidget(
title: LocaleKeys.searchByMobileNumber.tr(),
isForString: true,
actionWidget: TxtField(
onChanged: (value) => adVM.onCurrentAdMobilePhoneFilterChanged(value),
value: adVM.currentAdMobilePhoneFilter,
hint: LocaleKeys.enterMobileNumber.tr(),
postfixWidget: Consumer(
builder: (BuildContext context, AdVM adVM, Widget? child) {
if (adVM.currentAdMobilePhoneFilter.isEmpty) {
return const SizedBox();
}
return IconButton(
onPressed: () => adVM.addAdFilterMobilePhoneSearchHistory(value: adVM.currentAdMobilePhoneFilter),
icon: const Icon(Icons.done, color: MyColors.lightIconColor),
);
},
),
),
historyContentString: adVM.adFilterMobilePhoneSearchHistory,
onHistoryItemDeleted: (index) {
adVM.removeAdFilterMobilePhoneSearchHistory(index: index);
},
onHistoryItemTapped: (DropValue value) => null,
historyContent: const [], // ignore in the case of TEXT FIELD
),
],
).expand(),
Container(

@ -168,10 +168,15 @@ class AdDurationSelectionSheet extends StatelessWidget {
return;
} else {
if (isFromExtendAd && !isUpdateAdSelected) {
bool status = await adVM.createAdExtensionOrder(context, adId: adsID, adsDurationId: adVM.vehicleAdDurationId.selectedId);
log("hereStatus: $status");
if (status) {
List<bool> statuses =
await adVM.createAdExtensionOrder(context, adId: adsID, adsDurationId: adVM.vehicleAdDurationId.selectedId); // [0] Means API response [1] means isPaymentRequired
if (statuses[0] && statuses[1]) {
navigateWithName(context, AppRoutes.paymentMethodsView, arguments: PaymentTypes.extendAds);
} else if (statuses[0] == true && statuses[1] == false) {
pop(context);
pop(context);
pop(context);
adVM.applyFilterOnMyAds(adPostStatusEnum: AdPostStatus.active);
}
} else {
navigateReplaceWithName(context, AppRoutes.createAdView);

@ -82,10 +82,15 @@ class SelectAdTypeView extends StatelessWidget {
}
if (AppState().currentAppType == AppType.provider) {
if (isFromExtendAd && !adVM.isAdEditEnabled) {
bool status = await adVM.createAdExtensionOrder(context, adId: adsId, adsDurationId: adVM.vehicleAdDurationId.selectedId);
log("hereStatus: $status");
if (status) {
List<bool> statuses =
await adVM.createAdExtensionOrder(context, adId: adsId, adsDurationId: adVM.vehicleAdDurationId.selectedId); // [0] Means API response [1] means isPaymentRequired
if (statuses[0] && statuses[1]) {
navigateWithName(context, AppRoutes.paymentMethodsView, arguments: PaymentTypes.extendAds);
} else if (statuses[0] == true && statuses[1] == false) {
pop(context);
pop(context);
pop(context);
adVM.applyFilterOnMyAds(adPostStatusEnum: AdPostStatus.active);
}
} else {
navigateReplaceWithName(context, AppRoutes.createAdView);

@ -1,3 +1,5 @@
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';
@ -7,6 +9,7 @@ import 'package:mc_common_app/models/appointments_models/appointment_list_model.
import 'package:mc_common_app/models/chat_models/chat_message_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/date_helper.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';
@ -79,7 +82,7 @@ class AppointmentDetailView extends StatelessWidget {
}
}
Widget buildBottomActionButton({required AppointmentStatusEnum appointmentStatusEnum, required BuildContext context}) {
Widget buildBottomActionButton({required AppointmentStatusEnum appointmentStatusEnum, required BuildContext context, required bool shouldShowConfirmButton}) {
switch (appointmentStatusEnum) {
case AppointmentStatusEnum.booked:
return Align(
@ -87,13 +90,15 @@ class AppointmentDetailView extends StatelessWidget {
child: Row(
children: [
getBaseActionButtonWidget(color: MyColors.redColor, onPressed: () => buildCancelAppointmentReasonsBottomSheet(context: context), text: LocaleKeys.cancel.tr()),
12.width,
getBaseActionButtonWidget(
color: MyColors.greenColor,
onPressed: () {
context.read<AppointmentsVM>().onConfirmAppointmentPressed(context: context, appointmentId: appointmentListModel.id);
},
text: LocaleKeys.confirm.tr()),
if (shouldShowConfirmButton) ...[
12.width,
getBaseActionButtonWidget(
color: MyColors.greenColor,
onPressed: () {
context.read<AppointmentsVM>().onConfirmAppointmentPressed(context: context, appointmentId: appointmentListModel.id);
},
text: LocaleKeys.confirm.tr()),
]
],
),
);
@ -134,13 +139,15 @@ class AppointmentDetailView extends StatelessWidget {
child: Row(
children: [
getBaseActionButtonWidget(color: MyColors.redColor, onPressed: () => buildCancelAppointmentReasonsBottomSheet(context: context), text: LocaleKeys.cancel.tr()),
12.width,
getBaseActionButtonWidget(
color: MyColors.greenColor,
onPressed: () {
context.read<AppointmentsVM>().onConfirmAppointmentPressed(context: context, appointmentId: appointmentListModel.id);
},
text: LocaleKeys.confirm.tr()),
if (shouldShowConfirmButton) ...[
12.width,
getBaseActionButtonWidget(
color: MyColors.greenColor,
onPressed: () {
context.read<AppointmentsVM>().onConfirmAppointmentPressed(context: context, appointmentId: appointmentListModel.id);
},
text: LocaleKeys.confirm.tr()),
],
],
),
);
@ -256,6 +263,12 @@ class AppointmentDetailView extends StatelessWidget {
@override
Widget build(BuildContext context) {
AppointmentsVM appointmentsVM = context.read<AppointmentsVM>();
bool shouldShowConfirmButton = false;
final currentDateTime = DateTime.now();
if ((appointmentListModel.isPaymentRequiredAtBooking ?? false) && appointmentListModel.appointmentDate != null && appointmentListModel.appointmentDate!.isNotEmpty) {
final DateTime appointmentDatetime = DateHelper.parseStringToDate(appointmentListModel.appointmentDate!);
shouldShowConfirmButton = (appointmentListModel.isPaymentRequiredAtBooking ?? false) && (appointmentDatetime.isAfter(currentDateTime));
}
return Scaffold(
appBar: CustomAppBar(
title: LocaleKeys.appointment.tr(),
@ -337,7 +350,7 @@ class AppointmentDetailView extends StatelessWidget {
},
icon: MyAssets.scheduleAppointmentIcon.buildSvg(),
),
if (appointmentListModel.appointmentStatusEnum == AppointmentStatusEnum.booked) ...[
if (appointmentListModel.appointmentStatusEnum == AppointmentStatusEnum.booked && (shouldShowConfirmButton)) ...[
10.width,
CardButtonWithIcon(
title: LocaleKeys.payforAppointment.tr(),
@ -353,7 +366,7 @@ class AppointmentDetailView extends StatelessWidget {
],
],
).toWhiteContainer(width: double.infinity, allPading: 12),
buildBottomActionButton(appointmentStatusEnum: appointmentListModel.appointmentStatusEnum!, context: context),
buildBottomActionButton(appointmentStatusEnum: appointmentListModel.appointmentStatusEnum!, context: context, shouldShowConfirmButton: shouldShowConfirmButton),
],
),
),

@ -80,6 +80,18 @@ class MyRequestsFragment extends StatelessWidget {
title: LocaleKeys.manageRequests.tr(),
isRemoveBackButton: true,
actions: [
if (AppState().currentAppType == AppType.provider) ...[
Padding(
padding: const EdgeInsets.only(top: 8, bottom: 8, right: 15),
child: const Icon(Icons.messenger_outline_rounded, color: Colors.black, size: 18).toContainer(
borderRadius: 80,
borderColor: MyColors.lightGreyEFColor,
isEnabledBorder: true,
),
).onPress(() {
navigateWithName(context, AppRoutes.providersChatListPage);
})
],
Padding(
padding: EdgeInsets.only(top: requestsVM.requestsFiltersCounter > 0 ? 20 : 0, right: 21),
child: Badge(
@ -92,7 +104,7 @@ class MyRequestsFragment extends StatelessWidget {
),
).onPress(() {
navigateWithName(context, AppRoutes.requestsFilterView);
})
}),
],
).toViewOnly(context, onTap: () {
navigateWithName(context, AppRoutes.loginWithPassword, arguments: false);
@ -201,8 +213,8 @@ class MyRequestsFragment extends StatelessWidget {
color: MyColors.white,
),
).toViewOnly(context, onTap: () {
navigateWithName(context, AppRoutes.loginWithPassword, arguments: false);
})
navigateWithName(context, AppRoutes.loginWithPassword, arguments: false);
})
: null,
);
});

@ -0,0 +1,180 @@
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/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/requests_models/offers_model.dart';
import 'package:mc_common_app/models/requests_models/provider_offers_model.dart';
import 'package:mc_common_app/models/requests_models/providers_offers_chat_model.dart';
import 'package:mc_common_app/models/requests_models/request_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';
import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/view_models/chat_view_model.dart';
import 'package:mc_common_app/view_models/requests_view_model.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';
import 'package:easy_localization/easy_localization.dart';
class ProvidersChatListPage extends StatefulWidget {
const ProvidersChatListPage({super.key});
@override
State<ProvidersChatListPage> createState() => _ProvidersChatListPageState();
}
class _ProvidersChatListPageState extends State<ProvidersChatListPage> {
@override
void initState() {
_onRefresh();
super.initState();
}
_onRefresh() async {
scheduleMicrotask(() async {
RequestsVM requestsVM = context.read<RequestsVM>();
await requestsVM.getProviderOffersChatsList(serviceProviderId: AppState().getUser.data!.userInfo!.providerId ?? 0, context: context);
});
}
Future<void> onChatTapped({required BuildContext context, required int requestID}) async {
final requestsVM = context.read<RequestsVM>();
final chatVM = context.read<ChatVM>();
int requestIndex = requestsVM.myFilteredRequests.indexWhere((request) => request.id == requestID);
log("requestIndex1: $requestIndex");
if (requestIndex == -1) {
RequestsTypeEnum requestTypeEnum = requestsVM.requestsTypeFilterOptions.firstWhere((element) => element.isSelected).id.toRequestTypeEnum();
if (requestTypeEnum == RequestsTypeEnum.specialCarRequest) {
requestTypeEnum = RequestsTypeEnum.serviceRequest;
} else {
requestTypeEnum = RequestsTypeEnum.specialCarRequest;
}
await requestsVM.applyFilterOnRequestsVM(requestsTypeEnum: requestTypeEnum);
requestIndex = requestsVM.myFilteredRequests.indexWhere((request) => request.id == requestID);
}
if (requestIndex != -1) {
RequestModel request = requestsVM.myFilteredRequests[requestIndex];
requestsVM.updateCurrentSelectedRequest(request);
// if (request.requestStatus == RequestStatusEnum.pending || request.requestStatus == RequestStatusEnum.cancelled || request.requestStatus == RequestStatusEnum.expired) {
// Utils.showToast("${LocaleKeys.requests.tr()} ${request.requestStatusName}");
// return;
// }
RequestDetailPageArguments requestDetailPageArguments = RequestDetailPageArguments(requestIndex: requestIndex, requestModel: request);
ChatViewArgumentsForRequest chatViewArgumentsForRequest = ChatViewArgumentsForRequest(
chatTypeEnum: ChatTypeEnum.requestOffer,
receiverId: requestDetailPageArguments.requestModel.customerID,
senderId: AppState().getUser.data!.userInfo!.userId.toString(),
requestId: requestDetailPageArguments.requestModel.id,
providerIndex: -1,
// This will be only sent in case of customer
requestModel: requestDetailPageArguments.requestModel,
requestIndex: requestDetailPageArguments.requestIndex, // This will be only sent in case of provider
);
ChatViewArguments chatViewArguments = ChatViewArguments(
chatTypeEnum: ChatTypeEnum.requestOffer,
chatViewArgumentsForRequest: chatViewArgumentsForRequest,
);
log("requestIndex2: $requestIndex");
await chatVM
.getRequestsChatMessagesForProvider(
customerId: requestDetailPageArguments.requestModel.customerId,
context: navigatorKey.currentState!.overlay!.context,
requestOfferId: 0,
requestId: requestDetailPageArguments.requestModel.id,
customerRequestIndex: requestDetailPageArguments.requestIndex,
)
.whenComplete(() => navigateWithName(navigatorKey.currentState!.overlay!.context, AppRoutes.chatView, arguments: chatViewArguments));
}
}
@override
Widget build(BuildContext context) {
return Consumer<RequestsVM>(builder: (context, RequestsVM requestsVM, Widget? child) {
return Scaffold(
appBar: CustomAppBar(title: LocaleKeys.specialRequestChat.tr()),
body: RefreshIndicator(
onRefresh: () async {
_onRefresh();
},
child: requestsVM.state == ViewState.busy
? const Center(child: CircularProgressIndicator())
: requestsVM.providerOffersChatsList.isEmpty
? Center(
child: LocaleKeys.noOffersShow.tr().toText(
fontSize: 16,
color: MyColors.lightTextColor,
),
)
: ListView.separated(
itemCount: requestsVM.providerOffersChatsList.length,
padding: const EdgeInsets.all(16),
itemBuilder: (context, index) {
ProviderOffersChatsModel providerOffersChatsModel = requestsVM.providerOffersChatsList[index];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Utils.statusContainerChip(
text: Utils.getNameByRequestOfferStatusEnum(providerOffersChatsModel.requestOfferStatusEnum!),
chipColor: Utils.getChipColorByRequestOfferStatusEnum(providerOffersChatsModel.requestOfferStatusEnum!),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
(providerOffersChatsModel.customerName ?? "").toText(
fontSize: 16,
isBold: true,
),
if (providerOffersChatsModel.createdOn != null && providerOffersChatsModel.createdOn!.isNotEmpty) ...[
DateTime.parse(providerOffersChatsModel.createdOn!).getTimeAgo().toText(color: MyColors.lightTextColor, fontSize: 14),
],
// if (providerOffersChatsModel. != null && offersModel.offerCount! > 0) ...[
// Center(
// child: "${providerOffersChatsModel.offerCount}".toText(
// color: Colors.white,
// isBold: true,
// fontSize: 10,
// ),
// ).toContainer(
// backgroundColor: MyColors.cancelledColor,
// borderRadius: 100,
// paddingAll: 1,
// width: 22,
// height: 22,
// ),
// ],
],
),
4.height,
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: "${providerOffersChatsModel.comment}".toText(color: MyColors.lightTextColor, fontSize: 14),
),
const Icon(Icons.arrow_forward, color: MyColors.darkIconColor, size: 18),
],
),
],
).onPress(() async => await onChatTapped(context: context, requestID: providerOffersChatsModel.requestID ?? 0)).toContainer(isShadowEnabled: true);
},
separatorBuilder: (context, index) => 16.height,
),
),
);
});
}
}

@ -30,8 +30,10 @@ class SearchEntityWidget extends StatelessWidget {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
title.toText(fontSize: 16, isBold: true),
8.height,
if (title.isNotEmpty) ...[
title.toText(fontSize: 16, isBold: true),
8.height,
],
actionWidget,
10.height,
if (isForString && historyContentString != null && historyContentString!.isNotEmpty) ...[

Loading…
Cancel
Save