FixedThings Before QA

aamir_dev
Faiz Hashmi 1 year ago
parent 4949a141b9
commit e2f10aba52

@ -656,6 +656,16 @@
"unselectAll": "إلغاء اختيار الكل",
"copySelectedServices": "نسخ الخدمات المحددة",
"pictures": "الصور",
"noChatMessage": "لا توجد رسائل بعد. أرسل رسالة لبدء المحادثة!"
"noChatMessage": "لا توجد رسائل بعد. أرسل رسالة لبدء المحادثة!",
"shippingManagement": "إدارة الشحن",
"appointmentCancelled": "تم إلغاء الموعد",
"appointmentsPerSlot": "المواعيد لكل فترة زمنية",
"createSchedule": "إنشاء الجدول الزمني",
"addItems": "إضافة عناصر",
"itemName": "اسم العنصر",
"itemDescription": "وصف العنصر",
"itemPrice": "سعر العنصر",
"appointmentBookingOption": "سيسمح هذا الخيار للعميل بحجز موعد لهذه الخدمات.",
"workshopAvailabilityOption": "سيظهر هذا الخيار للعميل إذا كان يمكنه الحصول على هذه الخدمة في الورشة أم لا.",
"appointmentLocationOption": "سيسمح هذا الخيار للعميل بحجز موعد في الموقع الذي يختاره."
}

@ -657,7 +657,16 @@
"unselectAll": "Unselect All",
"copySelectedServices": "Copy Selected Services",
"pictures": "Pictures",
"noChatMessage": "No messages yet. Send a message to start the conversation!"
"noChatMessage": "No messages yet. Send a message to start the conversation!",
"shippingManagement": "Shipping Management",
"appointmentCancelled": "Appointment Cancelled",
"appointmentsPerSlot": "Appointments Per Slot",
"createSchedule": "Create Schedule",
"addItems": "Add Items",
"itemName": "Item Name",
"itemDescription": "Item Description",
"itemPrice": "Item Price",
"bookAppointmentForServices": "This option will allow customer to book appointment for these services.",
"showServiceAvailability": "This option will show to customer that you can avail this service on workshop or not.",
"bookAppointmentAtLocation": "This option will allow customer to book appointment at their desired location."
}

