Added Shipping Management

aamir_dev
Faiz Hashmi 1 year ago
parent fb41cd0770
commit 450dfff6e8

@ -145,8 +145,6 @@ class ApiConsts {
//Branch Users
static String getAllProviderDealers = "${baseUrlServices}api/ServiceProviders/DealershipUserBranchWise_Get";
// /api/ServiceProviders/BranchUser_Get
//DealershipUserBranchWise_Get
static String getBranchUser = "${baseUrlServices}api/ServiceProviders/BranchUser_Get";
static String assignDealerToBranch = "${baseUrlServices}api/ServiceProviders/BranchUser_Create";
static String removeDealerFromBranch = "${baseUrlServices}api/ServiceProviders/BranchUser_Update";
@ -164,6 +162,10 @@ class ApiConsts {
static String requestOffersSpsGet = "${baseUrlServices}api/RequestManagement/Request_OfferSPs_Get";
static String getServiceRequestsForProvider = "${baseUrlServices}api/RequestManagement/Request_ServiceProvider";
//Shipping
static String shippingRequestStatusUpdate = "${baseUrlServices}api/RequestManagement/ShippingRequestStatus_Update";
static String shippingRequestStatusGet = "${baseUrlServices}api/RequestManagement/ShippingRequestStatus_Get";
//Chat
static String chatHubUrl = "$baseUrlServices/McHub";
static String messageIsReadUpdateForRequests = "${baseUrlServices}api/RequestManagement/ReqOfferChatIsRead_Update";
@ -294,8 +296,6 @@ class MyAssets {
static String whatsAppIcon = "${assetPath}icons/whatsapp_icon.svg";
static const String arrowRight = "${assetPath}icons/ic_arrow_right.svg";
static const String brokenImage = "${assetPath}images/broken_image.png";
}
RegExp numReg = RegExp(r".*[0-9].*");

@ -12,6 +12,7 @@ import 'package:mc_common_app/repositories/branch_repo.dart';
import 'package:mc_common_app/repositories/chat_repo.dart';
import 'package:mc_common_app/repositories/common_repo.dart';
import 'package:mc_common_app/repositories/payments_repo.dart';
import 'package:mc_common_app/repositories/shipping_repo.dart';
import 'package:mc_common_app/repositories/user_repo.dart';
import 'package:mc_common_app/services/common_services.dart';
import 'package:mc_common_app/services/firebase_service.dart';
@ -42,6 +43,7 @@ class AppDependencies {
injector.registerSingleton<AppointmentRepo>(() => AppointmentRepoImp());
injector.registerSingleton<ChatRepo>(() => ChatRepoImp());
injector.registerSingleton<BranchRepo>(() => BranchRepoImp());
injector.registerSingleton<ShippingRepo>(() => ShippingRepoImp());
//
}

@ -23,6 +23,7 @@ import 'package:mc_common_app/views/setting_options/setting_option_help.dart';
import 'package:mc_common_app/views/setting_options/setting_options_faqs.dart';
import 'package:mc_common_app/views/setting_options/setting_options_invite_friends.dart';
import 'package:mc_common_app/views/setting_options/setting_options_language.dart';
import 'package:mc_common_app/views/shipping_management/shipping_management_view.dart';
import 'package:mc_common_app/views/user/change_email_page.dart';
import 'package:mc_common_app/views/user/change_mobile_page.dart';
import 'package:mc_common_app/views/user/change_password_page.dart';
@ -69,7 +70,7 @@ class AppRoutes {
static const String dashboard = "/dashboard";
static const String bookProviderAppView = "/bookProviderAppView";
// Appoinments
// Appointments
static const String appointmentDetailView = "/appointmentDetailView";
static const String bookAppointmenServicesView = "/bookAppointmenServicesView";
static const String bookAppointmenSchedulesView = "/bookAppointmenSchedulesView";
@ -87,6 +88,10 @@ class AppRoutes {
// Payments
static const String paymentMethodsView = "/paymentMethodsView";
//Shipping
static const shippingManagementView = "/shippingManagementView";
//Customer APP: Provider & Services
static const String branchDetailView = "/branchDetailPage";
static const String branchSearchFilterPage = "/branchSearchFilterPage";
@ -171,6 +176,9 @@ class AppRoutes {
//MediaViewer
AppRoutes.mediaViewerScreen: (context) => MediaViewerScreen(images: ModalRoute.of(context)!.settings.arguments as List<MessageImageModel>),
//Shipping
AppRoutes.shippingManagementView: (context) => const ShippingManagementView(),
};
}

@ -907,3 +907,38 @@ extension SubscriptionTypeEnumToString on SubscriptionTypeEnum {
}
}
}
extension ShippingStatusEnumExt on int {
ShippingRequestStatusEnum toShippingStatusEnum() {
if (this == 0) {
return ShippingRequestStatusEnum.allRequests;
} else if (this == 1) {
return ShippingRequestStatusEnum.initiated;
} else if (this == 2) {
return ShippingRequestStatusEnum.inTransit;
} else if (this == 3) {
return ShippingRequestStatusEnum.outForDelivery;
} else if (this == 4) {
return ShippingRequestStatusEnum.delivered;
}
return ShippingRequestStatusEnum.initiated;
}
}
extension ShippingStatusEnumToInt on ShippingRequestStatusEnum {
int getIdFromShippingStatusEnum() {
switch (this) {
case ShippingRequestStatusEnum.initiated:
return 1;
case ShippingRequestStatusEnum.inTransit:
return 2;
case ShippingRequestStatusEnum.outForDelivery:
return 3;
case ShippingRequestStatusEnum.delivered:
return 4;
default:
return 0;
}
}
}

@ -1,5 +1,7 @@
import 'dart:io';
import 'package:mc_common_app/utils/utils.dart';
class GenericRespModel {
GenericRespModel({
this.data,
@ -13,12 +15,19 @@ class GenericRespModel {
int? totalItemsCount;
String? message;
factory GenericRespModel.fromJson(Map<String, dynamic> json) => GenericRespModel(
data: json["data"],
messageStatus: json["messageStatus"],
totalItemsCount: json["totalItemsCount"],
message: json["message"],
);
factory GenericRespModel.fromJson(Map<String, dynamic> json) {
if (json.containsKey('StatusMessage')) {
if ((json['StatusMessage'] as String).contains('Internal server error')) {
Utils.showToast("${json['StatusMessage']}");
}
}
return GenericRespModel(
data: json["data"],
messageStatus: json["messageStatus"],
totalItemsCount: json["totalItemsCount"],
message: json["message"],
);
}
Map<String, dynamic> toJson() => {
"data": data,

@ -8,6 +8,8 @@ class RequestModel {
String requestTypeName;
String requestStatusName;
RequestStatusEnum requestStatus;
int? shippingStatus;
ShippingRequestStatusEnum? shippingStatusEnum;
String cityName;
String vehicleTypeName;
String countryName;
@ -46,6 +48,8 @@ class RequestModel {
required this.requestTypeName,
required this.requestStatusName,
required this.requestStatus,
required this.shippingStatus,
required this.shippingStatusEnum,
required this.cityName,
required this.vehicleTypeName,
required this.countryName,
@ -96,6 +100,8 @@ class RequestModel {
requestTypeName: json["requestTypeName"],
requestStatusName: json["requestStatusName"],
requestStatus: (json['requestStatus'] as int).toRequestStatusEnum(),
shippingStatus: json['shippingRequestStatus'],
shippingStatusEnum: json['shippingRequestStatus'] != null ? (json['shippingRequestStatus'] as int).toShippingStatusEnum() : ShippingRequestStatusEnum.initiated,
cityName: json["cityName"],
vehicleTypeName: json["vehicleTypeName"],
countryName: json["countryName"],

@ -42,7 +42,7 @@ class ItemData {
final String? price;
final String? manufactureDate;
final String? description;
final dynamic pictureUrl;
final String? pictureUrl;
final int? companyId;
final int? serviceProviderServiceId;
final String? serviceProviderServiceDescription;

@ -0,0 +1,27 @@
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/requests_models/request_model.dart';
import 'package:mc_common_app/utils/enums.dart';
class ShippingRequestModel {
int? id;
int? requestID;
RequestModel? request;
int? shippingStatus;
ShippingRequestStatusEnum? shippingStatusEnum;
String? deliveredOn;
String? comment;
String? createdOn;
ShippingRequestModel({this.id, this.requestID, this.request, this.shippingStatus, this.deliveredOn, this.comment, this.createdOn});
ShippingRequestModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
requestID = json['requestID'];
request = json['request'];
shippingStatus = json['shippingStatus'];
shippingStatusEnum = json['shippingStatus'] != null ? (json['shippingStatus'] as int).toShippingStatusEnum() : ShippingRequestStatusEnum.initiated;
deliveredOn = json['deliveredOn'];
comment = json['comment'];
createdOn = json['createdOn'];
}
}

@ -30,7 +30,7 @@ abstract class AdsRepo {
Future<AdsBankDetailsModel?> getAdBankingAccountInfo({required int adId});
Future<GenericRespModel> updateAdStatus({required int adId, required AdPostStatus adStatusToUpdate});
Future<GenericRespModel> updateAdStatus({required int adId, required AdPostStatus adStatusToUpdate, String? comment});
Future<GenericRespModel> createAppointmentForAdSpecialService({required int adId, required int photoOfficeID, required int photoOfficeSlotID, required int adsSpecialServiceID});
@ -263,11 +263,11 @@ class AdsRepoImp implements AdsRepo {
}
@override
Future<GenericRespModel> updateAdStatus({required int adId, required AdPostStatus adStatusToUpdate}) async {
Future<GenericRespModel> updateAdStatus({required int adId, required AdPostStatus adStatusToUpdate, String? comment}) async {
var postParams = {
"id": adId,
"status": adStatusToUpdate.getIdFromAdPostStatusEnum().toString(),
"comment": "",
"comment": comment ?? "",
};
String token = appState.getUser.data!.accessToken ?? "";

@ -131,11 +131,21 @@ class CommonRepoImp implements CommonRepo {
],
};
if (json.containsKey('StatusMessage')) {
if ((json['StatusMessage'] as String).contains('Internal server error')) {
Utils.showToast("${json['StatusMessage']}");
}
}
List<EnumsModel> enums = List.generate((json['data'] as List).length, (index) => EnumsModel.fromJson(json['data'][index]));
return enums;
}
if (enumTypeID == -2) {
// This is for the ShippingRequestStatus which will be added to API later
final Map<String, dynamic> json = {
"data": [
{"id": 1, "enumTypeID": 0, "enumValueStr": "Initiated", "enumValue": 1, "isActive": true},
{"id": 2, "enumTypeID": 0, "enumValueStr": "In Transit", "enumValue": 2, "isActive": true},
{"id": 3, "enumTypeID": 0, "enumValueStr": "Out for Delivery", "enumValue": 3, "isActive": true},
{"id": 4, "enumTypeID": 0, "enumValueStr": "Delivered", "enumValue": 4, "isActive": true},
],
};
List<EnumsModel> enums = List.generate((json['data'] as List).length, (index) => EnumsModel.fromJson(json['data'][index]));
return enums;
}

@ -0,0 +1,73 @@
import 'dart:developer';
import 'package:easy_localization/easy_localization.dart';
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/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/shipping_models/shipping_status_model.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/utils.dart';
abstract class ShippingRepo {
Future<List<ShippingRequestModel>> getShippingRequestListByStatus({ShippingRequestStatusEnum? shippingStatusEnum, int? requestId});
Future<GenericRespModel> updateShippingRequestStatus({required ShippingRequestStatusEnum shippingStatusEnum, required int shippingRequestId, String? comment});
}
class ShippingRepoImp extends ShippingRepo {
ApiClient apiClient = injector.get<ApiClient>();
AppState appState = injector.get<AppState>();
@override
Future<List<ShippingRequestModel>> getShippingRequestListByStatus({ShippingRequestStatusEnum? shippingStatusEnum, int? requestId}) async {
String token = appState.getUser.data!.accessToken ?? "";
Map<String, String> queryParameters = {
"requestID": "${requestId ?? 0}",
"shippingStatus": "${shippingStatusEnum != null ? shippingStatusEnum.getIdFromShippingStatusEnum() : 0}",
};
GenericRespModel genericRespModel = await injector.get<ApiClient>().postJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.shippingRequestStatusGet,
queryParameters,
token: token,
);
if (genericRespModel.messageStatus != 1 || genericRespModel.data == null) {
Utils.showToast(genericRespModel.message ?? LocaleKeys.somethingWrong.tr());
return [];
}
List<ShippingRequestModel> list = List.generate(genericRespModel.data.length, (index) => ShippingRequestModel.fromJson(genericRespModel.data[index]));
return list;
}
@override
Future<GenericRespModel> updateShippingRequestStatus({required ShippingRequestStatusEnum shippingStatusEnum, required int shippingRequestId, String? comment}) async {
String token = appState.getUser.data!.accessToken ?? "";
Map<String, String> queryParameters = {
"id": "$shippingRequestId",
"shippingStatus": "${shippingStatusEnum.getIdFromShippingStatusEnum()}",
"comment": comment ?? "",
};
GenericRespModel genericRespModel = await injector.get<ApiClient>().postJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.shippingRequestStatusUpdate,
queryParameters,
token: token,
);
if (genericRespModel.messageStatus != 1 || genericRespModel.data == null) {
Utils.showToast(genericRespModel.message ?? LocaleKeys.somethingWrong.tr());
}
return genericRespModel;
}
}

@ -16,6 +16,7 @@ class AppEnums {
static const int appointmentsFilterEnumId = 13; // Appointments Filter Enums
static const int requestStatusesFilterEnumId = 15; // Appointments Filter Enums
static const int conditionEnumId = -1; // to get the Condition Filter Enums
static const int shippingStatusEnumId = -2; // to get the Shipping Filter Enums
}
enum VehicleType {
@ -210,3 +211,11 @@ enum SubscriptionActionTypeEnum {
users,
branches,
}
enum ShippingRequestStatusEnum {
allRequests,
initiated,
inTransit,
outForDelivery,
delivered,
}

@ -209,7 +209,7 @@ class Utils {
return MyColors.inProgressColor;
case AdPostStatus.active:
return MyColors.adActiveStatusColor;
return MyColors.greenColor;
case AdPostStatus.expired:
return MyColors.adCancelledStatusColor;
@ -286,6 +286,44 @@ class Utils {
}
}
static String getNameByShippingRequestStatusEnum(ShippingRequestStatusEnum shippingRequestStatusEnum) {
switch (shippingRequestStatusEnum) {
case ShippingRequestStatusEnum.allRequests:
return "All Requests";
case ShippingRequestStatusEnum.initiated:
return "Initiated";
case ShippingRequestStatusEnum.inTransit:
return "In Transit";
case ShippingRequestStatusEnum.outForDelivery:
return "Out For Delivery";
case ShippingRequestStatusEnum.delivered:
return "Delivered";
}
}
static Color getChipColorByShippingRequestStatusEnum(ShippingRequestStatusEnum shippingRequestStatusEnum) {
switch (shippingRequestStatusEnum) {
case ShippingRequestStatusEnum.allRequests:
return MyColors.submittedColor;
case ShippingRequestStatusEnum.initiated:
return MyColors.submittedColor;
case ShippingRequestStatusEnum.inTransit:
return MyColors.shippingColor;
case ShippingRequestStatusEnum.outForDelivery:
return MyColors.deliveryColor;
case ShippingRequestStatusEnum.delivered:
return MyColors.greenColor;
}
}
static Color getChipColorByBranchStatus(BranchStatusEnum branchStatusEnum) {
switch (branchStatusEnum) {
case BranchStatusEnum.pending:
@ -538,9 +576,7 @@ class Utils {
static Widget buildStatusContainer(String text) {
return Center(
child: text.toText(color: MyColors.lightTextColor, fontSize: 14
// isItalic: true,
),
child: text.toText(color: MyColors.lightTextColor, fontSize: 14),
).toContainer(
marginAll: 8,
paddingAll: 15,

@ -361,9 +361,9 @@ class AdVM extends BaseVM {
navigateReplaceWithName(context, AppRoutes.dashboard);
}
Future<void> deactivateTheAd(BuildContext context, {required int adId}) async {
Future<void> deactivateTheAd(BuildContext context, {required int adId, String? comment}) async {
Utils.showLoading(context);
GenericRespModel respModel = await adsRepo.updateAdStatus(adId: adId, adStatusToUpdate: AdPostStatus.cancelled);
GenericRespModel respModel = await adsRepo.updateAdStatus(adId: adId, adStatusToUpdate: AdPostStatus.cancelled, comment: comment);
if (respModel.messageStatus != 1) {
Utils.hideLoading(context);
@ -372,8 +372,9 @@ class AdVM extends BaseVM {
}
Utils.hideLoading(context);
Utils.showToast(LocaleKeys.adDeactivatedSuccessfully.tr());
updateDeactivateAdReasonDescription('');
updateIsExploreAds(false);
applyFilterOnMyAds(adPostStatusEnum: AdPostStatus.cancelled); //pending for review
applyFilterOnMyAds(adPostStatusEnum: AdPostStatus.cancelled); //Cacncelled
navigateReplaceWithName(context, AppRoutes.dashboard);
}
@ -580,6 +581,76 @@ class AdVM extends BaseVM {
reservationCancelReason = value;
}
List<OfferRequestCommentModel> deActivateAdModelList = [
OfferRequestCommentModel(
index: 0,
isSelected: true,
title: LocaleKeys.changedMind.tr(),
),
OfferRequestCommentModel(
index: 1,
isSelected: false,
title: LocaleKeys.veryHighPrice.tr(),
),
OfferRequestCommentModel(
index: 2,
isSelected: false,
title: LocaleKeys.alreadySold.tr(),
),
OfferRequestCommentModel(
index: 3,
isSelected: false,
title: LocaleKeys.customerNotResponding.tr(),
),
OfferRequestCommentModel(
index: 4,
isSelected: false,
title: LocaleKeys.otherVar.tr(),
),
];
OfferRequestCommentModel selectedDeActivateAdCommentModel = OfferRequestCommentModel(
index: 0,
isSelected: true,
title: LocaleKeys.changedMind.tr(),
);
void updateSelectionInDeActivateAdModelList(int index) {
for (var value in deActivateAdModelList) {
value.isSelected = false;
}
selectedDeActivateAdCommentModel = deActivateAdModelList[index];
deActivateAdModelList[index].isSelected = true;
notifyListeners();
}
String deactivateAdReasonDescription = "";
String deactivateAdReasonDescriptionError = "";
void updateDeactivateAdReasonDescription(String value) {
deactivateAdReasonDescription = value;
if (value.isNotEmpty) {
deactivateAdReasonDescriptionError = "";
}
}
bool isDeActivateReasonSubmitValidated() {
if (selectedDeActivateAdCommentModel.index != deActivateAdModelList.length - 1) {
return true;
}
bool isValidated = true;
if (deactivateAdReasonDescription.isEmpty) {
deactivateAdReasonDescriptionError = GlobalConsts.descriptionError;
isValidated = false;
} else {
deactivateAdReasonDescriptionError = "";
}
notifyListeners();
return isValidated;
}
String completeDealNotesForAdmin = "";
void updateCompleteDealNotesForAdmin(String value) {

@ -218,8 +218,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;
@ -400,10 +400,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"),
"",
),
@ -586,7 +586,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,

@ -0,0 +1,110 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/main.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';
import 'package:mc_common_app/models/shipping_models/shipping_status_model.dart';
import 'package:mc_common_app/repositories/common_repo.dart';
import 'package:mc_common_app/repositories/shipping_repo.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/view_models/base_view_model.dart';
class ShippingManagementVM extends BaseVM {
final ShippingRepo shippingRepo;
final CommonRepo commonRepo;
ShippingManagementVM({required this.shippingRepo, required this.commonRepo});
List<ShippingRequestModel> shippingRequestsList = [];
List<EnumsModel> shippingStatusEnums = [];
List<FilterListModel> shippingRequestFilterOptions = [];
List<FilterListModel> shippingRequestStatusesList = [];
String requestStatusComments = "";
void updateRequestStatusComments(var value) {
requestStatusComments = value;
}
resetFilters() {
if (shippingRequestFilterOptions.isEmpty) return;
for (var value in shippingRequestFilterOptions) {
value.isSelected = false;
}
shippingRequestFilterOptions[0].isSelected = true;
requestStatusComments = "";
}
Future<void> populateShippingRequestFilterList() async {
if (shippingRequestFilterOptions.isNotEmpty && shippingRequestStatusesList.isNotEmpty) return;
shippingStatusEnums = await commonRepo.getEnumTypeValues(enumTypeID: AppEnums.shippingStatusEnumId);
shippingRequestFilterOptions.clear();
shippingRequestStatusesList.clear();
for (int i = 0; i < shippingStatusEnums.length; i++) {
shippingRequestFilterOptions.add(FilterListModel(title: shippingStatusEnums[i].enumValueStr, isSelected: false, id: shippingStatusEnums[i].enumValue));
shippingRequestStatusesList.add(FilterListModel(title: shippingStatusEnums[i].enumValueStr, isSelected: false, id: shippingStatusEnums[i].enumValue));
}
shippingRequestFilterOptions.insert(0, FilterListModel(title: Utils.getNameByShippingRequestStatusEnum(0.toShippingStatusEnum()), isSelected: true, id: 0));
notifyListeners();
}
Future<void> applyFiltersOnShippingRequests({required ShippingRequestStatusEnum shippingRequestStatusEnum}) async {
for (var value in shippingRequestFilterOptions) {
value.isSelected = false;
}
if (shippingRequestStatusEnum == ShippingRequestStatusEnum.allRequests) {
shippingRequestFilterOptions[0].isSelected = true;
await getShippingRequestsListByFilters();
notifyListeners();
return;
}
shippingRequestFilterOptions[shippingRequestStatusEnum.getIdFromShippingStatusEnum()].isSelected = true; // -1 to match with the index
await getShippingRequestsListByFilters(shippingStatusEnum: shippingRequestStatusEnum);
notifyListeners();
}
void updateSelectionInShippingRequestStatuses(int index) {
for (var value in shippingRequestStatusesList) {
value.isSelected = false;
}
shippingRequestStatusesList[index].isSelected = true;
notifyListeners();
}
Future<void> getShippingRequestsListByFilters({ShippingRequestStatusEnum? shippingStatusEnum}) async {
setState(ViewState.busy);
try {
shippingRequestsList = await shippingRepo.getShippingRequestListByStatus(shippingStatusEnum: shippingStatusEnum);
setState(ViewState.idle);
notifyListeners();
} catch (e) {
logger.i(e.toString());
Utils.showToast(e.toString());
setState(ViewState.idle);
}
}
Future<bool> onUpdateShippingStatusTapped({required BuildContext context, required ShippingRequestStatusEnum shippingStatusEnum, required int shippingRequestId}) async {
Utils.showLoading(context);
try {
GenericRespModel? genericRespModel = await shippingRepo.updateShippingRequestStatus(shippingStatusEnum: shippingStatusEnum, shippingRequestId: shippingRequestId);
Utils.showToast(genericRespModel.message.toString());
Utils.hideLoading(context);
return genericRespModel.messageStatus == 1;
} catch (e) {
logger.i(e.toString());
Utils.showToast(e.toString());
Utils.hideLoading(context);
return false;
}
}
}

@ -364,6 +364,7 @@ class _AdsDetailViewState extends State<AdsDetailView> {
child: Column(
children: [
if (!(widget.adDetails.isMyAd ?? false)) ...[
const Divider(thickness: 1, height: 1),
const Divider(thickness: 1, height: 1),
18.height,
Row(

@ -7,6 +7,7 @@ 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/advertisment_models/ad_details_model.dart';
import 'package:mc_common_app/models/advertisment_models/special_service_model.dart';
import 'package:mc_common_app/models/chat_models/chat_message_model.dart';
import 'package:mc_common_app/models/general_models/widgets_models.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/dialogs_and_bottomsheets.dart';
@ -19,6 +20,7 @@ import 'package:mc_common_app/views/advertisement/components/picked_images_conta
import 'package:mc_common_app/views/appointments/widgets/custom_calender_widget.dart';
import 'package:mc_common_app/widgets/bottom_sheet.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
import 'package:mc_common_app/widgets/checkbox_with_title_desc.dart';
import 'package:mc_common_app/widgets/common_widgets/info_bottom_sheet.dart';
import 'package:mc_common_app/widgets/common_widgets/time_slots.dart';
import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart';
@ -512,22 +514,6 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget {
);
}
Widget buildStatusContainer(String text, {bool isForShippingOrDelivery = true}) {
return Center(
child: text.toText(
color: isForShippingOrDelivery ? MyColors.lightTextColor : MyColors.adPendingStatusColor,
fontSize: isForShippingOrDelivery ? 14 : 16,
// isItalic: true,
),
).toContainer(
marginAll: 12,
paddingAll: 12,
borderRadius: 8,
width: double.infinity,
backgroundColor: isForShippingOrDelivery ? MyColors.grey98Color.withOpacity(0.1) : MyColors.adPendingStatusColor.withOpacity(0.16),
);
}
Widget pendingForPaymentAction(BuildContext context, {required AdDetailsModel ad}) {
SpecialServiceModelForAds? photoSpecialServiceModel;
for (var element in ad.specialservice!) {
@ -610,35 +596,7 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget {
title: LocaleKeys.deactivateAd.tr(),
txtColor: MyColors.redColor,
onPressed: () {
return actionConfirmationBottomSheet(
context: context,
title: LocaleKeys.doWantDeactivateAd.tr().toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
subtitle: LocaleKeys.stoptheBuyers.tr(),
actionButtonYes: Expanded(
child: ShowFillButton(
maxHeight: 55,
title: LocaleKeys.yes.tr(),
fontSize: 15,
onPressed: () {
Navigator.pop(context);
adVM.deactivateTheAd(context, adId: adDetailsModel.id!);
},
),
),
actionButtonNo: Expanded(
child: ShowFillButton(
maxHeight: 55,
isFilled: false,
borderColor: MyColors.darkPrimaryColor,
title: LocaleKeys.no.tr(),
txtColor: MyColors.darkPrimaryColor,
fontSize: 15,
onPressed: () {
Navigator.pop(context);
},
),
),
);
buildAdDeactivateReasonsBottomSheet(context, adDetails: adDetailsModel);
},
),
),
@ -648,6 +606,118 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget {
);
}
Future buildAdDeactivateReasonsBottomSheet(BuildContext context, {required AdDetailsModel adDetails}) {
return showModalBottomSheet(
context: context,
isScrollControlled: true,
enableDrag: true,
builder: (BuildContext context) {
return Consumer(builder: (BuildContext context, AdVM adVM, Widget? child) {
return InfoBottomSheet(
title: LocaleKeys.pleaseSpecify.tr().toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
description: Padding(
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
12.height,
ListView.separated(
shrinkWrap: true,
itemCount: adVM.deActivateAdModelList.length,
separatorBuilder: (BuildContext context, int index) {
if (adVM.deActivateAdModelList[index].index == 3) {
return const SizedBox();
}
return const Divider(thickness: 0.5);
},
itemBuilder: (BuildContext context, int index) {
if (adVM.deActivateAdModelList[index].index == 3) {
return const SizedBox();
}
OfferRequestCommentModel offerRequestCommentModel = adVM.deActivateAdModelList[index];
return CircleCheckBoxWithTitle(
isChecked: offerRequestCommentModel.isSelected ?? false,
title: '${offerRequestCommentModel.title}',
onSelected: () {
adVM.updateSelectionInDeActivateAdModelList(index);
},
selectedColor: MyColors.darkPrimaryColor,
);
},
),
if (adVM.selectedDeActivateAdCommentModel.index == adVM.deActivateAdModelList.length - 1) ...[
// comparing if the "other" is selected
12.height,
TxtField(
maxLines: 5,
value: adVM.deactivateAdReasonDescription,
errorValue: adVM.deactivateAdReasonDescriptionError,
keyboardType: TextInputType.text,
hint: LocaleKeys.reason.tr(),
onChanged: (v) => adVM.updateDeactivateAdReasonDescription(v),
),
],
],
),
25.height,
ShowFillButton(
title: LocaleKeys.submit.tr(),
onPressed: () {
String comments = "";
if (adVM.selectedDeActivateAdCommentModel.index == adVM.deActivateAdModelList.length - 1) //Other
{
comments = adVM.deactivateAdReasonDescription;
} else {
comments = adVM.selectedDeActivateAdCommentModel.title ?? "";
}
if (!adVM.isDeActivateReasonSubmitValidated()) {
return;
}
return actionConfirmationBottomSheet(
context: context,
title: LocaleKeys.doWantDeactivateAd.tr().toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
subtitle: LocaleKeys.stoptheBuyers.tr(),
actionButtonYes: Expanded(
child: ShowFillButton(
maxHeight: 55,
title: LocaleKeys.yes.tr(),
fontSize: 15,
onPressed: () {
adVM.deactivateTheAd(context, adId: adDetailsModel.id!, comment: comments);
},
),
),
actionButtonNo: Expanded(
child: ShowFillButton(
maxHeight: 55,
isFilled: false,
borderColor: MyColors.darkPrimaryColor,
title: LocaleKeys.no.tr(),
txtColor: MyColors.darkPrimaryColor,
fontSize: 15,
onPressed: () {
Navigator.pop(context);
},
),
),
);
},
maxWidth: double.infinity,
),
19.height,
],
),
));
});
},
);
}
Future buildCancelReservationBottomSheet(BuildContext context, {required AdDetailsModel adDetails}) {
return showModalBottomSheet(
context: context,

@ -23,6 +23,7 @@ import 'package:mc_common_app/views/requests/request_bottomsheets.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:mc_common_app/widgets/row_with_arrow.dart';
import 'package:mc_common_app/widgets/txt_field.dart';
import 'package:provider/provider.dart';
import 'package:easy_localization/easy_localization.dart' as lcl;
@ -93,8 +94,35 @@ class _ChatViewState extends State<ChatView> {
@override
Widget build(BuildContext context) {
Widget? appBarHeadlines;
final requestVM = context.read<RequestsVM>();
if (chatTypeEnum == ChatTypeEnum.requestOffer &&
requestVM.currentSelectedRequest != null &&
(requestVM.currentSelectedRequest!.requestStatus == RequestStatusEnum.shipping || requestVM.currentSelectedRequest!.requestStatus == RequestStatusEnum.delivery)) {
appBarHeadlines = Container(
width: double.infinity,
color: MyColors.darkIconColor,
padding: const EdgeInsets.symmetric(horizontal: 21, vertical: 10),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
"Your Delivery / Shipping Status is: ".toText(
fontSize: 12,
color: Colors.white,
decorationColor: MyColors.white,
),
Utils.getNameByShippingRequestStatusEnum(requestVM.currentSelectedRequest?.shippingStatusEnum ?? ShippingRequestStatusEnum.initiated).toText(
fontSize: 16,
color: Colors.white,
),
],
),
);
}
return Scaffold(
appBar: CustomAppBar(title: LocaleKeys.chat.tr()),
appBar: CustomAppBar(
title: LocaleKeys.chat.tr(),
),
body: Consumer2<ChatVM, RequestsVM>(builder: (BuildContext context, ChatVM chatVM, RequestsVM requestVM, Widget? child) {
List<ChatMessageModel> chatMessages = [];
if (chatTypeEnum == ChatTypeEnum.ads) {
@ -108,6 +136,10 @@ class _ChatViewState extends State<ChatView> {
}
return Column(
children: [
if (appBarHeadlines != null) ...[
appBarHeadlines,
5.height,
],
Expanded(
child: chatMessages.isEmpty
? Center(child: LocaleKeys.noChatMessage.tr().toText(fontSize: 16, color: MyColors.lightTextColor, textAlign: TextAlign.center)).paddingAll(22)

@ -110,7 +110,7 @@ class MyRequestsFragment extends StatelessWidget {
8.height,
Expanded(
child: RefreshIndicator(
onRefresh: () async => await requestsVM.getRequests(isNeedToRebuild: true),
onRefresh: () async => await requestsVM.getRequestsBasedOnFilters(),
child: requestsVM.state == ViewState.busy
? const Center(child: CircularProgressIndicator())
: requestsVM.myFilteredRequests.isEmpty

@ -37,7 +37,7 @@ class OfferListPage extends StatelessWidget {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Utils.statusContainerChip(text: Utils.getNameByRequestOfferStatusEnum(offersModel.requestOfferStatusEnum!), chipColor: Utils.getChipColorByRequestOfferStatusEnum(offersModel.requestOfferStatusEnum!)),
Utils.statusContainerChip(text: "Offer ${Utils.getNameByRequestOfferStatusEnum(offersModel.requestOfferStatusEnum!)}", chipColor: Utils.getChipColorByRequestOfferStatusEnum(offersModel.requestOfferStatusEnum!)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,

@ -43,7 +43,7 @@ class RequestItem extends StatelessWidget {
children: [
Utils.statusContainerChip(text: request.requestStatusName, chipColor: Utils.getChipColorByRequestStatus(request.requestStatus)),
6.height,
"${request.brand} ${request.model}".toText(fontSize: 16, letterSpacing: -0.64),
"${request.brand} ${request.model} | ${request.id}".toText(fontSize: 16, letterSpacing: -0.64),
showItem("${LocaleKeys.model.tr()}:", "${request.year}"),
if (request.customerName.isNotEmpty) ...[
showItem("${LocaleKeys.customerName.tr()}:", request.customerName),

@ -52,15 +52,16 @@ class _SettingOptionsLanguageState extends State<SettingOptionsLanguage> {
needBorderBelow: true,
onTap: () => navigateWithName(context, AppRoutes.favoriteListView),
),
] else ...[
CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.local_shipping, size: 20),
titleText: LocaleKeys.shippingManagement.tr(),
needBorderBelow: true,
onTap: () {
navigateWithName(context, AppRoutes.shippingManagementView);
},
),
],
// else ...[
// CustomSettingOptionsTile(
// leadingWidget: const Icon(Icons.local_shipping, size: 20),
// titleText: LocaleKeys.shippingManagement.tr(),
// needBorderBelow: true,
// onTap: () {},
// ),
// ],
CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.settings, size: 20),
titleText: LocaleKeys.settings.tr(),

@ -0,0 +1,199 @@
import 'dart:async';
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/general_models/widgets_models.dart';
import 'package:mc_common_app/models/shipping_models/shipping_status_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/shipping_management_view_model.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
import 'package:mc_common_app/widgets/checkbox_with_title_desc.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
import 'package:mc_common_app/widgets/common_widgets/categories_list.dart';
import 'package:mc_common_app/widgets/common_widgets/info_bottom_sheet.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';
import 'package:easy_localization/easy_localization.dart';
class ShippingManagementView extends StatefulWidget {
const ShippingManagementView({super.key});
@override
State<ShippingManagementView> createState() => _ShippingManagementViewState();
}
class _ShippingManagementViewState extends State<ShippingManagementView> {
late ShippingManagementVM shippingViewModel;
@override
void initState() {
shippingViewModel = context.read<ShippingManagementVM>();
scheduleMicrotask(() async {
if (shippingViewModel.shippingRequestFilterOptions.isNotEmpty) {
await shippingViewModel.populateShippingRequestFilterList();
}
await shippingViewModel.getShippingRequestsListByFilters();
});
super.initState();
}
Future buildUpdateShippingStatusBottomSheet({required int shippingRequestId}) {
return showModalBottomSheet(
context: context,
isScrollControlled: true,
enableDrag: true,
builder: (BuildContext context) {
return Consumer(builder: (BuildContext context, ShippingManagementVM shippingManagementVM, Widget? child) {
return InfoBottomSheet(
title: LocaleKeys.pleaseSpecify.tr().toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
description: Padding(
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
12.height,
ListView.separated(
shrinkWrap: true,
itemCount: shippingManagementVM.shippingRequestStatusesList.length,
separatorBuilder: (BuildContext context, int index) {
return const Padding(
padding: EdgeInsets.symmetric(vertical: 3.0),
child: Divider(thickness: 0.5),
);
},
itemBuilder: (BuildContext context, int index) {
List<FilterListModel> list = shippingManagementVM.shippingRequestStatusesList;
FilterListModel shippingFilterListModel = list[index];
return CircleCheckBoxWithTitle(
isChecked: shippingFilterListModel.isSelected,
title: shippingFilterListModel.title,
onSelected: () {
shippingManagementVM.updateSelectionInShippingRequestStatuses(index);
},
selectedColor: MyColors.darkPrimaryColor,
);
},
),
12.height,
TxtField(
maxLines: 4,
value: shippingManagementVM.requestStatusComments,
errorValue: "",
keyboardType: TextInputType.text,
hint: LocaleKeys.comment.tr(),
onChanged: (v) => shippingManagementVM.updateRequestStatusComments(v),
),
],
),
25.height,
ShowFillButton(
title: LocaleKeys.submit.tr(),
onPressed: () async {
FilterListModel value = shippingManagementVM.shippingRequestStatusesList.firstWhere((element) => element.isSelected);
ShippingRequestStatusEnum shippingStatusEnum = value.id.toShippingStatusEnum();
bool status = await shippingManagementVM.onUpdateShippingStatusTapped(shippingStatusEnum: shippingStatusEnum, shippingRequestId: shippingRequestId, context: context);
if (status) {
pop(context);
await shippingManagementVM.getShippingRequestsListByFilters();
}
},
maxWidth: double.infinity,
),
19.height,
],
),
));
});
},
);
}
@override
void dispose() {
shippingViewModel.resetFilters();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Consumer(builder: (BuildContext context, ShippingManagementVM shippingVm, Widget? child) {
return Scaffold(
appBar: CustomAppBar(title: LocaleKeys.shippingManagement.tr()),
body: Container(
color: MyColors.backgroundColor,
width: double.infinity,
height: double.infinity,
child: Column(
children: [
16.height,
FiltersList(
filterList: shippingVm.shippingRequestFilterOptions,
onFilterTapped: (index, selectedFilterId) {
shippingVm.applyFiltersOnShippingRequests(shippingRequestStatusEnum: selectedFilterId.toShippingStatusEnum());
},
),
8.height,
Expanded(
child: RefreshIndicator(
onRefresh: () async {
int index = shippingVm.shippingRequestFilterOptions.indexWhere((element) => element.isSelected);
await shippingVm.getShippingRequestsListByFilters(shippingStatusEnum: index.toShippingStatusEnum());
},
child: (shippingVm.state == ViewState.busy)
? const Center(
child: CircularProgressIndicator(),
)
: shippingVm.shippingRequestsList.isEmpty
? Center(child: LocaleKeys.noRequeststoShow.tr().toText(fontSize: 16, color: MyColors.lightTextColor))
: ListView.separated(
itemCount: shippingVm.shippingRequestsList.length,
padding: const EdgeInsets.all(16),
itemBuilder: (context, index) {
ShippingRequestModel shippingRequest = shippingVm.shippingRequestsList[index];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Utils.statusContainerChip(
text: Utils.getNameByShippingRequestStatusEnum(shippingRequest.shippingStatusEnum ?? ShippingRequestStatusEnum.initiated),
chipColor: Utils.getChipColorByShippingRequestStatusEnum(shippingRequest.shippingStatusEnum ?? ShippingRequestStatusEnum.initiated),
),
("Request Name | ${shippingRequest.id.toString()}").toText(fontSize: 16),
8.height,
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
"customer name".toText(color: MyColors.lightTextColor, fontSize: 14),
if (shippingRequest.createdOn != null && shippingRequest.createdOn!.isNotEmpty) ...[
" | ${DateTime.parse(shippingRequest.createdOn!).getTimeAgo()}".toText(color: MyColors.lightTextColor, fontSize: 14),
],
],
),
const Icon(Icons.arrow_forward, color: MyColors.darkIconColor, size: 18),
],
),
],
).onPress(() {
buildUpdateShippingStatusBottomSheet(shippingRequestId: shippingRequest.id!);
}).toContainer(isShadowEnabled: true);
},
separatorBuilder: (context, index) => 16.height,
),
)),
],
),
));
});
}
}
Loading…
Cancel
Save