Bug Fixes

aamir_dev
Faiz Hashmi 1 year ago
parent 0bbc288da9
commit d0e733ffd3

@ -329,7 +329,7 @@
"vehiclePart": "جزء المركبة", "vehiclePart": "جزء المركبة",
"damagePartPictures": "صور الأجزاء المتضررة", "damagePartPictures": "صور الأجزاء المتضررة",
"vehicleDamagePart": "جزء المركبة المتضرر", "vehicleDamagePart": "جزء المركبة المتضرر",
"duration": ":المدة", "duration": "المدة",
"specialServices": "الخدمات الخاصة", "specialServices": "الخدمات الخاصة",
"specialService": "خدمة خاصة", "specialService": "خدمة خاصة",
"adContactDetails": "تفاصيل الاتصال بالإعلان", "adContactDetails": "تفاصيل الاتصال بالإعلان",
@ -687,5 +687,23 @@
"createdBy": "تم الإنشاء بواسطة", "createdBy": "تم الإنشاء بواسطة",
"createGroupServices": "إنشاء خدمات المجموعة", "createGroupServices": "إنشاء خدمات المجموعة",
"logoutConfirmation": "هل أنت متأكد أنك تريد تسجيل الخروج؟", "logoutConfirmation": "هل أنت متأكد أنك تريد تسجيل الخروج؟",
"logoutConfirmationMessage": "سيتم تسجيل خروجك من التطبيق وسيتعين عليك إضافة اسم المستخدم وكلمة المرور مرة أخرى لتسجيل الدخول." "logoutConfirmationMessage": "سيتم تسجيل خروجك من التطبيق وسيتعين عليك إضافة اسم المستخدم وكلمة المرور مرة أخرى لتسجيل الدخول.",
"addToFavoritesOn": "تمت الإضافة إلى المفضلة في:",
"subscriptionDate": "تاريخ الاشتراك",
"expiresOn": "تنتهي صلاحيته",
"expired": "منتهي الصلاحية",
"upgradeBranches": "قم بترقية اشتراكك لإضافة المزيد من الفروع.",
"upgradeAds": "قم بترقية اشتراكك لإضافة المزيد من الإعلانات.",
"upgradeSubUsers": "قم بترقية اشتراكك لإضافة المزيد من المستخدمين الفرعيين.",
"explore": "استكشاف",
"manageRequests": "إدارة الطلبات",
"serviceNotAvailableAtHomeLocation": "الخدمة المختارة غير متوفرة في الموقع المحدد.",
"noAvailableItems": "لا توجد عناصر متاحة.",
"wantToRescheduleAppointment": "أرغب في إعادة جدولة الموعد.",
"noNeedForService": "لا أحتاج هذه الخدمة بعد الآن.",
"testTheService": "اختبر الخدمة.",
"companyLocation": "موقع الشركة",
"customerLocation": "موقع العميل",
"deliveryAvailable": "التوصيل متاح",
"viewed": "تم المشاهدة"
} }

@ -329,7 +329,7 @@
"vehiclePart": "Vehicle Part", "vehiclePart": "Vehicle Part",
"damagePartPictures": "Damage Part Pictures", "damagePartPictures": "Damage Part Pictures",
"vehicleDamagePart": "Vehicle Damage Part", "vehicleDamagePart": "Vehicle Damage Part",
"duration": "Duration:", "duration": "Duration",
"specialServices": "Special Services", "specialServices": "Special Services",
"specialService": "Special Service", "specialService": "Special Service",
"adContactDetails": "Ad Contact Details", "adContactDetails": "Ad Contact Details",
@ -680,10 +680,28 @@
"users": "Users", "users": "Users",
"adsRemaining": "Ads Remaining", "adsRemaining": "Ads Remaining",
"attachPDF": "Attach PDF", "attachPDF": "Attach PDF",
"noItemsToShow": "No Items to show.",
"serviceItem": "Service Item", "serviceItem": "Service Item",
"createdBy": "Created By", "createdBy": "Created By",
"createGroupServices": "Create Group Services", "createGroupServices": "Create Group Services",
"logoutConfirmation": "Are you sure you want want to Logout?", "logoutConfirmation": "Are you sure you want want to Logout?",
"logoutConfirmationMessage": "You will be logged out of the application and you have to add your username and password again to login" "logoutConfirmationMessage": "You will be logged out of the application and you have to add your username and password again to login",
"addToFavoritesOn": "Added to Favorites on:",
"subscriptionDate": "Subscription Date",
"expiresOn": "Expires On",
"expired": "Expired",
"upgradeBranches": "Upgrade your subscription to add more Branches.",
"upgradeAds": "Upgrade your subscription to add more Ads.",
"upgradeSubUsers": "Upgrade your subscription to add more Sub Users.",
"explore": "Explore",
"manageRequests": "Manage Requests",
"serviceNotAvailableAtHomeLocation": "The Selected Service is not available at Home Location.",
"noAvailableItems": "There are no available items.",
"wantToRescheduleAppointment": "I want to reschedule the appointment.",
"noNeedForService": "I do not need this service anymore.",
"testTheService": "Test the service.",
"companyLocation": "Company Location",
"customerLocation": "Customer Location",
"deliveryAvailable": "Delivery Available",
"viewed": "Viewed"
} }