@ -65,7 +65,7 @@ class AppState {
List<Subscription>? _providerSubscription;
List<Subscription> get getproviderSubscription => _providerSubscription!;
List<Subscription> get getproviderSubscription => _providerSubscription ?? [Subscription(name: "")];
set setproviderSubscription(List<Subscription> value) {
_providerSubscription = value;

@ -136,6 +136,7 @@ class ApiConsts {
// Payment
static String paymentWebViewUrl = "https://ms.hmg.com/pay/PaymentHome";
static String payForOrderDetailGet = "${baseUrlServices}api/Payment/PayFortOrderDetail_Get";
static String payForOrderIsPaidGet = "${baseUrlServices}api/Payment/PayFortOrderIsPaid_Get";
//Duplicate Services
static String getMatchedServices = "${baseUrlServices}api/ServiceProviders/ServiceProviderBranchServicesMapping_Get";

@ -142,10 +142,10 @@ class AppRoutes {
completeProfile: (context) => CompleteProfilePage(ModalRoute.of(context)!.settings.arguments as RegisterUserRespModel),
verifyPassword: (context) => VerifyPasswordPage(),
confirmNewPasswordPage: (context) => ConfirmNewPasswordPage(ModalRoute.of(context)!.settings.arguments as String),
changePassword: (context) => const ChangePasswordPage(),
forgetPasswordMethodPage: (context) => ForgetPasswordMethodPage(ModalRoute.of(context)!.settings.arguments as String),
changeMobilePage: (context) => ChangeMobilePage(),
changeEmailPage: (context) => const ChangeEmailPage(),
changePassword: (context) => const ChangePasswordPage(),
editAccountPage: (context) => const EditAccountPage(),
profileView: (context) => const ProfileScreen(),
settingOptionsLanguages: (context) => const SettingOptionsLanguage(),

@ -474,6 +474,30 @@ extension PaymentTypesToInt on PaymentTypes {
}
}
extension PaymentIdToPaymentTypes on int {
PaymentTypes getPaymentTypeFromId() {
switch (this) {
case 1:
return PaymentTypes.subscription;
case 2:
return PaymentTypes.appointment;
case 4:
return PaymentTypes.adReserve;
case 3:
return PaymentTypes.ads;
case 5:
return PaymentTypes.request;
case 6:
return PaymentTypes.extendAds;
case 7:
return PaymentTypes.partialAppointment;
default:
return PaymentTypes.ads;
}
}
}
extension CreatedByRoleEnumToInt on CreatedByRoleEnum {
int getIdFromCreatedByRoleEnum() {
switch (this) {

@ -672,7 +672,18 @@ class CodegenLoader extends AssetLoader{
"unselectAll": "إلغاء اختيار الكل",
"copySelectedServices": "نسخ الخدمات المحددة",
"pictures": "الصور",
"noChatMessage": "لا توجد رسائل بعد. أرسل رسالة لبدء المحادثة!"
"noChatMessage": "لا توجد رسائل بعد. أرسل رسالة لبدء المحادثة!",
"shippingManagement": "إدارة الشحن",
"appointmentCancelled": "تم إلغاء الموعد",
"appointmentsPerSlot": "المواعيد لكل فترة زمنية",
"createSchedule": "إنشاء الجدول الزمني",
"addItems": "إضافة عناصر",
"itemName": "اسم العنصر",
"itemDescription": "وصف العنصر",
"itemPrice": "سعر العنصر",
"appointmentBookingOption": "سيسمح هذا الخيار للعميل بحجز موعد لهذه الخدمات.",
"workshopAvailabilityOption": "سيظهر هذا الخيار للعميل إذا كان يمكنه الحصول على هذه الخدمة في الورشة أم لا.",
"appointmentLocationOption": "سيسمح هذا الخيار للعميل بحجز موعد في الموقع الذي يختاره."
};
static const Map<String,dynamic> en_US = {
"firstTimeLogIn": "First Time Log In",
@ -1333,7 +1344,18 @@ static const Map<String,dynamic> en_US = {
"unselectAll": "Unselect All",
"copySelectedServices": "Copy Selected Services",
"pictures": "Pictures",
"noChatMessage": "No messages yet. Send a message to start the conversation!"
"noChatMessage": "No messages yet. Send a message to start the conversation!",
"shippingManagement": "Shipping Management",
"appointmentCancelled": "Appointment Cancelled",
"appointmentsPerSlot": "Appointments Per Slot",
"createSchedule": "Create Schedule",
"addItems": "Add Items",
"itemName": "Item Name",
"itemDescription": "Item Description",
"itemPrice": "Item Price",
"bookAppointmentForServices": "This option will allow customer to book appointment for these services.",
"showServiceAvailability": "This option will show to customer that you can avail this service on workshop or not.",
"bookAppointmentAtLocation": "This option will allow customer to book appointment at their desired location."
};
static const Map<String, Map<String,dynamic>> mapLocales = {"ar_SA": ar_SA, "en_US": en_US};
}

@ -636,5 +636,16 @@ abstract class LocaleKeys {
static const copySelectedServices = 'copySelectedServices';
static const pictures = 'pictures';
static const noChatMessage = 'noChatMessage';
static const shippingManagement = 'shippingManagement';
static const appointmentCancelled = 'appointmentCancelled';
static const appointmentsPerSlot = 'appointmentsPerSlot';
static const createSchedule = 'createSchedule';
static const addItems = 'addItems';
static const itemName = 'itemName';
static const itemDescription = 'itemDescription';
static const itemPrice = 'itemPrice';
static const appointmentBookingOption = 'appointmentBookingOption';
static const workshopAvailabilityOption = 'workshopAvailabilityOption';
static const appointmentLocationOption = 'appointmentLocationOption';
}

@ -22,17 +22,17 @@ class Document {
String? message;
factory Document.fromJson(Map<String, dynamic> json) => Document(
totalItemsCount: json["totalItemsCount"] == null ? null : json["totalItemsCount"],
totalItemsCount: json["totalItemsCount"],
data: json["data"] == null ? null : List<DocumentData>.from(json["data"].map((x) => DocumentData.fromJson(x))),
messageStatus: json["messageStatus"] == null ? null : json["messageStatus"],
message: json["message"] == null ? null : json["message"],
messageStatus: json["messageStatus"],
message: json["message"],
);
Map<String, dynamic> toJson() => {
"totalItemsCount": totalItemsCount == null ? null : totalItemsCount,
"totalItemsCount": totalItemsCount,
"data": data == null ? null : List<dynamic>.from(data!.map((x) => x.toJson())),
"messageStatus": messageStatus == null ? null : messageStatus,
"message": message == null ? null : message,
"messageStatus": messageStatus,
"message": message,
};
}
@ -43,6 +43,7 @@ class DocumentData {
this.documentId,
this.documentUrl,
this.status,
this.statusText,
this.comment,
this.isActive,
this.document,
@ -60,29 +61,31 @@ class DocumentData {
bool? isActive;
String? document;
String? fileExt;
String? statusText;
String? documentName;
bool? isLocalFile;
factory DocumentData.fromJson(Map<String, dynamic> json) => DocumentData(
id: json["id"] == null ? null : json["id"],
serviceProviderId: json["serviceProviderID"] == null ? null : json["serviceProviderID"],
documentId: json["documentID"] == null ? null : json["documentID"],
id: json["id"],
serviceProviderId: json["serviceProviderID"],
documentId: json["documentID"],
documentUrl: json["documentURL"],
status: json["status"] == null ? null : json["status"],
status: json["status"],
statusText: json["statusText"],
comment: json["comment"],
isActive: json["isActive"] == null ? null : json["isActive"],
isActive: json["isActive"],
document: null,
fileExt: null,
documentName: json["documentName"] == null ? null : json["documentName"],
documentName: json["documentName"],
isLocalFile: false);
Map<String, dynamic> toJson() => {
"id": id == null ? null : id,
"serviceProviderID": serviceProviderId == null ? null : serviceProviderId,
"documentID": documentId == null ? null : documentId,
"id": id,
"serviceProviderID": serviceProviderId,
"documentID": documentId,
"documentURL": documentUrl,
"status": status == null ? null : status,
"status": status,
"comment": comment,
"isActive": isActive == null ? null : isActive,
"isActive": isActive,
};
}

@ -4,11 +4,13 @@ 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_list_model.dart';
import 'package:mc_common_app/models/appointments_models/schedule_model.dart';
import 'package:mc_common_app/models/appointments_models/service_schedule_model.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/provider_branches_models/profile/services.dart';
import 'package:mc_common_app/utils/enums.dart';
abstract class AppointmentRepo {
Future<List<AppointmentListModel>> getMyAppointmentsForProvider(Map<String, dynamic> map);
@ -20,7 +22,7 @@ abstract class AppointmentRepo {
List<String>? branchIdsList,
});
Future<GenericRespModel> updateAppointmentStatus(Map<String, dynamic> map);
Future<GenericRespModel> updateAppointmentStatus({required int appointmentId, required AppointmentStatusEnum appointmentStatusEnum});
Future<GenericRespModel> updateAppointmentPaymentStatus(Map<String, dynamic> map);
@ -240,9 +242,13 @@ class AppointmentRepoImp implements AppointmentRepo {
}
@override
Future<GenericRespModel> updateAppointmentStatus(Map<String, dynamic> map) async {
Future<GenericRespModel> updateAppointmentStatus({required int appointmentId, required AppointmentStatusEnum appointmentStatusEnum}) async {
String t = appState.getUser.data!.accessToken ?? "";
return await apiClient.postJsonForObject((json) => GenericRespModel.fromJson(json), ApiConsts.updateAppointmentStatus, map, token: t);
var params = {
"appointmentID": appointmentId.toString(),
"appointmentStatusID": appointmentStatusEnum.getIdFromAppointmentStatusEnum().toString(),
};
return await apiClient.postJsonForObject((json) => GenericRespModel.fromJson(json), ApiConsts.updateAppointmentStatus, params, token: t);
}
@override

@ -20,7 +20,6 @@ class ItemsRepoImp implements ItemsRepo {
@override
Future<GenericRespModel> createServiceItems(Map map) async {
String t = AppState().getUser.data!.accessToken ?? "";
debugPrint(t);
return await injector.get<ApiClient>().postJsonForObject((json) => GenericRespModel.fromJson(json), ApiConsts.createItems, map, token: t);
}
@ -30,7 +29,6 @@ class ItemsRepoImp implements ItemsRepo {
"ServiceProviderServiceID": serviceId.toString(),
};
String? token = AppState().getUser.data?.accessToken;
debugPrint(token);
return await injector
.get<ApiClient>()
.getJsonForObject((json) => ItemModel.fromJson(json), ApiConsts.getServiceItems, queryParameters: queryParameters, token: AppState().getUser.data!.accessToken ?? "");
@ -39,7 +37,6 @@ class ItemsRepoImp implements ItemsRepo {
@override
Future<GenericRespModel> updateServiceItem(Map map) async {
String t = AppState().getUser.data!.accessToken ?? "";
debugPrint(t);
return await injector.get<ApiClient>().postJsonForObject((json) => GenericRespModel.fromJson(json), ApiConsts.updateServiceItem, map, token: t);
}

@ -2,10 +2,14 @@ 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/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/payment_models/pay_order_detail_resp_model.dart';
import 'package:mc_common_app/utils/enums.dart';
abstract class PaymentsRepo {
Future<bool> verifyPayment({required int paymentTypeId, required int id, bool isForAppointments = false, List<int>? appointmentIds});
Future<PayOrderDetailRespModel> getPayOrderDetails({required int paymentTypeId, required int adId});
}
@ -29,4 +33,52 @@ class PaymentsRepoImp implements PaymentsRepo {
PayOrderDetailRespModel payOrderDetailRespModel = PayOrderDetailRespModel.fromJson(adsGenericModel.data);
return payOrderDetailRespModel;
}
String getKeyByPaymentType({required int paymentType}) {
PaymentTypes paymentTypeEnum = paymentType.getPaymentTypeFromId();
switch (paymentTypeEnum) {
case PaymentTypes.subscription:
return "SubscriptionAppliedID";
case PaymentTypes.appointment:
case PaymentTypes.partialAppointment:
return "appointmentIds";
case PaymentTypes.ads:
case PaymentTypes.adReserve:
case PaymentTypes.extendAds:
return "AdsID";
case PaymentTypes.request:
return "RequestID";
}
}
@override
Future<bool> verifyPayment({required int paymentTypeId, required int id, bool isForAppointments = false, List<int>? appointmentIds}) async {
Map<String, dynamic> queryParameters = {
"ID": id.toString(),
"PaymentType": paymentTypeId.toString(),
};
if (isForAppointments) {
List<String> ids = [];
if (appointmentIds != null) {
for (var element in appointmentIds) {
ids.add(element.toString());
}
}
queryParameters.removeWhere((key, value) => key == "ID");
queryParameters.addAll({"IDs": ids});
}
GenericRespModel adsGenericModel = await apiClient.getJsonForObject(
token: appState.getUser.data!.accessToken,
queryParameters: queryParameters,
(json) => GenericRespModel.fromJson(json),
ApiConsts.payForOrderIsPaidGet,
);
if (adsGenericModel.data == null) {
return false;
}
bool isPaid = adsGenericModel.data['isPaid'] ?? false;
return isPaid;
}
}

@ -8,6 +8,7 @@ import 'package:mc_common_app/generated/locale_keys.g.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/widgets/button/show_fill_button.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:path/path.dart' as p;
import 'package:fluttertoast/fluttertoast.dart';
@ -26,7 +27,13 @@ class Utils {
static bool get isLoading => _isLoadingVisible;
static void showToast(String message) {
Fluttertoast.showToast(msg: message, toastLength: Toast.LENGTH_SHORT, gravity: ToastGravity.BOTTOM, timeInSecForIosWeb: 2, backgroundColor: Colors.black54, textColor: Colors.white, fontSize: 16.0);
Fluttertoast.showToast(msg: message,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
timeInSecForIosWeb: 2,
backgroundColor: Colors.black54,
textColor: Colors.white,
fontSize: 16.0);
}
static Future<void> openNumberViaCaller({required String phoneNumber}) async {
@ -69,7 +76,11 @@ class Utils {
return "";
}
return ("${timeOfDay.hour.toString().length == 1 ? "0" : ""}${timeOfDay.hour}:${timeOfDay.minute.toString().length == 1 ? "0" : ""}${timeOfDay.minute}").toString();
return ("${timeOfDay.hour
.toString()
.length == 1 ? "0" : ""}${timeOfDay.hour}:${timeOfDay.minute
.toString()
.length == 1 ? "0" : ""}${timeOfDay.minute}").toString();
}
static dynamic getNotNullValue(List<dynamic> list, int index) {
@ -196,7 +207,7 @@ class Utils {
return MyColors.adPendingStatusColor;
case AdPostStatus.pendingForPayment:
return MyColors.adPendingStatusColor;
return MyColors.submittedColor;
case AdPostStatus.rejected:
return MyColors.adCancelledStatusColor;
@ -205,7 +216,7 @@ class Utils {
return MyColors.adCancelledStatusColor;
case AdPostStatus.pendingForPost:
return MyColors.adPendingStatusColor;
return MyColors.inProgressColor;
case AdPostStatus.active:
return MyColors.adActiveStatusColor;
@ -472,7 +483,7 @@ class Utils {
border: Border.all(
width: w, //
color: color // <--- border width here
),
),
borderRadius: BorderRadius.circular(radius),
);
}
@ -495,7 +506,7 @@ class Utils {
border: Border.all(
width: 1, //
color: color // <--- border width here
),
),
borderRadius: BorderRadius.circular(radius),
);
}
@ -513,7 +524,8 @@ class Utils {
}
static String getAdsPaymentBrowserForm({required int paymentId, required int adId}) {
return '<html> <head></head><body><form id="paymentForm" action="${ApiConsts.paymentWebViewUrl}" method="post"><input type="hidden" name="PaymentType" value="$paymentId"><input type="hidden" name="AdsID" value="$adId"></form><script type="text/javascript"> document.getElementById("paymentForm").submit(); </script></body></html>';
return '<html> <head></head><body><form id="paymentForm" action="${ApiConsts
.paymentWebViewUrl}" method="post"><input type="hidden" name="PaymentType" value="$paymentId"><input type="hidden" name="AdsID" value="$adId"></form><script type="text/javascript"> document.getElementById("paymentForm").submit(); </script></body></html>';
}
// BOTTOM SHEETS
@ -534,4 +546,18 @@ class Utils {
actionButtonNo: const SizedBox(),
);
}
static Widget buildStatusContainer(String text) {
return Center(
child: text.toText(color: MyColors.lightTextColor, fontSize: 14
// isItalic: true,
),
).toContainer(
marginAll: 8,
paddingAll: 15,
borderRadius: 8,
width: double.infinity,
backgroundColor: MyColors.grey98Color.withOpacity(0.1),
);
}
}

@ -382,10 +382,10 @@ class AppointmentsVM extends BaseVM {
setState(ViewState.idle);
}
updateAppointmentStatus(Map<String, dynamic> map, {bool isNeedToRebuild = false}) async {
updateAppointmentStatus({required int appointmentId, required AppointmentStatusEnum appointmentStatusEnum, bool isNeedToRebuild = false}) async {
if (isNeedToRebuild) setState(ViewState.busy);
try {
GenericRespModel genericRespModel = await appointmentRepo.updateAppointmentStatus(map);
GenericRespModel genericRespModel = await appointmentRepo.updateAppointmentStatus(appointmentId: appointmentId, appointmentStatusEnum: appointmentStatusEnum);
if (genericRespModel.messageStatus == 1) {
Utils.showToast(LocaleKeys.appointmentStatusUpdated.tr());

@ -1,7 +1,8 @@
import 'package:flutter/cupertino.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/main.dart';
import 'package:mc_common_app/utils/enums.dart';
class BaseVM extends ChangeNotifier {
ViewState _state = ViewState.idle;
bool isInternetConnection = true;

@ -303,7 +303,11 @@ class ChatVM extends ChangeNotifier {
MessageImageModel convertFileToMessageImageModel({required File file}) {
List<int> imageBytes = file.readAsBytesSync();
String image = base64Encode(imageBytes);
MessageImageModel vehiclePostingImages = MessageImageModel(imageStr: image, id: 0, isFromNetwork: false, reqOfferID: latestOfferId, imagePath: file.path);
MessageImageModel vehiclePostingImages = MessageImageModel(imageStr: image,
id: 0,
isFromNetwork: false,
reqOfferID: latestOfferId,
imagePath: file.path);
return vehiclePostingImages;
}
@ -409,7 +413,10 @@ class ChatVM extends ChangeNotifier {
serviceProviderOffersList[providerIndex].chatMessages!.add(chatMessageModel);
}
} else {
int providerIndex = context.read<RequestsVM>().myFilteredRequests.indexWhere((element) => (element.customerUserID == receiverId && element.id == requestId));
int providerIndex = context
.read<RequestsVM>()
.myFilteredRequests
.indexWhere((element) => (element.customerUserID == receiverId && element.id == requestId));
log("providerIndex2:$providerIndex");
if (providerIndex != -1) {
context.read<RequestsVM>().addChatMessagesInRequestsModel(msg: chatMessageModel, index: providerIndex);
@ -672,8 +679,7 @@ class ChatVM extends ChangeNotifier {
notifyListeners();
if (AppState().currentAppType == AppType.customer) {
} else {}
if (AppState().currentAppType == AppType.customer) {} else {}
return true;
}
return false;

@ -1,15 +1,10 @@
import 'dart:developer';
import 'dart:io';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/config/dependency_injection.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/main.dart';
import 'package:mc_common_app/models/general_models/widgets_models.dart';
import 'package:mc_common_app/models/user_models/image_response.dart';
import 'package:mc_common_app/repositories/user_repo.dart';
import 'package:mc_common_app/services/common_services.dart';
import 'package:mc_common_app/services/firebase_service.dart';
import 'package:mc_common_app/utils/enums.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/appointments_view_model.dart';

@ -1,20 +1,20 @@
import 'dart:developer';
import 'package:flutter/cupertino.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/config/routes.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/payment_models/pay_order_detail_resp_model.dart';
import 'package:mc_common_app/repositories/payments_repo.dart';
import 'package:mc_common_app/services/payments_service.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/view_models/base_view_model.dart';
import 'package:mc_common_app/view_models/dashboard_view_model_customer.dart';
import 'package:mc_common_app/view_models/subscriptions_view_model.dart';
import 'package:provider/provider.dart';
import 'package:easy_localization/easy_localization.dart';
import '../classes/app_state.dart';
class PaymentVM extends ChangeNotifier {
final PaymentService paymentService;
@ -47,6 +47,7 @@ class PaymentVM extends ChangeNotifier {
void updateAppointmentIdsForPayment({required List<int> ids}) {
appointmentIdsForPayment = ids;
log("appointmentIdsForPayment: ${appointmentIdsForPayment}");
}
updateSelectedPaymentMethod(PaymentMethods selectedMethod) {
@ -57,62 +58,43 @@ class PaymentVM extends ChangeNotifier {
Future<void> onContinuePressed(BuildContext context, {required PaymentTypes paymentType}) async {
switch (selectedPaymentMethod) {
case PaymentMethods.mada:
// TODO: Handle this case.
break;
case PaymentMethods.visa:
await onVisaCardSelected(context, paymentType);
break;
case PaymentMethods.applePay:
// TODO: Handle this case.
break;
case PaymentMethods.masterCard:
// TODO: Handle this case.
break;
case PaymentMethods.tamara:
// TODO: Handle this case.
break;
}
return;
}
Future<void> onAdsPaymentSuccess({required BuildContext context, required int currentAdId, required int paymentTypeId}) async {
Utils.showLoading(context);
PayOrderDetailRespModel payOrderDetailRespModel = await paymentRepo.getPayOrderDetails(paymentTypeId: paymentTypeId, adId: currentAdId);
await Future.delayed(const Duration(seconds: 2));
Utils.hideLoading(context);
log("payOrderDetailRespModel: ${payOrderDetailRespModel.toString()}");
if (payOrderDetailRespModel.isPaid == null || !payOrderDetailRespModel.isPaid!) {
Utils.showToast(LocaleKeys.paymentFailed.tr());
return;
}
if (payOrderDetailRespModel.isPaid != null && payOrderDetailRespModel.isPaid!) {
Future<void> verifyPayments({required BuildContext context, required int id, List<int>? appointmentIds, required int paymentTypeId, required Function() onVerified, bool isForAppointment = false}) async {
try {
Utils.showLoading(context);
bool isPaid = await paymentRepo.verifyPayment(
paymentTypeId: paymentTypeId,
id: id,
isForAppointments: isForAppointment,
appointmentIds: appointmentIds,
);
Utils.hideLoading(context);
if (!isPaid) {
Utils.showToast(LocaleKeys.paymentFailed.tr());
pop(context);
return;
}
Utils.showToast(LocaleKeys.paymentSuccessful.tr());
navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard);
}
}
Future<void> onAppointmentPaymentSuccess({required BuildContext context, required int currentAdId, required int paymentTypeId}) async {
Utils.showLoading(context);
//TODO: CONFIRM FROM ZAHOOR THAT WILL THIS METHOD WORK FOR APPOINTMENT
PayOrderDetailRespModel payOrderDetailRespModel = await paymentRepo.getPayOrderDetails(paymentTypeId: paymentTypeId, adId: currentAdId);
await Future.delayed(const Duration(seconds: 2));
Utils.hideLoading(context);
log("payOrderDetailRespModel: ${payOrderDetailRespModel.toString()}");
if (payOrderDetailRespModel.isPaid == null || !payOrderDetailRespModel.isPaid!) {
Utils.showToast(LocaleKeys.paymentFailed.tr());
onVerified();
} catch (e) {
Utils.showToast(e.toString());
return;
}
if (payOrderDetailRespModel.isPaid != null && payOrderDetailRespModel.isPaid!) {
Utils.showToast(LocaleKeys.paymentSuccessful.tr());
navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard);
}
}
int getIdTypeByPaymentType(PaymentTypes paymentTypes) {
@ -141,66 +123,58 @@ class PaymentVM extends ChangeNotifier {
Utils.showToast(LocaleKeys.paymentFailed.tr());
switch (paymentTypeEnum) {
case PaymentTypes.subscription:
// TODO: Handle this case.
Utils.showToast("Appointment Payment has been Failed!!");
break;
case PaymentTypes.request:
// TODO: Handle this case.
Utils.showToast("Request Payment has been Failed!!");
break;
case PaymentTypes.appointment:
case PaymentTypes.adReserve:
// TODO: Handle this case.
Utils.showToast("adReserve Payment has been Failed!!");
break;
case PaymentTypes.ads:
// TODO: Handle this case.
Utils.showToast("ads Payment has been Failed!!");
break;
case PaymentTypes.request:
case PaymentTypes.extendAds:
// TODO: Handle this case.
Utils.showToast("extendAds Payment has been Failed!!");
break;
case PaymentTypes.appointment:
// TODO: Handle this case.
Utils.showToast("Appointment Payment has been Failed!!");
break;
case PaymentTypes.partialAppointment:
Utils.showToast("partialAppointment Payment has been Failed!!");
break;
}
},
onSuccess: () async {
// TOD0: we have to take payment confirmation methods from Backend team and make success callbacks like onAdsPaymentSuccess
Utils.showToast("Verifying Payment..");
switch (paymentTypeEnum) {
case PaymentTypes.subscription:
onSubscriptionPaymentSuccess(context);
await verifyPayments(
context: context,
paymentTypeId: paymentTypeEnum.getIdFromPaymentTypesEnum(),
id: orderProviderSubscriptionId,
onVerified: () => onSubscriptionPaymentSuccess(context),
);
break;
case PaymentTypes.appointment:
Utils.showToast("Appointment Payment has been Succeeded");
break;
case PaymentTypes.partialAppointment:
Utils.showToast("Partial Appointment Payment has been Succeeded");
await verifyPayments(
id: 0,
isForAppointment: true,
appointmentIds: appointmentIdsForPayment,
context: context,
paymentTypeId: paymentTypeEnum.getIdFromPaymentTypesEnum(),
onVerified: () => onAppointmentSuccess(context),
);
break;
case PaymentTypes.request:
Utils.showToast("Request Payment has been Succeeded");
onRequestPaymentSuccess(context);
await verifyPayments(
context: context,
paymentTypeId: paymentTypeEnum.getIdFromPaymentTypesEnum(),
id: requestId,
onVerified: () => onRequestPaymentSuccess(context),
);
break;
case PaymentTypes.adReserve:
case PaymentTypes.ads:
case PaymentTypes.extendAds:
await onAdsPaymentSuccess(context: context, paymentTypeId: paymentTypeEnum.getIdFromPaymentTypesEnum(), currentAdId: currentAdId);
break;
await verifyPayments(
context: context,
paymentTypeId: paymentTypeEnum.getIdFromPaymentTypesEnum(),
id: currentAdId,
onVerified: () => onAdsPaymentSuccess(context),
);
}
},
);
@ -208,16 +182,22 @@ class PaymentVM extends ChangeNotifier {
void onRequestPaymentSuccess(BuildContext context) {
context.read<DashboardVmCustomer>().onNavbarTapped(4);
navigateReplaceWithName(context, AppRoutes.dashboard);
navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard);
}
onSubscriptionPaymentSuccess(BuildContext context) {
void onAdsPaymentSuccess(BuildContext context) {
context.read<DashboardVmCustomer>().onNavbarTapped(3);
navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard);
}
void onSubscriptionPaymentSuccess(BuildContext context) {
pop(context);
// context.read<SubscriptionsVM>().getSubscriptionBySP(AppState().getUser.data?.userInfo?.providerId.toString() ?? "", true);
navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard);
}
// context.read<SubscriptionsVM>().getMySubscriptions(AppState().getUser.data?.userInfo?.providerId.toString() ?? "");
context.read<SubscriptionsVM>().getSubscriptionBySP(AppState().getUser.data?.userInfo?.providerId.toString() ?? "", true);
// context.read<SubscriptionsVM>().mySubscriptionsBySp = [];
// context.read<SubscriptionsVM>().getMySubscriptionsBySP();
void onAppointmentSuccess(BuildContext context) {
context.read<DashboardVmCustomer>().onNavbarTapped(1);
navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard);
}

@ -1,4 +1,5 @@
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/app_state.dart';
@ -218,8 +219,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;
@ -228,6 +229,7 @@ class ServiceVM extends BaseVM {
}
Future<void> commerceRemove(String filePath) async {
log("commerceRemove with: $filePath");
int index = commerceCertificates.indexWhere((element) => element.filePath == filePath);
if (index == -1) {
return;
@ -237,6 +239,8 @@ class ServiceVM extends BaseVM {
}
Future<void> removeNetworkImag(String filePath) async {
log("removeNetworkImag with: $filePath");
int index = document!.data!.indexWhere((element) => element.documentUrl == filePath);
if (index == -1) {
return;
@ -247,6 +251,8 @@ class ServiceVM extends BaseVM {
}
Future<void> commercialRemove(String filePath) async {
log("commercialRemove with: $filePath");
int index = commercialCertificates.indexWhere((element) => element.filePath == filePath);
if (index == -1) {
return;
@ -256,6 +262,8 @@ class ServiceVM extends BaseVM {
}
Future<void> vatRemove(String filePath) async {
log("vatRemove with: $filePath");
int index = vatCertificates.indexWhere((element) => element.filePath == filePath);
if (index == -1) {
return;
@ -272,7 +280,11 @@ class ServiceVM extends BaseVM {
Future<void> getBranchAndServices() async {
setState(ViewState.busy);
branches = await branchRepo.getBranchAndServices();
homePageBranches = branches!.data!.serviceProviderBranch!.where((element) => element.branchStatus == BranchStatusEnum.approvedOrActive).toList();
if (branches!.data == null) {
homePageBranches = [];
} else {
homePageBranches = branches!.data!.serviceProviderBranch!.where((element) => element.branchStatus == BranchStatusEnum.approvedOrActive).toList();
}
setState(ViewState.idle);
}
@ -389,10 +401,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"),
"",
),
@ -574,9 +586,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,
@ -621,8 +631,8 @@ class ServiceVM extends BaseVM {
GenericRespModel res = await branchRepo.createBranch(
branchName: branchName,
branchDescription: branchDesc,
openTime: branchDesc,
closeTime: branchDesc,
openTime: openTime,
closeTime: closeTime,
cityId: cityID,
address: address,
latitude: latitude,
@ -656,6 +666,14 @@ class ServiceVM extends BaseVM {
required String latitude,
required String longitude,
}) async {
// log(branchName);
// log(branchDesc);
// log(openTime);
// log(closedTime);
// log(cityID.toString());
// log(address);
// log(latitude);
// log(longitude);
if (branchName.isEmpty || branchDesc.isEmpty || address.isEmpty) {
branchErrorScreen = GlobalConsts.fillAllFields;
notifyListeners();

@ -1,10 +1,6 @@
import 'dart:convert';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/main.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/subscriptions_models/branch_user_selection_model.dart';
import 'package:mc_common_app/models/subscriptions_models/provider_subscription_model.dart';
import 'package:mc_common_app/models/subscriptions_models/subscription_model.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/view_models/base_view_model.dart';
@ -118,12 +114,7 @@ class SubscriptionsVM extends BaseVM {
}
Future<GenericRespModel> createSubscriptionOrder(int subscriptionId, bool isStartNow, bool isRenew, {bool isDegrade = false, List<int>? listOfBranches, List<int>? listOfUsers}) async {
Map<String, dynamic> map = {
"providerID": AppState().getUser.data?.userInfo?.providerId.toString() ?? "",
"subscriptionID": subscriptionId.toString(),
"isStartNow": isStartNow.toString(),
"isRenew": isRenew.toString()
};
Map<String, dynamic> map = {"providerID": AppState().getUser.data?.userInfo?.providerId.toString() ?? "", "subscriptionID": subscriptionId.toString(), "isStartNow": isStartNow.toString(), "isRenew": isRenew.toString()};
GenericRespModel genericRespModel = await subscriptionRepo.payForProviderSubscription(map);
return genericRespModel;
}

@ -264,11 +264,13 @@ class VehicleDetails extends StatelessWidget {
28.height,
LocaleKeys.vehiclePictures.tr().toText(fontSize: 18, isBold: true),
8.height,
DottedRectContainer(
onTap: () => context.read<AdVM>().pickMultipleImages(),
text: LocaleKeys.attachImage.tr(),
icon: MyAssets.attachmentIcon.buildSvg(),
),
if (adVM.pickedPostingImages.isEmpty) ...[
DottedRectContainer(
onTap: () => context.read<AdVM>().pickMultipleImages(),
text: LocaleKeys.attachImage.tr(),
icon: MyAssets.attachmentIcon.buildSvg(),
),
],
if (adVM.vehicleImageError != "") ...[
10.height,
Row(

@ -305,7 +305,7 @@ class _AdsDetailViewState extends State<AdsDetailView> {
@override
Widget build(BuildContext context) {
Widget actionWidget = const SizedBox();
if ((widget.adDetails.isMyAd ?? false) && (widget.adDetails.adPostStatus != AdPostStatus.reserved) && (widget.adDetails.adPostStatus != AdPostStatus.active)) {
if ((widget.adDetails.isMyAd ?? false) && (widget.adDetails.adPostStatus != AdPostStatus.reserved) && (widget.adDetails.adPostStatus != AdPostStatus.active) && (widget.adDetails.adPostStatus != AdPostStatus.pendingForPost)) {
actionWidget = IconButton(
icon: const Icon(Icons.delete_outline, color: MyColors.redColor),
onPressed: () {

@ -496,11 +496,11 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget {
}
Widget pendingForReviewAction({required String pendingText}) {
bool isForShippingOrDelivery = false;
bool isForShippingOrDelivery = true;
return Center(
child: pendingText.toText(
color: isForShippingOrDelivery ? MyColors.lightTextColor : MyColors.adPendingStatusColor,
fontSize: isForShippingOrDelivery ? 14 : 16,
fontSize: isForShippingOrDelivery ? 15 : 16,
// isItalic: true,
),
).toContainer(

@ -137,9 +137,7 @@ class AdCard extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.start,
children: [
(adDetails.vehicle!.cityName ?? "").toText(
color: MyColors.lightTextColor,
),
(adDetails.vehicle!.cityName ?? "").toText(color: MyColors.lightTextColor),
adDetails.createdOn != null
? DateTime.parse(adDetails.createdOn!).getTimeAgo().toText(
color: MyColors.lightTextColor,
@ -159,7 +157,7 @@ class AdCard extends StatelessWidget {
children: [
(adDetails.vehicle!.demandAmount!.toInt().toString()).toText(fontSize: 19, isBold: true, letterSpacing: -1.16, height: 29 / 19),
2.width,
LocaleKeys.sar.tr().toText(color: MyColors.lightTextColor, fontSize: 10, letterSpacing: -0.4, height: 16 / 10),
LocaleKeys.sar.tr().toText(color: MyColors.lightTextColor, fontSize: 10, letterSpacing: -0.4, height: 16 / 10).paddingOnly(bottom: 3),
],
),
),

@ -1,6 +1,7 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
@ -46,6 +47,14 @@ class SelectAdTypeView extends StatelessWidget {
if (arguments.length > 2) {
adsId = arguments[2] ?? -1;
}
int totalAds = 0;
int remainingAds = 0;
if (AppState().getproviderSubscription.isNotEmpty && AppState().getproviderSubscription.first.adsRemaining != null) {
totalAds = AppState().getproviderSubscription.first.totalAds ?? 0;
remainingAds = AppState().getproviderSubscription.first.adsRemaining ?? 0;
}
return Scaffold(
appBar: CustomAppBar(
title: LocaleKeys.selectAdType.tr(),
@ -138,7 +147,7 @@ class SelectAdTypeView extends StatelessWidget {
children: [
Row(
children: [
"5 of 10 ".toText(fontSize: 29, isBold: true, letterSpacing: 0, height: 1),
"$remainingAds of $totalAds ".toText(fontSize: 29, isBold: true, letterSpacing: 0, height: 1),
LocaleKeys.adsRemainingVar.tr().toText(fontSize: 17, color: MyColors.lightTextColor, isBold: true),
],
),

@ -14,6 +14,7 @@ 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/view_models/appointments_view_model.dart';
import 'package:mc_common_app/view_models/base_view_model.dart';
import 'package:mc_common_app/view_models/dashboard_view_model_customer.dart';
import 'package:mc_common_app/widgets/common_widgets/custom_add_button_widget.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';

@ -110,7 +110,7 @@ class _ChatViewState extends State<ChatView> {
children: [
Expanded(
child: chatMessages.isEmpty
? Center(child: LocaleKeys.noChatMessage.tr().toText(fontSize: 16, color: MyColors.lightTextColor))
? Center(child: LocaleKeys.noChatMessage.tr().toText(fontSize: 16, color: MyColors.lightTextColor, textAlign: TextAlign.center)).paddingAll(22)
: ListView.separated(
controller: chatVM.scrollController,
itemCount: chatMessages.length,
@ -204,16 +204,18 @@ class _ChatViewState extends State<ChatView> {
).onPress(() => chatVM.pickMultipleImages()),
),
],
Expanded(
flex: 8,
child: TxtField(
value: chatVM.chatMessageText,
hint: LocaleKeys.typeMessageHere.tr(),
keyboardType: TextInputType.text,
isNeedBorder: false,
onChanged: (v) => chatVM.updateChatMessageText(v),
if (chatVM.pickedImagesForMessage.isEmpty) ...[
Expanded(
flex: 8,
child: TxtField(
value: chatVM.chatMessageText,
hint: LocaleKeys.typeMessageHere.tr(),
keyboardType: TextInputType.text,
isNeedBorder: false,
onChanged: (v) => chatVM.updateChatMessageText(v),
),
),
),
],
Expanded(
flex: 1,
child: const Icon(Icons.send_rounded, color: MyColors.darkPrimaryColor, size: 30).onPress(

@ -9,6 +9,7 @@ import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/dialogs_and_bottomsheets.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/view_models/base_view_model.dart';
import 'package:mc_common_app/view_models/chat_view_model.dart';
import 'package:mc_common_app/view_models/dashboard_view_model_customer.dart';
import 'package:mc_common_app/view_models/requests_view_model.dart';

@ -8,6 +8,7 @@ import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/view_models/user_view_model.dart';
import 'package:mc_common_app/views/setting_options/widgets/custom_setting_options_tile.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
@ -79,7 +80,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
color: Colors.white,
child: ListView(
children: [
20.height,
60.height,
"${AppState().getUser.data!.userInfo!.firstName} ${AppState().getUser.data!.userInfo!.lastName ?? ""}".toText(fontSize: 20).paddingOnly(left: 25),
Column(
children: [
@ -87,6 +88,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
titleText: LocaleKeys.country.tr(),
subtitleText: "Saudi Arabia",
needBorderBelow: true,
needEditButton: false,
onTap: () {},
),
CustomProfileOptionsTile(
@ -98,7 +100,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
},
),
CustomProfileOptionsTile(
titleText: LocaleKeys.phoneNumber.tr(),
titleText: LocaleKeys.phone.tr(),
subtitleText: "${AppState().getUser.data!.userInfo!.email}",
needBorderBelow: true,
onTap: () {
@ -121,16 +123,16 @@ class _ProfileScreenState extends State<ProfileScreen> {
],
),
Positioned(
top: MediaQuery.of(context).size.height * 0.25,
top: MediaQuery.of(context).size.height * 0.24,
child: Container(
height: 90,
height: 100,
alignment: Alignment.centerLeft,
child: ClipOval(
child: AppState().getUser.data!.userInfo!.userLocalImage != null
? Image.file(
AppState().getUser.data!.userInfo!.userLocalImage!,
width: 90,
height: 90,
width: 100,
height: 100,
fit: BoxFit.fill,
)
: CachedNetworkImage(
@ -145,11 +147,11 @@ class _ProfileScreenState extends State<ProfileScreen> {
),
placeholder: (context, url) => const Center(child: CircularProgressIndicator()),
errorWidget: (context, url, error) => const Icon(Icons.error),
width: 90,
height: 90,
width: 100,
height: 100,
fit: BoxFit.fill,
fadeInCurve: Curves.easeIn,
fadeInDuration: Duration(milliseconds: 1000),
fadeInDuration: const Duration(milliseconds: 1000),
useOldImageOnUrlChange: false,
),
),
@ -157,18 +159,32 @@ class _ProfileScreenState extends State<ProfileScreen> {
),
Positioned(
top: MediaQuery.of(context).size.height * 0.30,
right: MediaQuery.of(context).size.height * 0.036,
right: MediaQuery.of(context).size.height * 0.03,
child: Container(
height: 35,
width: 35,
height: 40,
width: 40,
padding: EdgeInsets.all(8),
decoration: BoxDecoration(color: MyColors.white, shape: BoxShape.circle, border: Border.all(color: MyColors.darkTextColor, width: 0.1)),
child: const Icon(Icons.edit_note, color: MyColors.darkIconColor, size: 27).paddingOnly(left: 5),
child: MyAssets.icEdit.buildSvg(),
).onPress(
() async {
model.updateUserImage(context);
await model.updateUserImage(context).whenComplete(() => setState(() {}));
},
),
),
Positioned(
top: MediaQuery.of(context).size.height * 0.05,
left: MediaQuery.of(context).size.height * 0.03,
child: const Icon(Icons.arrow_back_ios, color: Colors.black, size: 18)
.toContainer(
padding: const EdgeInsets.only(left: 5),
borderRadius: 100,
borderColor: MyColors.lightGreyEFColor,
isEnabledBorder: true,
height: 40,
width: 40,
)
.onPress(() => pop(context))),
],
);
}),

@ -7,7 +7,6 @@ import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/general_models/widgets_models.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/views/advertisement/ad_creation_steps/ad_creation_steps_containers.dart';
import 'package:mc_common_app/views/advertisement/components/picked_images_container_widget.dart';
import 'package:mc_common_app/views/location_views/pick_location_page.dart';
@ -121,7 +120,7 @@ class CreateRequestPage extends StatelessWidget {
vehicleOwnerDrop.add(DropValue(element.id.toInt(), element.enumValueStr, ""));
}
return DropdownField(
(DropValue value) => requestsVM.updateSelectionVehicleConditionId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true),
(DropValue value) => requestsVM.updateSelectionVehicleConditionId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleOwnerDrop,
dropdownValue: requestsVM.vehicleConditionId.selectedId != -1 ? DropValue(requestsVM.vehicleConditionId.selectedId, requestsVM.vehicleConditionId.selectedOption, "") : null,
hint: LocaleKeys.condition.tr(),

@ -38,9 +38,9 @@ class RequestDetailPage extends StatelessWidget {
case RequestStatusEnum.inProgress:
if (requestTypeEnum == RequestsTypeEnum.serviceRequest) {
return buildStatusContainer(LocaleKeys.awaitingPaymentFromCustomer.tr());
return Utils.buildStatusContainer(LocaleKeys.awaitingPaymentFromCustomer.tr());
} else {
return buildStatusContainer(LocaleKeys.awaitingResponseFromCustomer.tr());
return Utils.buildStatusContainer(LocaleKeys.awaitingResponseFromCustomer.tr());
}
case RequestStatusEnum.paid:
@ -56,13 +56,13 @@ class RequestDetailPage extends StatelessWidget {
},
);
} else {
return buildStatusContainer(LocaleKeys.awaitingResponseFromProvider.tr());
return Utils.buildStatusContainer(LocaleKeys.awaitingResponseFromProvider.tr());
}
case RequestStatusEnum.shipping:
case RequestStatusEnum.delivery:
if (AppState().currentAppType == AppType.provider) {
return buildStatusContainer(LocaleKeys.shippingManagementInstruction.tr(), isForShippingOrDelivery: true);
return Utils.buildStatusContainer(LocaleKeys.shippingManagementInstruction.tr());
} else {
return ShowFillButton(
maxWidth: double.infinity,
@ -78,26 +78,10 @@ class RequestDetailPage extends StatelessWidget {
case RequestStatusEnum.cancelled:
case RequestStatusEnum.expired:
case RequestStatusEnum.pending:
return buildStatusContainer(statusText);
return Utils.buildStatusContainer(statusText);
}
}
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),
);
}
Future<void> onViewChatTapped(BuildContext context) async {
ChatViewArgumentsForRequest chatViewArgumentsForRequest = ChatViewArgumentsForRequest(
chatTypeEnum: ChatTypeEnum.requestOffer,

@ -1,5 +1,6 @@
import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
@ -14,9 +15,11 @@ import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/provider_branches_models/profile/document.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/ad_view_model.dart';
import 'package:mc_common_app/view_models/service_view_model.dart';
import 'package:mc_common_app/views/advertisement/ad_creation_steps/ad_creation_steps_containers.dart';
import 'package:mc_common_app/views/advertisement/components/picked_images_container_widget.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
@ -24,6 +27,7 @@ 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:sizer/sizer.dart';
class ProviderLicensePage extends StatefulWidget {
const ProviderLicensePage({super.key});
@ -36,59 +40,72 @@ class _ProviderLicensePageState extends State<ProviderLicensePage> {
late ServiceVM branchVM;
bool showAttachment = false;
String? attachedFile;
bool isAllApproved = true;
@override
void initState() {
super.initState();
scheduleMicrotask(() {
// branchVM = Provider.of<ServiceVM>(context, listen: false);
// branchVM = Provider.of<ServiceVM>(context, listen: false);
context.read<ServiceVM>().getServiceProviderDocument(AppState().getUser.data!.userInfo!.providerId ?? 0);
});
}
@override
Widget build(BuildContext context) {
final serviceVm = context.read<ServiceVM>();
if (serviceVm.document != null && serviceVm.document!.data != null && serviceVm.document!.data!.isNotEmpty) {
for (var doc in serviceVm.document!.data!) {
if (doc.status != 3) {
isAllApproved = false;
}
}
setState(() {});
}
return Scaffold(
appBar: CustomAppBar(
title: LocaleKeys.defineLicences.tr(),
isRemoveBackButton: false,
),
body: Consumer<ServiceVM>(builder: (_, model, __) {
if (model.state == ViewState.busy) {
return const Center(
child: CircularProgressIndicator(),
);
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(0.0),
child: Column(
children: [
showWidget(model),
],
),
),
),
child: SingleChildScrollView(child: buildContent(model)),
),
Padding(
padding: const EdgeInsets.all(12.0),
child: ShowFillButton(
title: LocaleKeys.continu.tr(),
maxWidth: double.infinity,
onPressed: () {
if (AppState().getUser.data!.userInfo!.roleId == 5) {
if (validation(model)) {
updateDocument(model);
if (!isAllApproved) ...[
Padding(
padding: const EdgeInsets.all(12.0),
child: ShowFillButton(
title: LocaleKeys.continu.tr(),
maxWidth: double.infinity,
onPressed: () async {
bool status = false;
if (AppState().getUser.data!.userInfo!.roleId == 5) {
if (validation(model)) {
status = await updateDocument(model);
} else {
Utils.showToast(LocaleKeys.allDocumentMandatoryDealershipProvider.tr());
return;
}
} else {
Utils.showToast(LocaleKeys.allDocumentMandatoryDealershipProvider.tr());
status = await updateDocument(model);
}
} else {
updateDocument(model);
}
Future.delayed(const Duration(seconds: 1), () {
Navigator.of(context).pop();
});
},
Future.delayed(const Duration(seconds: 1), () {
if (status) {
pop(context);
}
});
},
),
),
),
],
],
);
}),
@ -105,120 +122,93 @@ class _ProviderLicensePageState extends State<ProviderLicensePage> {
return valid;
}
updateDocument(ServiceVM model) async {
Utils.showLoading(context);
GenericRespModel res = await model.updateDocument(model.document!.data);
Utils.hideLoading(context);
if (res.messageStatus == 1) {
Utils.showToast(LocaleKeys.documentsUploadedSuccessfully.tr());
Navigator.of(context).pop();
} else {
Utils.showToast(res.message ?? "");
Future<bool> updateDocument(ServiceVM model) async {
try {
Utils.showLoading(context);
GenericRespModel res = await model.updateDocument(model.document!.data);
Utils.hideLoading(context);
if (res.messageStatus == 1) {
Utils.showToast(LocaleKeys.documentsUploadedSuccessfully.tr());
Navigator.of(context).pop();
return true;
} else {
Utils.showToast(res.message ?? "");
return false;
}
} catch (e, s) {
return false;
}
}
Widget showWidget(ServiceVM model) {
if (model.state == ViewState.idle) {
return model.document!.data!.isEmpty
? Text(LocaleKeys.somethingWrong.tr())
: ListView.separated(
itemBuilder: (context, index) {
DocumentData? document = model.document?.data![index];
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
10.height,
(document!.documentName! ?? "").toText(fontSize: 16, letterSpacing: -0.56, fontWeight: MyFonts.SemiBold),
Padding(
padding: const EdgeInsets.only(left: 20, right: 20, top: 4, bottom: 8),
child: LocaleKeys.enter_licence_detail.tr().toText(fontSize: 14, color: MyColors.lightTextColor, textAlign: TextAlign.center),
),
TxtField(
hint: LocaleKeys.description.tr(),
maxLines: 3,
isBackgroundEnabled: true,
),
10.height,
if (isNeedToShow(model: model, document: document)) ...[
PickedFilesContainer(
// isReview: document.status == 3 ? true : false,
pickedFiles: isLocalOrNetworkFiles(model: model, document: document),
onCrossPressedPrimary: chkIsLocalOrNetwork(document: document)
? model.removeNetworkImag
: document.documentId == 1
? model.commerceRemove
: document.documentId == 2
? model.commercialRemove
: model.vatRemove,
isPdf: model.document!.data![index].fileExt == "pdf",
isFromNetwork: document.isLocalFile! ? false : true,
onAddFilePressed: () {
model.pickPdfReceiptFile(context, document.documentId!, index);
},
),
if (document.comment != null && document.comment.isNotEmpty && document.status == 4) ...[buildStatusContainer(document: document)]
] else
...[
Widget buildContent(ServiceVM model) {
return model.document!.data!.isEmpty
? Text(LocaleKeys.somethingWrong.tr())
: ListView.separated(
separatorBuilder: (context, index) {
return 20.height;
},
itemCount: model.document!.data!.length,
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: const EdgeInsets.symmetric(horizontal: 20),
itemBuilder: (context, index) {
DocumentData? document = model.document?.data![index];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
10.height,
InkWell(
onTap: () async {
model.pickPdfReceiptFile(context, document.documentId!, index) ?? "";
},
child: Container(
width: double.infinity,
height: 45,
decoration: BoxDecoration(
color: Colors.transparent,
border: Border.all(color: MyColors.greyACColor, width: 2),
borderRadius: const BorderRadius.all(Radius.circular(0)),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Icon(
Icons.attach_file,
size: 18,
color: MyColors.darkPrimaryColor,
),
8.width,
Text(
LocaleKeys.attachFile.tr(),
style: const TextStyle(
color: MyColors.darkPrimaryColor,
),
),
const Icon(
Icons.attach_file,
size: 18,
color: Colors.transparent,
),
],
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
(document!.documentName!).toText(fontSize: 16, letterSpacing: -0.56, fontWeight: MyFonts.SemiBold),
if (document.statusText != null && document.statusText!.isNotEmpty) ...[
10.width,
Utils.statusContainerChip(text: document.statusText!.replaceFirst('OrActive', ''), chipColor: getColorByStatus(document.status ?? 1)),
],
],
),
if (document.status != 1 && document.status != 3) ...[
Padding(
padding: const EdgeInsets.only(top: 4, bottom: 8),
child: LocaleKeys.enter_licence_detail.tr().toText(fontSize: 14, color: MyColors.lightTextColor),
),
TxtField(
hint: LocaleKeys.description.tr(),
maxLines: 3,
isBackgroundEnabled: true,
),
],
10.height,
if (isNeedToShow(model: model, document: document)) ...[
PickedFilesContainer(
isReview: document.status != 4,
pickedFiles: isLocalOrNetworkFiles(model: model, document: document),
onCrossPressedPrimary: chkIsLocalOrNetwork(document: document)
? model.removeNetworkImag
: document.documentId == 1
? model.commerceRemove
: document.documentId == 2
? model.commercialRemove
: model.vatRemove,
isPdf: model.document!.data![index].fileExt == "pdf",
isFromNetwork: !(document.isLocalFile ?? false),
onAddFilePressed: () {
model.pickPdfReceiptFile(context, document.documentId!, index);
},
),
buildCommentContainer(document: document),
] else ...[
10.height,
DottedRectContainer(
onTap: () => model.pickPdfReceiptFile(context, document.documentId!, index) ?? "",
text: LocaleKeys.attachImage.tr(),
icon: MyAssets.attachmentIcon.buildSvg(),
),
],
],
],
);
},
);
},
separatorBuilder: (context, index) {
return 20.height;
},
itemCount: model.document!.data!.length,
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: EdgeInsets.symmetric(horizontal: 20),
);
} else {
return Column(
children: [
20.height,
const Center(
child: CircularProgressIndicator(),
),
],
);
}
}
List<ImageModel> isLocalOrNetworkFiles({required ServiceVM model, required DocumentData document}) {
@ -281,19 +271,39 @@ class _ProviderLicensePageState extends State<ProviderLicensePage> {
return isNetworkImage;
}
Widget buildStatusContainer({required DocumentData document}) {
return Center(
child: document.comment.toString().toText(
color: MyColors.adCancelledStatusColor,
fontSize: 14,
// isItalic: true,
),
).toContainer(
marginAll: 10,
paddingAll: 10,
Widget buildCommentContainer({required DocumentData document}) {
String comment = "";
if (document.status == 4 && document.comment != null) {
comment = document.comment;
}
if (comment.isEmpty) {
return const SizedBox();
}
return Center(child: comment.toString().toText(color: MyColors.adCancelledStatusColor, fontSize: 14)).toContainer(
borderRadius: 8,
margin: const EdgeInsets.only(top: 10),
width: double.infinity,
backgroundColor: MyColors.adCancelledStatusColor.withOpacity(0.16),
);
}
Color getColorByStatus(int docStatus) {
switch (docStatus) {
case 1:
return MyColors.adPendingStatusColor;
case 2:
return MyColors.adActiveStatusColor;
case 3:
return MyColors.greenColor;
case 4:
return MyColors.adCancelledStatusColor;
default:
return MyColors.adPendingStatusColor;
}
}
}

@ -9,6 +9,7 @@ import 'package:mc_common_app/generated/locale_keys.g.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/view_models/base_view_model.dart';
import 'package:mc_common_app/view_models/dashboard_view_model_customer.dart';
import 'package:mc_common_app/view_models/user_view_model.dart';
import 'package:mc_common_app/views/setting_options/widgets/custom_setting_options_tile.dart';
@ -45,14 +46,6 @@ class _SettingOptionsLanguageState extends State<SettingOptionsLanguage> {
children: [
Column(
children: [
CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.quickreply_outlined, size: 20),
titleText: LocaleKeys.requests.tr(),
needBorderBelow: true,
onTap: () {
context.read<DashboardVmCustomer>().onNavbarTapped(4);
Navigator.pop(context);
}),
if (AppState().currentAppType == AppType.customer) ...[
CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.favorite, size: 20),
@ -61,6 +54,14 @@ class _SettingOptionsLanguageState extends State<SettingOptionsLanguage> {
onTap: () => navigateWithName(context, AppRoutes.favoriteListView),
),
],
// 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(),
@ -111,7 +112,7 @@ class _SettingOptionsLanguageState extends State<SettingOptionsLanguage> {
),
),
titleText: LocaleKeys.mySubscription.tr(),
subTitle: AppState().getproviderSubscription.first.name ?? "Silver",
subTitle: AppState().getproviderSubscription != null ? AppState().getproviderSubscription.first.name ?? "Silver" : "",
isForLanguage: false,
needBorderBelow: true,
onTap: () {
@ -185,7 +186,7 @@ class _SettingOptionsLanguageState extends State<SettingOptionsLanguage> {
// titleText: "My Requests",
// needBorderBelow: true,
// onTap: () {
// context.read<DashboardVmCustomer>().onNavbarTapped(4);
// context.read<BaseVM>().onNavbarTapped(4);
// Navigator.pop(context);
// }),
// CustomSettingOptionsTile(leadingWidget: const Icon(Icons.favorite, size: 20), titleText: "Favorite list", needBorderBelow: true, onTap: () {}),
@ -198,7 +199,6 @@ class _SettingOptionsLanguageState extends State<SettingOptionsLanguage> {
// ],
// ),
// ),
(AppState().currentAppType == AppType.provider) ? Text(LocaleKeys.provider.tr()) : Text(LocaleKeys.customer.tr()),
Row(
children: [
Expanded(

@ -1,5 +1,6 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
@ -76,10 +77,11 @@ class CustomSettingOptionsTile extends StatelessWidget {
class CustomProfileOptionsTile extends StatelessWidget {
final String titleText;
final bool needBorderBelow;
final bool needEditButton;
final Function() onTap;
final String subtitleText;
const CustomProfileOptionsTile({super.key, required this.onTap, required this.titleText, required this.subtitleText, this.needBorderBelow = false});
const CustomProfileOptionsTile({super.key, required this.onTap, required this.titleText, required this.subtitleText, this.needBorderBelow = false, this.needEditButton = true});
@override
Widget build(BuildContext context) {
@ -95,7 +97,9 @@ class CustomProfileOptionsTile extends StatelessWidget {
subtitleText.toText(fontSize: 12, color: MyColors.darkTextColor.withOpacity(0.7)),
],
),
const Icon(Icons.edit_note, size: 25),
if (needEditButton) ...[
MyAssets.icEdit.buildSvg()
],
],
).onPress(onTap),
5.height,

@ -31,7 +31,9 @@ class _ChangeEmailPageState extends State<ChangeEmailPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar( isRemoveBackButton: true, title: LocaleKeys.changeEmail.tr()),
appBar: CustomAppBar(
title: LocaleKeys.changeEmail.tr(),
),
body: SingleChildScrollView(
child: Container(
// width: double.infinity,
@ -39,7 +41,11 @@ class _ChangeEmailPageState extends State<ChangeEmailPage> {
padding: const EdgeInsets.all(20),
child: Column(
children: [
LocaleKeys.enterEmail.tr().toText(height: 23 / 24, fontSize: 24, letterSpacing: -1.44,),
LocaleKeys.enterEmail.tr().toText(
height: 23 / 24,
fontSize: 24,
letterSpacing: -1.44,
),
12.height,
TxtField(
hint: LocaleKeys.enterNewEmail.tr(),

@ -31,15 +31,19 @@ class _ChangeMobilePageState extends State<ChangeMobilePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar( isRemoveBackButton: true, title: LocaleKeys.changeMobile.tr()),
appBar: CustomAppBar(title: LocaleKeys.changeMobile.tr()),
body: SingleChildScrollView(
child: Container(
// width: double.infinity,
// height: double.infinity,
padding: EdgeInsets.all(20),
padding: const EdgeInsets.all(20),
child: Column(
children: [
LocaleKeys.enterNewPhoneNumber.tr().toText(height: 23 / 24, fontSize: 24, letterSpacing: -1.44,),
LocaleKeys.enterNewPhoneNumber.tr().toText(
height: 23 / 24,
fontSize: 24,
letterSpacing: -1.44,
),
12.height,
TxtField(
hint: LocaleKeys.enterNewPhoneNumber.tr(),

@ -31,7 +31,7 @@ class _ChangePasswordPageState extends State<ChangePasswordPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar( isRemoveBackButton: true, title: LocaleKeys.changePassword.tr()),
appBar: CustomAppBar(title: LocaleKeys.changePassword.tr()),
body: SingleChildScrollView(
child: Container(
// width: double.infinity,
@ -39,7 +39,11 @@ class _ChangePasswordPageState extends State<ChangePasswordPage> {
padding: const EdgeInsets.all(20),
child: Column(
children: [
LocaleKeys.enterNewPassword.tr().toText(height: 23 / 24, fontSize: 24, letterSpacing: -1.44,),
LocaleKeys.enterNewPassword.tr().toText(
height: 23 / 24,
fontSize: 24,
letterSpacing: -1.44,
),
12.height,
TxtField(
hint: LocaleKeys.enterOldPassword.tr(),

@ -73,7 +73,6 @@ class _EditAccountPageState extends State<EditAccountPage> {
),
],
).toWhiteContainer(width: double.infinity, pading: EdgeInsets.symmetric(horizontal: 12)),
Column(
children: [
CustomSettingOptionsTile(

@ -34,9 +34,9 @@ class _LoginWithPasswordState extends State<LoginWithPassword> {
//TODO: ONLY FOR DEVELOPMENT PURPOSE
// String phoneNum = "966504278212", password = "Fa@1234";
String phoneNum = "966504278213", password = "Fa@1234";
// String phoneNum = "966504278213", password = "Fa@1234";
// String phoneNum = "", password = "";
String phoneNum = "", password = "";
String email = "";
String countryCode = "";
Country? _country;
@ -52,8 +52,11 @@ class _LoginWithPasswordState extends State<LoginWithPassword> {
userVM = Provider.of(context, listen: false);
context.read<UserVM>().getAvailBio();
if (AppState().currentAppType == AppType.provider) {
phoneNum = "966530896018";
password = "Amir@1234";
// phoneNum = "966530896018";
// password = "Amir@1234";
//
// phoneNum = "966530896020"; // JAMES BOND
// password = "Amir@1234";
//
// // phoneNum = "966569755630";
// // password = "Amir12345@"; //AAmir Sal

@ -337,7 +337,6 @@ extension xDouble on int {
extension BuildSVG on String? {
Widget buildFileImage({double? height, double? width, BoxFit fit = BoxFit.contain, Color? color}) {
logger.i("!File(this!).existsSync(): ${!File(this!).existsSync()}");
if (this == null || this!.isEmpty || !File(this!).existsSync()) {
return SizedBox(
height: height,

Loading…
Cancel
Save