Duration Discount

aamir_dev
Faiz Hashmi 11 months ago
parent 30fc25c236
commit 98b6e03678

@ -748,5 +748,9 @@
"offerNotMatched": "العرض لم يتطابق مع الطلب.",
"offerRejected": "تم رفض العرض.",
"offerAccepted": "تم قبول العرض.",
"you": "أنتم"
"you": "أنتم",
"youCannotDeactivateThisServiceRightNow": "لا يمكنك تعطيل هذه الخدمة الآن لأن لديك مواعيد معلقة لهذه الخدمة. تفاصيل آخر موعد هي:",
"done": "تم",
"notice": "إشعار",
"serviceDeactivated": "تم تعطيل الخدمة"
}

@ -746,5 +746,9 @@
"offerNotMatched": "The offer did not match the request.",
"offerRejected": "Offer has been Rejected.",
"offerAccepted": "Offer has been Accepted.",
"you": "You"
"you": "You",
"youCannotDeactivateThisServiceRightNow": "You cannot deactivate this service right now because you have pending appointments for this service. The last appointment details are:",
"done": "Done",
"notice": "Notice",
"serviceDeactivated": "Service Deactivated"
}

@ -55,8 +55,10 @@ class ApiConsts {
static String servicesGet = "${baseUrlServices}api/ServiceProviders/Services_Get";
static String serviceProviderServiceCreate = "${baseUrlServices}api/ServiceProviders/ServiceProviderService_Create";
static String serviceProviderServiceUpdate = "${baseUrlServices}api/ServiceProviders/ServiceProviderService_Update";
static String serviceProviderServiceStatusUpdate = "${baseUrlServices}api/ServiceProviders/CategoryAndServiceDeactivateBySP";
static String getProviderServices = "${baseUrlServices}api/ServiceProviders/ServiceProviderService_Get";
static String setScheduleInactive = "${baseUrlServices}api/ServiceProviders/BranchAppointmentSchedule_IsActiveUpdate";
static String serviceProviderAppointmentGetByCategoryOrService = "${baseUrlServices}api/ServiceProviders/ServiceProviderAppointment_GetByCategoryOrService";
static String serviceProviderServiceGet = "${baseUrlServices}api/ServiceProviders/ServiceProviderService_Get";
static String branchesAndServices = "${baseUrlServices}api/ServiceProviders/ServiceProviderDetail_Get";

@ -764,7 +764,11 @@ class CodegenLoader extends AssetLoader{
"offerNotMatched": "العرض لم يتطابق مع الطلب.",
"offerRejected": "تم رفض العرض.",
"offerAccepted": "تم قبول العرض.",
"you": "أنتم"
"you": "أنتم",
"youCannotDeactivateThisServiceRightNow": "لا يمكنك تعطيل هذه الخدمة الآن لأن لديك مواعيد معلقة لهذه الخدمة. تفاصيل آخر موعد هي:",
"done": "تم",
"notice": "إشعار",
"serviceDeactivated": "تم تعطيل الخدمة"
};
static const Map<String,dynamic> en_US = {
"firstTimeLogIn": "First Time Log In",
@ -1514,7 +1518,11 @@ static const Map<String,dynamic> en_US = {
"offerNotMatched": "The offer did not match the request.",
"offerRejected": "Offer has been Rejected.",
"offerAccepted": "Offer has been Accepted.",
"you": "You"
"you": "You",
"youCannotDeactivateThisServiceRightNow": "You cannot deactivate this service right now because you have pending appointments for this service. The last appointment details are:",
"done": "Done",
"notice": "Notice",
"serviceDeactivated": "Service Deactivated"
};
static const Map<String, Map<String,dynamic>> mapLocales = {"ar_SA": ar_SA, "en_US": en_US};
}

@ -728,5 +728,9 @@ abstract class LocaleKeys {
static const offerRejected = 'offerRejected';
static const offerAccepted = 'offerAccepted';
static const you = 'you';
static const youCannotDeactivateThisServiceRightNow = 'youCannotDeactivateThisServiceRightNow';
static const done = 'done';
static const notice = 'notice';
static const serviceDeactivated = 'serviceDeactivated';
}

@ -0,0 +1,45 @@
class AppointmentBasicDetailsModel {
int? serviceSlotID;
String? slotDate;
String? startTime;
String? endTime;
int? appointmentStatusID;
String? appointmentStatusText;
int? serviceProviderID;
int? customerID;
AppointmentBasicDetailsModel({
this.serviceSlotID,
this.slotDate,
this.startTime,
this.endTime,
this.appointmentStatusID,
this.appointmentStatusText,
this.serviceProviderID,
this.customerID,
});
AppointmentBasicDetailsModel.fromJson(Map<String, dynamic> json) {
serviceSlotID = json['serviceSlotID'];
slotDate = json['slotDate'];
startTime = json['startTime'];
endTime = json['endTime'];
appointmentStatusID = json['appointmentStatusID'];
appointmentStatusText = json['appointmentStatusText'];
serviceProviderID = json['serviceProviderID'];
customerID = json['customerID'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['serviceSlotID'] = serviceSlotID;
data['slotDate'] = slotDate;
data['startTime'] = startTime;
data['endTime'] = endTime;
data['appointmentStatusID'] = appointmentStatusID;
data['appointmentStatusText'] = appointmentStatusText;
data['serviceProviderID'] = serviceProviderID;
data['customerID'] = customerID;
return data;
}
}

@ -5,6 +5,8 @@ import 'package:mc_common_app/api/api_client.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependency_injection.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/appointments_models/appointment_basic_detail_model.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/provider_branches_models/branch_detail_model.dart';
import 'package:mc_common_app/models/provider_branches_models/branch_review_model.dart';
@ -16,6 +18,7 @@ import 'package:mc_common_app/models/provider_branches_models/provider_model.dar
import 'package:mc_common_app/models/provider_branches_models/provider_profile_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/utils/enums.dart';
abstract class BranchRepo {
Future<GenericRespModel> createBranch({
@ -70,6 +73,10 @@ abstract class BranchRepo {
Future<GenericRespModel> updateService(List<Map<String, dynamic>> map);
Future<GenericRespModel> updateServiceStatus({required int branchId, required List<int> serviceIds, required ServiceStatusEnum serviceStatusEnum});
Future<List<AppointmentBasicDetailsModel>> getAppointmentsByCategoryOrService({required int branchId, required int serviceId});
Future<GenericRespModel> getMatchedServices(int oldBranchId, int newBranchId, int categoryId);
Future<GenericRespModel> duplicateItems({required String providerBranchID, required List<int> items});
@ -305,6 +312,45 @@ class BranchRepoImp implements BranchRepo {
return await apiClient.postJsonForObject((json) => GenericRespModel.fromJson(json), ApiConsts.serviceProviderServiceUpdate, map, token: t);
}
@override
Future<GenericRespModel> updateServiceStatus({required int branchId, required List<int> serviceIds, required ServiceStatusEnum serviceStatusEnum}) async {
List<String> ids = [];
for (var id in serviceIds) {
ids.add(id.toString());
}
int providerID = AppState().getUser.data!.userInfo!.providerId;
var map = {
"ServiceProviderID": providerID.toString(),
"ProviderBranchID": branchId.toString(),
"ProviderServiceIDs": ids,
"Status": serviceStatusEnum.getIdFromServiceStatusEnum().toString(),
};
String t = AppState().getUser.data!.accessToken ?? "";
return await apiClient.getJsonForObject((json) => GenericRespModel.fromJson(json), ApiConsts.serviceProviderServiceStatusUpdate, queryParameters: map, token: t);
}
@override
Future<List<AppointmentBasicDetailsModel>> getAppointmentsByCategoryOrService({required int branchId, required int serviceId}) async {
var map = {
"ProviderBranchID": branchId.toString(),
"ServiceProviderServiceID": serviceId.toString(),
};
String t = AppState().getUser.data!.accessToken ?? "";
GenericRespModel genericRespModel = await apiClient.getJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.serviceProviderAppointmentGetByCategoryOrService,
queryParameters: map,
token: t,
);
List<AppointmentBasicDetailsModel> basicAppointmentList = List.generate(genericRespModel.data.length, (index) => AppointmentBasicDetailsModel.fromJson(genericRespModel.data[index]));
return basicAppointmentList;
}
@override
Future<GenericRespModel> getMatchedServices(int oldBranchId, int newBranchId, int categoryId) async {
var postParams = {

@ -48,7 +48,7 @@ abstract class CommonRepo {
Future<SSCarCheckScheduleModel> getCarCheckServiceScheduleDetails({required double lat, required double long});
Future<List<SSPhotoOfficeScheduleModel>> getPhotographyServiceScheduleListByOffices({required double lat, required double long});
Future<List<SSPhotoOfficeScheduleModel>> getPhotographyServiceScheduleListByOffices({required double lat, required double long, required int cityID});
//TODO: Needs to remove common methods from AD's repo and delete all repeated methods.
Future<VehicleDetailsModel> getVehicleDetails({int? vehicleTypeId, int? vehicleBrandId});
@ -97,10 +97,11 @@ class CommonRepoImp implements CommonRepo {
}
@override
Future<List<SSPhotoOfficeScheduleModel>> getPhotographyServiceScheduleListByOffices({required double lat, required double long}) async {
Future<List<SSPhotoOfficeScheduleModel>> getPhotographyServiceScheduleListByOffices({required double lat, required double long, required int cityID}) async {
var params = {
"Latitude": lat.toString(),
"Longitude": long.toString(),
"cityID": cityID.toString(),
};
GenericRespModel genericRespModel = await apiClient.getJsonForObject(
token: appState.getUser.data!.accessToken,

@ -114,10 +114,7 @@ class AdVM extends BaseVM {
}
void removeSpecialServiceCard(int index) {
String option = specialServiceCards
.elementAt(index)
.serviceSelectedId!
.selectedOption;
String option = specialServiceCards.elementAt(index).serviceSelectedId!.selectedOption;
for (var value in vehicleAdsSpecialServices) {
if (value.name == option) {
@ -1258,10 +1255,7 @@ class AdVM extends BaseVM {
}
void removeDamagePartCard(int index) {
String option = vehicleDamageCards
.elementAt(index)
.partSelectedId!
.selectedOption;
String option = vehicleDamageCards.elementAt(index).partSelectedId!.selectedOption;
for (var value in vehicleDamageParts) {
if (value.partName == option) {
@ -1394,8 +1388,9 @@ class AdVM extends BaseVM {
Future<void> getPhotographyServiceScheduleListByOffices({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);
photoSSSchedulesByOffices = await commonRepo.getPhotographyServiceScheduleListByOffices(lat: latitude, long: longitude, cityID: cityID);
if (isNeedToRebuild) setState(ViewState.idle);
} catch (e) {
if (isNeedToRebuild) setState(ViewState.idle);
@ -1539,9 +1534,7 @@ class AdVM 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;
vehiclePostingImages = VehiclePostingImages(
imageName: fileName,
imageStr: image,
@ -2041,13 +2034,13 @@ class AdVM extends BaseVM {
final chatVM = context.read<ChatVM>();
await chatVM
.getUsersChatMessagesForAd(
context: context,
isForBuyer: true,
adsChatBuyerId: 1,
adID: adDetailsModel.id,
userID: myUserID,
senderName: adDetailsModel.adOwnerName,
)
context: context,
isForBuyer: true,
adsChatBuyerId: 1,
adID: adDetailsModel.id,
userID: myUserID,
senderName: adDetailsModel.adOwnerName,
)
.whenComplete(() => navigateWithName(context, AppRoutes.chatView, arguments: chatViewArguments));
}
}

@ -97,9 +97,9 @@ class ChatVM extends BaseVM {
notifyListeners();
}
List<int> indexesForCancelSpecialCarOffer = [0, 1, 6, 10];
List<int> indexesForCancelSparePartOffer = [2, 10];
List<int> indexesForRejectOffer = [3, 4, 5, 10];
List<int> indexesForCancelSpecialCarOffer = [0, 1, 5, 6, 10];
List<int> indexesForCancelSparePartOffer = [2, 5, 10];
List<int> indexesForRejectOffer = [3, 4, 10];
List<int> indexesForDealNotCompleted = [7, 4, 8, 9, 10];
List<OfferRequestCommentModel> offerRejectModelList = [

@ -1,4 +1,5 @@
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
@ -6,8 +7,10 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/appointments_models/appointment_basic_detail_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/general_models/widgets_models.dart';
@ -24,12 +27,17 @@ import 'package:mc_common_app/models/user_models/country.dart';
import 'package:mc_common_app/repositories/branch_repo.dart';
import 'package:mc_common_app/repositories/common_repo.dart';
import 'package:mc_common_app/services/common_services.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/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/utils/utils.dart';
import 'package:mc_common_app/view_models/ad_view_model.dart';
import 'package:mc_common_app/view_models/base_view_model.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
import 'package:mc_common_app/widgets/common_widgets/info_bottom_sheet.dart';
import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
class ServiceVM extends BaseVM {
final BranchRepo branchRepo;
@ -201,7 +209,6 @@ class ServiceVM extends BaseVM {
}
branchServicesFilterOptions[serviceStatusEnum.getIdFromServiceStatusEnum() - 1].isSelected = true; // -1 to match with the index
}
// Future<String?> selectFile(BuildContext context, int index) async {
@ -264,11 +271,7 @@ 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;
}
@ -282,8 +285,8 @@ class ServiceVM extends BaseVM {
documentID == 1
? commerceCertificates.addAll(imageModels)
: documentID == 2
? commercialCertificates.addAll(imageModels)
: vatCertificates.addAll(imageModels);
? commercialCertificates.addAll(imageModels)
: vatCertificates.addAll(imageModels);
document!.data![index].document = Utils.convertFileToBase64(files.first);
document!.data![index].fileExt = Utils.checkFileExt(files.first.path);
document!.data![index].documentUrl = files.first.path;
@ -459,10 +462,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"),
"",
),
@ -528,6 +531,92 @@ class ServiceVM extends BaseVM {
return await branchRepo.updateService(map);
}
Future<List<AppointmentBasicDetailsModel>> getAppointmentsByServiceID({required BuildContext context, required int branchId, required int serviceId}) async {
try {
Utils.showLoading(context);
List<AppointmentBasicDetailsModel> appointmentList = await branchRepo.getAppointmentsByCategoryOrService(branchId: branchId, serviceId: serviceId);
// log("list: ${mResponse.}");
Utils.hideLoading(context);
return appointmentList;
} catch (e) {
Utils.hideLoading(context);
log(e.toString());
Utils.showToast(e.toString() ?? "");
return [];
}
}
Future<bool> updateServiceStatus({required BuildContext context, required ServiceStatusEnum serviceStatusEnum, required int branchId, required List<int> providerServiceIds}) async {
try {
Utils.showLoading(context);
GenericRespModel genericRespModel = await branchRepo.updateServiceStatus(branchId: branchId, serviceIds: providerServiceIds, serviceStatusEnum: serviceStatusEnum);
Utils.hideLoading(context);
Utils.showToast(genericRespModel.message ?? "");
return genericRespModel.messageStatus == 1;
} catch (e) {
Utils.hideLoading(context);
log(e.toString());
Utils.showToast(e.toString());
return false;
}
}
Future buildDealNotCompletedBottomSheetOptions({required BuildContext mainContext, required List<AppointmentBasicDetailsModel> appointments, required String branchName}) async {
return actionConfirmationBottomSheet(
isOnlyOneButton: true,
context: mainContext,
title: LocaleKeys.notice.tr().toText(fontSize: 26, isBold: true, letterSpacing: -1.44),
subtitle: LocaleKeys.youCannotDeactivateThisServiceRightNow.tr(),
checkBoxConfirmationWidget: ListView.builder(
shrinkWrap: true,
itemCount: appointments.length,
itemBuilder: (BuildContext context, int index) {
AppointmentBasicDetailsModel appointmentBasicDetailsModel = appointments[index];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (appointmentBasicDetailsModel.appointmentStatusText != null && appointmentBasicDetailsModel.appointmentStatusText!.isNotEmpty) ...[
Utils.statusContainerChip(text: appointmentBasicDetailsModel.appointmentStatusText!, chipColor: MyColors.black),
],
6.height,
"${appointmentBasicDetailsModel.customerID}".toText(fontSize: 16, letterSpacing: -0.64),
showItem("${LocaleKeys.branchName.tr()}:", "${appointmentBasicDetailsModel.slotDate}"),
showItem("${LocaleKeys.date.tr()}:", "${appointmentBasicDetailsModel.slotDate}"),
showItem("${LocaleKeys.time.tr()}:", "${appointmentBasicDetailsModel.startTime} - ${appointmentBasicDetailsModel.startTime}"),
],
).toContainer(isShadowEnabled: true);
}),
actionButtonYes: Expanded(
child: ShowFillButton(
maxHeight: 55,
title: LocaleKeys.done.tr(),
fontSize: 15,
onPressed: () => Navigator.pop(mainContext),
),
),
actionButtonNo: Expanded(
child: ShowFillButton(
maxHeight: 55,
title: LocaleKeys.done.tr(),
fontSize: 15,
onPressed: () => Navigator.pop(mainContext),
),
),
);
}
Widget showItem(String title, String value) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
title.toText(color: MyColors.lightTextColor, letterSpacing: -0.48),
3.width,
Flexible(child: value.toText(isBold: true, overflow: TextOverflow.ellipsis)),
],
);
}
void updateSelectedBranchType(int status) {
selectedBranchStatus = status;
notifyListeners();
@ -657,9 +746,7 @@ 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,

@ -769,8 +769,8 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
],
),
] else if (AppState().currentAppType == AppType.provider &&
widget.chatMessageModel.reqOffer!.requestOfferStatusEnum == RequestOfferStatusEnum.offer &&
chatMessageTypeEnum == ChatMessageTypeEnum.offer &&
widget.chatMessageModel.reqOffer!.requestOfferStatusEnum == RequestOfferStatusEnum.offer &&
(widget.chatMessageModel.isMyMessage == true)) ...[
MyAssets.icEdit.buildSvg(color: MyColors.white, height: 15).onPress(() => onOfferEditIconPressed()),
],

Loading…
Cancel
Save