@ -1,5 +1,9 @@
import 'dart:io';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/generated/codegen_loader.g.dart'; import 'package:mc_common_app/generated/codegen_loader.g.dart';
import 'package:mc_common_app/utils/enums.dart';
class ApiConsts { class ApiConsts {
// static String baseUrl = "http://10.200.204.20:2801/"; // Local server // static String baseUrl = "http://10.200.204.20:2801/"; // Local server
@ -176,7 +180,7 @@ class ApiConsts {
//Settings Options //Settings Options
static String getAllFAQs = "${baseUrlServices}api/Common/FAQ_Get"; static String getAllFAQs = "${baseUrlServices}api/Common/FAQ_Get";
static String getAppInvitationLink = "${baseUrlServices}api/Common/AppInvitation_Get"; static String createAppInvitation = "${baseUrlServices}api/Common/AppInvitation_Create";
static String getContactInfo = "${baseUrlServices}api/Master/ContactInfo_Get"; static String getContactInfo = "${baseUrlServices}api/Master/ContactInfo_Get";
static String getAppInfo = "${baseUrlServices}api/Master/AppInfo_Get"; static String getAppInfo = "${baseUrlServices}api/Master/AppInfo_Get";
static String getTermsAndConditions = "${baseUrlServices}api/Master/TermAndCondition_Get"; static String getTermsAndConditions = "${baseUrlServices}api/Master/TermAndCondition_Get";
@ -185,6 +189,21 @@ class ApiConsts {
} }
class GlobalConsts { class GlobalConsts {
static String appNameCustomer = "MOWATER Customer";
static String appNameProvider = "MOWATER Provider";
//Android
static String appPackageNameCustomerAndroid = "com.cloud.solutions.mowater.ksa.customer";
static String appPackageNameProviderAndroid = "com.cloud.solutions.mowater.ksa.provider";
static String appPlayStoreLinkCustomerAndroid = "https://play.google.com/store/apps/details?id=$appPackageNameCustomerAndroid";
static String appPlayStoreLinkProviderAndroid = "https://play.google.com/store/apps/details?id=$appPackageNameProviderAndroid";
//IOS
static String appIDCustomerIOS = "";
static String appIDProviderIOS = "";
static String appAppStoreStoreLinkCustomerIos = "https://apps.apple.com/us/app/$appIDCustomerIOS";
static String appAppStoreStoreLinkProviderIos = "https://apps.apple.com/us/app/$appIDProviderIOS";
static String isRememberMe = "remember_me"; static String isRememberMe = "remember_me";
static String email = "email"; static String email = "email";
static String password = "password"; static String password = "password";
@ -194,7 +213,7 @@ class GlobalConsts {
static String doNotShowWelcomeVideo = "doNotShowWelcomeVideo"; static String doNotShowWelcomeVideo = "doNotShowWelcomeVideo";
static String demandAmountError = "Amount Cannot be Empty"; static String demandAmountError = "Amount Cannot be Empty";
static String reservationCancelError = "Cancellation Reason Cannot be Empty"; static String reservationCancelError = "Cancellation Reason Cannot be Empty";
static String descriptionError = "Description Cannot be Empty"; static String descriptionError = "Description should be more than 5 letters.";
static String acceptingThisOffer = "I am accepting this offer."; static String acceptingThisOffer = "I am accepting this offer.";
static String vehicleVinError = "Vehicle VIN Cannot be Empty"; static String vehicleVinError = "Vehicle VIN Cannot be Empty";
static String vehicleTitleError = "Vehicle Title Cannot be Empty"; static String vehicleTitleError = "Vehicle Title Cannot be Empty";
@ -209,6 +228,26 @@ class GlobalConsts {
static String fillAllFields = "Please fill out all the fields."; static String fillAllFields = "Please fill out all the fields.";
static String requestTypeCannotBeEmpty = "Request type cannot be empty."; static String requestTypeCannotBeEmpty = "Request type cannot be empty.";
static String reserveAdPriceInfo = "Some dummy description to explain the following concept. This price will be for 24 hours and if a user cancels the reservations before 24 hours then the amount will be automatically refunded to the buyer."; static String reserveAdPriceInfo = "Some dummy description to explain the following concept. This price will be for 24 hours and if a user cancels the reservations before 24 hours then the amount will be automatically refunded to the buyer.";
static String appInvitationMessageEn = "🚗 Hey , check out MOWATER to book car services, buy/sell vehicles, and more—join here! [Invite Link]";
static String getAppInvitationLink() {
String appInvitationMessageEn = "";
if (Platform.isAndroid) {
if (AppState().currentAppType == AppType.customer) {
appInvitationMessageEn = "🚗 Hey , check out $appNameCustomer to book car services, buy/sell vehicles, and more—join here! \n\n $appPlayStoreLinkCustomerAndroid";
} else {
appInvitationMessageEn = "🚗 Hey , check out $appNameProvider to book car services, buy/sell vehicles, and more—join here! \n\n $appPlayStoreLinkProviderAndroid";
}
} else if (Platform.isIOS) {
if (AppState().currentAppType == AppType.customer) {
appInvitationMessageEn = "🚗 Hey , check out $appNameCustomer to book car services, buy/sell vehicles, and more—join here! \n\n $appPlayStoreLinkCustomerAndroid";
} else {
appInvitationMessageEn = "🚗 Hey , check out $appNameProvider to book car services, buy/sell vehicles, and more—join here! \n\n $appPlayStoreLinkProviderAndroid";
}
}
return appInvitationMessageEn;
}
} }
class MyAssets { class MyAssets {

@ -345,7 +345,7 @@ class CodegenLoader extends AssetLoader{
"vehiclePart": "جزء المركبة", "vehiclePart": "جزء المركبة",
"damagePartPictures": "صور الأجزاء المتضررة", "damagePartPictures": "صور الأجزاء المتضررة",
"vehicleDamagePart": "جزء المركبة المتضرر", "vehicleDamagePart": "جزء المركبة المتضرر",
"duration": ":المدة", "duration": "المدة",
"specialServices": "الخدمات الخاصة", "specialServices": "الخدمات الخاصة",
"specialService": "خدمة خاصة", "specialService": "خدمة خاصة",
"adContactDetails": "تفاصيل الاتصال بالإعلان", "adContactDetails": "تفاصيل الاتصال بالإعلان",
@ -703,7 +703,25 @@ class CodegenLoader extends AssetLoader{
"createdBy": "تم الإنشاء بواسطة", "createdBy": "تم الإنشاء بواسطة",
"createGroupServices": "إنشاء خدمات المجموعة", "createGroupServices": "إنشاء خدمات المجموعة",
"logoutConfirmation": "هل أنت متأكد أنك تريد تسجيل الخروج؟", "logoutConfirmation": "هل أنت متأكد أنك تريد تسجيل الخروج؟",
"logoutConfirmationMessage": "سيتم تسجيل خروجك من التطبيق وسيتعين عليك إضافة اسم المستخدم وكلمة المرور مرة أخرى لتسجيل الدخول." "logoutConfirmationMessage": "سيتم تسجيل خروجك من التطبيق وسيتعين عليك إضافة اسم المستخدم وكلمة المرور مرة أخرى لتسجيل الدخول.",
"addToFavoritesOn": "تمت الإضافة إلى المفضلة في:",
"subscriptionDate": "تاريخ الاشتراك",
"expiresOn": "تنتهي صلاحيته",
"expired": "منتهي الصلاحية",
"upgradeBranches": "قم بترقية اشتراكك لإضافة المزيد من الفروع.",
"upgradeAds": "قم بترقية اشتراكك لإضافة المزيد من الإعلانات.",
"upgradeSubUsers": "قم بترقية اشتراكك لإضافة المزيد من المستخدمين الفرعيين.",
"explore": "استكشاف",
"manageRequests": "إدارة الطلبات",
"serviceNotAvailableAtHomeLocation": "الخدمة المختارة غير متوفرة في الموقع المحدد.",
"noAvailableItems": "لا توجد عناصر متاحة.",
"wantToRescheduleAppointment": "أرغب في إعادة جدولة الموعد.",
"noNeedForService": "لا أحتاج هذه الخدمة بعد الآن.",
"testTheService": "اختبر الخدمة.",
"companyLocation": "موقع الشركة",
"customerLocation": "موقع العميل",
"deliveryAvailable": "التوصيل متاح",
"viewed": "تم المشاهدة"
}; };
static const Map<String,dynamic> en_US = { static const Map<String,dynamic> en_US = {
"firstTimeLogIn": "First Time Log In", "firstTimeLogIn": "First Time Log In",
@ -1036,7 +1054,7 @@ static const Map<String,dynamic> en_US = {
"vehiclePart": "Vehicle Part", "vehiclePart": "Vehicle Part",
"damagePartPictures": "Damage Part Pictures", "damagePartPictures": "Damage Part Pictures",
"vehicleDamagePart": "Vehicle Damage Part", "vehicleDamagePart": "Vehicle Damage Part",
"duration": "Duration:", "duration": "Duration",
"specialServices": "Special Services", "specialServices": "Special Services",
"specialService": "Special Service", "specialService": "Special Service",
"adContactDetails": "Ad Contact Details", "adContactDetails": "Ad Contact Details",
@ -1387,12 +1405,29 @@ static const Map<String,dynamic> en_US = {
"users": "Users", "users": "Users",
"adsRemaining": "Ads Remaining", "adsRemaining": "Ads Remaining",
"attachPDF": "Attach PDF", "attachPDF": "Attach PDF",
"noItemsToShow": "No Items to show.",
"serviceItem": "Service Item", "serviceItem": "Service Item",
"createdBy": "Created By", "createdBy": "Created By",
"createGroupServices": "Create Group Services", "createGroupServices": "Create Group Services",
"logoutConfirmation": "Are you sure you want want to Logout?", "logoutConfirmation": "Are you sure you want want to Logout?",
"logoutConfirmationMessage": "You will be logged out of the application and you have to add your username and password again to login" "logoutConfirmationMessage": "You will be logged out of the application and you have to add your username and password again to login",
"addToFavoritesOn": "Added to Favorites on:",
"subscriptionDate": "Subscription Date",
"expiresOn": "Expires On",
"expired": "Expired",
"upgradeBranches": "Upgrade your subscription to add more Branches.",
"upgradeAds": "Upgrade your subscription to add more Ads.",
"upgradeSubUsers": "Upgrade your subscription to add more Sub Users.",
"explore": "Explore",
"manageRequests": "Manage Requests",
"serviceNotAvailableAtHomeLocation": "The Selected Service is not available at Home Location.",
"noAvailableItems": "There are no available items.",
"wantToRescheduleAppointment": "I want to reschedule the appointment.",
"noNeedForService": "I do not need this service anymore.",
"testTheService": "Test the service.",
"companyLocation": "Company Location",
"customerLocation": "Customer Location",
"deliveryAvailable": "Delivery Available",
"viewed": "Viewed"
}; };
static const Map<String, Map<String,dynamic>> mapLocales = {"ar_SA": ar_SA, "en_US": en_US}; static const Map<String, Map<String,dynamic>> mapLocales = {"ar_SA": ar_SA, "en_US": en_US};
} }

@ -667,5 +667,23 @@ abstract class LocaleKeys {
static const createGroupServices = 'createGroupServices'; static const createGroupServices = 'createGroupServices';
static const logoutConfirmation = 'logoutConfirmation'; static const logoutConfirmation = 'logoutConfirmation';
static const logoutConfirmationMessage = 'logoutConfirmationMessage'; static const logoutConfirmationMessage = 'logoutConfirmationMessage';
static const addToFavoritesOn = 'addToFavoritesOn';
static const subscriptionDate = 'subscriptionDate';
static const expiresOn = 'expiresOn';
static const expired = 'expired';
static const upgradeBranches = 'upgradeBranches';
static const upgradeAds = 'upgradeAds';
static const upgradeSubUsers = 'upgradeSubUsers';
static const explore = 'explore';
static const manageRequests = 'manageRequests';
static const serviceNotAvailableAtHomeLocation = 'serviceNotAvailableAtHomeLocation';
static const noAvailableItems = 'noAvailableItems';
static const wantToRescheduleAppointment = 'wantToRescheduleAppointment';
static const noNeedForService = 'noNeedForService';
static const testTheService = 'testTheService';
static const companyLocation = 'companyLocation';
static const customerLocation = 'customerLocation';
static const deliveryAvailable = 'deliveryAvailable';
static const viewed = 'viewed';
} }

@ -2,6 +2,7 @@ import 'package:logger/logger.dart';
Logger logger = Logger(printer: PrettyPrinter(printEmojis: false, colors: true, printTime: false)); Logger logger = Logger(printer: PrettyPrinter(printEmojis: false, colors: true, printTime: false));
bool disableThingsForQA = true; bool disableThingsForQA = true;
// Language Tile in Settings // Language Tile in Settings

@ -33,21 +33,7 @@ class BranchDetailModel {
bool isExpanded = false; bool isExpanded = false;
bool? isFavorite; bool? isFavorite;
//I/flutter (23146): "id": 1021,
// I/flutter (23146): "serviceProviderID": 10,
// I/flutter (23146): "serviceProviderName": "string",
// I/flutter (23146): "cityID": 1,
// I/flutter (23146): "cityName": "Riyadh",
// I/flutter (23146): "branchName": "Al Arouba Cars",
// I/flutter (23146): "branchDescription": "des",
// I/flutter (23146): "address": "3289 Hilal Bin Omayah St - حي العليا, حي العليا, الرياض, RHOD3289, Saudi Arabia",
// I/flutter (23146): "latitude": "24.708521303151027",
// I/flutter (23146): "longitude": "46.666924171149724",
// I/flutter (23146): "distanceKM": 0.0,
// I/flutter (23146): "openTime": "09:00",
// I/flutter (23146): "closeTime": "18:00",
// I/flutter (23146): "branchStatus": 3,
// I/flutter (23146): "branchStatusText": "ApprovedOrActive",
BranchDetailModel({ BranchDetailModel({
this.id, this.id,
this.serviceProviderId, this.serviceProviderId,

@ -10,8 +10,6 @@ import '../../utils/enums.dart';
Subscription subscriptionFromJson(String str) => Subscription.fromJson(json.decode(str)); Subscription subscriptionFromJson(String str) => Subscription.fromJson(json.decode(str));
String subscriptionToJson(Subscription data) => json.encode(data.toJson());
class SubscriptionModel { class SubscriptionModel {
SubscriptionModel({ SubscriptionModel({
this.messageStatus, this.messageStatus,
@ -31,13 +29,6 @@ class SubscriptionModel {
data: json["data"] == null ? [] : List<Subscription>.from(json["data"]!.map((x) => Subscription.fromJson(x))), data: json["data"] == null ? [] : List<Subscription>.from(json["data"]!.map((x) => Subscription.fromJson(x))),
message: json["message"], message: json["message"],
); );
Map<String, dynamic> toJson() => {
"messageStatus": messageStatus,
"totalItemsCount": totalItemsCount,
"data": data == null ? [] : List<dynamic>.from(data!.map((x) => x.toJson())),
"message": message,
};
} }
class Subscription { class Subscription {
@ -83,8 +74,8 @@ class Subscription {
bool? isSubscribed; bool? isSubscribed;
int? subscriptionAppliedId; int? subscriptionAppliedId;
int? serviceProviderId; int? serviceProviderId;
DateTime? dateStart; String? dateStart;
DateTime? dateEnd; String? dateEnd;
bool? isExpired; bool? isExpired;
bool? isActive; bool? isActive;
SubscriptionTypeEnum? subscriptionTypeEnum; SubscriptionTypeEnum? subscriptionTypeEnum;
@ -114,8 +105,8 @@ class Subscription {
isSubscribed: json["isSubscribed"], isSubscribed: json["isSubscribed"],
subscriptionAppliedId: json["subscriptionAppliedID"], subscriptionAppliedId: json["subscriptionAppliedID"],
serviceProviderId: json["serviceProviderID"], serviceProviderId: json["serviceProviderID"],
dateStart: json["dateStart"] == null ? null : DateTime.parse(json["dateStart"]), dateStart: json["dateStart"],
dateEnd: json["dateEnd"] == null ? null : DateTime.parse(json["dateEnd"]), dateEnd: json["dateEnd"],
isExpired: json["isExpired"], isExpired: json["isExpired"],
isActive: json["isActive"], isActive: json["isActive"],
isMyCurrentPackage: false, isMyCurrentPackage: false,
@ -131,33 +122,4 @@ class Subscription {
subUsersRemaining: json["subUsersRemaining"], subUsersRemaining: json["subUsersRemaining"],
adsRemaining: json["adsRemaining"], adsRemaining: json["adsRemaining"],
); );
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
"description": description,
"durationName": durationName,
"durationDays": durationDays,
"price": price,
"currency": currency,
"countryID": countryId,
"countryName": countryName,
"isSubscribed": isSubscribed,
"subscriptionAppliedID": subscriptionAppliedId,
"serviceProviderID": serviceProviderId,
"dateStart": dateStart?.toIso8601String(),
"dateEnd": dateEnd?.toIso8601String(),
"isExpired": isExpired,
"isActive": isActive,
"isRenewable": isRenewable,
"subscriptionBranches": subscriptionBranches,
"subscriptionSubUsers": subscriptionSubUsers,
"subscriptionAds": subscriptionAds,
"totalBranches": totalBranches,
"totalSubUsers": totalSubUsers,
"totalAds": totalAds,
"branchesRemaining": branchesRemaining,
"subUsersRemaining": subUsersRemaining,
"adsRemaining": adsRemaining,
};
} }

@ -16,7 +16,7 @@ import 'package:mc_common_app/utils/enums.dart';
abstract class AdsRepo { abstract class AdsRepo {
Future<List<AdsDurationModel>> getAdsDuration(); Future<List<AdsDurationModel>> getAdsDuration();
Future<List<SpecialServiceModel>> getSpecialServices({required int specialServiceId}); Future<List<SpecialServiceModel>> getSpecialServices({required int specialServiceType});
Future<GenericRespModel> createOrUpdateAd({required AdsCreationPayloadModel adsCreationPayloadModel, required bool isCreateNew}); Future<GenericRespModel> createOrUpdateAd({required AdsCreationPayloadModel adsCreationPayloadModel, required bool isCreateNew});
@ -63,9 +63,9 @@ class AdsRepoImp implements AdsRepo {
} }
@override @override
Future<List<SpecialServiceModel>> getSpecialServices({required int specialServiceId}) async { Future<List<SpecialServiceModel>> getSpecialServices({required int specialServiceType}) async {
var params = { var params = {
"SpecialServiceType": specialServiceId.toString(), "SpecialServiceType": specialServiceType.toString(),
}; };
GenericRespModel adsGenericModel = await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleAdsSpecialServicesGet, queryParameters: params); GenericRespModel adsGenericModel = await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleAdsSpecialServicesGet, queryParameters: params);
List<SpecialServiceModel> vehicleAdsDuration = List.generate(adsGenericModel.data.length, (index) => SpecialServiceModel.fromJson(adsGenericModel.data[index])); List<SpecialServiceModel> vehicleAdsDuration = List.generate(adsGenericModel.data.length, (index) => SpecialServiceModel.fromJson(adsGenericModel.data[index]));

@ -108,16 +108,21 @@ class AppointmentRepoImp implements AppointmentRepo {
required List<String> serviceItemIdsForWorkshop, required List<String> serviceItemIdsForWorkshop,
}) async { }) async {
String t = appState.getUser.data!.accessToken ?? ""; String t = appState.getUser.data!.accessToken ?? "";
var queryParameters = [ var queryParameters = [];
// {
// "appointmentType": 2, if (serviceItemIdsForWorkshop.isNotEmpty) {
// "ServiceItemIDs": serviceItemIdsForHome, queryParameters.add({
// },
{
"appointmentType": 1, "appointmentType": 1,
"ServiceItemIDs": serviceItemIdsForWorkshop, "ServiceItemIDs": serviceItemIdsForWorkshop,
} });
]; }
if (serviceItemIdsForHome.isNotEmpty) {
queryParameters.add({
"appointmentType": 2,
"ServiceItemIDs": serviceItemIdsForHome,
});
}
GenericRespModel adsGenericModel = await apiClient.postJsonForObject( GenericRespModel adsGenericModel = await apiClient.postJsonForObject(
(json) => GenericRespModel.fromJson(json), (json) => GenericRespModel.fromJson(json),
ApiConsts.getServiceItemAppointmentScheduleSlots, ApiConsts.getServiceItemAppointmentScheduleSlots,

@ -19,6 +19,8 @@ abstract class SettingOptionsRepo {
Future<List<AppInfoModel>> getAppInfoList(); Future<List<AppInfoModel>> getAppInfoList();
Future<List<AppInfoModel>> getTermsAndConditions(); Future<List<AppInfoModel>> getTermsAndConditions();
Future<void> appInvitationCreate({required int channelId});
} }
class SettingOptionsRepoImp extends SettingOptionsRepo { class SettingOptionsRepoImp extends SettingOptionsRepo {
@ -140,4 +142,31 @@ class SettingOptionsRepoImp extends SettingOptionsRepo {
return list; return list;
} }
@override
Future<void> appInvitationCreate({required int channelId}) async {
String token = appState.getUser.data!.accessToken ?? "";
final params = {
"channelID": channelId.toString(),
"comments": "string",
};
if (AppState().currentAppType == AppType.provider) {
params.addAll({
"customerID": (appState.getUser.data!.userInfo!.customerId ?? "0").toString(),
});
} else {
params.addAll({
"providerID": (appState.getUser.data!.userInfo!.providerId ?? "0").toString(),
});
}
GenericRespModel genericRespModel = await injector.get<ApiClient>().postJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.createAppInvitation,
token: token,
params,
);
}
} }

@ -52,7 +52,7 @@ class MyColors {
static const Color pendingColor = Colors.amber; static const Color pendingColor = Colors.amber;
static const Color submittedColor = Colors.blue; static const Color submittedColor = Colors.blue;
static const Color inProgressColor = Colors.deepOrange; static const Color inProgressColor = Colors.indigo;
static const Color completedColor = Colors.green; static const Color completedColor = Colors.green;
static const Color cancelledColor = Colors.red; static const Color cancelledColor = Colors.red;
static const Color paidColor = Colors.teal; static const Color paidColor = Colors.teal;

@ -19,6 +19,20 @@ class AppEnums {
static const int shippingStatusEnumId = -2; // to get the Shipping Filter Enums static const int shippingStatusEnumId = -2; // to get the Shipping Filter Enums
} }
enum DashboardRouteEnum {
fromAdsPayment,
fromAdsSubmit,
none,
}
enum VehicleType { enum VehicleType {
car, car,
motorCycle, motorCycle,

@ -19,6 +19,7 @@ import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/widgets/loading_dialog.dart'; import 'package:mc_common_app/widgets/loading_dialog.dart';
import 'package:share_plus/share_plus.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'package:url_launcher/url_launcher_string.dart'; import 'package:url_launcher/url_launcher_string.dart';
@ -28,13 +29,7 @@ class Utils {
static bool get isLoading => _isLoadingVisible; static bool get isLoading => _isLoadingVisible;
static void showToast(String message) { static void showToast(String message) {
Fluttertoast.showToast(msg: message, Fluttertoast.showToast(msg: message, toastLength: Toast.LENGTH_SHORT, gravity: ToastGravity.BOTTOM, timeInSecForIosWeb: 2, backgroundColor: Colors.black54, textColor: Colors.white, fontSize: 16.0);
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 { static Future<void> openNumberViaCaller({required String phoneNumber}) async {
@ -49,6 +44,18 @@ class Utils {
} }
} }
static Future<void> openEmailViaEmailApp({required String emailAddress}) async {
Uri emailLaunchUrl = Uri.parse('mailto:$emailAddress');
if (await canLaunchUrl(emailLaunchUrl)) {
try {
await launchUrl(emailLaunchUrl);
} catch (e) {
await launchUrl(emailLaunchUrl);
}
}
}
static Future<void> openNumberViaWhatsApp({required String phoneNumber}) async { static Future<void> openNumberViaWhatsApp({required String phoneNumber}) async {
final url = 'https://wa.me/$phoneNumber?text='; final url = 'https://wa.me/$phoneNumber?text=';
@ -77,11 +84,7 @@ class Utils {
return ""; return "";
} }
return ("${timeOfDay.hour return ("${timeOfDay.hour.toString().length == 1 ? "0" : ""}${timeOfDay.hour}:${timeOfDay.minute.toString().length == 1 ? "0" : ""}${timeOfDay.minute}").toString();
.toString()
.length == 1 ? "0" : ""}${timeOfDay.hour}:${timeOfDay.minute
.toString()
.length == 1 ? "0" : ""}${timeOfDay.minute}").toString();
} }
static dynamic getNotNullValue(List<dynamic> list, int index) { static dynamic getNotNullValue(List<dynamic> list, int index) {
@ -275,23 +278,20 @@ class Utils {
return MyColors.cancelledColor; return MyColors.cancelledColor;
case RequestOfferStatusEnum.cancel: case RequestOfferStatusEnum.cancel:
return MyColors.redColor; return MyColors.cancelledColor;
} }
} }
static String getNameByRequestOfferStatusEnum(RequestOfferStatusEnum requestOfferStatusEnum) { static String getNameByRequestOfferStatusEnum(RequestOfferStatusEnum requestOfferStatusEnum) {
switch (requestOfferStatusEnum) { switch (requestOfferStatusEnum) {
case RequestOfferStatusEnum.offer: case RequestOfferStatusEnum.offer:
return "Pending"; return "Offer";
case RequestOfferStatusEnum.negotiate: case RequestOfferStatusEnum.negotiate:
return "Negotiate"; return "Negotiate";
case RequestOfferStatusEnum.accepted: case RequestOfferStatusEnum.accepted:
return "Accepted"; return "Accepted";
case RequestOfferStatusEnum.rejected: case RequestOfferStatusEnum.rejected:
return "Rejected"; return "Rejected";
case RequestOfferStatusEnum.cancel: case RequestOfferStatusEnum.cancel:
return "Cancelled"; return "Cancelled";
} }
@ -383,7 +383,6 @@ class Utils {
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: chipColor, color: chipColor,
borderRadius: const BorderRadius.all(Radius.circular(200)),
), ),
padding: padding, padding: padding,
child: text.toText(fontSize: 10, color: textColor, letterSpacing: -0.50)); child: text.toText(fontSize: 10, color: textColor, letterSpacing: -0.50));
@ -522,7 +521,7 @@ class Utils {
border: Border.all( border: Border.all(
width: w, // width: w, //
color: color // <--- border width here color: color // <--- border width here
), ),
borderRadius: BorderRadius.circular(radius), borderRadius: BorderRadius.circular(radius),
); );
} }
@ -545,7 +544,7 @@ class Utils {
border: Border.all( border: Border.all(
width: 1, // width: 1, //
color: color // <--- border width here color: color // <--- border width here
), ),
borderRadius: BorderRadius.circular(radius), borderRadius: BorderRadius.circular(radius),
); );
} }
@ -563,8 +562,7 @@ class Utils {
} }
static String getAdsPaymentBrowserForm({required int paymentId, required int adId}) { static String getAdsPaymentBrowserForm({required int paymentId, required int adId}) {
return '<html> <head></head><body><form id="paymentForm" action="${ApiConsts 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>';
.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 // BOTTOM SHEETS
@ -589,6 +587,9 @@ class Utils {
} }
static Widget buildStatusContainer(String text, {double marginAll = 8, double fontSize = 14}) { static Widget buildStatusContainer(String text, {double marginAll = 8, double fontSize = 14}) {
if (text.isEmpty) {
return const SizedBox();
}
return Center( return Center(
child: text.toText(color: MyColors.lightTextColor, fontSize: fontSize), child: text.toText(color: MyColors.lightTextColor, fontSize: fontSize),
).toContainer( ).toContainer(
@ -611,4 +612,9 @@ class Utils {
} }
} }
} }
static Future<ShareResult> shareAppInvitation() async {
ShareResult result = await Share.share(GlobalConsts.getAppInvitationLink(), subject: 'Join Mowater');
return result;
}
} }

@ -108,7 +108,7 @@ class AdVM extends BaseVM {
vehicleAdsSpecialServices[index].isSelected = true; vehicleAdsSpecialServices[index].isSelected = true;
} }
specialServiceCards.add(specialServiceCard); specialServiceCards.add(specialServiceCard);
vehicleAdsSpecialServicesId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); selectedVehicleAdsSpecialServicesId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
adSpecialServiceDate = ""; adSpecialServiceDate = "";
notifyListeners(); notifyListeners();
} }
@ -302,7 +302,7 @@ class AdVM extends BaseVM {
} }
Future<void> getVehicleAdsSpecialServices() async { Future<void> getVehicleAdsSpecialServices() async {
vehicleAdsSpecialServices = await adsRepo.getSpecialServices(specialServiceId: 1); vehicleAdsSpecialServices = await adsRepo.getSpecialServices(specialServiceType: 1);
notifyListeners(); notifyListeners();
} }
@ -748,10 +748,10 @@ class AdVM extends BaseVM {
notifyListeners(); notifyListeners();
} }
SelectionModel vehicleAdsSpecialServicesId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); SelectionModel selectedVehicleAdsSpecialServicesId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
void updateVehicleAdsSpecialServicesId(SelectionModel id) async { void updateSelectedVehicleAdsSpecialServicesId(SelectionModel id) async {
vehicleAdsSpecialServicesId = id; selectedVehicleAdsSpecialServicesId = id;
// isFetchingLists = true; // isFetchingLists = true;
// adSSTimeSlots.clear(); // adSSTimeSlots.clear();
// vehicleAdsPhotoServiceDate = SelectionModel(selectedId: -1, selectedOption: ""); // vehicleAdsPhotoServiceDate = SelectionModel(selectedId: -1, selectedOption: "");
@ -1136,7 +1136,7 @@ class AdVM extends BaseVM {
resetValues(); resetValues();
updateIsExploreAds(false); updateIsExploreAds(false);
applyFilterOnMyAds(adPostStatusEnum: AdPostStatus.pendingForReview); //pending for review applyFilterOnMyAds(adPostStatusEnum: AdPostStatus.pendingForReview); //pending for review
navigateReplaceWithName(context, AppRoutes.dashboard); navigateReplaceWithName(context, AppRoutes.dashboard, arguments: DashboardRouteEnum.fromAdsSubmit);
} catch (e) { } catch (e) {
Utils.hideLoading(context); Utils.hideLoading(context);
Utils.showToast("Error: ${e.toString()}"); Utils.showToast("Error: ${e.toString()}");
@ -1285,6 +1285,7 @@ class AdVM extends BaseVM {
vehicleAdsSpecialServices.clear(); vehicleAdsSpecialServices.clear();
currentProgressStep = AdCreationSteps.vehicleDetails; currentProgressStep = AdCreationSteps.vehicleDetails;
vehicleTypeId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); vehicleTypeId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
vehicleModelId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
// vehicleAdDurationId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); // vehicleAdDurationId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
vehicleBrandId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); vehicleBrandId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
vehicleModelYearId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); vehicleModelYearId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");

@ -12,6 +12,7 @@ import 'package:mc_common_app/main.dart';
import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart'; import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart';
import 'package:mc_common_app/models/appointments_models/appointment_slots.dart'; import 'package:mc_common_app/models/appointments_models/appointment_slots.dart';
import 'package:mc_common_app/models/appointments_models/service_schedule_model.dart'; import 'package:mc_common_app/models/appointments_models/service_schedule_model.dart';
import 'package:mc_common_app/models/chat_models/chat_message_model.dart';
import 'package:mc_common_app/models/general_models/enums_model.dart'; import 'package:mc_common_app/models/general_models/enums_model.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart'; import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/general_models/widgets_models.dart'; import 'package:mc_common_app/models/general_models/widgets_models.dart';
@ -163,6 +164,54 @@ class AppointmentsVM extends BaseVM {
navigateWithName(context, AppRoutes.paymentMethodsView, arguments: PaymentTypes.appointment); navigateWithName(context, AppRoutes.paymentMethodsView, arguments: PaymentTypes.appointment);
} }
OfferRequestCommentModel selectedCancelAppointmentReason = OfferRequestCommentModel(
index: 0,
isSelected: true,
title: LocaleKeys.changedMind.tr(),
);
List<OfferRequestCommentModel> cancelAppointmentReasonList = [
OfferRequestCommentModel(
index: 0,
isSelected: true,
title: LocaleKeys.wantToRescheduleAppointment.tr(),
),
OfferRequestCommentModel(
index: 1,
isSelected: false,
title: LocaleKeys.noNeedForService.tr(),
),
OfferRequestCommentModel(
index: 2,
isSelected: false,
title: LocaleKeys.testTheService.tr(),
),
OfferRequestCommentModel(
index: 3,
isSelected: false,
title: LocaleKeys.otherVar.tr(),
),
];
void updateSelectedCancelAppointmentReason(int index) {
for (var value in cancelAppointmentReasonList) {
value.isSelected = false;
}
selectedCancelAppointmentReason = cancelAppointmentReasonList[index];
cancelAppointmentReasonList[index].isSelected = true;
notifyListeners();
}
String cancelAppointmentDescription = "";
String cancelAppointmentDescriptionError = "";
void updateCancelAppointmentDescription(String value) {
cancelAppointmentDescription = value;
if (value.isNotEmpty) {
cancelAppointmentDescriptionError = "";
}
}
Future<void> onCancelAppointmentPressed({required BuildContext context, required AppointmentListModel appointmentListModel}) async { Future<void> onCancelAppointmentPressed({required BuildContext context, required AppointmentListModel appointmentListModel}) async {
Utils.showLoading(context); Utils.showLoading(context);
try { try {
@ -498,6 +547,8 @@ class AppointmentsVM extends BaseVM {
serviceItemsFromApi[index].isUpdateOrSelected = selected; serviceItemsFromApi[index].isUpdateOrSelected = selected;
serviceItemsFromApi[index].isHomeSelected = isHomeTapped; serviceItemsFromApi[index].isHomeSelected = isHomeTapped;
log(" serviceItemsFromApi[index].isHomeSelected: ${serviceItemsFromApi[index].isHomeSelected}");
if (selected) { if (selected) {
selectedSubServicesCounter = selectedSubServicesCounter + 1; selectedSubServicesCounter = selectedSubServicesCounter + 1;
selectSubServicesError = ""; selectSubServicesError = "";
@ -611,6 +662,7 @@ class AppointmentsVM extends BaseVM {
isScrollControlled: true, isScrollControlled: true,
enableDrag: true, enableDrag: true,
builder: (BuildContext context) { builder: (BuildContext context) {
// TODO: It should be calculated from API
double totalKms = 15.3; double totalKms = 15.3;
return InfoBottomSheet( return InfoBottomSheet(
title: LocaleKeys.chargesBreakdown.tr().toText(fontSize: 24, isBold: true), title: LocaleKeys.chargesBreakdown.tr().toText(fontSize: 24, isBold: true),
@ -625,7 +677,7 @@ class AppointmentsVM extends BaseVM {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
"${selectedService.serviceItems![index].name}".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), "${selectedService.serviceItems![index].name}".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
"${selectedService.serviceItems![index].price} SAR".toText(fontSize: 12, isBold: true), "${selectedService.serviceItems![index].price} ${LocaleKeys.sar.tr()}".toText(fontSize: 12, isBold: true),
], ],
), ),
), ),
@ -633,7 +685,7 @@ class AppointmentsVM extends BaseVM {
Row( Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
children: [ children: [
"${selectedService.currentTotalServicePrice} SAR".toText(fontSize: 16, isBold: true), "${selectedService.currentTotalServicePrice} ${LocaleKeys.sar.tr()}".toText(fontSize: 16, isBold: true),
], ],
), ),
if (selectedService.isHomeSelected) ...[ if (selectedService.isHomeSelected) ...[
@ -650,7 +702,7 @@ class AppointmentsVM extends BaseVM {
Row( Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
children: [ children: [
"${selectedService.rangePricePerKm ?? 0 * totalKms} SAR".toText(fontSize: 16, isBold: true), "${(double.parse(selectedService.rangePricePerKm!)) * totalKms} ${LocaleKeys.sar.tr()}".toText(fontSize: 16, isBold: true),
], ],
), ),
], ],
@ -662,7 +714,7 @@ class AppointmentsVM extends BaseVM {
Row( Row(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
(selectedService.isHomeSelected ? "${(selectedService.currentTotalServicePrice) + (double.parse((selectedService.rangePricePerKm ?? "0.0")) * totalKms)}" : "${selectedService.currentTotalServicePrice}") (selectedService.isHomeSelected ? "${(selectedService.currentTotalServicePrice) + ((double.parse((selectedService.rangePricePerKm ?? "0.0")) * totalKms))}" : "${selectedService.currentTotalServicePrice}")
.toText(fontSize: 29, isBold: true), .toText(fontSize: 29, isBold: true),
2.width, 2.width,
LocaleKeys.sar.tr().toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5), LocaleKeys.sar.tr().toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5),
@ -718,6 +770,8 @@ class AppointmentsVM extends BaseVM {
List<String> serviceItemIdsForHome = []; List<String> serviceItemIdsForHome = [];
List<String> serviceItemIdsForWorkshop = []; List<String> serviceItemIdsForWorkshop = [];
for (var serviceItem in allSelectedItemsInAppointments) { for (var serviceItem in allSelectedItemsInAppointments) {
log("homeselcted for : ${serviceItem.isHomeSelected}");
if (serviceItem.isHomeSelected!) { if (serviceItem.isHomeSelected!) {
serviceItemIdsForHome.add(serviceItem.id!.toString()); serviceItemIdsForHome.add(serviceItem.id!.toString());
} else { } else {
@ -1098,22 +1152,14 @@ class AppointmentsVM extends BaseVM {
setState(ViewState.idle); setState(ViewState.idle);
} }
Future<void> fetchAllCategories(String countryCode) async { Future<void> fetchAllCategories() async {
if (categoryDropList.isNotEmpty) return; if (categoryDropList.isNotEmpty) return;
categoryDropList.clear(); categoryDropList.clear();
setOnlyState(ViewState.busy); setOnlyState(ViewState.busy);
Category category = await branchRepo.fetchBranchCategory(); Category category = await branchRepo.fetchBranchCategory();
category.data?.forEach((element) { category.data?.forEach((element) {
categoryDropList.add( categoryDropList.add(
DropValue( DropValue(element.id ?? 0, ((element.categoryName!.isEmpty ? "N/A" : element.categoryName) ?? "N/A"), ""),
element.id ?? 0,
((element.categoryName!.isEmpty
? "N/A"
: countryCode == "SA"
? element.categoryNameN
: element.categoryName) ??
"N/A"),
""),
); );
}); });
setState(ViewState.idle); setState(ViewState.idle);
@ -1139,7 +1185,7 @@ class AppointmentsVM extends BaseVM {
Future<void> populateDataForBranchesFilter() async { Future<void> populateDataForBranchesFilter() async {
await fetchAllProviders(); // saudi arabia await fetchAllProviders(); // saudi arabia
await fetchAllCategories("SA"); // saudi arabia await fetchAllCategories(); // saudi arabia
await fetchAllServices(); // saudi arabia await fetchAllServices(); // saudi arabia
updateBranchFilterCurrentDistance(25.0); updateBranchFilterCurrentDistance(25.0);
} }
@ -1231,9 +1277,9 @@ class AppointmentsVM extends BaseVM {
} }
Future<void> populateDataForAppointmentsFilter() async { Future<void> populateDataForAppointmentsFilter() async {
await fetchAllProviders(); // saudi arabia await fetchAllProviders();
await fetchAllCategories("SA"); // saudi arabia await fetchAllCategories();
await fetchAllServices(); // saudi arabia await fetchAllServices();
} }
int appointmentFiltersCounter = 0; int appointmentFiltersCounter = 0;

@ -103,12 +103,6 @@ class ChatVM extends ChangeNotifier {
), ),
]; ];
OfferRequestCommentModel selectedOfferRequestCommentModel = OfferRequestCommentModel(
index: 0,
isSelected: true,
title: LocaleKeys.changedMind.tr(),
);
void updateSelectionInOfferRejectModelList(int index) { void updateSelectionInOfferRejectModelList(int index) {
for (var value in offerRejectModelList) { for (var value in offerRejectModelList) {
value.isSelected = false; value.isSelected = false;
@ -118,6 +112,12 @@ class ChatVM extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
OfferRequestCommentModel selectedOfferRequestCommentModel = OfferRequestCommentModel(
index: 0,
isSelected: true,
title: LocaleKeys.changedMind.tr(),
);
String rejectOfferDescription = ""; String rejectOfferDescription = "";
String rejectOfferDescriptionError = ""; String rejectOfferDescriptionError = "";
@ -154,8 +154,6 @@ class ChatVM extends ChangeNotifier {
if (currentMessage.chatMessageTypeEnum == ChatMessageTypeEnum.offer) { if (currentMessage.chatMessageTypeEnum == ChatMessageTypeEnum.offer) {
for (var chatMessage in serviceProviderOffersList[providerIndex].chatMessages!) { for (var chatMessage in serviceProviderOffersList[providerIndex].chatMessages!) {
if (chatMessage.chatMessageTypeEnum == ChatMessageTypeEnum.offer && chatMessage.reqOffer!.id == currentMessage.reqOffer!.id) { if (chatMessage.chatMessageTypeEnum == ChatMessageTypeEnum.offer && chatMessage.reqOffer!.id == currentMessage.reqOffer!.id) {
logger.i("chatMessage reqOfferID: ${chatMessage.reqOffer!.id.toString()}");
logger.i("currentMessage reqOfferID: ${currentMessage.reqOffer!.id.toString()}");
chatMessage.reqOffer!.requestOfferStatusEnum = currentMessage.reqOffer!.requestOfferStatusEnum; chatMessage.reqOffer!.requestOfferStatusEnum = currentMessage.reqOffer!.requestOfferStatusEnum;
} }
} }
@ -253,6 +251,7 @@ class ChatVM extends ChangeNotifier {
required String serviceItemName, required String serviceItemName,
required int manufacturedById, required int manufacturedById,
required String manufacturedOn, required String manufacturedOn,
required List<dynamic> offerImages,
required BuildContext context, required BuildContext context,
}) async { }) async {
if (hubConnection == null || hubConnection!.state != HubConnectionState.connected) { if (hubConnection == null || hubConnection!.state != HubConnectionState.connected) {
@ -272,6 +271,7 @@ class ChatVM extends ChangeNotifier {
"RequestID": requestId, "RequestID": requestId,
"Price": double.parse(offerPrice), "Price": double.parse(offerPrice),
"ServiceItem": serviceItemName, "ServiceItem": serviceItemName,
"ReqOfferImages": offerImages,
"OfferedItemCreatedBy": manufacturedById, // TODO: The ID should be used from the manufacturer database "OfferedItemCreatedBy": manufacturedById, // TODO: The ID should be used from the manufacturer database
// "OfferedItemCreatedOn": manufacturedOn, // TODO: This should be in String on Server, Right now it is in DateTime // "OfferedItemCreatedOn": manufacturedOn, // TODO: This should be in String on Server, Right now it is in DateTime
"ServiceProviderID": providerId, "ServiceProviderID": providerId,
@ -464,6 +464,7 @@ class ChatVM extends ChangeNotifier {
} }
if (unreadMessageIds.isNotEmpty) { if (unreadMessageIds.isNotEmpty) {
log("unreadMessageIds: ${unreadMessageIds.toString()}");
await markMessagesAsRead(context, unreadMessageIds, ChatTypeEnum.requestOffer); await markMessagesAsRead(context, unreadMessageIds, ChatTypeEnum.requestOffer);
} }
Utils.hideLoading(context); Utils.hideLoading(context);

@ -1,3 +1,4 @@
import 'dart:developer';
import 'dart:io'; import 'dart:io';
import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart'; import 'package:mc_common_app/generated/locale_keys.g.dart';
@ -5,6 +6,7 @@ import 'package:mc_common_app/main.dart';
import 'package:mc_common_app/models/user_models/image_response.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/repositories/user_repo.dart';
import 'package:mc_common_app/services/common_services.dart'; import 'package:mc_common_app/services/common_services.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/utils.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/ad_view_model.dart';
import 'package:mc_common_app/view_models/appointments_view_model.dart'; import 'package:mc_common_app/view_models/appointments_view_model.dart';
@ -56,7 +58,8 @@ class DashboardVmCustomer extends BaseVM {
} }
} }
Future<void> onRefresh(BuildContext context) async { Future<void> onRefresh(BuildContext context, {DashboardRouteEnum dashboardRouteEnum = DashboardRouteEnum.none}) async {
log("onRefresh dashboardRouteEnum: $dashboardRouteEnum");
AdVM adVM = Provider.of<AdVM>(context, listen: false); AdVM adVM = Provider.of<AdVM>(context, listen: false);
AppointmentsVM appointmentsVM = Provider.of<AppointmentsVM>(context, listen: false); AppointmentsVM appointmentsVM = Provider.of<AppointmentsVM>(context, listen: false);
RequestsVM requestsVM = Provider.of<RequestsVM>(context, listen: false); RequestsVM requestsVM = Provider.of<RequestsVM>(context, listen: false);
@ -67,9 +70,13 @@ class DashboardVmCustomer extends BaseVM {
requestsVM.populateDataForRequestsFilter(); requestsVM.populateDataForRequestsFilter();
await appointmentsVM.getMyAppointmentsForCustomer(); await appointmentsVM.getMyAppointmentsForCustomer();
await appointmentsVM.applyFilterOnBranches(index: 0); // to get all branches! await appointmentsVM.applyFilterOnBranches(index: 0); // to get all branches!
await appointmentsVM.getMyRecentBranches(); // to get my recent branches! await appointmentsVM.getMyRecentBranches(); // to get my recent branches
await adVM.getMyAds();
await adVM.getExploreAds(); if (dashboardRouteEnum != DashboardRouteEnum.fromAdsPayment && dashboardRouteEnum != DashboardRouteEnum.fromAdsSubmit) {
await adVM.getMyAds();
await adVM.getExploreAds();
}
await requestsVM.getRequests(); await requestsVM.getRequests();
await adVM.getVehicleTypes(); await adVM.getVehicleTypes();
await adVM.getVehicleAdsDuration(); await adVM.getVehicleAdsDuration();

@ -15,7 +15,6 @@ import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/view_models/shipping_management_view_model.dart'; import 'package:mc_common_app/view_models/shipping_management_view_model.dart';
import 'package:mc_common_app/widgets/common_widgets/add_phone_num_wiget.dart'; import 'package:mc_common_app/widgets/common_widgets/add_phone_num_wiget.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:mc_common_app/utils/location/Location.dart';
import 'package:mc_common_app/utils/utils.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/ad_view_model.dart';
import 'package:mc_common_app/view_models/appointments_view_model.dart'; import 'package:mc_common_app/view_models/appointments_view_model.dart';
@ -71,29 +70,35 @@ class DashboardVMProvider extends BaseVM {
return await userRepo.updateUserImage(image); return await userRepo.updateUserImage(image);
} }
Future<void> onRefresh(BuildContext context) async { Future<void> onRefresh(BuildContext context, { DashboardRouteEnum dashboardRouteEnum = DashboardRouteEnum.none }) async {
final requestsVM = context.read<RequestsVM>(); final requestsVM = context.read<RequestsVM>();
final chatVM = context.read<ChatVM>(); final chatVM = context.read<ChatVM>();
final appointmentVM = context.read<AppointmentsVM>(); final appointmentVM = context.read<AppointmentsVM>();
final shippingManagementVM = context.read<ShippingManagementVM>(); final shippingManagementVM = context.read<ShippingManagementVM>();
final serviceVM = context.read<ServiceVM>(); final serviceVM = context.read<ServiceVM>();
final adVm = context.read<AdVM>(); final adVM = context.read<AdVM>();
final subscriptionsVM = context.read<SubscriptionsVM>(); final subscriptionsVM = context.read<SubscriptionsVM>();
requestsVM.populateDataForRequestsFilter(); requestsVM.populateDataForRequestsFilter();
appointmentVM.populateAppointmentsFilterList(); appointmentVM.populateAppointmentsFilterList();
shippingManagementVM.populateShippingRequestFilterList(); shippingManagementVM.populateShippingRequestFilterList();
await serviceVM.getBranchAndServices(); await serviceVM.getBranchAndServices();
await appointmentVM.getMyAppointmentsForProvider({"ServiceProviderID": injector.get<AppState>().getUser.data?.userInfo?.providerId.toString() ?? "0"}); await appointmentVM.getMyAppointmentsForProvider({"ServiceProviderID": injector
adVm.populateAdsFilterList(); .get<AppState>()
.getUser
.data
?.userInfo
?.providerId
.toString() ?? "0"});
adVM.populateAdsFilterList();
await subscriptionsVM.getSubscriptionBySP(AppState().getUser.data?.userInfo?.providerId.toString() ?? "", true); await subscriptionsVM.getSubscriptionBySP(AppState().getUser.data?.userInfo?.providerId.toString() ?? "", true);
await chatVM.buildHubConnection(context); await chatVM.buildHubConnection(context);
await adVm.getMyAds(); if (dashboardRouteEnum != DashboardRouteEnum.fromAdsPayment && dashboardRouteEnum != DashboardRouteEnum.fromAdsSubmit) {
await adVm.getExploreAds(); await adVM.getMyAds();
await adVm.getVehicleTypes(); await adVM.getExploreAds();
await adVm.getVehicleAdsDuration(); }
await adVM.getVehicleTypes();
await adVM.getVehicleAdsDuration();
await requestsVM.getRequests(); await requestsVM.getRequests();
// await subscriptionsVM.getMySubscriptionsBySP(AppState().getUser.data?.userInfo?.providerId.toString() ?? "");
// await subscriptionsVM.getMySubscriptionsBySP(AppState().getUser.data?.userInfo?.providerId.toString() ?? "");
} }
void checkUserSubscription(SubscriptionActionTypeEnum actionType, BuildContext context, {required Function() callback}) async { void checkUserSubscription(SubscriptionActionTypeEnum actionType, BuildContext context, {required Function() callback}) async {
@ -112,29 +117,25 @@ class DashboardVMProvider extends BaseVM {
void performCheckOnBranches(BuildContext context) async { void performCheckOnBranches(BuildContext context) async {
if (AppState().getproviderSubscription.isNotEmpty && AppState().getproviderSubscription.first.branchesRemaining! > 0) { if (AppState().getproviderSubscription.isNotEmpty && AppState().getproviderSubscription.first.branchesRemaining! > 0) {
logger.d(AppState().getproviderSubscription.first.toJson());
await navigateWithName(context, AppRoutes.defineBranch); await navigateWithName(context, AppRoutes.defineBranch);
} else { } else {
Utils.showToast("Upgrade your subscription to add more Branches."); Utils.showToast(LocaleKeys.upgradeBranches.tr());
} }
} }
void performCheckOnAds(BuildContext context) async { void performCheckOnAds(BuildContext context) async {
//adsRemaining
if (AppState().getproviderSubscription.isNotEmpty && AppState().getproviderSubscription.first.adsRemaining! > 0) { if (AppState().getproviderSubscription.isNotEmpty && AppState().getproviderSubscription.first.adsRemaining! > 0) {
logger.d(AppState().getproviderSubscription.first.toJson());
await navigateWithName(context, AppRoutes.defineBranch); await navigateWithName(context, AppRoutes.defineBranch);
} else { } else {
Utils.showToast("Upgrade your subscription to add more Ads."); Utils.showToast(LocaleKeys.upgradeAds.tr());
} }
} }
void performCheckOnUsers(BuildContext context, Function() callBack) async { void performCheckOnUsers(BuildContext context, Function() callBack) async {
if (AppState().getproviderSubscription.isNotEmpty && AppState().getproviderSubscription.first.subUsersRemaining! > 0) { if (AppState().getproviderSubscription.isNotEmpty && AppState().getproviderSubscription.first.subUsersRemaining! > 0) {
logger.d(AppState().getproviderSubscription.first.toJson());
showMyBottomSheet(context, isDismissible: false, child: const AddPhoneNumWidget(), callBackFunc: callBack); showMyBottomSheet(context, isDismissible: false, child: const AddPhoneNumWidget(), callBackFunc: callBack);
} else { } else {
Utils.showToast("Upgrade your subscription to add more Sub Users."); Utils.showToast(LocaleKeys.upgradeSubUsers.tr());
} }
} }
} }

@ -10,10 +10,9 @@ import 'package:mc_common_app/services/payments_service.dart';
import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart'; import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/utils/utils.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/ad_view_model.dart';
import 'package:mc_common_app/view_models/dashboard_view_model_customer.dart'; import 'package:mc_common_app/view_models/dashboard_view_model_customer.dart';
import 'package:mc_common_app/view_models/dashboard_view_model_provider.dart'; import 'package:mc_common_app/view_models/dashboard_view_model_provider.dart';
import 'package:mc_common_app/view_models/subscriptions_view_model.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
@ -192,12 +191,15 @@ class PaymentVM extends ChangeNotifier {
} }
void onAdsPaymentSuccess(BuildContext context) { void onAdsPaymentSuccess(BuildContext context) {
context.read<AdVM>().updateIsExploreAds(false);
if (AppState().currentAppType == AppType.provider) { if (AppState().currentAppType == AppType.provider) {
context.read<DashboardVMProvider>().onNavbarTapped(3); context.read<DashboardVMProvider>().onNavbarTapped(3);
context.read<AdVM>().applyFilterOnMyAds(adPostStatusEnum: AdPostStatus.active);
} else { } else {
context.read<DashboardVmCustomer>().onNavbarTapped(3); context.read<DashboardVmCustomer>().onNavbarTapped(3);
context.read<AdVM>().applyFilterOnMyAds(adPostStatusEnum: AdPostStatus.pendingForPost);
} }
navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard); navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard, arguments: DashboardRouteEnum.fromAdsPayment);
} }
void onSubscriptionPaymentSuccess(BuildContext context) { void onSubscriptionPaymentSuccess(BuildContext context) {

@ -796,6 +796,13 @@ class RequestsVM extends BaseVM {
serviceItem = value; serviceItem = value;
} }
bool isDeliveryAvailableStatus = false;
void updateIsDeliveryAvailableStatus(bool value) {
isDeliveryAvailableStatus = value;
notifyListeners();
}
String serviceItemCreatedOn = ""; String serviceItemCreatedOn = "";
void updateServiceItemCreatedOn(String value) { void updateServiceItemCreatedOn(String value) {
@ -807,7 +814,7 @@ class RequestsVM extends BaseVM {
void updateOfferDescription(String value) { void updateOfferDescription(String value) {
offerDescription = value; offerDescription = value;
if (value.isNotEmpty) { if (value.isNotEmpty || value.length <= 5) {
offerDescriptionError = ""; offerDescriptionError = "";
} }
} }
@ -885,6 +892,7 @@ class RequestsVM extends BaseVM {
serviceItem = ""; serviceItem = "";
serviceItemCreatedOn = ""; serviceItemCreatedOn = "";
itemManufacturer = ""; itemManufacturer = "";
pickedVehicleImages.clear();
notifyListeners(); notifyListeners();
} }
@ -903,6 +911,14 @@ class RequestsVM extends BaseVM {
}) async { }) async {
if (isSendOfferValidated()) { if (isSendOfferValidated()) {
final chatVM = context.read<ChatVM>(); final chatVM = context.read<ChatVM>();
Utils.showLoading(context);
List<RequestPostingImages> vehicleImages = await getVehiclePostingImageList();
List offerImages = [];
vehicleImages.forEach((element) {
offerImages.add(element.toJson());
});
bool status = await chatVM.onOfferSendForRequest( bool status = await chatVM.onOfferSendForRequest(
receiverId: receiverId, receiverId: receiverId,
chatMessageType: ChatMessageTypeEnum.offer, chatMessageType: ChatMessageTypeEnum.offer,
@ -912,52 +928,58 @@ class RequestsVM extends BaseVM {
manufacturedById: manufacturedById, manufacturedById: manufacturedById,
manufacturedOn: manufacturedOn, manufacturedOn: manufacturedOn,
serviceItemName: serviceItemName, serviceItemName: serviceItemName,
offerImages: offerImages,
context: context, context: context,
); );
Utils.hideLoading(context);
log("status from onOfferSendForRequest: $status");
if (status) { if (!status) {
final senderName = AppState().getUser.data!.userInfo!.firstName; Utils.showToast(LocaleKeys.somethingWrong.tr());
final senderId = AppState().getUser.data!.userInfo!.userId; return;
resetSendOfferBottomSheet(); }
Navigator.pop(context);
ChatMessageModel chatMessageModel = ChatMessageModel( final senderName = AppState().getUser.data!.userInfo!.firstName;
isMyMessage: true, final senderId = AppState().getUser.data!.userInfo!.userId;
chatText: message, resetSendOfferBottomSheet();
messageType: ChatMessageTypeEnum.offer.getIdFromChatMessageTypeEnum(), Navigator.pop(context);
senderName: senderName, ChatMessageModel chatMessageModel = ChatMessageModel(
senderUserID: senderId, isMyMessage: true,
receiverUserID: receiverId, chatText: message,
chatMessageTypeEnum: ChatMessageTypeEnum.offer, messageType: ChatMessageTypeEnum.offer.getIdFromChatMessageTypeEnum(),
requestID: requestModel.id, senderName: senderName,
senderUserID: senderId,
receiverUserID: receiverId,
chatMessageTypeEnum: ChatMessageTypeEnum.offer,
requestID: requestModel.id,
offerStatus: RequestOfferStatusEnum.offer.getIdFromRequestOfferStatusEnum(),
reqOffer: ReqOffer(
offerStatus: RequestOfferStatusEnum.offer.getIdFromRequestOfferStatusEnum(), offerStatus: RequestOfferStatusEnum.offer.getIdFromRequestOfferStatusEnum(),
reqOffer: ReqOffer( requestID: requestModel.id,
offerStatus: RequestOfferStatusEnum.offer.getIdFromRequestOfferStatusEnum(), price: double.parse(offerPrice),
requestID: requestModel.id, manufacturedById: manufacturedById,
price: double.parse(offerPrice), manufacturedOn: manufacturedOn,
manufacturedById: manufacturedById, serviceItemName: serviceItemName,
manufacturedOn: manufacturedOn, requestOfferStatusEnum: RequestOfferStatusEnum.offer,
serviceItemName: serviceItemName, comment: message,
requestOfferStatusEnum: RequestOfferStatusEnum.offer, offerStatusText: "",
comment: message, ),
offerStatusText: "", );
), context.read<ChatVM>().onNewMessageReceivedForRequestOffer(messages: [chatMessageModel], requestsVM: this, isMyOwnOffer: true);
if (!isFromChatScreen) {
ChatViewArgumentsForRequest chatViewArgumentsForRequest = ChatViewArgumentsForRequest(
chatTypeEnum: ChatTypeEnum.requestOffer,
requestId: requestModel.id,
receiverId: requestModel.customerID,
senderId: senderId ?? "",
requestIndex: requestIndex,
providerIndex: -1,
requestModel: requestModel,
); );
context.read<ChatVM>().onNewMessageReceivedForRequestOffer(messages: [chatMessageModel], requestsVM: this, isMyOwnOffer: true);
ChatViewArguments chatViewArguments = ChatViewArguments(chatTypeEnum: ChatTypeEnum.requestOffer, chatViewArgumentsForRequest: chatViewArgumentsForRequest);
if (!isFromChatScreen) { navigateWithName(context, AppRoutes.chatView, arguments: chatViewArguments);
ChatViewArgumentsForRequest chatViewArgumentsForRequest = ChatViewArgumentsForRequest(
chatTypeEnum: ChatTypeEnum.requestOffer,
requestId: requestModel.id,
receiverId: requestModel.customerID,
senderId: senderId ?? "",
requestIndex: requestIndex,
providerIndex: -1,
requestModel: requestModel,
);
ChatViewArguments chatViewArguments = ChatViewArguments(chatTypeEnum: ChatTypeEnum.requestOffer, chatViewArgumentsForRequest: chatViewArgumentsForRequest);
navigateWithName(context, AppRoutes.chatView, arguments: chatViewArguments);
}
} }
} }
} }

@ -1,3 +1,4 @@
import 'package:flutter/cupertino.dart';
import 'package:mc_common_app/main.dart'; import 'package:mc_common_app/main.dart';
import 'package:mc_common_app/models/setting_utils_models/app_info_model.dart'; import 'package:mc_common_app/models/setting_utils_models/app_info_model.dart';
import 'package:mc_common_app/models/setting_utils_models/contact_infos_model.dart'; import 'package:mc_common_app/models/setting_utils_models/contact_infos_model.dart';
@ -6,6 +7,7 @@ import 'package:mc_common_app/repositories/setting_options_repo.dart';
import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/utils.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/base_view_model.dart';
import 'package:share_plus/share_plus.dart';
class SettingOptionsVM extends BaseVM { class SettingOptionsVM extends BaseVM {
final SettingOptionsRepo settingOptionsRepo; final SettingOptionsRepo settingOptionsRepo;
@ -71,4 +73,21 @@ class SettingOptionsVM extends BaseVM {
setState(ViewState.idle); setState(ViewState.idle);
} }
} }
Future<void> appInvitationCreate({required BuildContext context, required int channelId}) async {
ShareResult result = await Utils.shareAppInvitation();
if (result.status != ShareResultStatus.success) {
return;
}
Utils.showLoading(context);
try {
await settingOptionsRepo.appInvitationCreate(channelId: channelId);
Utils.hideLoading(context);
} catch (e) {
logger.i(e.toString());
Utils.showToast(e.toString());
Utils.hideLoading(context);
}
}
} }

@ -282,7 +282,7 @@ class AdDuration extends StatelessWidget {
Row( Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
(LocaleKeys.description.tr() + ": ").toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), ("${LocaleKeys.description.tr()}: ").toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
(specialServicesCard.description ?? "").toText(fontSize: 12, isBold: true).expand(), (specialServicesCard.description ?? "").toText(fontSize: 12, isBold: true).expand(),
], ],
), ),

@ -283,7 +283,7 @@ class VehicleDetails extends StatelessWidget {
).paddingOnly(right: 10) ).paddingOnly(right: 10)
], ],
if (adVM.pickedPostingImages.isNotEmpty) ...[ if (adVM.pickedPostingImages.isNotEmpty) ...[
16.height, 8.height,
PickedFilesContainer( PickedFilesContainer(
pickedFiles: adVM.pickedPostingImages, pickedFiles: adVM.pickedPostingImages,
onCrossPressedPrimary: adVM.removeImageFromList, onCrossPressedPrimary: adVM.removeImageFromList,

@ -15,6 +15,7 @@ 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/ad_view_model.dart';
import 'package:mc_common_app/view_models/payment_view_model.dart'; import 'package:mc_common_app/view_models/payment_view_model.dart';
import 'package:mc_common_app/views/advertisement/ads_detail_view/components.dart'; import 'package:mc_common_app/views/advertisement/ads_detail_view/components.dart';
import 'package:mc_common_app/views/advertisement/bottom_sheets/ad_duration_selection_sheet.dart';
import 'package:mc_common_app/views/advertisement/bottom_sheets/ads_damage_part_pictures_sheet.dart'; import 'package:mc_common_app/views/advertisement/bottom_sheets/ads_damage_part_pictures_sheet.dart';
import 'package:mc_common_app/views/advertisement/components/ads_images_corousel_widget.dart'; import 'package:mc_common_app/views/advertisement/components/ads_images_corousel_widget.dart';
import 'package:mc_common_app/widgets/bottom_sheet.dart'; import 'package:mc_common_app/widgets/bottom_sheet.dart';
@ -252,34 +253,79 @@ class _AdsDetailViewState extends State<AdsDetailView> {
}).toWhiteContainer(width: double.infinity, allPading: 12); }).toWhiteContainer(width: double.infinity, allPading: 12);
} }
Future<void> onExtendAdPressed() async {
final AdVM adVM = context.read<AdVM>();
return actionConfirmationBottomSheet(
context: context,
title: LocaleKeys.updateAdDetails.tr().toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
subtitle: LocaleKeys.durationExtendingAd.tr(),
actionButtonYes: Expanded(
child: ShowFillButton(
maxHeight: 55,
title: LocaleKeys.yes.tr(),
fontSize: 15,
onPressed: () async {
Utils.showLoading(context);
await adVM.getVehicleTypes();
await adVM.getVehicleBrandsByVehicleTypeId(vehicleIdForEditAd: widget.adDetails.vehicle!.vehicleType ?? -1);
Utils.hideLoading(context);
adVM.onEditUpdateAdPressed(context: context, previousDetails: widget.adDetails, isFromExtendAd: true);
},
),
),
actionButtonNo: Expanded(
child: ShowFillButton(
maxHeight: 55,
isFilled: false,
borderColor: MyColors.darkPrimaryColor,
title: LocaleKeys.no.tr(),
txtColor: MyColors.darkPrimaryColor,
fontSize: 15,
onPressed: () {
adVM.updateSelectionVehicleTypeId(
SelectionModel(selectedId: widget.adDetails.vehicle!.vehicleType!, selectedOption: (widget.adDetails.vehicle!.vehicleType!).toVehicleTypeString(), errorValue: ""),
);
showMyBottomSheet(context, child: AdDurationSelectionSheet(isFromExtendAd: true, isUpdateAdSelected: false, adsID: widget.adDetails.id ?? -1));
},
),
),
);
}
Widget buildAdStartEndDates() { Widget buildAdStartEndDates() {
return Row( return Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
("${LocaleKeys.startDate.tr()}: ").toText(fontSize: 12, color: MyColors.lightTextColor), Row(
widget.adDetails.startdate != null children: [
? DateHelper.formatAsDayMonthYear(DateTime.parse(widget.adDetails.startdate!)).toText( ("${LocaleKeys.startDate.tr()}: ").toText(fontSize: 12, color: MyColors.lightTextColor),
fontSize: 10, widget.adDetails.startdate != null
) ? DateHelper.formatAsDayMonthYear(DateTime.parse(widget.adDetails.startdate!)).toText(
: const SizedBox(), fontSize: 10,
)
: const SizedBox(),
],
),
Row(
children: [
("${LocaleKeys.endDate.tr()}: ").toText(fontSize: 12, color: MyColors.lightTextColor),
widget.adDetails.enddate != null ? DateHelper.formatAsDayMonthYear(DateTime.parse(widget.adDetails.enddate!)).toText(fontSize: 10) : const SizedBox(),
],
),
], ],
), ),
3.height,
Row( Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [ children: [
("${LocaleKeys.endDate.tr()}: ").toText(fontSize: 12, color: MyColors.lightTextColor), (LocaleKeys.extendAd.tr()).toText(fontSize: 12, color: MyColors.darkPrimaryColor, isUnderLine: true).onPress(() async => await onExtendAdPressed()),
widget.adDetails.enddate != null
? DateHelper.formatAsDayMonthYear(DateTime.parse(widget.adDetails.enddate!)).toText(
fontSize: 10,
)
: const SizedBox(),
], ],
), )
], ],
).paddingOnly(top: 5, bottom: 5).onPress(() { ).paddingOnly(top: 5, bottom: 2).toWhiteContainer(width: double.infinity, allPading: 12);
showMyBottomSheet(context, child: AdDamagePartPicturesSheet(adDamageReportList: widget.adDetails.vehicle!.damagereport ?? []));
}).toWhiteContainer(width: double.infinity, allPading: 12);
} }
@override @override

@ -5,6 +5,7 @@ import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/advertisment_models/vehicle_details_models.dart'; import 'package:mc_common_app/models/advertisment_models/vehicle_details_models.dart';
import 'package:mc_common_app/models/general_models/widgets_models.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/theme/colors.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/ad_view_model.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart'; import 'package:mc_common_app/widgets/button/show_fill_button.dart';
import 'package:mc_common_app/widgets/common_widgets/time_slots.dart'; import 'package:mc_common_app/widgets/common_widgets/time_slots.dart';
@ -149,7 +150,7 @@ class BottomSheetAdSpecialServiceContent extends StatelessWidget {
const BottomSheetAdSpecialServiceContent({Key? key}) : super(key: key); const BottomSheetAdSpecialServiceContent({Key? key}) : super(key: key);
bool isButtonTappable(AdVM adVM) { bool isButtonTappable(AdVM adVM) {
bool status = (adVM.vehicleAdsSpecialServicesId.selectedId != -1) && (adVM.vehicleAdsSpecialServicesId.selectedOption != ""); bool status = (adVM.selectedVehicleAdsSpecialServicesId.selectedId != -1) && (adVM.selectedVehicleAdsSpecialServicesId.selectedOption != "");
if (status) { if (status) {
return true; return true;
} }
@ -157,21 +158,16 @@ class BottomSheetAdSpecialServiceContent extends StatelessWidget {
} }
Widget descriptionCard({required String description}) { Widget descriptionCard({required String description}) {
return Container( if (description.isEmpty) {
height: 100, return const SizedBox();
decoration: BoxDecoration(color: MyColors.greyButtonColor, border: Border.all(width: 2, color: MyColors.greyAddBorderColor)), }
child: Row( return Column(
mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Flexible( ("${LocaleKeys.description.tr()}:").toText(fontSize: 14),
child: description.toText( description.toText(color: MyColors.lightTextColor),
fontSize: 15, ],
color: MyColors.lightTextColor, ).paddingOnly(left: 2);
),
),
],
),
);
} }
@override @override
@ -179,7 +175,7 @@ class BottomSheetAdSpecialServiceContent extends StatelessWidget {
return Consumer( return Consumer(
builder: (BuildContext context, AdVM adVM, Widget? child) { builder: (BuildContext context, AdVM adVM, Widget? child) {
return SizedBox( return SizedBox(
height: MediaQuery.of(context).size.height * 0.85, height: MediaQuery.of(context).size.height * 0.7,
child: Column( child: Column(
children: [ children: [
Container( Container(
@ -204,19 +200,19 @@ class BottomSheetAdSpecialServiceContent extends StatelessWidget {
} }
} }
return DropdownField( return DropdownField(
(DropValue value) => adVM.updateVehicleAdsSpecialServicesId(SelectionModel(selectedId: value.id, selectedOption: value.value, itemPrice: value.subValue)), (DropValue value) => adVM.updateSelectedVehicleAdsSpecialServicesId(SelectionModel(selectedId: value.id, selectedOption: value.value, itemPrice: value.subValue)),
list: vehicleAdsSpecialServices, list: vehicleAdsSpecialServices,
hint: LocaleKeys.selectService.tr(), hint: LocaleKeys.selectService.tr(),
dropdownValue: adVM.vehicleAdsSpecialServicesId.selectedId != -1 ? DropValue(adVM.vehicleAdsSpecialServicesId.selectedId, adVM.vehicleAdsSpecialServicesId.selectedOption, "") : null, dropdownValue: adVM.selectedVehicleAdsSpecialServicesId.selectedId != -1 ? DropValue(adVM.selectedVehicleAdsSpecialServicesId.selectedId, adVM.selectedVehicleAdsSpecialServicesId.selectedOption, "") : null,
); );
}, },
), ),
if (adVM.vehicleAdsSpecialServicesId.selectedId != -1) ...[ if (adVM.selectedVehicleAdsSpecialServicesId.selectedId != -1) ...[
if (adVM.isFetchingLists) ...[ if (adVM.isFetchingLists) ...[
Center(child: const CircularProgressIndicator().paddingAll(20)), Center(child: const CircularProgressIndicator().paddingAll(20)),
] else ...[ ] else ...[
8.height, 8.height,
if ((adVM.vehicleAdsSpecialServicesId.selectedId == 1 && adVM.ssPhotoScheduleModel != null)) ...[ if ((adVM.selectedVehicleAdsSpecialServicesId.selectedId == 1 && adVM.ssPhotoScheduleModel != null)) ...[
// Builder( // Builder(
// builder: (context) { // builder: (context) {
// List<DropValue> vehicleAdsSpecialServiceDates = adVM.populateScheduleDatesForAdPhotoService(); // List<DropValue> vehicleAdsSpecialServiceDates = adVM.populateScheduleDatesForAdPhotoService();
@ -239,7 +235,7 @@ class BottomSheetAdSpecialServiceContent extends StatelessWidget {
// }, // },
// ), // ),
// 22.height, // 22.height,
] else if ((adVM.vehicleAdsSpecialServicesId.selectedId == 3 && adVM.ssCarCheckScheduleModel != null)) ...[ ] else if ((adVM.selectedVehicleAdsSpecialServicesId.selectedId == 3 && adVM.ssCarCheckScheduleModel != null)) ...[
// Builder( // Builder(
// builder: (context) { // builder: (context) {
// List<DropValue> vehicleAdsSpecialServiceDates = adVM.populateScheduleDatesForAdCarCheckService(); // List<DropValue> vehicleAdsSpecialServiceDates = adVM.populateScheduleDatesForAdCarCheckService();
@ -263,9 +259,9 @@ class BottomSheetAdSpecialServiceContent extends StatelessWidget {
// ), // ),
// 22.height, // 22.height,
], ],
if (adVM.vehicleAdsSpecialServicesId.selectedId != 3 && adVM.vehicleAdsSpecialServicesId.selectedId != 1) ...[ if (adVM.selectedVehicleAdsSpecialServicesId.selectedId != 3 && adVM.selectedVehicleAdsSpecialServicesId.selectedId != 1) ...[
descriptionCard( descriptionCard(
description: adVM.vehicleAdsSpecialServices.firstWhere((element) => element.id == adVM.vehicleAdsSpecialServicesId.selectedId).description ?? "Some Dummy Service Description!!", description: adVM.vehicleAdsSpecialServices.firstWhere((element) => element.id == adVM.selectedVehicleAdsSpecialServicesId.selectedId).description ?? "",
), ),
], ],
if (adVM.adSSTimeSlots.isNotEmpty) ...[ if (adVM.adSSTimeSlots.isNotEmpty) ...[
@ -281,7 +277,7 @@ class BottomSheetAdSpecialServiceContent extends StatelessWidget {
Row( Row(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
adVM.vehicleAdsSpecialServicesId.itemPrice.toText(fontSize: 20, isBold: true), adVM.selectedVehicleAdsSpecialServicesId.itemPrice.toText(fontSize: 20, isBold: true),
SizedBox(width: 1.w), SizedBox(width: 1.w),
LocaleKeys.sar.tr().toText(fontSize: 12, isBold: true, color: MyColors.lightTextColor).paddingOnly(bottom: 2), LocaleKeys.sar.tr().toText(fontSize: 12, isBold: true, color: MyColors.lightTextColor).paddingOnly(bottom: 2),
], ],
@ -294,7 +290,7 @@ class BottomSheetAdSpecialServiceContent extends StatelessWidget {
SizedBox( SizedBox(
width: double.infinity, width: double.infinity,
child: ShowFillButton( child: ShowFillButton(
backgroundColor: !isButtonTappable(adVM) ? MyColors.lightTextColor.withOpacity(0.6) : MyColors.primaryColor, backgroundColor: !isButtonTappable(adVM) ? MyColors.lightTextColor.withOpacity(0.6) : MyColors.darkPrimaryColor,
title: LocaleKeys.addService.tr(), title: LocaleKeys.addService.tr(),
onPressed: () { onPressed: () {
if (!isButtonTappable(adVM)) { if (!isButtonTappable(adVM)) {
@ -304,8 +300,8 @@ class BottomSheetAdSpecialServiceContent extends StatelessWidget {
adVM.addNewSpecialServiceCard( adVM.addNewSpecialServiceCard(
specialServiceCard: SpecialServiceCard( specialServiceCard: SpecialServiceCard(
serviceSelectedId: adVM.vehicleAdsSpecialServicesId, serviceSelectedId: adVM.selectedVehicleAdsSpecialServicesId,
description: adVM.vehicleAdsSpecialServices.firstWhere((element) => element.id == adVM.vehicleAdsSpecialServicesId.selectedId).description ?? "", description: adVM.vehicleAdsSpecialServices.firstWhere((element) => element.id == adVM.selectedVehicleAdsSpecialServicesId.selectedId).description ?? "",
duration: "", duration: "",
serviceDate: "", serviceDate: "",
serviceDateError: "", serviceDateError: "",

@ -4,16 +4,21 @@ import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_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/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart'; import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart';
import 'package:mc_common_app/models/chat_models/chat_message_model.dart';
import 'package:mc_common_app/models/services_models/service_model.dart'; import 'package:mc_common_app/models/services_models/service_model.dart';
import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/dialogs_and_bottomsheets.dart'; import 'package:mc_common_app/utils/dialogs_and_bottomsheets.dart';
import 'package:mc_common_app/utils/enums.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/utils/utils.dart';
import 'package:mc_common_app/view_models/appointments_view_model.dart'; import 'package:mc_common_app/view_models/appointments_view_model.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.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/app_bar.dart';
import 'package:mc_common_app/widgets/common_widgets/card_button_with_icon.dart'; import 'package:mc_common_app/widgets/common_widgets/card_button_with_icon.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/extensions/extensions_widget.dart';
import 'package:mc_common_app/widgets/txt_field.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:sizer/sizer.dart'; import 'package:sizer/sizer.dart';
@ -81,7 +86,7 @@ class AppointmentDetailView extends StatelessWidget {
alignment: Alignment.bottomCenter, alignment: Alignment.bottomCenter,
child: Row( child: Row(
children: [ children: [
getBaseActionButtonWidget(color: MyColors.redColor, onPressed: () => appointmentCancelConfirmationSheet(context), text: LocaleKeys.cancel.tr()), getBaseActionButtonWidget(color: MyColors.redColor, onPressed: () => buildCancelAppointmentReasonsBottomSheet(context: context), text: LocaleKeys.cancel.tr()),
12.width, 12.width,
getBaseActionButtonWidget( getBaseActionButtonWidget(
color: MyColors.greenColor, color: MyColors.greenColor,
@ -97,7 +102,7 @@ class AppointmentDetailView extends StatelessWidget {
alignment: Alignment.bottomCenter, alignment: Alignment.bottomCenter,
child: Row( child: Row(
children: [ children: [
getBaseActionButtonWidget(color: MyColors.redColor, onPressed: () => appointmentCancelConfirmationSheet(context), text: "Cancel"), getBaseActionButtonWidget(color: MyColors.redColor, onPressed: () => buildCancelAppointmentReasonsBottomSheet(context: context), text: LocaleKeys.cancel.tr()),
], ],
), ),
); );
@ -128,7 +133,7 @@ class AppointmentDetailView extends StatelessWidget {
alignment: Alignment.bottomCenter, alignment: Alignment.bottomCenter,
child: Row( child: Row(
children: [ children: [
getBaseActionButtonWidget(color: MyColors.redColor, onPressed: () => appointmentCancelConfirmationSheet(context), text: LocaleKeys.cancel.tr()), getBaseActionButtonWidget(color: MyColors.redColor, onPressed: () => buildCancelAppointmentReasonsBottomSheet(context: context), text: LocaleKeys.cancel.tr()),
12.width, 12.width,
getBaseActionButtonWidget( getBaseActionButtonWidget(
color: MyColors.greenColor, color: MyColors.greenColor,
@ -177,6 +182,77 @@ class AppointmentDetailView extends StatelessWidget {
); );
} }
Future buildCancelAppointmentReasonsBottomSheet({required BuildContext context}) {
return showModalBottomSheet(
context: context,
isScrollControlled: true,
enableDrag: true,
builder: (BuildContext context) {
return Consumer(builder: (BuildContext context, AppointmentsVM appointmentsVM, 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: appointmentsVM.cancelAppointmentReasonList.length,
separatorBuilder: (BuildContext context, int index) {
return const Divider(thickness: 0.5);
},
itemBuilder: (BuildContext context, int index) {
OfferRequestCommentModel offerRequestCommentModel = appointmentsVM.cancelAppointmentReasonList[index];
return CircleCheckBoxWithTitle(
isChecked: offerRequestCommentModel.isSelected ?? false,
title: '${offerRequestCommentModel.title}',
onSelected: () {
appointmentsVM.updateSelectedCancelAppointmentReason(index);
},
selectedColor: MyColors.darkPrimaryColor,
);
},
),
if (appointmentsVM.selectedCancelAppointmentReason.index == appointmentsVM.cancelAppointmentReasonList.length - 1) ...[
// comparing if the "other" is selected
12.height,
TxtField(
maxLines: 5,
value: appointmentsVM.cancelAppointmentDescription,
errorValue: appointmentsVM.cancelAppointmentDescriptionError,
keyboardType: TextInputType.text,
hint: LocaleKeys.description.tr(),
onChanged: (v) => appointmentsVM.updateCancelAppointmentDescription(v),
),
],
],
),
25.height,
ShowFillButton(
title: LocaleKeys.submit.tr(),
onPressed: () {
if (appointmentsVM.selectedCancelAppointmentReason.index == 0) {
appointmentsVM.onRescheduleAppointmentPressed(context: context, appointmentListModel: appointmentListModel);
} else {
context.read<AppointmentsVM>().onCancelAppointmentPressed(context: context, appointmentListModel: appointmentListModel);
}
},
maxWidth: double.infinity,
),
19.height,
],
),
));
});
},
);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
AppointmentsVM appointmentsVM = context.read<AppointmentsVM>(); AppointmentsVM appointmentsVM = context.read<AppointmentsVM>();

@ -96,6 +96,7 @@ class _AppointmentsFilterViewState extends State<AppointmentsFilterView> {
children: [ children: [
SizedBox( SizedBox(
height: 5.h, height: 5.h,
width: 5.h,
child: const CircularProgressIndicator(), child: const CircularProgressIndicator(),
), ),
], ],

@ -14,6 +14,7 @@ import 'package:mc_common_app/widgets/common_widgets/time_slots.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:sizer/sizer.dart';
class ScreenArgumentsForAppointmentDetailPage { class ScreenArgumentsForAppointmentDetailPage {
final int routeFlag; // 1 = coming from create appointment || 2 = coming from reschedule appointment final int routeFlag; // 1 = coming from create appointment || 2 = coming from reschedule appointment
@ -63,7 +64,8 @@ class BookAppointmentSchedulesView extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
(LocaleKeys.serviceLocation.tr()).toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), (LocaleKeys.serviceLocation.tr()).toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
(scheduleData.appointmentTypeEnum == AppointmentTypeEnum.home ? LocaleKeys.home.tr() : LocaleKeys.workshop.tr()).toText(fontSize: 12, isBold: true).expand(), 2.width,
(scheduleData.appointmentTypeEnum == AppointmentTypeEnum.home ? LocaleKeys.customerLocation.tr() : LocaleKeys.companyLocation.tr()).toText(fontSize: 12, isBold: true).expand(),
], ],
), ),
Column( Column(
@ -110,9 +112,7 @@ class BookAppointmentSchedulesView extends StatelessWidget {
SizedBox( SizedBox(
width: double.infinity, width: double.infinity,
child: BuildTimeSlots( child: BuildTimeSlots(
timeSlots: appointmentsVM.serviceAppointmentScheduleList[scheduleIndex] timeSlots: appointmentsVM.serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![appointmentsVM.serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex!].availableSlots ?? [],
.customTimeDateSlotList![appointmentsVM.serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex!].availableSlots ??
[],
onPressed: (slotIndex) { onPressed: (slotIndex) {
appointmentsVM.updateSelectedAppointmentSlotByDate(scheduleIndex: scheduleIndex, slotIndex: slotIndex); appointmentsVM.updateSelectedAppointmentSlotByDate(scheduleIndex: scheduleIndex, slotIndex: slotIndex);
}, },

@ -67,17 +67,17 @@ class BookAppointmentServicesView extends StatelessWidget {
return Row( return Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
"${itemData.name}: ".toText(fontSize: 13, color: MyColors.lightTextColor, isBold: true), "${itemData.name}: ".toText(fontSize: 13, color: MyColors.lightTextColor),
("${itemData.price}").toText(fontSize: 13, isBold: true).expand(), ("${itemData.price}").toText(fontSize: 13, isBold: true).expand(),
], ],
); );
}), }),
), ),
8.height, // 8.height,
Row( Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
(LocaleKeys.serviceLocation.tr()).toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), (LocaleKeys.serviceLocation.tr()).toText(fontSize: 12, color: MyColors.lightTextColor),
4.width, 4.width,
(serviceData.isHomeSelected ? serviceData.homeLocation : LocaleKeys.workshop.tr()).toText(fontSize: 12, isBold: true).expand(), (serviceData.isHomeSelected ? serviceData.homeLocation : LocaleKeys.workshop.tr()).toText(fontSize: 12, isBold: true).expand(),
], ],
@ -86,12 +86,12 @@ class BookAppointmentServicesView extends StatelessWidget {
Row( Row(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
((appointmentsVM.servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice).toString()).toText(fontSize: 32, isBold: true), ((serviceData.currentTotalServicePrice).toString()).toText(fontSize: 32, isBold: true),
2.width, 2.width,
LocaleKeys.sar.tr().toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5), LocaleKeys.sar.tr().toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5),
const Icon(Icons.arrow_drop_down, size: 30) const Icon(Icons.arrow_drop_down, size: 30)
], ],
).onPress(() => appointmentsVM.priceBreakDownClicked(context, appointmentsVM.servicesInCurrentAppointment[serviceIndex])), ).onPress(() => appointmentsVM.priceBreakDownClicked(context, serviceData)),
], ],
], ],
).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10)); ).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10));

@ -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/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/services_models/item_model.dart'; import 'package:mc_common_app/models/services_models/item_model.dart';
import 'package:mc_common_app/theme/colors.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/navigator.dart';
import 'package:mc_common_app/view_models/appointments_view_model.dart'; import 'package:mc_common_app/view_models/appointments_view_model.dart';
import 'package:mc_common_app/views/appointments/widgets/service_item_with_price_checkbox.dart'; import 'package:mc_common_app/views/appointments/widgets/service_item_with_price_checkbox.dart';
@ -63,31 +64,32 @@ class BookAppointmentsItemView extends StatelessWidget {
const Divider(), const Divider(),
], ],
).horPaddingMain(), ).horPaddingMain(),
appointmentsVM.serviceItemsFromApi.isEmpty appointmentsVM.state == ViewState.busy
? Expanded(child: Center(child: LocaleKeys.noItemsToShow.toText(fontSize: 16, color: MyColors.lightTextColor))) ? const Center(child: CircularProgressIndicator())
: ListView.separated( : appointmentsVM.serviceItemsFromApi.isEmpty
separatorBuilder: (BuildContext context, int index) => const Divider(), ? Expanded(child: Center(child: LocaleKeys.noAvailableItems.toText(fontSize: 16, color: MyColors.lightTextColor)))
itemCount: appointmentsVM.serviceItemsFromApi.length, : ListView.separated(
itemBuilder: (BuildContext context, int index) { separatorBuilder: (BuildContext context, int index) => const Divider(),
ItemData itemData = appointmentsVM.serviceItemsFromApi[index]; itemCount: appointmentsVM.serviceItemsFromApi.length,
return ServiceItemWithPriceCheckBox( itemBuilder: (BuildContext context, int index) {
description: itemData.description ?? LocaleKeys.someDescriptionSubServices.tr(), ItemData itemData = appointmentsVM.serviceItemsFromApi[index];
title: itemData.name!, return ServiceItemWithPriceCheckBox(
isSelected: itemData.isUpdateOrSelected!, description: itemData.description ?? LocaleKeys.someDescriptionSubServices.tr(),
onSelection: (bool value) { title: itemData.name!,
print("itemId: ${itemData.id}"); isSelected: itemData.isUpdateOrSelected!,
appointmentsVM.onItemUpdateOrSelected(index, !itemData.isUpdateOrSelected!, itemData.id!); onSelection: (bool value) {
appointmentsVM.onItemUpdateOrSelected(index, !itemData.isUpdateOrSelected!, itemData.id!);
},
priceWidget: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
itemData.price!.split(".").first.toText(fontSize: 30, isBold: true),
LocaleKeys.sar.tr().toText(fontSize: 15, isBold: true, color: MyColors.lightTextColor).paddingOnly(bottom: 5),
],
),
);
}, },
priceWidget: Row( ).expand(),
crossAxisAlignment: CrossAxisAlignment.end,
children: [
itemData.price!.split(".").first.toText(fontSize: 30, isBold: true),
LocaleKeys.sar.tr().toText(fontSize: 15, isBold: true, color: MyColors.lightTextColor).paddingOnly(bottom: 5),
],
),
);
},
).expand(),
Column( Column(
children: [ children: [
const Divider(height: 1, thickness: 0.7), const Divider(height: 1, thickness: 0.7),

@ -1,170 +1,170 @@
import 'package:flutter/material.dart'; // import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/consts.dart'; // import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/extensions/int_extensions.dart'; // import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_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/generated/locale_keys.g.dart';
import 'package:mc_common_app/theme/colors.dart'; // import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.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/common_widgets/app_bar.dart';
import 'package:mc_common_app/widgets/common_widgets/branch_details_card.dart'; // import 'package:mc_common_app/widgets/common_widgets/branch_details_card.dart';
import 'package:mc_common_app/widgets/common_widgets/time_slots.dart'; // import 'package:mc_common_app/widgets/common_widgets/time_slots.dart';
import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart'; // import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; // import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:easy_localization/easy_localization.dart'; // import 'package:easy_localization/easy_localization.dart';
//
class BookProviderAppView extends StatefulWidget { // class BookProviderAppView extends StatefulWidget {
const BookProviderAppView({Key? key}) : super(key: key); // const BookProviderAppView({Key? key}) : super(key: key);
//
@override // @override
State<BookProviderAppView> createState() => _BookProviderAppViewState(); // State<BookProviderAppView> createState() => _BookProviderAppViewState();
} // }
//
class _BookProviderAppViewState extends State<BookProviderAppView> { // class _BookProviderAppViewState extends State<BookProviderAppView> {
bool isReview = false; // bool isReview = false;
//
@override // @override
Widget build(BuildContext context) { // Widget build(BuildContext context) {
return Scaffold( // return Scaffold(
appBar: CustomAppBar( // appBar: CustomAppBar(
title: LocaleKeys.appointment.tr(), // title: LocaleKeys.appointment.tr(),
profileImageUrl: MyAssets.bnCar, // profileImageUrl: MyAssets.bnCar,
isRemoveBackButton: false, // isRemoveBackButton: false,
isDrawerEnabled: false, // isDrawerEnabled: false,
), // ),
body: Container( // body: Container(
color: MyColors.backgroundColor, // color: MyColors.backgroundColor,
width: double.infinity, // width: double.infinity,
height: double.infinity, // height: double.infinity,
child: Column( // child: Column(
children: [ // children: [
Expanded( // Expanded(
child: ListView( // child: ListView(
children: [ // children: [
BranchDetailCard( // BranchDetailCard(
onCardTapped: () {}, // onCardTapped: () {},
providerImageUrl: MyAssets.bnCar, // providerImageUrl: MyAssets.bnCar,
providerLocation: "3km", // providerLocation: "3km",
title: "Al Ahmed Maintenance", // title: "Al Ahmed Maintenance",
providerRatings: 4.9, // providerRatings: 4.9,
), // ),
12.height, // 12.height,
isReview ? const ReviewAppointmentSection() : const ServicesSelectionSection(), // isReview ? const ReviewAppointmentSection() : const ServicesSelectionSection(),
10.height, // 10.height,
], // ],
), // ),
), // ),
10.height, // 10.height,
Padding( // Padding(
padding: const EdgeInsets.only(bottom: 10, left: 21, right: 21), // padding: const EdgeInsets.only(bottom: 10, left: 21, right: 21),
child: ShowFillButton( // child: ShowFillButton(
title: LocaleKeys.bookAppointment.tr(), // title: LocaleKeys.bookAppointment.tr(),
maxWidth: double.infinity, // maxWidth: double.infinity,
onPressed: () { // onPressed: () {
isReview = !isReview; // isReview = !isReview;
setState(() {}); // setState(() {});
}, // },
), // ),
), // ),
], // ],
), // ),
), // ),
); // );
} // }
} // }
//
class ServicesSelectionSection extends StatelessWidget { // class ServicesSelectionSection extends StatelessWidget {
const ServicesSelectionSection({Key? key}) : super(key: key); // const ServicesSelectionSection({Key? key}) : super(key: key);
//
@override // @override
Widget build(BuildContext context) { // Widget build(BuildContext context) {
List<DropValue> dropList = [ // List<DropValue> dropList = [
DropValue(0, "Maintenance", ""), // DropValue(0, "Maintenance", ""),
DropValue(1, "Car Wash", ""), // DropValue(1, "Car Wash", ""),
DropValue(2, "Monthly Checkup", ""), // DropValue(2, "Monthly Checkup", ""),
DropValue(3, "Friendly Visit", ""), // DropValue(3, "Friendly Visit", ""),
DropValue(4, "Muftaa", ""), // DropValue(4, "Muftaa", ""),
]; // ];
return Container( // return Container(
padding: const EdgeInsets.only(bottom: 10, left: 21, right: 21), // padding: const EdgeInsets.only(bottom: 10, left: 21, right: 21),
child: Column( // child: Column(
crossAxisAlignment: CrossAxisAlignment.start, // crossAxisAlignment: CrossAxisAlignment.start,
children: [ // children: [
LocaleKeys.selectServicesYouWant.tr().toText(fontSize: 18, isBold: true), // LocaleKeys.selectServicesYouWant.tr().toText(fontSize: 18, isBold: true),
8.height, // 8.height,
DropdownField( // DropdownField(
(DropValue value) {}, // (DropValue value) {},
list: dropList, // list: dropList,
hint: LocaleKeys.selectServiceType.tr(), // hint: LocaleKeys.selectServiceType.tr(),
), // ),
8.height, // 8.height,
DropdownField( // DropdownField(
(DropValue value) {}, // (DropValue value) {},
list: dropList, // list: dropList,
hint: LocaleKeys.selectServiceType.tr(), // hint: LocaleKeys.selectServiceType.tr(),
), // ),
8.height, // 8.height,
DropdownField( // DropdownField(
(DropValue value) {}, // (DropValue value) {},
list: dropList, // list: dropList,
hint: LocaleKeys.selectServiceType.tr(), // hint: LocaleKeys.selectServiceType.tr(),
), // ),
22.height, // 22.height,
LocaleKeys.selectDateAndTime.tr().toText(fontSize: 18, isBold: true), // LocaleKeys.selectDateAndTime.tr().toText(fontSize: 18, isBold: true),
8.height, // 8.height,
DropdownField( // DropdownField(
(DropValue value) {}, // (DropValue value) {},
list: dropList, // list: dropList,
hint: LocaleKeys.selectServiceType.tr(), // hint: LocaleKeys.selectServiceType.tr(),
), // ),
22.height, // 22.height,
LocaleKeys.availableSlots.tr().toText(fontSize: 15, isBold: true), // LocaleKeys.availableSlots.tr().toText(fontSize: 15, isBold: true),
8.height, // 8.height,
BuildTimeSlots(onPressed: (index) {}, timeSlots: []), // BuildTimeSlots(onPressed: (index) {}, timeSlots: []),
22.height, // 22.height,
LocaleKeys.totalAmount.tr().toText(fontSize: 18, isBold: true), // LocaleKeys.totalAmount.tr().toText(fontSize: 18, isBold: true),
Row( // Row(
crossAxisAlignment: CrossAxisAlignment.end, // crossAxisAlignment: CrossAxisAlignment.end,
children: [ // children: [
"3000".toText(fontSize: 20, isBold: true), // "3000".toText(fontSize: 20, isBold: true),
LocaleKeys.sar.tr().toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor), // LocaleKeys.sar.tr().toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor),
], // ],
), // ),
10.height, // 10.height,
], // ],
).toWhiteContainer(width: double.infinity, allPading: 12), // ).toWhiteContainer(width: double.infinity, allPading: 12),
); // );
} // }
} // }
//
class ReviewAppointmentSection extends StatelessWidget { // class ReviewAppointmentSection extends StatelessWidget {
const ReviewAppointmentSection({Key? key}) : super(key: key); // const ReviewAppointmentSection({Key? key}) : super(key: key);
//
@override // @override
Widget build(BuildContext context) { // Widget build(BuildContext context) {
return Container( // return Container(
padding: const EdgeInsets.only(bottom: 10, left: 21, right: 21), // padding: const EdgeInsets.only(bottom: 10, left: 21, right: 21),
child: Column( // child: Column(
crossAxisAlignment: CrossAxisAlignment.start, // crossAxisAlignment: CrossAxisAlignment.start,
children: [ // children: [
LocaleKeys.reviewAppointment.tr().toText(fontSize: 18, isBold: true), // LocaleKeys.reviewAppointment.tr().toText(fontSize: 18, isBold: true),
15.height, // 15.height,
LocaleKeys.services.tr().toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), // LocaleKeys.services.tr().toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
LocaleKeys.carEngineCheck.tr().toText(fontSize: 18, isBold: true), // LocaleKeys.carEngineCheck.tr().toText(fontSize: 18, isBold: true),
13.height, // 13.height,
LocaleKeys.dateAndTime.tr().toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), // LocaleKeys.dateAndTime.tr().toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
"2 Feb, 2023 at 09:00am".toText(fontSize: 18, isBold: true), // "2 Feb, 2023 at 09:00am".toText(fontSize: 18, isBold: true),
13.height, // 13.height,
LocaleKeys.totalAmount.tr().toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), // LocaleKeys.totalAmount.tr().toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
Row( // Row(
crossAxisAlignment: CrossAxisAlignment.end, // crossAxisAlignment: CrossAxisAlignment.end,
children: [ // children: [
"3000".toText(fontSize: 20, isBold: true), // "3000".toText(fontSize: 20, isBold: true),
LocaleKeys.sar.tr().toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor), // LocaleKeys.sar.tr().toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor),
], // ],
), // ),
100.height, // 100.height,
], // ],
).toWhiteContainer(width: double.infinity, allPading: 12), // ).toWhiteContainer(width: double.infinity, allPading: 12),
); // );
} // }
} // }

@ -1,5 +1,8 @@
import 'dart:developer';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/extensions/string_extensions.dart';
@ -9,15 +12,104 @@ import 'package:mc_common_app/models/services_models/item_model.dart';
import 'package:mc_common_app/models/services_models/service_model.dart'; import 'package:mc_common_app/models/services_models/service_model.dart';
import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/view_models/appointments_view_model.dart'; import 'package:mc_common_app/view_models/appointments_view_model.dart';
import 'package:mc_common_app/views/setting_options/widgets/custom_setting_options_tile.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart'; 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/common_widgets/app_bar.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/extensions/extensions_widget.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class ReviewAppointment extends StatelessWidget { class ReviewAppointment extends StatelessWidget {
const ReviewAppointment({Key? key}) : super(key: key); const ReviewAppointment({Key? key}) : super(key: key);
// buildProviderContactInfoBottomSheet(BuildContext context) {
// final appointmentsVM = context.read<AppointmentsVM>();
// log(": ${appointmentsVM.selectedBranchModel}");
// return showModalBottomSheet(
// context: context,
// isScrollControlled: true,
// enableDrag: true,
// builder: (BuildContext context) {
// return InfoBottomSheet(
// title: LocaleKeys.contactDetails.tr().toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
// description: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// if (requestVM.currentSelectedOffer!.mobileNo != null && requestVM.currentSelectedOffer!.mobileNo!.isNotEmpty) ...[
// CustomSettingOptionsTile(
// leadingWidget: const Icon(
// Icons.call,
// size: 20,
// color: MyColors.greyColor,
// ),
// titleText: LocaleKeys.phoneNumber.tr(),
// subTitle: " ${requestVM.currentSelectedOffer!.mobileNo ?? ""}",
// needBorderBelow: true,
// showTrailingArrow: false,
// subtitleTextColor: MyColors.greyColor,
// onTap: () {
// Utils.openNumberViaCaller(phoneNumber: requestVM.currentSelectedOffer!.mobileNo ?? "");
// },
// ),
// ],
// if (requestVM.currentSelectedOffer!.email != null && requestVM.currentSelectedOffer!.email!.isNotEmpty) ...[
// CustomSettingOptionsTile(
// leadingWidget: const Icon(
// Icons.email_outlined,
// size: 20,
// color: MyColors.greyColor,
// ),
// titleText: LocaleKeys.emailAddress.tr(),
// subTitle: " ${requestVM.currentSelectedOffer!.email ?? ""}",
// needBorderBelow: false,
// showTrailingArrow: false,
// subtitleTextColor: MyColors.greyColor,
// onTap: () {
// Utils.openEmailViaEmailApp(emailAddress: requestVM.currentSelectedOffer!.email ?? "");
// },
// ),
// ],
// 30.height,
// ],
// ),
// );
// },
// );
// }
Widget showItem(String title, String value) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"$title: ".toText(color: MyColors.lightTextColor, letterSpacing: -0.48),
3.width,
Flexible(child: value.toText(isBold: true, overflow: TextOverflow.ellipsis)),
],
);
}
Widget buildPersonalInformationCard({required BuildContext context}) {
return Padding(
padding: const EdgeInsets.only(
bottom: 0,
left: 21,
right: 21,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
(LocaleKeys.personalInformation.tr()).toText(fontSize: 16, isBold: true),
showItem(LocaleKeys.name.tr(), "${AppState().getUser.data!.userInfo!.firstName ?? ""} ${AppState().getUser.data!.userInfo!.lastName ?? ""}"),
showItem(LocaleKeys.phoneNumber.tr(), AppState().getUser.data!.userInfo!.mobileNo ?? ""),
showItem(LocaleKeys.email.tr(), AppState().getUser.data!.userInfo!.email ?? ""),
],
).toWhiteContainer(width: double.infinity, allPading: 12),
);
}
Widget buildBranchInfoCard({required BuildContext context}) { Widget buildBranchInfoCard({required BuildContext context}) {
AppointmentsVM appointmentsVM = context.read<AppointmentsVM>(); AppointmentsVM appointmentsVM = context.read<AppointmentsVM>();
return Padding( return Padding(
@ -28,8 +120,7 @@ class ReviewAppointment extends StatelessWidget {
), ),
child: Row( child: Row(
children: [ children: [
Image.asset( appointmentsVM.selectedBranchModel!.branchProfileImage.buildNetworkImage(
MyAssets.bnCar,
width: 80, width: 80,
height: 60, height: 60,
fit: BoxFit.cover, fit: BoxFit.cover,
@ -53,10 +144,38 @@ class ReviewAppointment extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Flexible( Flexible(
child: (appointmentsVM.selectedBranchModel!.branchDescription ?? "").toText(fontSize: 12), child: (appointmentsVM.selectedBranchModel!.branchDescription ?? "").toText(fontSize: 12, color: MyColors.lightTextColor),
), ),
], ],
), ),
if ((appointmentsVM.selectedBranchModel!.latitude != null && appointmentsVM.selectedBranchModel!.latitude!.isNotEmpty) &&
(appointmentsVM.selectedBranchModel!.longitude != null && appointmentsVM.selectedBranchModel!.longitude!.isNotEmpty)) ...[
Row(
children: [
LocaleKeys.openMapLocation.tr().toText(
fontSize: 12,
isBold: true,
color: MyColors.primaryColor,
isUnderLine: true,
),
4.width,
Image.asset(
MyAssets.icRightUpPng,
height: 6,
width: 6,
color: MyColors.primaryColor,
),
],
).onPress(() async {
double latitude, longitude = 0.0;
latitude = double.parse(appointmentsVM.selectedBranchModel!.latitude!);
longitude = double.parse(appointmentsVM.selectedBranchModel!.longitude!);
await Utils.openLocationInMaps(latitude: latitude, longitude: longitude);
}),
] else ...[
const SizedBox(),
],
], ],
), ),
), ),
@ -80,7 +199,7 @@ class ReviewAppointment extends StatelessWidget {
), ),
), ),
], ],
).onPress(() {}).toWhiteContainer(width: double.infinity, allPading: 12)); ).toWhiteContainer(width: double.infinity, allPading: 12));
} }
Widget buildServicesInfoCard({required BuildContext context}) { Widget buildServicesInfoCard({required BuildContext context}) {
@ -135,13 +254,20 @@ class ReviewAppointment extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
("${itemData.name}: ${itemData.price} ${LocaleKeys.sar.tr()}").toText(fontSize: 13, isBold: true, color: MyColors.lightTextColor), ("${itemData.name}: ${itemData.price} ${LocaleKeys.sar.tr()}").toText(fontSize: 13, color: MyColors.lightTextColor),
],
),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
("${itemData.description}").toText(fontSize: 11, color: MyColors.lightTextColor),
], ],
), ),
], ],
); );
}), }),
), ).paddingOnly(bottom: 10),
], ],
); );
}), }),
@ -156,12 +282,12 @@ class ReviewAppointment extends StatelessWidget {
LocaleKeys.timeLocation.tr().toText(fontSize: 16, isBold: true), LocaleKeys.timeLocation.tr().toText(fontSize: 16, isBold: true),
3.height, 3.height,
Row(children: [ Row(children: [
"${LocaleKeys.dateAndTime.tr()}: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), "${LocaleKeys.dateAndTime.tr()}: ".toText(fontSize: 12, color: MyColors.lightTextColor),
"${scheduleData.selectedCustomTimeDateSlotModel!.date!.date} at $selectedTimeSlot".toText(fontSize: 12, isBold: true), "${scheduleData.selectedCustomTimeDateSlotModel!.date!.date} at $selectedTimeSlot".toText(fontSize: 12),
]), ]),
Row(children: [ Row(children: [
("${LocaleKeys.location.tr()}: ").toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), ("${LocaleKeys.location.tr()}: ").toText(fontSize: 12, color: MyColors.lightTextColor),
(scheduleData.appointmentTypeEnum == AppointmentTypeEnum.home ? LocaleKeys.home.tr() : LocaleKeys.workshop.tr()).toText(fontSize: 12, isBold: true), (scheduleData.appointmentTypeEnum == AppointmentTypeEnum.home ? LocaleKeys.home.tr() : LocaleKeys.workshop.tr()).toText(fontSize: 12),
]), ]),
], ],
), ),
@ -169,6 +295,7 @@ class ReviewAppointment extends StatelessWidget {
10.height, 10.height,
const Divider(thickness: 0.7), const Divider(thickness: 0.7),
Builder(builder: (BuildContext context) { Builder(builder: (BuildContext context) {
//TODO: THIS SHOULD BE FINALIZED FROM API
double totalServicePrice = 0.0; double totalServicePrice = 0.0;
double totalKms = 15.3; double totalKms = 15.3;
double rangePricePerKm = 5; double rangePricePerKm = 5;
@ -181,7 +308,7 @@ class ReviewAppointment extends StatelessWidget {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
LocaleKeys.serviceCharges.tr().toText(fontSize: 14, color: MyColors.lightTextColor, isBold: true), LocaleKeys.serviceCharges.tr().toText(fontSize: 14, color: MyColors.lightTextColor),
"${scheduleData.amountTotal.toString()} ${LocaleKeys.sar.tr()}".toText(fontSize: 16, isBold: true), "${scheduleData.amountTotal.toString()} ${LocaleKeys.sar.tr()}".toText(fontSize: 16, isBold: true),
], ],
), ),
@ -189,7 +316,7 @@ class ReviewAppointment extends StatelessWidget {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
("${LocaleKeys.locationCharges.tr()} ($rangePricePerKm x $totalKms )").toText(fontSize: 14, color: MyColors.lightTextColor, isBold: true), ("${LocaleKeys.locationCharges.tr()} ($rangePricePerKm x $totalKms )").toText(fontSize: 14, color: MyColors.lightTextColor),
("${totalServicePrice.toString()} ${LocaleKeys.sar.tr()}").toText(fontSize: 16, isBold: true), ("${totalServicePrice.toString()} ${LocaleKeys.sar.tr()}").toText(fontSize: 16, isBold: true),
], ],
), ),
@ -289,6 +416,14 @@ class ReviewAppointment extends StatelessWidget {
isRemoveBackButton: false, isRemoveBackButton: false,
isDrawerEnabled: false, isDrawerEnabled: false,
onBackButtonTapped: () => Navigator.pop(context), onBackButtonTapped: () => Navigator.pop(context),
actions: [
IconButton(
onPressed: () {
// buildProviderContactInfoBottomSheet(context);
},
icon: const Icon(Icons.help_outline_outlined).paddingOnly(right: 21),
),
],
), ),
body: Column( body: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -299,6 +434,8 @@ class ReviewAppointment extends StatelessWidget {
buildBranchInfoCard(context: context), buildBranchInfoCard(context: context),
10.height, 10.height,
buildServicesInfoCard(context: context), buildServicesInfoCard(context: context),
10.height,
buildPersonalInformationCard(context: context),
], ],
).expand(), ).expand(),
buildNextButtonFooter(context: context), buildNextButtonFooter(context: context),

@ -99,7 +99,7 @@ class AppointmentServicePickBottomSheet extends StatelessWidget {
if (appointmentsVM.currentServiceSelection != null && (appointmentsVM.currentServiceSelection!.isAllowAppointmentHome ?? false)) { if (appointmentsVM.currentServiceSelection != null && (appointmentsVM.currentServiceSelection!.isAllowAppointmentHome ?? false)) {
appointmentsVM.updateIsHomeTapped(true); appointmentsVM.updateIsHomeTapped(true);
} else { } else {
Utils.showToast("The Selected Service is not available at Home Location."); Utils.showToast(LocaleKeys.serviceNotAvailableAtHomeLocation.tr());
} }
}, },
), ),

@ -4,6 +4,7 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/routes.dart'; import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/extensions/string_extensions.dart';
@ -20,8 +21,10 @@ import 'package:mc_common_app/views/advertisement/components/picked_images_conta
import 'package:mc_common_app/views/chat/widgets/chat_bottom_sheets.dart'; import 'package:mc_common_app/views/chat/widgets/chat_bottom_sheets.dart';
import 'package:mc_common_app/views/chat/widgets/chat_message_widget.dart'; import 'package:mc_common_app/views/chat/widgets/chat_message_widget.dart';
import 'package:mc_common_app/views/requests/request_bottomsheets.dart'; import 'package:mc_common_app/views/requests/request_bottomsheets.dart';
import 'package:mc_common_app/views/setting_options/widgets/custom_setting_options_tile.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart'; 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/common_widgets/app_bar.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/extensions/extensions_widget.dart';
import 'package:mc_common_app/widgets/txt_field.dart'; import 'package:mc_common_app/widgets/txt_field.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -129,10 +132,9 @@ class _ChatViewState extends State<ChatView> {
), ),
); );
} }
return Scaffold( return Scaffold(
appBar: CustomAppBar( appBar: CustomAppBar(title: LocaleKeys.chat.tr()),
title: LocaleKeys.chat.tr(),
),
body: Consumer2<ChatVM, RequestsVM>(builder: (BuildContext context, ChatVM chatVM, RequestsVM requestVM, Widget? child) { body: Consumer2<ChatVM, RequestsVM>(builder: (BuildContext context, ChatVM chatVM, RequestsVM requestVM, Widget? child) {
List<ChatMessageModel> chatMessages = []; List<ChatMessageModel> chatMessages = [];
if (chatTypeEnum == ChatTypeEnum.general) { if (chatTypeEnum == ChatTypeEnum.general) {

@ -1,3 +1,5 @@
import 'dart:developer';
import 'package:cached_network_image/cached_network_image.dart'; import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/classes/app_state.dart';
@ -21,6 +23,7 @@ import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:mc_common_app/widgets/txt_field.dart'; import 'package:mc_common_app/widgets/txt_field.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:easy_localization/easy_localization.dart' as lcl; import 'package:easy_localization/easy_localization.dart' as lcl;
import 'package:sizer/sizer.dart';
class ChatMessageCustomWidget extends StatefulWidget { class ChatMessageCustomWidget extends StatefulWidget {
final ChatMessageModel chatMessageModel; final ChatMessageModel chatMessageModel;
@ -407,10 +410,20 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
return widget.toCircle(borderRadius: 100); return widget.toCircle(borderRadius: 100);
} }
Widget buildFreeTextDetailsInMessage() { Widget buildFreeTextDetailsInMessage({required ChatMessageTypeEnum chatMessageTypeEnum}) {
log(": ${widget.chatMessageModel.isMyMessage}");
return Row( return Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
if (chatMessageTypeEnum == ChatMessageTypeEnum.offer && (widget.chatMessageModel.isMyMessage == true)) ...[
Row(
children: [
const Icon(Icons.remove_red_eye_outlined, size: 12, color: MyColors.lightTextColor),
4.width,
LocaleKeys.viewed.tr().toText(fontSize: 10, color: MyColors.lightTextColor, fontWeight: MyFonts.Medium),
],
),
],
Expanded( Expanded(
child: Directionality( child: Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
@ -421,17 +434,12 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
), ),
), ),
), ),
], ],
); );
} }
Widget buildImageGridWidget({ Widget buildImageGridWidget({required List<MessageImageModel> messagesImages, double gridItemSize = 50.0, double spacing = 8.0, double borderWidth = 1, Color borderColor = MyColors.textColor}) {
required List<MessageImageModel> messagesImages,
double gridItemSize = 50.0,
double spacing = 8.0,
double borderWidth = 1,
Color borderColor = MyColors.textColor,
}) {
int imageCount = messagesImages.length; int imageCount = messagesImages.length;
if (imageCount == 1) { if (imageCount == 1) {
return Container( return Container(
@ -529,7 +537,7 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
} }
switch (chatMessageTypeEnum) { switch (chatMessageTypeEnum) {
case ChatMessageTypeEnum.freeText: case ChatMessageTypeEnum.freeText:
messageTypeWidget = Column(children: [buildFreeTextDetailsInMessage(), 10.height]); messageTypeWidget = Column(children: [buildFreeTextDetailsInMessage(chatMessageTypeEnum: chatMessageTypeEnum), 10.height]);
break; break;
case ChatMessageTypeEnum.image: case ChatMessageTypeEnum.image:
messageTypeWidget = buildImageGridWidget(messagesImages: widget.chatMessageModel.messageImages ?? []); messageTypeWidget = buildImageGridWidget(messagesImages: widget.chatMessageModel.messageImages ?? []);
@ -540,7 +548,7 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
case ChatMessageTypeEnum.offer: case ChatMessageTypeEnum.offer:
messageTypeWidget = Column( messageTypeWidget = Column(
children: [ children: [
buildFreeTextDetailsInMessage(), buildFreeTextDetailsInMessage(chatMessageTypeEnum: chatMessageTypeEnum),
10.height, 10.height,
buildOfferDetailsInChatMessage(requestStatusEnum: widget.requestStatusEnum!, chatMessageModel: widget.chatMessageModel, context: context), buildOfferDetailsInChatMessage(requestStatusEnum: widget.requestStatusEnum!, chatMessageModel: widget.chatMessageModel, context: context),
], ],

@ -76,7 +76,7 @@ class MyRequestsFragment extends StatelessWidget {
return Consumer(builder: (BuildContext context, RequestsVM requestsVM, Widget? child) { return Consumer(builder: (BuildContext context, RequestsVM requestsVM, Widget? child) {
return Scaffold( return Scaffold(
appBar: CustomAppBar( appBar: CustomAppBar(
title: LocaleKeys.myRequests.tr(), title: LocaleKeys.manageRequests.tr(),
isRemoveBackButton: true, isRemoveBackButton: true,
actions: [ actions: [
Padding( Padding(

@ -1,3 +1,4 @@
import 'dart:developer';
import 'dart:ui'; import 'dart:ui';
import 'package:cached_network_image/cached_network_image.dart'; import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -7,7 +8,10 @@ import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_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/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/subscriptions_models/subscription_model.dart';
import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/date_helper.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.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/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/views/setting_options/widgets/custom_setting_options_tile.dart';
@ -34,10 +38,26 @@ class _ProfileScreenState extends State<ProfileScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Subscription? mySubscription;
return Scaffold( return Scaffold(
extendBody: true, extendBody: true,
backgroundColor: const Color(0xffefefef), backgroundColor: const Color(0xffefefef),
body: Consumer<UserVM>(builder: (_, model, __) { body: Consumer<UserVM>(builder: (_, model, __) {
String startDate = "";
String endDate = "";
String freeTrialName = "";
if (AppState().currentAppType == AppType.provider && AppState().getproviderSubscription.isNotEmpty) {
mySubscription = AppState().getproviderSubscription.first;
log("mySubscription!.dateStart.toString(): ${mySubscription!.dateStart}");
log("mySubscription!.dateEnd.toString(): ${mySubscription!.dateEnd}");
if (mySubscription!.id == 1) {
freeTrialName = mySubscription!.name ?? "";
} else {
startDate = (mySubscription!.dateStart != null && mySubscription!.dateStart!.isNotEmpty) ? DateHelper.formatAsDayMonthYear(DateHelper.parseStringToDate(DateHelper.formatDateT(mySubscription!.dateStart!))) : "";
endDate = (mySubscription!.dateEnd != null && mySubscription!.dateEnd!.isNotEmpty) ? DateHelper.formatAsDayMonthYear(DateHelper.parseStringToDate(DateHelper.formatDateT(mySubscription!.dateEnd!))) : "";
}
}
return Stack( return Stack(
children: [ children: [
Column( Column(
@ -84,6 +104,15 @@ class _ProfileScreenState extends State<ProfileScreen> {
"${AppState().getUser.data!.userInfo!.firstName} ${AppState().getUser.data!.userInfo!.lastName ?? ""}".toText(fontSize: 20).paddingOnly(left: 25), "${AppState().getUser.data!.userInfo!.firstName} ${AppState().getUser.data!.userInfo!.lastName ?? ""}".toText(fontSize: 20).paddingOnly(left: 25),
Column( Column(
children: [ children: [
if (AppState().currentAppType == AppType.provider && mySubscription != null) ...[
CustomProfileOptionsTile(
titleText: LocaleKeys.mySubscription.tr(),
subtitleText: freeTrialName.isNotEmpty ? freeTrialName : "${startDate.isNotEmpty ? "${LocaleKeys.startDate.tr()}: $startDate" : ""} ${endDate.isNotEmpty ? "${LocaleKeys.expiresOn.tr()}: $endDate" : ""}",
needBorderBelow: true,
needEditButton: false,
onTap: () {},
),
],
CustomProfileOptionsTile( CustomProfileOptionsTile(
titleText: LocaleKeys.country.tr(), titleText: LocaleKeys.country.tr(),
subtitleText: "Saudi Arabia", subtitleText: "Saudi Arabia",
@ -163,7 +192,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
child: Container( child: Container(
height: 40, height: 40,
width: 40, width: 40,
padding: EdgeInsets.all(8), padding: const EdgeInsets.all(8),
decoration: BoxDecoration(color: MyColors.white, shape: BoxShape.circle, border: Border.all(color: MyColors.darkTextColor, width: 0.1)), decoration: BoxDecoration(color: MyColors.white, shape: BoxShape.circle, border: Border.all(color: MyColors.darkTextColor, width: 0.1)),
child: MyAssets.icEdit.buildSvg(), child: MyAssets.icEdit.buildSvg(),
).onPress( ).onPress(

@ -27,6 +27,10 @@ class CreateRequestPage extends StatelessWidget {
return Scaffold( return Scaffold(
appBar: CustomAppBar( appBar: CustomAppBar(
title: LocaleKeys.createRequest.tr(), title: LocaleKeys.createRequest.tr(),
onBackButtonTapped: () {
context.read<RequestsVM>().resetRequestCreationForm();
pop(context);
},
), ),
body: Consumer<RequestsVM>(builder: (context, requestsVM, widget) { body: Consumer<RequestsVM>(builder: (context, requestsVM, widget) {
return Column( return Column(
@ -133,8 +137,7 @@ class CreateRequestPage extends StatelessWidget {
return DropdownField( return DropdownField(
(DropValue value) => requestsVM.updateSelectionVehicleConditionId(SelectionModel(selectedId: value.id, selectedOption: value.value)), (DropValue value) => requestsVM.updateSelectionVehicleConditionId(SelectionModel(selectedId: value.id, selectedOption: value.value)),
list: vehicleOwnerDrop, list: vehicleOwnerDrop,
dropdownValue: dropdownValue: requestsVM.vehicleConditionId.selectedId != -1 ? DropValue(requestsVM.vehicleConditionId.selectedId, requestsVM.vehicleConditionId.selectedOption, "") : null,
requestsVM.vehicleConditionId.selectedId != -1 ? DropValue(requestsVM.vehicleConditionId.selectedId, requestsVM.vehicleConditionId.selectedOption, "") : null,
hint: LocaleKeys.condition.tr(), hint: LocaleKeys.condition.tr(),
errorValue: requestsVM.vehicleConditionId.errorValue, errorValue: requestsVM.vehicleConditionId.errorValue,
); );

@ -39,7 +39,7 @@ class OfferListPage extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Utils.statusContainerChip( Utils.statusContainerChip(
text: "Offer ${Utils.getNameByRequestOfferStatusEnum(offersModel.requestOfferStatusEnum!)}", text: Utils.getNameByRequestOfferStatusEnum(offersModel.requestOfferStatusEnum!),
chipColor: Utils.getChipColorByRequestOfferStatusEnum(offersModel.requestOfferStatusEnum!), chipColor: Utils.getChipColorByRequestOfferStatusEnum(offersModel.requestOfferStatusEnum!),
), ),
Row( Row(
@ -54,7 +54,7 @@ class OfferListPage extends StatelessWidget {
fontSize: 10, fontSize: 10,
), ),
).toContainer( ).toContainer(
backgroundColor: MyColors.redColor, backgroundColor: MyColors.cancelledColor,
borderRadius: 100, borderRadius: 100,
paddingAll: 1, paddingAll: 1,
width: 22, width: 22,
@ -85,6 +85,7 @@ class OfferListPage extends StatelessWidget {
], ],
).onPress(() async { ).onPress(() async {
context.read<RequestsVM>().currentSelectedOffer = offersModel; context.read<RequestsVM>().currentSelectedOffer = offersModel;
ChatViewArgumentsForRequest chatViewArgumentsForRequest = ChatViewArgumentsForRequest( ChatViewArgumentsForRequest chatViewArgumentsForRequest = ChatViewArgumentsForRequest(
chatTypeEnum: ChatTypeEnum.requestOffer, chatTypeEnum: ChatTypeEnum.requestOffer,
receiverId: "${offersModel.providerUserId}", receiverId: "${offersModel.providerUserId}",
@ -106,9 +107,7 @@ class OfferListPage extends StatelessWidget {
requestId: offerListPageArguments.requestId ?? 0, requestId: offerListPageArguments.requestId ?? 0,
providerOfferIndex: index, providerOfferIndex: index,
) )
.whenComplete( .whenComplete(() => navigateWithName(context, AppRoutes.chatView, arguments: chatViewArguments));
() => navigateWithName(context, AppRoutes.chatView, arguments: chatViewArguments),
);
}).toContainer(isShadowEnabled: true); }).toContainer(isShadowEnabled: true);
}, },
separatorBuilder: (context, index) => 16.height, separatorBuilder: (context, index) => 16.height,

@ -1,4 +1,6 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/routes.dart'; import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/extensions/string_extensions.dart';
@ -9,9 +11,12 @@ import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart'; import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/utils/utils.dart'; import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/view_models/requests_view_model.dart'; import 'package:mc_common_app/view_models/requests_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/button/show_fill_button.dart';
import 'package:mc_common_app/widgets/checkbox_with_title_desc.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/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:mc_common_app/widgets/txt_field.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
@ -81,6 +86,50 @@ Future buildSendOfferBottomSheet({required BuildContext context, required Reques
hint: LocaleKeys.description.tr(), hint: LocaleKeys.description.tr(),
onChanged: (v) => requestsVM.updateOfferDescription(v), onChanged: (v) => requestsVM.updateOfferDescription(v),
), ),
12.height,
if (requestDetail.requestType == RequestsTypeEnum.serviceRequest.getIdFromRequestTypeStatusEnum()) ...[
LocaleKeys.deliveryAvailable.tr().toText(fontSize: 16),
8.height,
Container(
width: 50,
height: 30,
decoration: BoxDecoration(
color: requestsVM.isDeliveryAvailableStatus ? MyColors.darkPrimaryColor : MyColors.white,
borderRadius: BorderRadius.circular(25.0),
border: Border.all(color: MyColors.black, width: 1),
),
child: Transform.scale(
scale: 0.8,
child: CupertinoSwitch(
activeColor: MyColors.darkPrimaryColor,
trackColor: MyColors.white,
thumbColor: MyColors.grey98Color,
value: requestsVM.isDeliveryAvailableStatus,
onChanged: (value) {
requestsVM.updateIsDeliveryAvailableStatus(value);
},
),
),
),
],
12.height,
if (requestsVM.pickedVehicleImages.isEmpty) ...[
DottedRectContainer(
onTap: () => context.read<RequestsVM>().pickMultipleImages(),
text: LocaleKeys.attachImage.tr(),
icon: MyAssets.attachmentIcon.buildSvg(),
),
],
if (requestsVM.pickedVehicleImages.isNotEmpty) ...[
16.height,
PickedFilesContainer(
pickedFiles: requestsVM.pickedVehicleImages,
onCrossPressedPrimary: requestsVM.removeImageFromList,
onAddFilePressed: () {
context.read<RequestsVM>().pickMultipleImages();
},
),
],
], ],
), ),
25.height, 25.height,

@ -137,7 +137,7 @@ class RequestDetailPage extends StatelessWidget {
children: [ children: [
ImagesCorouselWidget(imagesList: requestDetailPageArguments.requestModel.requestImages ?? []), ImagesCorouselWidget(imagesList: requestDetailPageArguments.requestModel.requestImages ?? []),
24.height, 24.height,
buildRequestContainer(context), buildRequestDetailsContainer(context),
], ],
).toWhiteContainer( ).toWhiteContainer(
width: double.infinity, width: double.infinity,
@ -169,7 +169,7 @@ class RequestDetailPage extends StatelessWidget {
); );
} }
Widget buildRequestContainer(BuildContext context) { Widget buildRequestDetailsContainer(BuildContext context) {
final requestDetail = requestDetailPageArguments.requestModel; final requestDetail = requestDetailPageArguments.requestModel;
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -184,8 +184,9 @@ class RequestDetailPage extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
requestDetail.vehicleTypeName.toText(fontSize: 16, letterSpacing: -0.64), requestDetail.vehicleTypeName.toText(fontSize: 16, letterSpacing: -0.64),
showItem("${LocaleKeys.manufacturer.tr()}: ", requestDetail.brand), showItem("${LocaleKeys.brand.tr()}: ", requestDetail.brand),
showItem("${LocaleKeys.model.tr()}: ", "${requestDetail.year}"), showItem("${LocaleKeys.model.tr()}: ", requestDetail.model),
showItem("${LocaleKeys.year.tr()}: ", "${requestDetail.year}"),
], ],
), ),
), ),
@ -205,7 +206,9 @@ class RequestDetailPage extends StatelessWidget {
), ),
], ],
), ),
showItem("${LocaleKeys.customerName.tr()}: ", requestDetail.customerName), if (requestDetail.customerName.isNotEmpty) ...[
showItem("${LocaleKeys.customerName.tr()}: ", requestDetail.customerName),
],
showItem("${LocaleKeys.description.tr()}: ", requestDetail.description), showItem("${LocaleKeys.description.tr()}: ", requestDetail.description),
16.height, 16.height,
// showItem("${LocaleKeys.priceRange.tr()}:", ""), // showItem("${LocaleKeys.priceRange.tr()}:", ""),

@ -7,6 +7,7 @@ import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_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/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/user_models/user.dart'; import 'package:mc_common_app/models/user_models/user.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/date_helper.dart'; import 'package:mc_common_app/utils/date_helper.dart';
import 'package:mc_common_app/utils/dialogs_and_bottomsheets.dart'; import 'package:mc_common_app/utils/dialogs_and_bottomsheets.dart';
import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/utils/enums.dart';
@ -16,6 +17,7 @@ import 'package:mc_common_app/view_models/chat_view_model.dart';
import 'package:mc_common_app/view_models/requests_view_model.dart'; import 'package:mc_common_app/view_models/requests_view_model.dart';
import 'package:mc_common_app/views/advertisement/ad_creation_steps/ad_review_containers.dart'; import 'package:mc_common_app/views/advertisement/ad_creation_steps/ad_review_containers.dart';
import 'package:mc_common_app/views/location_views/pick_location_page.dart'; import 'package:mc_common_app/views/location_views/pick_location_page.dart';
import 'package:mc_common_app/views/setting_options/widgets/custom_setting_options_tile.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart'; 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/common_widgets/app_bar.dart';
import 'package:mc_common_app/widgets/common_widgets/info_bottom_sheet.dart'; import 'package:mc_common_app/widgets/common_widgets/info_bottom_sheet.dart';
@ -255,6 +257,61 @@ class _ReviewRequestOfferState extends State<ReviewRequestOffer> {
); );
} }
buildProviderContactInfoBottomSheet(BuildContext context) {
final requestVM = context.read<RequestsVM>();
return showModalBottomSheet(
context: context,
isScrollControlled: true,
enableDrag: true,
builder: (BuildContext context) {
return InfoBottomSheet(
title: LocaleKeys.contactDetails.tr().toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
description: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (requestVM.currentSelectedOffer!.mobileNo != null && requestVM.currentSelectedOffer!.mobileNo!.isNotEmpty) ...[
CustomSettingOptionsTile(
leadingWidget: const Icon(
Icons.call,
size: 20,
color: MyColors.greyColor,
),
titleText: LocaleKeys.phoneNumber.tr(),
subTitle: " ${requestVM.currentSelectedOffer!.mobileNo ?? ""}",
needBorderBelow: true,
showTrailingArrow: false,
subtitleTextColor: MyColors.greyColor,
onTap: () {
Utils.openNumberViaCaller(phoneNumber: requestVM.currentSelectedOffer!.mobileNo ?? "");
},
),
],
if (requestVM.currentSelectedOffer!.email != null && requestVM.currentSelectedOffer!.email!.isNotEmpty) ...[
CustomSettingOptionsTile(
leadingWidget: const Icon(
Icons.email_outlined,
size: 20,
color: MyColors.greyColor,
),
titleText: LocaleKeys.emailAddress.tr(),
subTitle: " ${requestVM.currentSelectedOffer!.email ?? ""}",
needBorderBelow: false,
showTrailingArrow: false,
subtitleTextColor: MyColors.greyColor,
onTap: () {
Utils.openEmailViaEmailApp(emailAddress: requestVM.currentSelectedOffer!.email ?? "");
},
),
],
30.height,
],
),
);
},
);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@ -265,7 +322,7 @@ class _ReviewRequestOfferState extends State<ReviewRequestOffer> {
onBackButtonTapped: () => Navigator.pop(context), onBackButtonTapped: () => Navigator.pop(context),
actions: [ actions: [
IconButton( IconButton(
onPressed: () => Utils.showHelpBottomSheet(context), onPressed: () => buildProviderContactInfoBottomSheet(context),
icon: const Icon(Icons.help_outline_outlined).paddingOnly(right: 21), icon: const Icon(Icons.help_outline_outlined).paddingOnly(right: 21),
), ),
], ],

@ -35,10 +35,10 @@ class RequestItem extends StatelessWidget {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Utils.statusContainerChip(text: request.requestStatusName, chipColor: Utils.getChipColorByRequestStatus(request.requestStatus)), Utils.statusContainerChip(text: request.requestStatusName.toLowerCase() == "InProgress".toLowerCase() ? "In Progress" : request.requestStatusName, chipColor: Utils.getChipColorByRequestStatus(request.requestStatus)),
6.height, 6.height,
"${request.brand} ${request.model} | ${request.id}".toText(fontSize: 16, letterSpacing: -0.64), "${request.brand} ${request.model} | ${request.id}".toText(fontSize: 16, letterSpacing: -0.64),
showItem("${LocaleKeys.model.tr()}:", "${request.year}"), showItem("${LocaleKeys.year.tr()}:", "${request.year}"),
if (request.customerName.isNotEmpty) ...[ if (request.customerName.isNotEmpty) ...[
showItem("${LocaleKeys.customerName.tr()}:", request.customerName), showItem("${LocaleKeys.customerName.tr()}:", request.customerName),
], ],

@ -1,15 +1,20 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/routes.dart'; import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/int_extensions.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/generated/locale_keys.g.dart';
import 'package:mc_common_app/theme/colors.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/navigator.dart';
import 'package:mc_common_app/view_models/setting_options_view_model.dart';
import 'package:mc_common_app/views/setting_options/widgets/custom_setting_options_tile.dart'; import 'package:mc_common_app/views/setting_options/widgets/custom_setting_options_tile.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
import 'package:mc_common_app/widgets/common_widgets/info_bottom_sheet.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/extensions/extensions_widget.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:provider/provider.dart';
class SettingOptionsInviteFriends extends StatelessWidget { class SettingOptionsInviteFriends extends StatelessWidget {
const SettingOptionsInviteFriends({super.key}); const SettingOptionsInviteFriends({super.key});
@ -21,22 +26,24 @@ class SettingOptionsInviteFriends extends StatelessWidget {
enableDrag: true, enableDrag: true,
builder: (BuildContext context) { builder: (BuildContext context) {
return InfoBottomSheet( return InfoBottomSheet(
description: Column( title: LocaleKeys.inviteFriends.tr().toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
crossAxisAlignment: CrossAxisAlignment.start, description: Column(
children: [ crossAxisAlignment: CrossAxisAlignment.start,
20.height, children: [
CustomSettingOptionsTile( CustomSettingOptionsTile(
leadingWidget: MyAssets.whatsAppIcon.buildSvg( leadingWidget: MyAssets.whatsAppIcon.buildSvg(
height: 20, height: 20,
width: 20, width: 20,
color: MyColors.greyColor, color: MyColors.greyColor,
),
titleText: LocaleKeys.inviteFriendsByWhatsApp.tr(),
needBorderBelow: true,
showTrailingArrow: false,
onTap: () {},
), ),
CustomSettingOptionsTile( titleText: LocaleKeys.inviteFriendsByWhatsApp.tr(),
needBorderBelow: true,
showTrailingArrow: false,
onTap: () async {
await context.read<SettingOptionsVM>().appInvitationCreate(context: context, channelId: 1);
},
),
CustomSettingOptionsTile(
leadingWidget: const Icon( leadingWidget: const Icon(
Icons.sms_outlined, Icons.sms_outlined,
size: 20, size: 20,
@ -45,23 +52,26 @@ class SettingOptionsInviteFriends extends StatelessWidget {
titleText: LocaleKeys.inviteFriendsBySMS.tr(), titleText: LocaleKeys.inviteFriendsBySMS.tr(),
needBorderBelow: true, needBorderBelow: true,
showTrailingArrow: false, showTrailingArrow: false,
onTap: () {}, onTap: () async {
), await context.read<SettingOptionsVM>().appInvitationCreate(context: context, channelId: 2);
CustomSettingOptionsTile( }),
leadingWidget: const Icon( CustomSettingOptionsTile(
Icons.email_outlined, leadingWidget: const Icon(
size: 20, Icons.email_outlined,
color: MyColors.greyColor, size: 20,
), color: MyColors.greyColor,
titleText: LocaleKeys.inviteFriendsByEmail.tr(),
needBorderBelow: false,
showTrailingArrow: false,
onTap: () {},
), ),
30.height, titleText: LocaleKeys.inviteFriendsByEmail.tr(),
], needBorderBelow: false,
), showTrailingArrow: false,
title: const SizedBox()); onTap: () async {
await context.read<SettingOptionsVM>().appInvitationCreate(context: context, channelId: 3);
},
),
30.height,
],
),
);
}, },
); );
} }
@ -82,14 +92,16 @@ class SettingOptionsInviteFriends extends StatelessWidget {
children: [ children: [
Column( Column(
children: [ children: [
CustomSettingOptionsTile( if (AppState().currentAppType == AppType.customer) ...[
leadingWidget: const Icon(Icons.group, size: 20), CustomSettingOptionsTile(
titleText: LocaleKeys.inviteFriends.tr(), leadingWidget: const Icon(Icons.group, size: 20),
needBorderBelow: true, titleText: LocaleKeys.inviteFriends.tr(),
onTap: () { needBorderBelow: true,
return buildInviteFriendsBottomSheet(context); onTap: () {
}, return buildInviteFriendsBottomSheet(context);
), },
),
],
CustomSettingOptionsTile( CustomSettingOptionsTile(
leadingWidget: const Icon(Icons.question_mark_outlined, size: 20), leadingWidget: const Icon(Icons.question_mark_outlined, size: 20),
titleText: LocaleKeys.help.tr(), titleText: LocaleKeys.help.tr(),

@ -143,10 +143,7 @@ class _SettingOptionsMoreState extends State<SettingOptionsMore> {
leadingWidget: SizedBox( leadingWidget: SizedBox(
width: 16, width: 16,
height: 16, height: 16,
child: SvgPicture.asset( child: SvgPicture.asset(MyAssets.icGroupStar),
MyAssets.icGroupStar,
// color: MyColors.primaryColor,
),
), ),
titleText: LocaleKeys.subscriptions.tr(), titleText: LocaleKeys.subscriptions.tr(),
subTitle: null, subTitle: null,

@ -15,6 +15,7 @@ class CustomSettingOptionsTile extends StatelessWidget {
final bool showTrailingArrow; final bool showTrailingArrow;
final Function() onTap; final Function() onTap;
final String? subTitle; final String? subTitle;
final Color subtitleTextColor;
const CustomSettingOptionsTile({ const CustomSettingOptionsTile({
super.key, super.key,
@ -25,6 +26,7 @@ class CustomSettingOptionsTile extends StatelessWidget {
this.isForLanguage = false, this.isForLanguage = false,
this.showTrailingArrow = true, this.showTrailingArrow = true,
this.subTitle, this.subTitle,
this.subtitleTextColor = MyColors.primaryColor,
}); });
@override @override
@ -48,7 +50,7 @@ class CustomSettingOptionsTile extends StatelessWidget {
Row( Row(
children: [ children: [
28.width, 28.width,
subTitle!.toText(fontSize: 14, color: MyColors.primaryColor), subTitle!.toText(fontSize: 14, color: subtitleTextColor),
], ],
), ),
], ],

@ -40,7 +40,7 @@ class CustomBottomNavbar extends StatelessWidget {
color: MyColors.lightIconColor, color: MyColors.lightIconColor,
).paddingAll(5), ).paddingAll(5),
activeIcon: SvgPicture.asset(MyAssets.homeIcon, color: MyColors.darkIconColor).paddingAll(5), activeIcon: SvgPicture.asset(MyAssets.homeIcon, color: MyColors.darkIconColor).paddingAll(5),
label: LocaleKeys.home.tr(), label: LocaleKeys.explore.tr(),
), ),
BottomNavigationBarItem( BottomNavigationBarItem(
icon: SvgPicture.asset(MyAssets.announcementIcon).paddingAll(5), icon: SvgPicture.asset(MyAssets.announcementIcon).paddingAll(5),

@ -17,6 +17,7 @@ class ProviderDetailCard extends StatelessWidget {
final String description; final String description;
final List<BranchDetailModel> branches; final List<BranchDetailModel> branches;
final Function() onCardTapped; final Function() onCardTapped;
final bool isFromFavoriteList;
const ProviderDetailCard({ const ProviderDetailCard({
Key? key, Key? key,
@ -27,6 +28,7 @@ class ProviderDetailCard extends StatelessWidget {
required this.description, required this.description,
required this.startedSince, required this.startedSince,
required this.onCardTapped, required this.onCardTapped,
this.isFromFavoriteList = false,
}) : super(key: key); }) : super(key: key);
@override @override
@ -57,21 +59,23 @@ class ProviderDetailCard extends StatelessWidget {
title.toText(fontSize: 16, isBold: true), title.toText(fontSize: 16, isBold: true),
Row( Row(
children: [ children: [
("Total Branches:").toText(color: MyColors.lightTextColor, fontSize: 12), ("${LocaleKeys.totalBranches.tr()}:").toText(color: MyColors.lightTextColor, fontSize: 12),
4.width, 4.width,
totalBranches.toText(fontSize: 12, isBold: true), totalBranches.toText(fontSize: 12, isBold: true),
], ],
), ),
if (description.isNotEmpty) ...[
Row(
children: [
("${LocaleKeys.description.tr()}:").toText(color: MyColors.lightTextColor, fontSize: 12),
4.width,
description.toText(fontSize: 12, isBold: true),
],
),
],
Row( Row(
children: [ children: [
("${LocaleKeys.description.tr()}:").toText(color: MyColors.lightTextColor, fontSize: 12), (isFromFavoriteList ? LocaleKeys.addToFavoritesOn.tr() : LocaleKeys.memberSince.tr()).toText(color: MyColors.lightTextColor, fontSize: 12),
4.width,
description.toText(fontSize: 12, isBold: true),
],
),
Row(
children: [
("Since:").toText(color: MyColors.lightTextColor, fontSize: 12),
4.width, 4.width,
startedSince.toText(fontSize: 12, isBold: true), startedSince.toText(fontSize: 12, isBold: true),
], ],

@ -202,7 +202,7 @@ class TxtField extends StatelessWidget {
Row( Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
children: [ children: [
errorValue.toText(fontSize: 14, color: Colors.red), errorValue.toText(fontSize: 12, color: Colors.red),
], ],
).paddingOnly(right: 10), ).paddingOnly(right: 10),
], ],

@ -42,6 +42,7 @@ dependencies:
logging: ^1.2.0 logging: ^1.2.0
percent_indicator: ^4.2.3 percent_indicator: ^4.2.3
change_app_package_name: ^1.3.0 change_app_package_name: ^1.3.0
share_plus: any
# Firebase Packages # Firebase Packages

Loading…
Cancel
Save