From d6f3c5653a4f857b0717c71f951886d6aa16206b Mon Sep 17 00:00:00 2001 From: "mirza.shafique" Date: Wed, 24 May 2023 16:50:06 +0300 Subject: [PATCH] add services and items --- android/build.gradle | 2 +- lib/common/item_model.dart | 100 ++++ lib/common/schedule_model.dart | 81 ++++ lib/common/subscription_model.dart | 125 +++++ .../widget/checkbox_with_title_desc.dart | 40 ++ lib/common/widget/empty_widget.dart | 11 + lib/config/provider_dependencies.dart | 8 +- lib/config/provider_routes.dart | 51 ++- lib/main.dart | 31 +- lib/repositories/branch_repo.dart | 6 +- lib/repositories/items_repo.dart | 44 ++ lib/repositories/schedule_repo.dart | 43 ++ lib/repositories/subscription_repo.dart | 25 + lib/view_models/branch_view_model.dart | 426 +++++++++--------- lib/view_models/items_view_model.dart | 54 +++ lib/view_models/schedule_view_model.dart | 94 ++++ lib/view_models/service_view_model.dart | 185 ++++++++ lib/view_models/subscriptions_view_model.dart | 73 +++ .../dashboard/fragments/home_fragment.dart | 20 +- .../settings/branch/branch_detail_page.dart | 211 ++++++--- .../settings/branch/branch_list_page.dart | 5 +- .../settings/branch/define_branch_page.dart | 29 +- lib/views/settings/create_services_page.dart | 420 ++++++++--------- lib/views/settings/dealership_page.dart | 2 +- lib/views/settings/define_license_page.dart | 13 +- .../settings/schedule/add_schedules_page.dart | 286 ++++++++++++ .../schedule/schedules_list_page.dart | 35 ++ .../schedule/widgets/chips_picker_item.dart | 87 ++++ .../schedule/widgets/select_days_sheet.dart | 97 ++++ .../widgets/select_services_sheet.dart | 106 +++++ .../settings/services/create_item_page.dart | 289 ++++++++++++ .../services/create_services_page2.dart | 234 ++++++++++ .../services/create_services_page3.dart | 272 +++++++++++ .../settings/services/items_list_page.dart | 136 ++++++ .../settings/services/services_list_page.dart | 176 ++++++++ .../subscriptions/my_subscritions_page.dart | 43 +- .../subscriptions/subscriptions_page.dart | 64 ++- .../widget/subscriptions_card.dart | 36 +- pubspec.lock | 86 +++- 39 files changed, 3451 insertions(+), 595 deletions(-) create mode 100644 lib/common/item_model.dart create mode 100644 lib/common/schedule_model.dart create mode 100644 lib/common/subscription_model.dart create mode 100644 lib/common/widget/checkbox_with_title_desc.dart create mode 100644 lib/common/widget/empty_widget.dart create mode 100644 lib/repositories/items_repo.dart create mode 100644 lib/repositories/schedule_repo.dart create mode 100644 lib/repositories/subscription_repo.dart create mode 100644 lib/view_models/items_view_model.dart create mode 100644 lib/view_models/schedule_view_model.dart create mode 100644 lib/view_models/service_view_model.dart create mode 100644 lib/view_models/subscriptions_view_model.dart create mode 100644 lib/views/settings/schedule/add_schedules_page.dart create mode 100644 lib/views/settings/schedule/schedules_list_page.dart create mode 100644 lib/views/settings/schedule/widgets/chips_picker_item.dart create mode 100644 lib/views/settings/schedule/widgets/select_days_sheet.dart create mode 100644 lib/views/settings/schedule/widgets/select_services_sheet.dart create mode 100644 lib/views/settings/services/create_item_page.dart create mode 100644 lib/views/settings/services/create_services_page2.dart create mode 100644 lib/views/settings/services/create_services_page3.dart create mode 100644 lib/views/settings/services/items_list_page.dart create mode 100644 lib/views/settings/services/services_list_page.dart diff --git a/android/build.gradle b/android/build.gradle index 09fbd64..1c8bb53 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -24,6 +24,6 @@ subprojects { project.evaluationDependsOn(':app') } -task clean(type: Delete) { +tasks.register("clean", Delete) { delete rootProject.buildDir } diff --git a/lib/common/item_model.dart b/lib/common/item_model.dart new file mode 100644 index 0000000..6bfd075 --- /dev/null +++ b/lib/common/item_model.dart @@ -0,0 +1,100 @@ +// To parse this JSON data, do +// +// final itemModel = itemModelFromJson(jsonString); + +import 'dart:convert'; + +ItemModel itemModelFromJson(String str) => ItemModel.fromJson(json.decode(str)); + +String itemModelToJson(ItemModel data) => json.encode(data.toJson()); + +class ItemModel { + final int? messageStatus; + final int? totalItemsCount; + final List? data; + final String? message; + + ItemModel({ + this.messageStatus, + this.totalItemsCount, + this.data, + this.message, + }); + + factory ItemModel.fromJson(Map json) => ItemModel( + messageStatus: json["messageStatus"], + totalItemsCount: json["totalItemsCount"], + data: json["data"] == null ? [] : List.from(json["data"]!.map((x) => ItemData.fromJson(x))), + message: json["message"], + ); + + Map toJson() => { + "messageStatus": messageStatus, + "totalItemsCount": totalItemsCount, + "data": data == null ? [] : List.from(data!.map((x) => x.toJson())), + "message": message, + }; +} + +class ItemData { + final int? id; + final String? name; + final String? price; + final String? manufactureDate; + final String? description; + final dynamic pictureUrl; + final int? companyId; + final int? serviceProviderServiceId; + final bool? isActive; + final bool? isAllowAppointment; + final bool? isAppointmentCompanyLoc; + final bool? isAppointmentCustomerLoc; + bool? isUpdate; + + ItemData({ + this.id, + this.name, + this.price, + this.manufactureDate, + this.description, + this.pictureUrl, + this.companyId, + this.serviceProviderServiceId, + this.isActive, + this.isAllowAppointment, + this.isAppointmentCompanyLoc, + this.isAppointmentCustomerLoc, + this.isUpdate, + }); + + factory ItemData.fromJson(Map json) => ItemData( + id: json["id"], + name: json["name"], + price: json["price"].toString(), + manufactureDate: json["manufactureDate"], + description: json["description"], + pictureUrl: json["pictureUrl"], + companyId: json["companyID"], + serviceProviderServiceId: json["serviceProviderServiceID"], + isActive: json["isActive"], + isAllowAppointment: json["isAllowAppointment"], + isAppointmentCompanyLoc: json["isAppointmentCompanyLoc"], + isAppointmentCustomerLoc: json["isAppointmentCustomerLoc"], + isUpdate: false, + ); + + Map toJson() => { + "id": id, + "name": name, + "price": price, + "manufactureDate": manufactureDate, + "description": description, + "pictureUrl": pictureUrl, + "companyID": companyId, + "serviceProviderServiceID": serviceProviderServiceId, + "isActive": isActive, + "isAllowAppointment": isAllowAppointment, + "isAppointmentCompanyLoc": isAppointmentCompanyLoc, + "isAppointmentCustomerLoc": isAppointmentCustomerLoc, + }; +} diff --git a/lib/common/schedule_model.dart b/lib/common/schedule_model.dart new file mode 100644 index 0000000..8d4f423 --- /dev/null +++ b/lib/common/schedule_model.dart @@ -0,0 +1,81 @@ +// To parse this JSON data, do +// +// final schedule = scheduleFromJson(jsonString); + +import 'dart:convert'; + +Schedule scheduleFromJson(String str) => Schedule.fromJson(json.decode(str)); + +String scheduleToJson(Schedule data) => json.encode(data.toJson()); + +class Schedule { + final int? messageStatus; + final int? totalItemsCount; + final List? data; + final String? message; + + Schedule({ + this.messageStatus, + this.totalItemsCount, + this.data, + this.message, + }); + + factory Schedule.fromJson(Map json) => Schedule( + messageStatus: json["messageStatus"], + totalItemsCount: json["totalItemsCount"], + data: json["data"] == null ? [] : List.from(json["data"]!.map((x) => ScheduleData.fromJson(x))), + message: json["message"], + ); + + Map toJson() => { + "messageStatus": messageStatus, + "totalItemsCount": totalItemsCount, + "data": data == null ? [] : List.from(data!.map((x) => x.toJson())), + "message": message, + }; +} + +class ScheduleData { + final int? id; + final int? branchId; + final DateTime? fromDate; + final DateTime? toDate; + final String? startTime; + final String? endTime; + final int? slotDurationMinute; + final int? perSlotAppointment; + + ScheduleData({ + this.id, + this.branchId, + this.fromDate, + this.toDate, + this.startTime, + this.endTime, + this.slotDurationMinute, + this.perSlotAppointment, + }); + + factory ScheduleData.fromJson(Map json) => ScheduleData( + id: json["id"], + branchId: json["branchID"], + fromDate: json["fromDate"] == null ? null : DateTime.parse(json["fromDate"]), + toDate: json["toDate"] == null ? null : DateTime.parse(json["toDate"]), + startTime: json["startTime"], + endTime: json["endTime"], + slotDurationMinute: json["slotDurationMinute"], + perSlotAppointment: json["perSlotAppointment"], + ); + + Map toJson() => { + "id": id, + "branchID": branchId, + "fromDate": fromDate?.toIso8601String(), + "toDate": toDate?.toIso8601String(), + "startTime": startTime, + "endTime": endTime, + "slotDurationMinute": slotDurationMinute, + "perSlotAppointment": perSlotAppointment, + }; +} diff --git a/lib/common/subscription_model.dart b/lib/common/subscription_model.dart new file mode 100644 index 0000000..d192566 --- /dev/null +++ b/lib/common/subscription_model.dart @@ -0,0 +1,125 @@ +// To parse this JSON data, do +// +// final subscription = subscriptionFromJson(jsonString); + +import 'dart:convert'; + +Subscription subscriptionFromJson(String str) => Subscription.fromJson(json.decode(str)); + +String subscriptionToJson(Subscription data) => json.encode(data.toJson()); + +class SubscriptionModel { + SubscriptionModel({ + this.messageStatus, + this.totalItemsCount, + this.data, + this.message, + }); + + int? messageStatus; + int? totalItemsCount; + List? data; + String? message; + + factory SubscriptionModel.fromJson(Map json) => SubscriptionModel( + messageStatus: json["messageStatus"], + totalItemsCount: json["totalItemsCount"], + data: json["data"] == null ? [] : List.from(json["data"]!.map((x) => Subscription.fromJson(x))), + message: json["message"], + ); + + Map toJson() => { + "messageStatus": messageStatus, + "totalItemsCount": totalItemsCount, + "data": data == null ? [] : List.from(data!.map((x) => x.toJson())), + "message": message, + }; +} + +class Subscription { + Subscription({ + this.id, + this.name, + this.description, + this.durationName, + this.durationDays, + this.price, + this.currency, + this.numberOfBranches, + this.numberOfSubUsers, + this.numberOfAds, + this.countryId, + this.countryName, + this.isSubscribed, + this.subscriptionAppliedId, + this.serviceProviderId, + this.dateStart, + this.dateEnd, + this.isExpired, + this.isActive, + }); + + int? id; + String? name; + String? description; + String? durationName; + int? durationDays; + double? price; + String? currency; + int? numberOfBranches; + int? numberOfSubUsers; + int? numberOfAds; + int? countryId; + String? countryName; + bool? isSubscribed; + int? subscriptionAppliedId; + int? serviceProviderId; + DateTime? dateStart; + DateTime? dateEnd; + bool? isExpired; + bool? isActive; + + factory Subscription.fromJson(Map json) => Subscription( + id: json["id"], + name: json["name"], + description: json["description"], + durationName: json["durationName"], + durationDays: json["durationDays"], + price: json["price"]?.toDouble(), + currency: json["currency"], + numberOfBranches: json["numberOfBranches"], + numberOfSubUsers: json["numberOfSubUsers"], + numberOfAds: json["numberOfAds"], + countryId: json["countryID"], + countryName: json["countryName"]!, + isSubscribed: json["isSubscribed"], + subscriptionAppliedId: json["subscriptionAppliedID"], + serviceProviderId: json["serviceProviderID"], + dateStart: json["dateStart"] == null ? null : DateTime.parse(json["dateStart"]), + dateEnd: json["dateEnd"] == null ? null : DateTime.parse(json["dateEnd"]), + isExpired: json["isExpired"], + isActive: json["isActive"], + ); + + Map toJson() => { + "id": id, + "name": name, + "description": description, + "durationName": durationName, + "durationDays": durationDays, + "price": price, + "currency": currency, + "numberOfBranches": numberOfBranches, + "numberOfSubUsers": numberOfSubUsers, + "numberOfAds": numberOfAds, + "countryID": countryId, + "countryName": countryName, + "isSubscribed": isSubscribed, + "subscriptionAppliedID": subscriptionAppliedId, + "serviceProviderID": serviceProviderId, + "dateStart": dateStart?.toIso8601String(), + "dateEnd": dateEnd?.toIso8601String(), + "isExpired": isExpired, + "isActive": isActive, + }; +} diff --git a/lib/common/widget/checkbox_with_title_desc.dart b/lib/common/widget/checkbox_with_title_desc.dart new file mode 100644 index 0000000..99088aa --- /dev/null +++ b/lib/common/widget/checkbox_with_title_desc.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/theme/colors.dart'; + +class CheckBoxWithTitleDescription extends StatelessWidget { + bool isSelected; + String title, description; + Function(bool) onSelection; + + CheckBoxWithTitleDescription({required this.isSelected, required this.title, required this.description, required this.onSelection, Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SizedBox( + width: double.infinity, + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Checkbox( + value: isSelected, + onChanged: (bool? v) { + onSelection(v ?? false); + }, + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + title.toText(fontSize: 14, isBold: true), + description.toText(fontSize: 12, color: MyColors.lightTextColor), + ], + ), + ), + ], + ), + ); + } +} diff --git a/lib/common/widget/empty_widget.dart b/lib/common/widget/empty_widget.dart new file mode 100644 index 0000000..3e4cac0 --- /dev/null +++ b/lib/common/widget/empty_widget.dart @@ -0,0 +1,11 @@ +import 'package:flutter/material.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; + +class EmptyWidget extends StatelessWidget { + const EmptyWidget({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Center(child: "No Data Found".toText()); + } +} diff --git a/lib/config/provider_dependencies.dart b/lib/config/provider_dependencies.dart index 7711aba..09030bd 100644 --- a/lib/config/provider_dependencies.dart +++ b/lib/config/provider_dependencies.dart @@ -1,4 +1,7 @@ import 'package:car_provider_app/repositories/branch_repo.dart'; +import 'package:car_provider_app/repositories/items_repo.dart'; +import 'package:car_provider_app/repositories/schedule_repo.dart'; +import 'package:car_provider_app/repositories/subscription_repo.dart'; import 'package:mc_common_app/api/api_client.dart'; import 'package:mc_common_app/config/dependencies.dart'; @@ -9,6 +12,9 @@ class ProviderAppDependencies { static void addDependencies() { AppDependencies.addDependencies(); injector.registerSingleton(() => BranchRepoImp()); - injector.registerSingleton(() => CommonRepoImp()); + injector.registerSingleton(() => ItemsRepoImp()); + // injector.registerSingleton(() => CommonRepoImp()); + injector.registerSingleton(() => SubscriptionRepoImp()); + injector.registerSingleton(() => ScheduleRepoImp()); } } diff --git a/lib/config/provider_routes.dart b/lib/config/provider_routes.dart index 6792e2c..bcd3f82 100644 --- a/lib/config/provider_routes.dart +++ b/lib/config/provider_routes.dart @@ -6,8 +6,15 @@ import 'package:car_provider_app/views/settings/branch/branch_detail_page.dart'; import 'package:car_provider_app/views/settings/branch/branch_list_page.dart'; import 'package:car_provider_app/views/settings/branch/define_branch_page.dart'; import 'package:car_provider_app/views/settings/create_services_page.dart'; +import 'package:car_provider_app/views/settings/schedule/add_schedules_page.dart'; +import 'package:car_provider_app/views/settings/schedule/schedules_list_page.dart'; +import 'package:car_provider_app/views/settings/services/create_item_page.dart'; +import 'package:car_provider_app/views/settings/services/create_services_page2.dart'; import 'package:car_provider_app/views/settings/dealership_page.dart'; import 'package:car_provider_app/views/settings/define_license_page.dart'; +import 'package:car_provider_app/views/settings/services/create_services_page3.dart'; +import 'package:car_provider_app/views/settings/services/items_list_page.dart'; +import 'package:car_provider_app/views/settings/services/services_list_page.dart'; import 'package:car_provider_app/views/subscriptions/my_subscritions_page.dart'; import 'package:car_provider_app/views/subscriptions/subscriptions_page.dart'; import 'package:mc_common_app/config/routes.dart'; @@ -19,22 +26,31 @@ import '../views/dashboard/dashboard_page.dart'; class ProviderAppRoutes { //settings - static const String defineLicense = "/defineLicese"; - static final String dealershipSetting = "/dealershipSetting"; - static final String branchList = "/branchList"; - static final String branchDetail = "/branchDetail"; - static final String defineBranch = "/defineBranch"; - static final String createServices = "/createServices"; + static const defineLicense = "/defineLicese"; + static const String dealershipSetting = "/dealershipSetting"; + static const String branchList = "/branchList"; + static const String branchDetail = "/branchDetail"; + static const String defineBranch = "/defineBranch"; //Appointments - static final String appointmentDetailList = "/appointmentDetailList"; - static final String updateAppointmentPage = "/updateAppointmentPage"; + static const String appointmentDetailList = "/appointmentDetailList"; + static const String updateAppointmentPage = "/updateAppointmentPage"; //Requests - static final String requestsDetailPage = "/requestsDetailPage"; - static final String sendOfferPage = "/sendOfferPage"; + static const String requestsDetailPage = "/requestsDetailPage"; + static const String sendOfferPage = "/sendOfferPage"; + //Services + static const String servicesList = "/servicesList"; + static const String itemsList = "/itemsList"; + static const String createItem = "/createItem"; + static const String createServices = "/createServices"; + static const String createServices2 = "/createServices2"; + static const String createServices3 = "/createServices3"; + //Schedules + static const String schedulesList = "/schedulesList"; + static const String addSchedule = "/addSchedule"; static final Map routes = { //Home page @@ -46,7 +62,6 @@ class ProviderAppRoutes { branchList: (context) => BranchListPage(), defineBranch: (context) => DefineBranchPage((ModalRoute.of(context)!.settings.arguments) == null ? null : (ModalRoute.of(context)!.settings.arguments as ServiceProviderBranch)), branchDetail: (context) => BranchDetailPage(ModalRoute.of(context)!.settings.arguments as ServiceProviderBranch), - createServices: (context) => CreateServicesPage((ModalRoute.of(context)!.settings.arguments) == null ? null : (ModalRoute.of(context)!.settings.arguments as ServiceProviderBranch)), //Appointments appointmentDetailList: (context) => const AppointmentDetailListPage(), @@ -56,8 +71,20 @@ class ProviderAppRoutes { requestsDetailPage: (context) => const RequestDetailPage(), sendOfferPage: (context) => const SendOfferPage(), - //Subcriptions + //Subscriptions AppRoutes.mySubscriptionsPage: (context) => const MySubscriptionsPage(), AppRoutes.subscriptionsPage: (context) => const SubscriptionsPage(), + + //Services + servicesList: (context) => const ServicesListPage(), + itemsList: (context) => ItemsListPage(), + createItem: (context) => const CreateItemPage(), + //createServices: (context) => CreateServicesPage((ModalRoute.of(context)!.settings.arguments) == null ? null : (ModalRoute.of(context)!.settings.arguments as ServiceProviderBranch)), + //createServices2: (context) => CreateServicesPage2((ModalRoute.of(context)!.settings.arguments) == null ? null : (ModalRoute.of(context)!.settings.arguments as ServiceProviderBranch)), + createServices3: (context) => CreateServicesPage3((ModalRoute.of(context)!.settings.arguments) == null ? null : (ModalRoute.of(context)!.settings.arguments as CreateBranchModel)), + + //Schedules + schedulesList: (context) => const SchedulesListPage(), + addSchedule: (context) => AddSchedulesPage(), }; } diff --git a/lib/main.dart b/lib/main.dart index e067a97..9617e09 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,7 +1,14 @@ import 'package:car_provider_app/config/provider_dependencies.dart'; import 'package:car_provider_app/repositories/branch_repo.dart'; +import 'package:car_provider_app/repositories/items_repo.dart'; +import 'package:car_provider_app/repositories/schedule_repo.dart'; +import 'package:car_provider_app/repositories/subscription_repo.dart'; import 'package:car_provider_app/view_models/branch_view_model.dart'; import 'package:car_provider_app/view_models/dashboard_view_model.dart'; +import 'package:car_provider_app/view_models/items_view_model.dart'; +import 'package:car_provider_app/view_models/schedule_view_model.dart'; +import 'package:car_provider_app/view_models/service_view_model.dart'; +import 'package:car_provider_app/view_models/subscriptions_view_model.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:mc_common_app/classes/app_state.dart'; @@ -42,13 +49,33 @@ Future main() async { ChangeNotifierProvider( create: (_) => UserVM(userRepo: injector.get()), ), - ChangeNotifierProvider( - create: (_) => BranchVM( + // ChangeNotifierProvider( + // create: (_) => BranchVM( + // branchRepo: injector.get(), + // commonServices: injector.get(), + // commonRepo: injector.get(), + // ), + // ), + ChangeNotifierProvider( + create: (_) => ServiceVM( branchRepo: injector.get(), commonServices: injector.get(), commonRepo: injector.get(), ), ), + ChangeNotifierProvider( + create: (_) => SubscriptionsVM(subscriptionRepo: injector.get()), + ), + ChangeNotifierProvider( + create: (_) => ItemsVM( + itemsRepo: injector.get(), + commonServices: injector.get(), + ), + ), + ChangeNotifierProvider( + create: (_) => ScheduleVM(scheduleRepo: injector.get(), + ), + ), ], child: const MyApp(), ).setupLocale()); diff --git a/lib/repositories/branch_repo.dart b/lib/repositories/branch_repo.dart index 0843a95..9405733 100644 --- a/lib/repositories/branch_repo.dart +++ b/lib/repositories/branch_repo.dart @@ -1,9 +1,11 @@ import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; +import 'package:http/http.dart' as http; import 'package:mc_common_app/api/api_client.dart'; import 'package:mc_common_app/classes/app_state.dart'; - import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/config/dependencies.dart'; import 'package:mc_common_app/models/m_response.dart'; @@ -119,6 +121,7 @@ class BranchRepoImp implements BranchRepo { return await injector.get().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.ServiceProviderDocument_Update, map, token: t); } + @override Future getBranchAndServices() async { var postParams = {"serviceProviderID": AppState().getUser.data?.userInfo?.providerId.toString() ?? ""}; @@ -146,7 +149,6 @@ class BranchRepoImp implements BranchRepo { "isActive": isNeedToDelete }; String t = AppState().getUser.data!.accessToken ?? ""; - print("tokeen " + t); return await injector.get().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.updateProviderBranch, postParams, token: t); } diff --git a/lib/repositories/items_repo.dart b/lib/repositories/items_repo.dart new file mode 100644 index 0000000..7063974 --- /dev/null +++ b/lib/repositories/items_repo.dart @@ -0,0 +1,44 @@ +import 'package:car_provider_app/common/item_model.dart'; +import 'package:flutter/material.dart'; +import 'package:mc_common_app/api/api_client.dart'; +import 'package:mc_common_app/classes/app_state.dart'; +import 'package:mc_common_app/classes/consts.dart'; +import 'package:mc_common_app/config/dependencies.dart'; +import 'package:mc_common_app/models/m_response.dart'; + +abstract class ItemsRepo { + Future createServiceItems(Map map); + + Future getServiceItems(int serviceId); + + Future updateServiceItem(Map map); +} + +class ItemsRepoImp implements ItemsRepo { + @override + Future createServiceItems(Map map) async { + String t = AppState().getUser.data!.accessToken ?? ""; + debugPrint(t); + return await injector.get().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.createItems, map, token: t); + } + + @override + Future getServiceItems(int serviceId) async { + var queryParameters = { + "ServiceProviderServiceID": serviceId.toString(), + }; + String? token = AppState().getUser.data?.accessToken; + debugPrint(token); + return await injector + .get() + .getJsonForObject((json) => ItemModel.fromJson(json), ApiConsts.getServiceItems, queryParameters: queryParameters, token: AppState().getUser.data!.accessToken ?? ""); + } + + @override + Future updateServiceItem(Map map) async { + String t = AppState().getUser.data!.accessToken ?? ""; + debugPrint(t); + return await injector.get().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.updateServiceItem, map, token: t); + + } +} diff --git a/lib/repositories/schedule_repo.dart b/lib/repositories/schedule_repo.dart new file mode 100644 index 0000000..ff6e034 --- /dev/null +++ b/lib/repositories/schedule_repo.dart @@ -0,0 +1,43 @@ +import 'package:car_provider_app/common/schedule_model.dart'; +import 'package:mc_common_app/api/api_client.dart'; +import 'package:mc_common_app/classes/app_state.dart'; +import 'package:mc_common_app/classes/consts.dart'; +import 'package:mc_common_app/config/dependencies.dart'; +import 'package:mc_common_app/models/m_response.dart'; +import 'package:mc_common_app/models/profile/services.dart'; + +abstract class ScheduleRepo { + Future getAllServices(); + + Future createSchedule(Map map); + + Future addServicesInSchedule(Map map); + + Future getSchedules(); +} + +class ScheduleRepoImp implements ScheduleRepo { + @override + Future getAllServices() async { + String t = AppState().getUser.data!.accessToken ?? ""; + return await injector.get().getJsonForObject((json) => Services.fromJson(json), ApiConsts.Services_Get, token: t); + } + + @override + Future createSchedule(Map map) async { + String t = AppState().getUser.data!.accessToken ?? ""; + return await injector.get().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.createSchedule, map, token: t); + } + + @override + Future addServicesInSchedule(Map map) async { + String t = AppState().getUser.data!.accessToken ?? ""; + return await injector.get().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.createGroup, map, token: t); + } + + @override + Future getSchedules() async { + String t = AppState().getUser.data!.accessToken ?? ""; + return await injector.get().getJsonForObject((json) => Schedule.fromJson(json), ApiConsts.getSchedule, token: t); + } +} diff --git a/lib/repositories/subscription_repo.dart b/lib/repositories/subscription_repo.dart new file mode 100644 index 0000000..d685127 --- /dev/null +++ b/lib/repositories/subscription_repo.dart @@ -0,0 +1,25 @@ +import 'package:car_provider_app/common/subscription_model.dart'; +import 'package:mc_common_app/api/api_client.dart'; +import 'package:mc_common_app/classes/app_state.dart'; +import 'package:mc_common_app/classes/consts.dart'; +import 'package:mc_common_app/config/dependencies.dart'; +import 'package:mc_common_app/models/m_response.dart'; + +abstract class SubscriptionRepo { + Future getAllSubscriptions(String? serviceProviderID); +} + +class SubscriptionRepoImp extends SubscriptionRepo { + @override + Future getAllSubscriptions(String? serviceProviderID) async { + String t = AppState().getUser.data!.accessToken ?? ""; + Map queryParameters = {}; + if (serviceProviderID != null) { + queryParameters = { + "ID": serviceProviderID, + }; + } + + return await injector.get().getJsonForObject((json) => SubscriptionModel.fromJson(json), ApiConsts.getAllSubscriptions, token: t, queryParameters: queryParameters); + } +} diff --git a/lib/view_models/branch_view_model.dart b/lib/view_models/branch_view_model.dart index e830a6f..ac49869 100644 --- a/lib/view_models/branch_view_model.dart +++ b/lib/view_models/branch_view_model.dart @@ -1,208 +1,218 @@ -import 'dart:io'; - -import 'package:car_provider_app/repositories/branch_repo.dart'; -import 'package:file_picker/file_picker.dart'; -import 'package:mc_common_app/models/m_response.dart'; -import 'package:mc_common_app/models/model/branch2.dart'; -import 'package:mc_common_app/models/profile/branch.dart'; -import 'package:mc_common_app/models/profile/categroy.dart'; -import 'package:mc_common_app/models/profile/document.dart'; -import 'package:mc_common_app/models/profile/services.dart'; -import 'package:mc_common_app/models/user/cities.dart'; -import 'package:mc_common_app/models/user/country.dart'; -import 'package:mc_common_app/repositories/common_repo.dart'; -import 'package:mc_common_app/services/services.dart'; -import 'package:mc_common_app/utils/enums.dart'; -import 'package:mc_common_app/utils/utils.dart'; -import 'package:mc_common_app/view_models/base_view_model.dart'; -import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart'; -import 'package:permission_handler/permission_handler.dart'; - -class BranchVM extends BaseVM { - final BranchRepo branchRepo; - final CommonServices commonServices; - final CommonRepo commonRepo; - - BranchVM({required this.branchRepo, required this.commonServices, required this.commonRepo}); - - Document? document; - Branch2? branchs; - - //Create Branch - String countryCode = "", address = "", branchName = "", branchDescription = ""; - double latitude = 0, longitude = 0; - int role = -1, countryId = -1, cityId = -1; - List countryDropList = []; - List citiesDropList = []; - DropValue? countryValue; - DropValue? cityValue; - - Country? country; - Cities? cities; - - //Create Service - String? branchNameForService; - int categoryId = -1, branchId = -1; - DropValue? branchValue; - - List countryDropListForService = []; - List categoryDropList = []; - - Branch? branch; - Category? category; - Services? services; - - getServiceProviderDocument(int providerId) async { - setState(ViewState.busy); - document = await branchRepo.getServiceProviderDocument(providerId); - setState(ViewState.idle); - } - - selectFile(int index) async { - File? file = await commonServices.pickFile(fileType: FileType.custom, allowedExtensions: ['png', 'pdf', 'jpeg']); - - if (file != null) { - int sizeInBytes = file.lengthSync(); - // double sizeInMb = sizeInBytes / (1024 * 1024); - if (sizeInBytes > 1000) { - Utils.showToast("File is larger then 1KB"); - } else { - document!.data![index].document = Utils.convertFileToBase64(file); - document!.data![index].fileExt = Utils.checkFileExt(file.path); - document!.data![index].documentUrl = file.path; - setState(ViewState.idle); - } - } else { - // User canceled the picker - } - } - - Future updateDocument(List? data) async { - return await branchRepo.serviceProviderDocumentsUpdate(data); - } - - //Create new branch - getBranchAndServices() async { - setState(ViewState.busy); - branchs = await branchRepo.getBranchAndServices(); - setState(ViewState.idle); - } - - getAllCountriesList(ServiceProviderBranch? branchData, String countryCode) async { - setState(ViewState.busy); - resetValues(); - country = await commonRepo.getAllCountries(); - country!.data?.forEach((element) { - if (branchData != null) if (branchData.id != null) { - if (element.id == branchData.countryID) { - countryValue = DropValue(element.id ?? 0, countryCode == "SA" ? (element.countryNameN ?? "") : (element.countryName ?? ""), element.countryCode ?? ""); - } - } - countryDropList.add(DropValue(element.id ?? 0, countryCode == "SA" ? (element.countryNameN ?? "") : (element.countryName ?? ""), element.countryCode ?? "")); - }); - if (branchData != null) if (branchData.id != null) getAllCities(branchData, countryCode); - setState(ViewState.idle); - } - - getAllCities(ServiceProviderBranch? branchData, String countryCode) async { - setState(ViewState.busy); - citiesDropList.clear(); - cities = null; - cityId = -1; - cities = await commonRepo.getAllCites(countryId.toString()); - cities!.data?.forEach((element) { - if (branchData != null && branchData.id != null) { - if (element.id == branchData.cityId) { - address = branchData.address!; - branchName = branchData.branchName!; - branchDescription = branchData.branchDescription!; - latitude = double.parse(branchData.latitude ?? ""); - longitude = double.parse(branchData.longitude ?? ""); - countryId = branchData.countryID!; - cityId = branchData.cityId!; - cityValue = DropValue(element.id ?? 0, countryCode == "SA" ? (element.cityNameN ?? "") : (element.cityName ?? ""), element.id.toString() ?? ""); - } - } - citiesDropList.add(DropValue(element.id ?? 0, countryCode == "SA" ? (element.cityNameN ?? "") : (element.cityName ?? ""), element.id.toString() ?? "")); - }); - setState(ViewState.idle); - } - - resetValues() { - countryCode = ""; - address = ""; - branchName = ""; - branchDescription = ""; - latitude = 0; - longitude = 0; - role = -1; - countryId = -1; - cityId = -1; - countryDropList.clear(); - countryId = -1; - cityId = -1; - cities = null; - branchNameForService = null; - categoryId = -1; - branchId = -1; - branchValue = null; - - countryDropListForService = []; - categoryDropList = []; - - branch = null; - category = null; - services = null; - } - - Future createBranch(String branchName, String branchDescription, String cityId, String address, String latitude, String longitude) async { - return await branchRepo.createBranch(branchName, branchDescription, cityId.toString(), address, latitude.toString(), longitude.toString()); - } - - Future updateBranch(int id, String branchName, String branchDescription, String cityId, String address, String latitude, String longitude, {bool isNeedToDelete = true}) async { - return await branchRepo.updateBranch(id ?? 0, branchName, branchDescription, cityId.toString(), address, latitude.toString(), longitude.toString()); - } - - //Create Service - - fetchBranches() async { - resetValues(); - setState(ViewState.busy); - branch = await branchRepo.fetchAllBranches(); - branch!.data?.forEach((element) { - countryDropListForService.add(DropValue(element.id ?? 0, ((element.branchName!.isEmpty ? "N/A" : element.branchName) ?? "N/A"), "")); - }); - setState(ViewState.idle); - } - - fetchBranchCategory(String countryCode) async { - setState(ViewState.busy); - category = await branchRepo.fetchBranchCategory(); - category!.data?.forEach((element) { - categoryDropList.add(DropValue( - element.id ?? 0, - ((element.categoryName!.isEmpty - ? "N/A" - : countryCode == "SA" - ? element.categoryNameN - : element.categoryName) ?? - "N/A"), - "")); - }); - setState(ViewState.idle); - } - - fetchServicesByCategoryId() async { - setState(ViewState.busy); - services = await branchRepo.fetchServicesByCategoryId(categoryId.toString()); - setState(ViewState.idle); - } - - Future createService(List> map) async { - return await branchRepo.createService(map); - } - - Future updateServices(List> map) async { - return await branchRepo.updateService(map); - } -} +// import 'dart:io'; +// +// import 'package:car_provider_app/repositories/branch_repo.dart'; +// import 'package:file_picker/file_picker.dart'; +// import 'package:mc_common_app/models/m_response.dart'; +// import 'package:mc_common_app/models/model/branch2.dart'; +// import 'package:mc_common_app/models/profile/branch.dart'; +// import 'package:mc_common_app/models/profile/categroy.dart'; +// import 'package:mc_common_app/models/profile/document.dart'; +// import 'package:mc_common_app/models/profile/services.dart'; +// import 'package:mc_common_app/models/user/cities.dart'; +// import 'package:mc_common_app/models/user/country.dart'; +// import 'package:mc_common_app/repositories/common_repo.dart'; +// import 'package:mc_common_app/services/services.dart'; +// import 'package:mc_common_app/utils/enums.dart'; +// import 'package:mc_common_app/utils/utils.dart'; +// import 'package:mc_common_app/view_models/base_view_model.dart'; +// import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart'; +// import 'package:permission_handler/permission_handler.dart'; +// +// class BranchVM extends BaseVM { +// final BranchRepo branchRepo; +// final CommonServices commonServices; +// final CommonRepo commonRepo; +// +// BranchVM({required this.branchRepo, required this.commonServices, required this.commonRepo}); +// +// Document? document; +// Branch2? branchs; +// +// //Create Branch +// String countryCode = "", address = "", branchName = "", branchDescription = ""; +// double latitude = 0, longitude = 0; +// int role = -1, countryId = -1, cityId = -1; +// List countryDropList = []; +// List citiesDropList = []; +// DropValue? countryValue; +// DropValue? cityValue; +// +// Country? country; +// Cities? cities; +// +// //Create Service +// String? branchNameForService; +// int categoryId = -1, branchId = -1, serviceId = -1; +// DropValue? branchValue; +// +// List countryDropListForService = []; +// List categoryDropList = []; +// List servicesDropList = []; +// +// Branch? branch; +// Category? category; +// Services? services; +// +// getServiceProviderDocument(int providerId) async { +// setState(ViewState.busy); +// document = await branchRepo.getServiceProviderDocument(providerId); +// setState(ViewState.idle); +// } +// +// selectFile(int index) async { +// File? file = await commonServices.pickFile(fileType: FileType.custom, allowedExtensions: ['png', 'pdf', 'jpeg']); +// +// if (file != null) { +// int sizeInBytes = file.lengthSync(); +// // double sizeInMb = sizeInBytes / (1024 * 1024); +// if (sizeInBytes > 1000) { +// Utils.showToast("File is larger then 1KB"); +// } else { +// document!.data![index].document = Utils.convertFileToBase64(file); +// document!.data![index].fileExt = Utils.checkFileExt(file.path); +// document!.data![index].documentUrl = file.path; +// setState(ViewState.idle); +// } +// } else { +// // User canceled the picker +// } +// } +// +// Future updateDocument(List? data) async { +// return await branchRepo.serviceProviderDocumentsUpdate(data); +// } +// +// //Create new branch +// getBranchAndServices() async { +// setState(ViewState.busy); +// branchs = await branchRepo.getBranchAndServices(); +// setState(ViewState.idle); +// } +// +// getAllCountriesList(ServiceProviderBranch? branchData, String countryCode) async { +// setState(ViewState.busy); +// resetValues(); +// country = await commonRepo.getAllCountries(); +// country!.data?.forEach((element) { +// if (branchData != null) if (branchData.id != null) { +// if (element.id == branchData.countryID) { +// countryValue = DropValue(element.id ?? 0, countryCode == "SA" ? (element.countryNameN ?? "") : (element.countryName ?? ""), element.countryCode ?? ""); +// } +// } +// countryDropList.add(DropValue(element.id ?? 0, countryCode == "SA" ? (element.countryNameN ?? "") : (element.countryName ?? ""), element.countryCode ?? "")); +// }); +// if (branchData != null) if (branchData.id != null) getAllCities(branchData, countryCode); +// setState(ViewState.idle); +// } +// +// getAllCities(ServiceProviderBranch? branchData, String countryCode) async { +// setState(ViewState.busy); +// citiesDropList.clear(); +// cities = null; +// cityId = -1; +// cities = await commonRepo.getAllCites(countryId.toString()); +// cities!.data?.forEach((element) { +// if (branchData != null && branchData.id != null) { +// if (element.id == branchData.cityId) { +// address = branchData.address!; +// branchName = branchData.branchName!; +// branchDescription = branchData.branchDescription!; +// latitude = double.parse(branchData.latitude ?? ""); +// longitude = double.parse(branchData.longitude ?? ""); +// countryId = branchData.countryID!; +// cityId = branchData.cityId!; +// cityValue = DropValue(element.id ?? 0, countryCode == "SA" ? (element.cityNameN ?? "") : (element.cityName ?? ""), element.id.toString() ?? ""); +// } +// } +// citiesDropList.add(DropValue(element.id ?? 0, countryCode == "SA" ? (element.cityNameN ?? "") : (element.cityName ?? ""), element.id.toString() ?? "")); +// }); +// setState(ViewState.idle); +// } +// +// resetValues() { +// countryCode = ""; +// address = ""; +// branchName = ""; +// branchDescription = ""; +// latitude = 0; +// longitude = 0; +// role = -1; +// countryId = -1; +// cityId = -1; +// countryDropList.clear(); +// countryId = -1; +// cityId = -1; +// cities = null; +// branchNameForService = null; +// categoryId = -1; +// branchId = -1; +// branchValue = null; +// serviceId = -1; +// +// countryDropListForService = []; +// categoryDropList = []; +// servicesDropList = []; +// +// branch = null; +// category = null; +// services = null; +// } +// +// Future createBranch(String branchName, String branchDescription, String cityId, String address, String latitude, String longitude) async { +// return await branchRepo.createBranch(branchName, branchDescription, cityId.toString(), address, latitude.toString(), longitude.toString()); +// } +// +// Future updateBranch(int id, String branchName, String branchDescription, String cityId, String address, String latitude, String longitude, {bool isNeedToDelete = true}) async { +// return await branchRepo.updateBranch(id ?? 0, branchName, branchDescription, cityId.toString(), address, latitude.toString(), longitude.toString()); +// } +// +// //Create Service +// fetchBranches() async { +// resetValues(); +// setState(ViewState.busy); +// branch = await branchRepo.fetchAllBranches(); +// branch!.data?.forEach((element) { +// countryDropListForService.add(DropValue(element.id ?? 0, ((element.branchName!.isEmpty ? "N/A" : element.branchName) ?? "N/A"), "")); +// }); +// setState(ViewState.idle); +// } +// +// fetchBranchCategory(String countryCode) async { +// category = null; +// services = null; +// categoryId = -1; +// categoryDropList.clear(); +// setState(ViewState.busy); +// category = await branchRepo.fetchBranchCategory(); +// category!.data?.forEach((element) { +// categoryDropList.add(DropValue( +// element.id ?? 0, +// ((element.categoryName!.isEmpty +// ? "N/A" +// : countryCode == "SA" +// ? element.categoryNameN +// : element.categoryName) ?? +// "N/A"), +// "")); +// }); +// setState(ViewState.idle); +// } +// +// fetchServicesByCategoryId() async { +// setState(ViewState.busy); +// services = await branchRepo.fetchServicesByCategoryId(categoryId.toString()); +// servicesDropList = []; +// for (var element in services!.data!) { +// servicesDropList.add(DropValue(element.id ?? 0, element.description ?? "N/aA", "")); +// } +// setState(ViewState.idle); +// } +// +// Future createService(List> map) async { +// return await branchRepo.createService(map); +// } +// +// Future updateServices(List> map) async { +// return await branchRepo.updateService(map); +// } +// } diff --git a/lib/view_models/items_view_model.dart b/lib/view_models/items_view_model.dart new file mode 100644 index 0000000..29bacfc --- /dev/null +++ b/lib/view_models/items_view_model.dart @@ -0,0 +1,54 @@ +import 'dart:io'; + +import 'package:car_provider_app/common/item_model.dart'; +import 'package:car_provider_app/repositories/items_repo.dart'; +import 'package:mc_common_app/models/m_response.dart'; +import 'package:mc_common_app/services/services.dart'; +import 'package:mc_common_app/utils/enums.dart'; +import 'package:mc_common_app/utils/utils.dart'; +import 'package:mc_common_app/view_models/base_view_model.dart'; +import 'package:file_picker/file_picker.dart'; + +class ItemsVM extends BaseVM { + final ItemsRepo itemsRepo; + final CommonServices commonServices; + + ItemsVM({required this.itemsRepo, required this.commonServices}); + + //Items + ItemModel? serviceItems; + + Future selectFile() async { + File? file = await commonServices.pickFile(fileType: FileType.image); + + if (file != null) { + int sizeInBytes = file.lengthSync(); + // double sizeInMb = sizeInBytes / (1024 * 1024); + if (sizeInBytes > 1000) { + Utils.showToast("File is larger then 1KB"); + } else { + return Utils.convertFileToBase64(file); + } + } else { + // User canceled the picker + } + return null; + } + + Future createServiceItem(Map map) async { + MResponse response = await itemsRepo.createServiceItems(map); + return response; + } + + Future getServiceItems(int serviceId) async { + setState(ViewState.busy); + serviceItems = await itemsRepo.getServiceItems(serviceId); + setState(ViewState.idle); + return serviceItems; + } + + Future updateServiceItem(Map map) async { + MResponse response = await itemsRepo.updateServiceItem(map); + return response; + } +} diff --git a/lib/view_models/schedule_view_model.dart b/lib/view_models/schedule_view_model.dart new file mode 100644 index 0000000..3e05e7d --- /dev/null +++ b/lib/view_models/schedule_view_model.dart @@ -0,0 +1,94 @@ +import 'package:car_provider_app/common/schedule_model.dart'; +import 'package:car_provider_app/repositories/schedule_repo.dart'; +import 'package:car_provider_app/views/settings/schedule/widgets/chips_picker_item.dart'; +import 'package:mc_common_app/models/m_response.dart'; +import 'package:mc_common_app/models/profile/services.dart'; +import 'package:mc_common_app/utils/enums.dart'; +import 'package:mc_common_app/view_models/base_view_model.dart'; + +class ScheduleVM extends BaseVM { + ScheduleRepo scheduleRepo; + + ScheduleVM({required this.scheduleRepo}); + + List selectedServicesItems = []; + List? servicesList; + List selectedDaysItems = []; + Schedule? schedule; + + refresh() { + setState(ViewState.idle); + } + + getAllServices() async { + if (servicesList == null) { + Services services = await scheduleRepo.getAllServices(); + if (services.messageStatus == 1) { + servicesList = services.data; + } + setState(ViewState.idle); + } + } + + filterSelectedServices() { + if (servicesList != null) { + selectedServicesItems = []; + for (var element in servicesList!) { + if (element.isSelected ?? false) { + selectedServicesItems.add(PickerItem(id: element.id ?? 0, title: element.description ?? "")); + } + } + setState(ViewState.idle); + } + } + + //Days + List intiDays() { + List initDays = [ + PickerItem(id: 1, title: "Monday", isSelected: false), + PickerItem(id: 2, title: "Tuesday", isSelected: false), + PickerItem(id: 3, title: "Wednesday", isSelected: false), + PickerItem(id: 4, title: "Thursday", isSelected: false), + PickerItem(id: 5, title: "Friday", isSelected: false), + PickerItem(id: 6, title: "Saturday", isSelected: false), + PickerItem(id: 7, title: "Sunday", isSelected: false), + ]; + if (selectedDaysItems.isNotEmpty) { + for (var element in selectedDaysItems) { + if (element.isSelected ?? false) { + for (var innerElement in initDays) { + if (element.id == innerElement.id) { + innerElement.isSelected = true; + } + } + } + } + } + return initDays; + } + + filterDays(List picked) { + selectedDaysItems = []; + for (var element in picked) { + if (element.isSelected ?? false) { + selectedDaysItems.add(element); + } + } + setState(ViewState.idle); + } + + Future createSchedule(Map map) async { + MResponse response = await scheduleRepo.createSchedule(map); + return response; + } + + Future addServicesInSchedule(Map map) async { + MResponse response = await scheduleRepo.addServicesInSchedule(map); + return response; + } + + getSchedules() async { + schedule = await scheduleRepo.getSchedules(); + setState(ViewState.idle); + } +} diff --git a/lib/view_models/service_view_model.dart b/lib/view_models/service_view_model.dart new file mode 100644 index 0000000..67644e7 --- /dev/null +++ b/lib/view_models/service_view_model.dart @@ -0,0 +1,185 @@ +import 'dart:io'; + +import 'package:car_provider_app/repositories/branch_repo.dart'; +import 'package:mc_common_app/models/m_response.dart'; +import 'package:mc_common_app/models/model/branch2.dart'; +import 'package:mc_common_app/models/profile/categroy.dart'; +import 'package:mc_common_app/models/profile/document.dart'; +import 'package:mc_common_app/models/profile/services.dart'; +import 'package:mc_common_app/models/user/cities.dart'; +import 'package:mc_common_app/models/user/country.dart'; +import 'package:mc_common_app/repositories/common_repo.dart'; +import 'package:mc_common_app/services/services.dart'; +import 'package:mc_common_app/utils/enums.dart'; +import 'package:mc_common_app/utils/utils.dart'; +import 'package:mc_common_app/view_models/base_view_model.dart'; +import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart'; +import 'package:file_picker/file_picker.dart'; + +class ServiceVM extends BaseVM { + final BranchRepo branchRepo; + final CommonServices commonServices; + final CommonRepo commonRepo; + + ServiceVM({required this.branchRepo, required this.commonServices, required this.commonRepo}); + + //Documents & Branches + Document? document; + Branch2? branchs; + Country? country; + Cities? cities; + DropValue? countryValue; + DropValue? cityValue; + List countryDropList = []; + List citiesDropList = []; + double latitude = 0, longitude = 0; + int role = -1, countryId = -1, cityId = -1; + String countryCode = "", address = "", branchName = "", branchDescription = ""; + + getServiceProviderDocument(int providerId) async { + setState(ViewState.busy); + document = await branchRepo.getServiceProviderDocument(providerId); + setState(ViewState.idle); + } + + selectFile(int index) async { + File? file = await commonServices.pickFile(fileType: FileType.custom, allowedExtensions: ['png', 'pdf', 'jpeg']); + + if (file != null) { + int sizeInBytes = file.lengthSync(); + // double sizeInMb = sizeInBytes / (1024 * 1024); + if (sizeInBytes > 1000) { + Utils.showToast("File is larger then 1KB"); + } else { + document!.data![index].document = Utils.convertFileToBase64(file); + document!.data![index].fileExt = Utils.checkFileExt(file.path); + document!.data![index].documentUrl = file.path; + setState(ViewState.idle); + } + } else { + // User canceled the picker + } + } + + Future updateDocument(List? data) async { + return await branchRepo.serviceProviderDocumentsUpdate(data); + } + + //Create new branch + getBranchAndServices() async { + setState(ViewState.busy); + branchs = await branchRepo.getBranchAndServices(); + setState(ViewState.idle); + } + + getAllCountriesList(ServiceProviderBranch? branchData, String countryCode) async { + setState(ViewState.busy); + resetValues(); + country = await commonRepo.getAllCountries(); + country!.data?.forEach((element) { + if (branchData != null) if (branchData.id != null) { + if (element.id == branchData.countryID) { + countryValue = DropValue(element.id ?? 0, countryCode == "SA" ? (element.countryNameN ?? "") : (element.countryName ?? ""), element.countryCode ?? ""); + } + } + countryDropList.add(DropValue(element.id ?? 0, countryCode == "SA" ? (element.countryNameN ?? "") : (element.countryName ?? ""), element.countryCode ?? "")); + }); + if (branchData != null) if (branchData.id != null) getAllCities(branchData, countryCode); + setState(ViewState.idle); + } + + getAllCities(ServiceProviderBranch? branchData, String countryCode) async { + setState(ViewState.busy); + citiesDropList.clear(); + cities = null; + cityId = -1; + cities = await commonRepo.getAllCites(countryId.toString()); + cities!.data?.forEach((element) { + if (branchData != null && branchData.id != null) { + if (element.id == branchData.cityId) { + address = branchData.address!; + branchName = branchData.branchName!; + branchDescription = branchData.branchDescription!; + latitude = double.parse(branchData.latitude ?? ""); + longitude = double.parse(branchData.longitude ?? ""); + countryId = branchData.countryID!; + cityId = branchData.cityId!; + cityValue = DropValue(element.id ?? 0, countryCode == "SA" ? (element.cityNameN ?? "") : (element.cityName ?? ""), element.id.toString() ?? ""); + } + } + citiesDropList.add(DropValue(element.id ?? 0, countryCode == "SA" ? (element.cityNameN ?? "") : (element.cityName ?? ""), element.id.toString() ?? "")); + }); + setState(ViewState.idle); + } + + Future createBranch(String branchName, String branchDescription, String cityId, String address, String latitude, String longitude) async { + return await branchRepo.createBranch(branchName, branchDescription, cityId.toString(), address, latitude.toString(), longitude.toString()); + } + + Future updateBranch(int id, String branchName, String branchDescription, String cityId, String address, String latitude, String longitude, {bool isNeedToDelete = true}) async { + return await branchRepo.updateBranch(id ?? 0, branchName, branchDescription, cityId.toString(), address, latitude.toString(), longitude.toString()); + } + + resetValues() { + countryCode = ""; + address = ""; + branchName = ""; + branchDescription = ""; + latitude = 0; + longitude = 0; + role = -1; + countryId = -1; + cityId = -1; + countryDropList.clear(); + countryId = -1; + cityId = -1; + cities = null; + categoryDropList = []; + servicesDropList = []; + services = null; + } + + //Create Services + Services? services; + List categoryDropList = []; + List servicesDropList = []; + + fetchBranchCategory(String countryCode) async { + categoryDropList.clear(); + servicesDropList = []; + services = null; + setState(ViewState.busy); + Category? category = await branchRepo.fetchBranchCategory(); + category.data?.forEach((element) { + categoryDropList.add(DropValue( + element.id ?? 0, + ((element.categoryName!.isEmpty + ? "N/A" + : countryCode == "SA" + ? element.categoryNameN + : element.categoryName) ?? + "N/A"), + "")); + }); + setState(ViewState.idle); + } + + fetchServicesByCategoryId(String categoryId) async { + servicesDropList = []; + setState(ViewState.busy); + services = await branchRepo.fetchServicesByCategoryId(categoryId); + + for (var element in services!.data!) { + servicesDropList.add(DropValue(element.id ?? 0, element.description ?? "N/aA", "")); + } + setState(ViewState.idle); + } + + Future createService(List> map) async { + return await branchRepo.createService(map); + } + + Future updateServices(List> map) async { + return await branchRepo.updateService(map); + } +} diff --git a/lib/view_models/subscriptions_view_model.dart b/lib/view_models/subscriptions_view_model.dart new file mode 100644 index 0000000..3609798 --- /dev/null +++ b/lib/view_models/subscriptions_view_model.dart @@ -0,0 +1,73 @@ +import 'package:car_provider_app/common/subscription_model.dart'; +import 'package:car_provider_app/repositories/subscription_repo.dart'; +import 'package:mc_common_app/utils/enums.dart'; +import 'package:mc_common_app/view_models/base_view_model.dart'; +import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart'; + +class SubscriptionsVM extends BaseVM { + final SubscriptionRepo subscriptionRepo; + + SubscriptionsVM({required this.subscriptionRepo}); + + //All Subscriptions + int selectedIndex = 0; + late DropValue selectedMothlyTab; + List monthlyTabs = []; + late SubscriptionModel allSubscriptions; + List tempSubscriptions = []; + + //My Subscriptions + + //All Subscriptions + getAllAvailableSubscriptions(String? serviceProviderID) async { + selectedIndex = 0; + setState(ViewState.busy); + allSubscriptions = await subscriptionRepo.getAllSubscriptions(serviceProviderID); + if (allSubscriptions.messageStatus == 1) { + monthlyTabs.clear(); + var idSet = {}; + for (var d in allSubscriptions.data ?? []) { + if (idSet.add(d.durationDays ?? 0)) { + monthlyTabs.add(DropValue(d.durationDays, _convertDaysToMonths(d.durationDays ?? 0), "")); + } + } + monthlyTabs.sort((a, b) => a.value.compareTo(b.value)); + selectedMothlyTab = monthlyTabs.first; + filterSubscriptions(); + setState(ViewState.idle); + } else { + setState(ViewState.error); + } + } + + String _convertDaysToMonths(int days) { + final int months = days ~/ 30; + final int remainingDays = days % 30; + + String _result = months > 0 ? '$months Month${months > 1 ? 's' : ''}${remainingDays > 0 ? ' & ' : ''}' : ''; + _result += remainingDays > 0 ? '$remainingDays Day${remainingDays > 1 ? 's' : ''}' : ''; + return _result; + } + + filterSubscriptions() { + tempSubscriptions.clear(); + for (var element in allSubscriptions.data!) { + if (selectedMothlyTab.id == element.durationDays) { + tempSubscriptions.add(element); + } + } + } + +//My Subscriptions + getMySubscriptions(String? serviceProviderID) async { + selectedIndex = 0; + setState(ViewState.busy); + allSubscriptions = await subscriptionRepo.getAllSubscriptions(serviceProviderID); + if (allSubscriptions.messageStatus == 1) { + // allSubscriptions.data!.sort((a, b) => a.value.compareTo(b.value)); + setState(ViewState.idle); + } else { + setState(ViewState.error); + } + } +} diff --git a/lib/views/dashboard/fragments/home_fragment.dart b/lib/views/dashboard/fragments/home_fragment.dart index d77ef82..2552527 100644 --- a/lib/views/dashboard/fragments/home_fragment.dart +++ b/lib/views/dashboard/fragments/home_fragment.dart @@ -3,7 +3,7 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/theme/colors.dart'; -import 'package:mc_common_app/widgets/common_widgets/ad_widget.dart'; + import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; import 'package:mc_common_app/widgets/common_widgets/my_service_provider.dart'; import 'package:mc_common_app/widgets/common_widgets/view_all_widget.dart'; @@ -13,7 +13,8 @@ import '../widget/appointment_slider_widget.dart'; class HomeFragment extends StatelessWidget { VoidCallback onTap; - HomeFragment({required this.onTap,Key? key}) : super(key: key); + + HomeFragment({required this.onTap, Key? key}) : super(key: key); @override Widget build(BuildContext context) { @@ -52,25 +53,28 @@ class HomeFragment extends StatelessWidget { padding: const EdgeInsets.only(top: 8, left: 21, right: 21, bottom: 21), child: Column( children: [ - const ViewAllWidget( + ViewAllWidget( title: 'Upcoming Appointment', subTitle: 'View All', + onSubtitleTapped: () {}, ), const AppointmentSliderWidget(), 21.height, - const ViewAllWidget( + ViewAllWidget( title: 'My Branches', subTitle: 'View All', + onSubtitleTapped: () {}, ), const ServiceProviderWidget(), 21.height, - const ViewAllWidget( + ViewAllWidget( title: 'Recommended Ads', subTitle: 'View All', + onSubtitleTapped: () {}, ), - const AdWidget( - count: 4, - ), + // const AdWidget( + // count: 4, + // ), ], ), ), diff --git a/lib/views/settings/branch/branch_detail_page.dart b/lib/views/settings/branch/branch_detail_page.dart index 110c85f..959abe9 100644 --- a/lib/views/settings/branch/branch_detail_page.dart +++ b/lib/views/settings/branch/branch_detail_page.dart @@ -1,4 +1,6 @@ import 'package:car_provider_app/config/provider_routes.dart'; +import 'package:car_provider_app/view_models/service_view_model.dart'; +import 'package:car_provider_app/views/settings/services/services_list_page.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; @@ -14,14 +16,12 @@ import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/utils/navigator.dart'; import 'package:mc_common_app/widgets/button/show_fill_button.dart'; import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; - +import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:provider/provider.dart'; - import '../../../generated/locale_keys.g.dart'; - class BranchDetailPage extends StatelessWidget { ServiceProviderBranch branchData; @@ -52,9 +52,9 @@ class BranchDetailPage extends StatelessWidget { branchData.categories = categories; return Scaffold( appBar: CustomAppBar( - title: LocaleKeys.branchName.tr(), + title: branchData.branchName.toString(), ), - body: Consumer(builder: (context, model, _) { + body: Consumer(builder: (context, model, _) { return SizedBox( width: double.infinity, height: double.infinity, @@ -62,71 +62,160 @@ class BranchDetailPage extends StatelessWidget { children: [ Expanded( child: SingleChildScrollView( - padding: EdgeInsets.all(20), child: Column( children: [ - Row( - children: [ - Expanded( - child: titleWidget(MyAssets.icBranches, LocaleKeys.branchInfo), - ), - IconButton( - onPressed: () { - navigateWithName(context, ProviderAppRoutes.defineBranch, arguments: branchData); - }, - icon: const Icon( - Icons.edit, + Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + children: [ + Row( + children: [ + Expanded( + child: titleWidget(MyAssets.icBranches, LocaleKeys.branchInfo.tr()), + ), + IconButton( + onPressed: () { + navigateWithName(context, ProviderAppRoutes.defineBranch, arguments: branchData); + }, + icon: SvgPicture.asset(MyAssets.icEdit), + ) + ], ), - ) - ], - ), - 8.height, - Column( - children: [ - showData("${LocaleKeys.country.tr()}:", branchData.countryName.toString()), - showData("${LocaleKeys.city.tr()}:", branchData.cityName.toString()), - showData("${LocaleKeys.branchName.tr()}:", branchData.branchName.toString()), - showData("${LocaleKeys.branchDescription.tr()}:", branchData.branchDescription.toString()), - showData("${LocaleKeys.address.tr()}:", branchData.address.toString()), - ], + Column( + children: [ + showData("${LocaleKeys.country.tr()}:", branchData.countryName.toString()), + showData("${LocaleKeys.city.tr()}:", branchData.cityName.toString()), + showData("${LocaleKeys.branchName.tr()}:", branchData.branchName.toString()), + showData("${LocaleKeys.branchDescription.tr()}:", branchData.branchDescription.toString()), + showData("${LocaleKeys.address.tr()}:", branchData.address.toString()), + ], + ), + ], + ), ), Container( width: double.infinity, - height: 1, - color: Colors.grey, - margin: EdgeInsets.symmetric(vertical: 12), - ), + color: MyColors.darkIconColor, + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 8), + child: Row( + children: [ + const Icon( + Icons.calendar_month, + color: Colors.white, + ), + 8.width, + Expanded( + child: "Set or Edit Branch Schedule".toText( + isUnderLine: true, + fontSize: 14, + isBold: true, + color: Colors.white, + ), + ), + const Icon( + Icons.arrow_forward, + size: 20, + color: Colors.white, + ), + ], + ), + ).onPress(() { + navigateWithName(context, ProviderAppRoutes.schedulesList, arguments: branchData.id.toString()); + }), categories.isEmpty ? LocaleKeys.no_branch.tr().toText(fontSize: 12) - : ListView.builder( + : ListView.separated( itemBuilder: (context, pIndex) { - return Container( - width: double.infinity, - child: Column( + return InkWell( + onTap: () { + categories[pIndex].branchId = branchData.id.toString(); + categories[pIndex].branchName = branchData.branchName.toString(); + navigateWithName(context, ProviderAppRoutes.servicesList, arguments: categories[pIndex]); + }, + child: Row( crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.min, children: [ - categories[pIndex].categoryName.toString().toText(fontSize: 16, isBold: true), - ListView.builder( - itemBuilder: (context, index) { - return Container( - child: - ("- ${EasyLocalization.of(context)?.currentLocale?.countryCode == "SA" ? categories[pIndex].services![index].serviceNameN.toString() : categories[pIndex].services![index].serviceName.toString()}") - .toText(fontSize: 14), - ); - }, - itemCount: categories[pIndex].services?.length, - physics: NeverScrollableScrollPhysics(), - shrinkWrap: true, - ) + Padding( + padding: const EdgeInsets.only(top: 5), + child: SvgPicture.asset( + MyAssets.maintenanceIcon, + width: 16, + height: 16, + ), + ), + 8.width, + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Row( + children: [ + categories[pIndex].categoryName.toString().toText(fontSize: 16, isBold: true), + // Padding( + // padding: const EdgeInsets.all(4.0), + // child: SvgPicture.asset( + // MyAssets.icEdit, + // width: 16, + // height: 16, + // ), + // ), + ], + mainAxisAlignment: MainAxisAlignment.spaceBetween, + ), + Row( + children: [ + Expanded( + child: ListView.builder( + itemBuilder: (context, index) { + return Container( + child: (EasyLocalization.of(context)?.currentLocale?.countryCode == "SA" + ? categories[pIndex].services![index].serviceNameN.toString() + : categories[pIndex].services![index].serviceName.toString()) + .toText( + fontSize: 12, + color: MyColors.lightTextColor, + isBold: true, + ), + ); + }, + itemCount: categories[pIndex].services?.length, + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + padding: EdgeInsets.zero, + ), + ), + const Padding( + padding: EdgeInsets.all(4.0), + child: Icon( + Icons.arrow_forward, + size: 20, + ), + ), + ], + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.end, + ) + ], + )), ], + ).toContainer( + width: double.infinity, + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + isShadowEnabled: true, ), ); }, itemCount: categories.length, - physics: NeverScrollableScrollPhysics(), + physics: const NeverScrollableScrollPhysics(), shrinkWrap: true, + padding: const EdgeInsets.all(20), + separatorBuilder: (BuildContext context, int index) { + return 12.height; + }, ), + 12.height, ], ), ), @@ -139,13 +228,16 @@ class BranchDetailPage extends StatelessWidget { Padding( padding: const EdgeInsets.all(12.0), child: ShowFillButton( - title: LocaleKeys.editServices, + title: "Add Services", maxWidth: double.infinity, onPressed: () { navigateWithName( context, - ProviderAppRoutes.createServices, - arguments: branchData, + ProviderAppRoutes.createServices3, + arguments: CreateBranchModel( + branchId: branchData.id.toString(), + branchName: branchData.branchName.toString(), + ), ); }, ), @@ -174,12 +266,15 @@ class BranchDetailPage extends StatelessWidget { Widget showData(String title, String value) { return Row( + crossAxisAlignment: CrossAxisAlignment.start, children: [ title.toText(fontSize: 10, color: Colors.black, isBold: true), 8.width, - value.toText( - fontSize: 12, - color: MyColors.textColor, + Flexible( + child: value.toText( + fontSize: 12, + color: MyColors.textColor, + ), ) ], ); diff --git a/lib/views/settings/branch/branch_list_page.dart b/lib/views/settings/branch/branch_list_page.dart index d91b35e..00ae035 100644 --- a/lib/views/settings/branch/branch_list_page.dart +++ b/lib/views/settings/branch/branch_list_page.dart @@ -1,4 +1,5 @@ import 'package:car_provider_app/config/provider_routes.dart'; +import 'package:car_provider_app/view_models/service_view_model.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; @@ -29,7 +30,7 @@ class BranchListPage extends StatelessWidget { @override Widget build(BuildContext context) { - BranchVM branchVM = context.read(); + ServiceVM branchVM = context.read(); branchVM.getBranchAndServices(); return Scaffold( appBar: !isNeedAppBar @@ -49,7 +50,7 @@ class BranchListPage extends StatelessWidget { body: SizedBox( width: double.infinity, height: double.infinity, - child: Consumer( + child: Consumer( builder: (context, model, _) { if (model.state == ViewState.busy) { return const Center(child: CircularProgressIndicator()); diff --git a/lib/views/settings/branch/define_branch_page.dart b/lib/views/settings/branch/define_branch_page.dart index c703d74..8d9d9ba 100644 --- a/lib/views/settings/branch/define_branch_page.dart +++ b/lib/views/settings/branch/define_branch_page.dart @@ -1,4 +1,5 @@ import 'package:car_provider_app/generated/locale_keys.g.dart'; +import 'package:car_provider_app/view_models/service_view_model.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; @@ -19,8 +20,6 @@ import 'package:mc_common_app/widgets/txt_field.dart'; import 'package:provider/provider.dart'; - - class DefineBranchPage extends StatelessWidget { ServiceProviderBranch? branchData; @@ -28,11 +27,13 @@ class DefineBranchPage extends StatelessWidget { @override Widget build(BuildContext context) { - BranchVM branchVM = context.read(); + ServiceVM branchVM = context.read(); branchVM.getAllCountriesList(branchData, EasyLocalization.of(context)?.currentLocale?.countryCode ?? "SA"); return Scaffold( - appBar: const CustomAppBar(), - body: Consumer(builder: (context, model, _) { + appBar: CustomAppBar( + title: LocaleKeys.defineBranches.tr(), + ), + body: Consumer(builder: (context, model, _) { return SizedBox( width: double.infinity, height: double.infinity, @@ -44,12 +45,8 @@ class DefineBranchPage extends StatelessWidget { padding: const EdgeInsets.all(20.0), child: Column( children: [ - LocaleKeys.defineBranches.tr().toText(fontSize: 20, isBold: true), - 12.height, - LocaleKeys.branchLocation.tr().toText(fontSize: 14, color: MyColors.lightTextColor), - 20.height, - LocaleKeys.chooseCountry.tr().toText(fontSize: 14, color: MyColors.lightTextColor), - 8.height, + // LocaleKeys.chooseCountry.tr().toText(fontSize: 14, color: MyColors.lightTextColor), + // 8.height, model.country != null ? DropdownField( (DropValue value) { @@ -129,7 +126,7 @@ class DefineBranchPage extends StatelessWidget { decoration: BoxDecoration( color: Colors.transparent, border: Border.all(color: MyColors.darkPrimaryColor, width: 2), - borderRadius: BorderRadius.all(Radius.circular(8)), + borderRadius: const BorderRadius.all(Radius.circular(8)), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, @@ -170,10 +167,10 @@ class DefineBranchPage extends StatelessWidget { child: ShowFillButton( title: branchData != null ? (branchData!.id == null ? LocaleKeys.createBranch.tr() : LocaleKeys.updateBranch.tr()) : LocaleKeys.createBranch.tr(), onPressed: () async { - if (branchData == null) { Utils.showLoading(context); - MResponse res = await model.createBranch(model.branchName, model.branchDescription,model. cityId.toString(), model.address, model.latitude.toString(), model.longitude.toString()); + MResponse res = + await model.createBranch(model.branchName, model.branchDescription, model.cityId.toString(), model.address, model.latitude.toString(), model.longitude.toString()); Utils.hideLoading(context); if (res.messageStatus == 1) { Utils.showToast(LocaleKeys.branch_created.tr()); @@ -184,8 +181,8 @@ class DefineBranchPage extends StatelessWidget { } } else { Utils.showLoading(context); - MResponse res = - await model.updateBranch(branchData!.id ?? 0, model.branchName, model.branchDescription, model.cityId.toString(), model.address, model.latitude.toString(), model.longitude.toString()); + MResponse res = await model.updateBranch( + branchData!.id ?? 0, model.branchName, model.branchDescription, model.cityId.toString(), model.address, model.latitude.toString(), model.longitude.toString()); Utils.hideLoading(context); if (res.messageStatus == 1) { Utils.showToast(LocaleKeys.branch_updated.tr()); diff --git a/lib/views/settings/create_services_page.dart b/lib/views/settings/create_services_page.dart index 2d824f4..81fc545 100644 --- a/lib/views/settings/create_services_page.dart +++ b/lib/views/settings/create_services_page.dart @@ -1,209 +1,211 @@ -import 'package:easy_localization/easy_localization.dart'; - -import 'package:flutter/material.dart'; - -import 'package:car_provider_app/generated/locale_keys.g.dart'; - -import 'package:car_provider_app/view_models/branch_view_model.dart'; -import 'package:mc_common_app/extensions/int_extensions.dart'; -import 'package:mc_common_app/extensions/string_extensions.dart'; -import 'package:mc_common_app/models/m_response.dart'; -import 'package:mc_common_app/models/model/branch2.dart'; -import 'package:mc_common_app/theme/colors.dart'; -import 'package:mc_common_app/utils/enums.dart'; -import 'package:mc_common_app/utils/navigator.dart'; -import 'package:mc_common_app/utils/utils.dart'; -import 'package:mc_common_app/widgets/button/show_fill_button.dart'; -import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; -import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart'; -import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; - -import 'package:provider/provider.dart'; - -class CreateServicesPage extends StatelessWidget { - ServiceProviderBranch? serviceProviderBranch; - CreateServicesPage(this.serviceProviderBranch); - - @override - Widget build(BuildContext context) { - BranchVM branchVM = context.read(); - branchVM.getBranchAndServices(); - branchVM.fetchBranches(); - if (serviceProviderBranch != null) { - branchVM.branchId = serviceProviderBranch!.id ?? -1; - branchVM.branchValue = DropValue(branchVM.branchId, serviceProviderBranch!.branchName ?? "", ""); - print("llll1 ${branchVM.branchId} ${serviceProviderBranch!.branchName} ${branchVM.branchValue!.value}"); - if (branchVM.branchId != 1) branchVM.fetchBranchCategory(EasyLocalization.of(context)?.currentLocale?.countryCode ?? "SA"); - } - - return Scaffold( - appBar: CustomAppBar(title: LocaleKeys.defineServices.tr()), - body: SizedBox( - width: double.infinity, - height: double.infinity, - child: Consumer(builder: (context, model, _) { - return Column( - children: [ - Expanded( - child: SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.all(12.0), - child: Column( - children: [ - model.branch != null - ? (model.branchValue != null && model.branchId != -1) - ? Text( - model.branchValue!.value ?? "", - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - ), - ).toContainer( - padding: const EdgeInsets.only(left: 8, right: 8, bottom: 12, top: 12), - backgroundColor: MyColors.textFieldColor, - borderRadius: 0, - width: double.infinity, - ) - : DropdownField( - (DropValue value) { - // countryCode = value.subValue; - // countryId = value.id; - // fetchCites(); - model.branchId = value.id; - model.fetchBranchCategory(EasyLocalization.of(context)?.currentLocale?.countryCode ?? "SA"); - model.setState(ViewState.idle); - }, - list: model.countryDropListForService, - hint: LocaleKeys.selectBranch.tr(), - dropdownValue: model.branchValue, - ) - : const CircularProgressIndicator(), - 12.height, - (model.category != null) - ? DropdownField((DropValue value) { - // countryCode = value.subValue; - // countryId = value.id; - // fetchCites(); - model.categoryId = value.id; - model.fetchServicesByCategoryId(); - model.setState(ViewState.idle); - }, list: model.categoryDropList, hint: LocaleKeys.selectServiceCategory.tr()) - : model.branchId == -1 - ? Container() - : const CircularProgressIndicator(), - 12.height, - if ((model.categoryId != -1)) - model.services == null - ? const CircularProgressIndicator() - : ListView.separated( - itemBuilder: (context, index) { - return Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - children: [ - Checkbox( - value: model.services!.data![index].isSelected, - onChanged: (v) { - model.services!.data![index].isSelected = v; - model.setState(ViewState.idle); - }, - ), - 12.width, - ((EasyLocalization.of(context)?.currentLocale?.countryCode == "SA" ? model.services!.data![index].descriptionN : model.services!.data![index].description) ?? - "") - .toText(fontSize: 12) - ], - ), - ); - }, - separatorBuilder: (context, index) { - return 1.height; - }, - itemCount: model.services!.data!.length, - physics: NeverScrollableScrollPhysics(), - shrinkWrap: true, - ) - ], - ), - ), - ), - ), - if (checkServicesSelection(model)) - Padding( - padding: const EdgeInsets.all(12.0), - child: ShowFillButton( - title: LocaleKeys.save.tr(), - maxWidth: double.infinity, - onPressed: () { - createService(context, model); - }, - ), - ), - ], - ); - }), - ), - ); - } - - bool checkServicesSelection(BranchVM model) { - bool isServiceSelected = false; - try { - for (var element in model.services!.data!) { - if (element.isSelected ?? false) isServiceSelected = true; - } - } catch (e) { - isServiceSelected = false; - } - - return isServiceSelected; - } - - createService(BuildContext context, BranchVM model) async { - List> map = []; - if (serviceProviderBranch != null && model.branchId != -1) { - for (int i = 0; i < model.services!.data!.length; i++) { - if (model.services!.data![i].isSelected ?? false) { - var postParams = { - // "id": services!.data![i].id, - "providerBranchID": model.branchId, - "serviceID": model.services!.data![i].id, - "isAllowAppointment": true, - "isActive": true - }; - map.add(postParams); - } - } - Utils.showLoading(context); - MResponse mResponse = await model.createService(map); - Utils.hideLoading(context); - - if (serviceProviderBranch != null) { - Utils.showToast(mResponse.message ?? ""); - if (mResponse.messageStatus != 2) { - pop(context); - pop(context); - model.getBranchAndServices(); - } - } - } else { - for (int i = 0; i < model.services!.data!.length; i++) { - if (model.services!.data![i].isSelected ?? false) { - var postParams = { - // "id": services!.data![i].id, - "providerBranchID": model.branchId, - "serviceID": model.services!.data![i].id, - "isAllowAppointment": true, - "isActive": true - }; - map.add(postParams); - } - } - Utils.showLoading(context); - MResponse mResponse = await model.createService(map); - model.getBranchAndServices(); - Utils.hideLoading(context); - Utils.showToast(mResponse.message ?? ""); - } - } -} +// import 'package:car_provider_app/view_models/service_view_model.dart'; +// import 'package:easy_localization/easy_localization.dart'; +// +// import 'package:flutter/material.dart'; +// +// import 'package:car_provider_app/generated/locale_keys.g.dart'; +// +// import 'package:car_provider_app/view_models/branch_view_model.dart'; +// import 'package:mc_common_app/extensions/int_extensions.dart'; +// import 'package:mc_common_app/extensions/string_extensions.dart'; +// import 'package:mc_common_app/models/m_response.dart'; +// import 'package:mc_common_app/models/model/branch2.dart'; +// import 'package:mc_common_app/theme/colors.dart'; +// import 'package:mc_common_app/utils/enums.dart'; +// import 'package:mc_common_app/utils/navigator.dart'; +// import 'package:mc_common_app/utils/utils.dart'; +// import 'package:mc_common_app/widgets/button/show_fill_button.dart'; +// import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; +// import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart'; +// import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; +// +// import 'package:provider/provider.dart'; +// +// class CreateServicesPage extends StatelessWidget { +// ServiceProviderBranch? serviceProviderBranch; +// +// CreateServicesPage(this.serviceProviderBranch, {Key? key}) : super(key: key); +// +// @override +// Widget build(BuildContext context) { +// ServiceVM branchVM = context.read(); +// branchVM.getBranchAndServices(); +// branchVM.fetchBranches(); +// if (serviceProviderBranch != null) { +// // branchVM.branchId = serviceProviderBranch!.id ?? -1; +// // branchVM.branchValue = DropValue(branchVM.branchId, serviceProviderBranch!.branchName ?? "", ""); +// // print("llll1 ${branchVM.branchId} ${serviceProviderBranch!.branchName} ${branchVM.branchValue!.value}"); +// if (branchVM.branchId != 1) branchVM.fetchBranchCategory(EasyLocalization.of(context)?.currentLocale?.countryCode ?? "SA"); +// } +// +// return Scaffold( +// appBar: CustomAppBar(title: LocaleKeys.defineServices.tr()), +// body: SizedBox( +// width: double.infinity, +// height: double.infinity, +// child: Consumer(builder: (context, model, _) { +// return Column( +// children: [ +// Expanded( +// child: SingleChildScrollView( +// child: Padding( +// padding: const EdgeInsets.all(12.0), +// child: Column( +// children: [ +// model.branch != null +// ? (model.branchValue != null && model.branchId != -1) +// ? Text( +// model.branchValue!.value ?? "", +// style: const TextStyle( +// fontSize: 12, +// fontWeight: FontWeight.bold, +// ), +// ).toContainer( +// padding: const EdgeInsets.only(left: 8, right: 8, bottom: 12, top: 12), +// backgroundColor: MyColors.textFieldColor, +// borderRadius: 0, +// width: double.infinity, +// ) +// : DropdownField( +// (DropValue value) { +// // countryCode = value.subValue; +// // countryId = value.id; +// // fetchCites(); +// model.branchId = value.id; +// model.fetchBranchCategory(EasyLocalization.of(context)?.currentLocale?.countryCode ?? "SA"); +// model.setState(ViewState.idle); +// }, +// list: model.countryDropListForService, +// hint: LocaleKeys.selectBranch.tr(), +// dropdownValue: model.branchValue, +// ) +// : const CircularProgressIndicator(), +// 12.height, +// (model.category != null) +// ? DropdownField((DropValue value) { +// // countryCode = value.subValue; +// // countryId = value.id; +// // fetchCites(); +// model.categoryId = value.id; +// model.fetchServicesByCategoryId(); +// model.setState(ViewState.idle); +// }, list: model.categoryDropList, hint: LocaleKeys.selectServiceCategory.tr()) +// : model.branchId == -1 +// ? Container() +// : const CircularProgressIndicator(), +// 12.height, +// if ((model.categoryId != -1)) +// model.services == null +// ? const CircularProgressIndicator() +// : ListView.separated( +// itemBuilder: (context, index) { +// return Padding( +// padding: const EdgeInsets.all(8.0), +// child: Row( +// children: [ +// Checkbox( +// value: model.services!.data![index].isSelected, +// onChanged: (v) { +// model.services!.data![index].isSelected = v; +// model.setState(ViewState.idle); +// }, +// ), +// 12.width, +// ((EasyLocalization.of(context)?.currentLocale?.countryCode == "SA" ? model.services!.data![index].descriptionN : model.services!.data![index].description) ?? +// "") +// .toText(fontSize: 12) +// ], +// ), +// ); +// }, +// separatorBuilder: (context, index) { +// return 1.height; +// }, +// itemCount: model.services!.data!.length, +// physics: NeverScrollableScrollPhysics(), +// shrinkWrap: true, +// ) +// ], +// ), +// ), +// ), +// ), +// if (checkServicesSelection(model)) +// Padding( +// padding: const EdgeInsets.all(12.0), +// child: ShowFillButton( +// title: LocaleKeys.save.tr(), +// maxWidth: double.infinity, +// onPressed: () { +// createService(context, model); +// }, +// ), +// ), +// ], +// ); +// }), +// ), +// ); +// } +// +// bool checkServicesSelection(BranchVM model) { +// bool isServiceSelected = false; +// try { +// for (var element in model.services!.data!) { +// if (element.isSelected ?? false) isServiceSelected = true; +// } +// } catch (e) { +// isServiceSelected = false; +// } +// +// return isServiceSelected; +// } +// +// createService(BuildContext context, BranchVM model) async { +// List> map = []; +// if (serviceProviderBranch != null && model.branchId != -1) { +// for (int i = 0; i < model.services!.data!.length; i++) { +// if (model.services!.data![i].isSelected ?? false) { +// var postParams = { +// // "id": services!.data![i].id, +// "providerBranchID": model.branchId, +// "serviceID": model.services!.data![i].id, +// "isAllowAppointment": true, +// "isActive": true +// }; +// map.add(postParams); +// } +// } +// Utils.showLoading(context); +// MResponse mResponse = await model.createService(map); +// Utils.hideLoading(context); +// +// if (serviceProviderBranch != null) { +// Utils.showToast(mResponse.message ?? ""); +// if (mResponse.messageStatus != 2) { +// pop(context); +// pop(context); +// model.getBranchAndServices(); +// } +// } +// } else { +// for (int i = 0; i < model.services!.data!.length; i++) { +// if (model.services!.data![i].isSelected ?? false) { +// var postParams = { +// // "id": services!.data![i].id, +// "providerBranchID": model.branchId, +// "serviceID": model.services!.data![i].id, +// "isAllowAppointment": true, +// "isActive": true +// }; +// map.add(postParams); +// } +// } +// Utils.showLoading(context); +// MResponse mResponse = await model.createService(map); +// model.getBranchAndServices(); +// Utils.hideLoading(context); +// Utils.showToast(mResponse.message ?? ""); +// } +// } +// } diff --git a/lib/views/settings/dealership_page.dart b/lib/views/settings/dealership_page.dart index e8dc7b4..359fb82 100644 --- a/lib/views/settings/dealership_page.dart +++ b/lib/views/settings/dealership_page.dart @@ -44,7 +44,7 @@ class DealershipPage extends StatelessWidget { ), title: LocaleKeys.defineServices.tr().toText(fontSize: 12), onTap: () { - navigateWithName(context, ProviderAppRoutes.createServices); + navigateWithName(context, ProviderAppRoutes.createServices2); }, ), ListTile( diff --git a/lib/views/settings/define_license_page.dart b/lib/views/settings/define_license_page.dart index b950aa8..0943f17 100644 --- a/lib/views/settings/define_license_page.dart +++ b/lib/views/settings/define_license_page.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'dart:io'; +import 'package:car_provider_app/view_models/service_view_model.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; @@ -29,13 +30,13 @@ class DefineLicensePage extends StatefulWidget { } class _DefineLicensePageState extends State { - late BranchVM branchVM; + late ServiceVM branchVM; @override void initState() { // TODO: implement initState super.initState(); - branchVM = Provider.of(context, listen: false); + branchVM = Provider.of(context, listen: false); branchVM.getServiceProviderDocument(AppState().getUser.data!.userInfo!.providerId ?? 0); } @@ -46,7 +47,7 @@ class _DefineLicensePageState extends State { title: LocaleKeys.defineLicences.tr(), isRemoveBackButton: false, ), - body: Consumer(builder: (_, model, __) { + body: Consumer(builder: (_, model, __) { return Column( children: [ Expanded( @@ -89,7 +90,7 @@ class _DefineLicensePageState extends State { ); } - validation(BranchVM model) { + validation(ServiceVM model) { bool valid = true; model.document!.data!.forEach((element) { if (element.documentUrl == null) { @@ -99,7 +100,7 @@ class _DefineLicensePageState extends State { return valid; } - updateDocument(BranchVM model) async { + updateDocument(ServiceVM model) async { Utils.showLoading(context); MResponse res = await model.updateDocument(model.document!.data); Utils.hideLoading(context); @@ -110,7 +111,7 @@ class _DefineLicensePageState extends State { } } - Widget showWidget(BranchVM model) { + Widget showWidget(ServiceVM model) { if (model.state == ViewState.idle) { return model.document!.data!.isEmpty ? Text("LocaleKeys.somethingWrong.tr()") diff --git a/lib/views/settings/schedule/add_schedules_page.dart b/lib/views/settings/schedule/add_schedules_page.dart new file mode 100644 index 0000000..11659cb --- /dev/null +++ b/lib/views/settings/schedule/add_schedules_page.dart @@ -0,0 +1,286 @@ +import 'package:car_provider_app/view_models/schedule_view_model.dart'; +import 'package:car_provider_app/view_models/service_view_model.dart'; +import 'package:car_provider_app/views/settings/schedule/widgets/chips_picker_item.dart'; +import 'package:car_provider_app/views/settings/schedule/widgets/select_days_sheet.dart'; +import 'package:car_provider_app/views/settings/schedule/widgets/select_services_sheet.dart'; +import 'package:flutter/material.dart'; +import 'package:mc_common_app/classes/app_state.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/models/m_response.dart'; +import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/utils/utils.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/txt_field.dart'; +import 'package:provider/provider.dart'; +import 'package:mc_common_app/widgets/bottom_sheet.dart'; + +class AddSchedulesPage extends StatelessWidget { + ScheduleVM? mModel; + String branchId = "", name = "", startDate = "", endDate = "", startTime = "", endTime = "", slotsTime = "", appointmentPerSlot = ""; + + AddSchedulesPage({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + branchId = ModalRoute.of(context)!.settings.arguments as String; + return Scaffold( + appBar: const CustomAppBar( + title: "Create Schedules", + ), + body: SizedBox( + width: double.infinity, + child: Consumer( + builder: (_, ScheduleVM model, child) { + return Column( + children: [ + Expanded( + child: SingleChildScrollView( + padding: const EdgeInsets.all(20), + child: Column( + children: [ + TxtField( + hint: "Name of Schedule", + value: name, + onChanged: (v) { + name = v; + }, + ), + 8.height, + ChipsPickerItem( + hint: 'Select Services', + itemsList: [...model.selectedServicesItems], + onClick: () { + showMyBottomSheet( + context, + child: SelectServicesSheet( + onSelectServices: () { + model.filterSelectedServices(); + FocusManager.instance.primaryFocus?.unfocus(); + }, + ), + ); + }, + ), + 8.height, + TxtField( + hint: "Starting Date", + value: startDate, + postfixWidget: const Icon( + Icons.calendar_month, + size: 16, + ), + isNeedClickAll: true, + onTap: () async { + startDate = await Utils.pickDateFromDatePicker( + context, + firstDate: DateTime.now(), + ); + FocusManager.instance.primaryFocus?.unfocus(); + model.refresh(); + }, + ), + 8.height, + TxtField( + hint: "End Date", + postfixWidget: const Icon( + Icons.calendar_month, + size: 16, + ), + value: endDate, + isNeedClickAll: true, + onTap: () async { + endDate = await Utils.pickDateFromDatePicker( + context, + firstDate: DateTime.now(), + ); + FocusManager.instance.primaryFocus?.unfocus(); + model.refresh(); + }, + ), + 8.height, + ChipsPickerItem( + hint: 'Days', + itemsList: [...model.selectedDaysItems], + onClick: () { + showMyBottomSheet( + context, + child: SelectDaysSheet( + onSelected: (List picked) { + model.filterDays(picked); + FocusManager.instance.primaryFocus?.unfocus(); + }, + ), + ); + }, + ), + 8.height, + Row( + children: [ + Expanded( + child: TxtField( + hint: "Shift Start Time", + postfixWidget: const Icon( + Icons.access_time_filled_outlined, + size: 16, + ), + value: startTime, + isNeedClickAll: true, + onTap: () async { + startTime = await Utils.pickTime(context); + FocusManager.instance.primaryFocus?.unfocus(); + model.refresh(); + }, + ), + ), + 8.width, + Expanded( + child: TxtField( + hint: "Shift End Time", + postfixWidget: const Icon( + Icons.access_time_filled_outlined, + size: 16, + ), + value: endTime, + isNeedClickAll: true, + onTap: () async { + TimeOfDay _startTime = TimeOfDay.now(); + if (startTime.isNotEmpty) _startTime = TimeOfDay(hour: int.parse(startTime.split(":")[0]), minute: int.parse(startTime.split(":")[1])); + endTime = await Utils.pickTime( + context, + initialTime: _startTime, + ); + FocusManager.instance.primaryFocus?.unfocus(); + model.refresh(); + }, + ), + ), + ], + ), + 8.height, + TxtField( + hint: "Slots Time", + postfixWidget: Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + "Min".toText(color: MyColors.lightTextColor), + ], + ), + keyboardType: TextInputType.number, + value: slotsTime, + onChanged: (v) { + slotsTime = v; + }, + ), + 8.height, + TxtField( + hint: "Appointment Per Slot", + value: appointmentPerSlot, + keyboardType: TextInputType.number, + onChanged: (v) { + appointmentPerSlot = v; + }, + ), + ], + ), + ), + ), + ShowFillButton( + title: "Create", + maxWidth: double.infinity, + margin: const EdgeInsets.all(20), + onPressed: () { + if (validation(model)) { + createSchedule(context, model); + } + }, + ), + ], + ); + }, + ), + ), + ); + } + + bool validation(ScheduleVM model) { + bool valid = true; + if (name.length < 3) { + Utils.showToast("Please enter valid schedule Name"); + valid = false; + } else if (model.selectedServicesItems.isEmpty) { + Utils.showToast(""); + valid = false; + } else if (startDate.isEmpty) { + Utils.showToast(""); + valid = false; + } else if (endDate.isEmpty) { + Utils.showToast(""); + valid = false; + } else if (model.selectedDaysItems.isEmpty) { + Utils.showToast(""); + valid = false; + } else if (startTime.isEmpty) { + Utils.showToast(""); + valid = false; + } else if (endTime.isEmpty) { + Utils.showToast(""); + valid = false; + } else if (slotsTime.isEmpty) { + Utils.showToast(""); + valid = false; + } else if (appointmentPerSlot.isEmpty) { + Utils.showToast(""); + valid = false; + } + return valid; + } + + createSchedule(BuildContext context, ScheduleVM model) async { + List days = []; + for (var element in model.selectedDaysItems) { + days.add(element.id); + } + + var map = { + "branchID": branchId, + "fromDate": startDate, + "toDate": endDate, + "startTime": startTime, + "endTime": endDate, + "slotDurationMinute": slotsTime, + "perSlotAppointment": appointmentPerSlot, + "deliveryServiceType": 1, + "weeklyOffDays": days + }; + + Utils.showLoading(context); + MResponse scheduleResponse = await model.createSchedule(map); + if (scheduleResponse.messageStatus == 1) { + List services = []; + for (var element in model.selectedServicesItems) { + services.add(element.id); + } + var map1 = { + // "id": 0, + "branchAppointmentScheduleID": scheduleResponse.data["id"], + "serviceProviderServiceID": services, + "serviceGroupDescription": "string" + }; + + MResponse servicesResponse = await model.addServicesInSchedule(map1); + Utils.hideLoading(context); + if (servicesResponse.messageStatus == 1) { + Utils.showToast("Successfully schedule created"); + } else { + Utils.showToast("Something went wrong while adding services in schedule"); + } + } else { + Utils.hideLoading(context); + Utils.showToast("Something went wrong"); + } + } +} diff --git a/lib/views/settings/schedule/schedules_list_page.dart b/lib/views/settings/schedule/schedules_list_page.dart new file mode 100644 index 0000000..03a887d --- /dev/null +++ b/lib/views/settings/schedule/schedules_list_page.dart @@ -0,0 +1,35 @@ +import 'package:car_provider_app/config/provider_routes.dart'; +import 'package:flutter/material.dart'; +import 'package:mc_common_app/utils/navigator.dart'; +import 'package:mc_common_app/widgets/button/show_fill_button.dart'; +import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; + +class SchedulesListPage extends StatelessWidget { + const SchedulesListPage({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + String branchId = ModalRoute.of(context)!.settings.arguments as String; + return Scaffold( + appBar: const CustomAppBar( + title: "Schedules", + ), + body: SizedBox( + width: double.infinity, + child: Column( + children: [ + Expanded(child: Container()), + ShowFillButton( + title: "Create Schedule", + maxWidth: double.infinity, + margin: const EdgeInsets.all(20), + onPressed: () { + navigateWithName(context, ProviderAppRoutes.addSchedule, arguments: branchId); + }, + ) + ], + ), + ), + ); + } +} diff --git a/lib/views/settings/schedule/widgets/chips_picker_item.dart b/lib/views/settings/schedule/widgets/chips_picker_item.dart new file mode 100644 index 0000000..e7515e2 --- /dev/null +++ b/lib/views/settings/schedule/widgets/chips_picker_item.dart @@ -0,0 +1,87 @@ +import 'package:flutter/material.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; +import 'package:sizer/sizer.dart'; + +class PickerItem { + int id; + String title; + bool? isSelected; + + PickerItem({required this.id, required this.title, this.isSelected}); +} + +class ChipsPickerItem extends StatelessWidget { + String hint; + List itemsList; + Function onClick; + + ChipsPickerItem({Key? key, required this.hint, required this.itemsList, required this.onClick}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Row( + children: [ + if (itemsList.isEmpty) Expanded(child: hint.toText(fontSize: 9.sp, color: borderColor)), + if (itemsList.isNotEmpty) + Expanded( + child: ListView( + scrollDirection: Axis.horizontal, + children: [ + showItem(itemsList[0].title), + 6.width, + if (itemsList.length > 1) showItem(itemsList[1].title), + 6.width, + if (itemsList.length > 2) showItem("${itemsList.length - 2}+ more", isNeedToShowIcon: false), + 6.width, + ], + ), + ), + const Icon( + Icons.arrow_forward_ios_rounded, + size: 16, + color: MyColors.lightIconColor, + ), + ], + ) + .toContainer( + width: double.infinity, + height: 45, + isEnabledBorder: true, + borderWidget: 2, + borderRadius: 0, + borderColor: MyColors.darkPrimaryColor, + ) + .onPress(() { + onClick(); + }); + } + + Widget showItem(String title, {bool isNeedToShowIcon = true}) { + return Container( + child: Row( + children: [ + title.toText(fontSize: 12), + if (isNeedToShowIcon) 4.width, + if (isNeedToShowIcon) + const Icon( + Icons.close, + size: 8, + color: Colors.white, + ).toContainer( + borderRadius: 100, + width: 12, + height: 12, + paddingAll: 0, + backgroundColor: MyColors.grey70Color, + ), + ], + ), + padding: const EdgeInsets.symmetric(horizontal: 6), + height: double.infinity, + color: MyColors.chipColor, + ); + } +} diff --git a/lib/views/settings/schedule/widgets/select_days_sheet.dart b/lib/views/settings/schedule/widgets/select_days_sheet.dart new file mode 100644 index 0000000..be3312b --- /dev/null +++ b/lib/views/settings/schedule/widgets/select_days_sheet.dart @@ -0,0 +1,97 @@ +import 'package:car_provider_app/view_models/schedule_view_model.dart'; +import 'package:car_provider_app/views/settings/schedule/widgets/chips_picker_item.dart'; +import 'package:flutter/material.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/widgets/button/show_fill_button.dart'; +import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; +import 'package:provider/provider.dart'; + +class SelectDaysSheet extends StatefulWidget { + Function(List) onSelected; + + SelectDaysSheet({Key? key, required this.onSelected}) : super(key: key); + + @override + State createState() => _SelectDaysSheetState(); +} + +class _SelectDaysSheetState extends State { + List list = []; + + @override + void initState() { + super.initState(); + list = context.read().intiDays(); + } + + @override + Widget build(BuildContext context) { + return Container( + width: double.infinity, + height: MediaQuery.of(context).size.height / 1.4, + padding: const EdgeInsets.only(left: 20, right: 20, top: 6, bottom: 20), + child: Column( + children: [ + Row( + children: [ + Expanded( + child: "Select Days".toText(fontSize: 24, isBold: true), + ), + Center( + child: list.where((element) => element.isSelected == true).toList().length.toString().toText( + fontSize: 10, + isBold: true, + color: Colors.white, + ), + ).toContainer( + borderRadius: 100, + width: 24, + height: 24, + paddingAll: 0, + backgroundColor: MyColors.darkPrimaryColor, + ), + ], + ), + 12.height, + Expanded( + child: ListView.separated( + itemBuilder: (BuildContext context, int index) { + return Row( + children: [ + Checkbox( + value: list[index].isSelected, + onChanged: (bool? v) { + list[index].isSelected = v; + setState(() {}); + }, + ), + 12.width, + Expanded( + child: list[index].title.toText(), + ), + ], + ); + }, + separatorBuilder: (BuildContext context, int index) { + return const Divider( + height: 1, + ); + }, + itemCount: list.length, + ), + ), + ShowFillButton( + title: 'Add Selected Days', + maxWidth: double.infinity, + onPressed: () { + widget.onSelected(list); + Navigator.pop(context); + }, + ) + ], + ), + ); + } +} diff --git a/lib/views/settings/schedule/widgets/select_services_sheet.dart b/lib/views/settings/schedule/widgets/select_services_sheet.dart new file mode 100644 index 0000000..a49fa27 --- /dev/null +++ b/lib/views/settings/schedule/widgets/select_services_sheet.dart @@ -0,0 +1,106 @@ +import 'package:car_provider_app/view_models/schedule_view_model.dart'; +import 'package:car_provider_app/view_models/service_view_model.dart'; +import 'package:flutter/material.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/widgets/button/show_fill_button.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'; + +class SelectServicesSheet extends StatelessWidget { + Function onSelectServices; + + SelectServicesSheet({Key? key, required this.onSelectServices}) : super(key: key); + + @override + Widget build(BuildContext context) { + context.read().getAllServices(); + return SizedBox( + width: double.infinity, + height: MediaQuery.of(context).size.height / 1.4, + child: Column( + children: [ + Expanded( + child: Consumer( + builder: (_, model, child) { + return Padding( + padding: const EdgeInsets.only(left: 20, right: 20, top: 6), + child: Column( + children: [ + Row( + children: [ + Expanded( + child: "Select Services".toText(fontSize: 24, isBold: true), + ), + Center( + child: model.servicesList!.where((element) => element.isSelected == true).toList().length.toString().toText( + fontSize: 10, + isBold: true, + color: Colors.white, + ), + ).toContainer( + borderRadius: 100, + width: 24, + height: 24, + paddingAll: 0, + backgroundColor: MyColors.darkPrimaryColor, + ), + ], + ), + 12.height, + TxtField( + hint: "Search Service", + onChanged: (v) {}, + ), + 12.height, + Expanded( + child: model.servicesList == null + ? const Center(child: CircularProgressIndicator()) + : ListView.separated( + itemBuilder: (BuildContext context, int index) { + return Row( + children: [ + Checkbox( + value: model.servicesList![index].isSelected, + onChanged: (bool? v) { + model.servicesList![index].isSelected = v; + model.notifyListeners(); + }, + ), + 12.width, + Expanded( + child: model.servicesList![index].description!.toText(), + ), + ], + ); + }, + separatorBuilder: (BuildContext context, int index) { + return const Divider( + height: 1, + ); + }, + itemCount: model.servicesList!.length, + ), + ), + ], + ), + ); + }, + ), + ), + ShowFillButton( + title: 'Add Selected Services', + maxWidth: double.infinity, + margin: const EdgeInsets.all(20), + onPressed: () { + onSelectServices(); + Navigator.pop(context); + }, + ) + ], + ), + ); + } +} diff --git a/lib/views/settings/services/create_item_page.dart b/lib/views/settings/services/create_item_page.dart new file mode 100644 index 0000000..ed3e3b0 --- /dev/null +++ b/lib/views/settings/services/create_item_page.dart @@ -0,0 +1,289 @@ +import 'dart:convert'; + +import 'package:car_provider_app/common/item_model.dart'; +import 'package:car_provider_app/common/widget/checkbox_with_title_desc.dart'; +import 'package:car_provider_app/view_models/items_view_model.dart'; +import 'package:flutter/material.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/models/m_response.dart'; +import 'package:mc_common_app/models/model/branch2.dart'; +import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/utils/AppPermissionHandler.dart'; +import 'package:mc_common_app/utils/date_helper.dart'; +import 'package:mc_common_app/utils/navigator.dart'; +import 'package:mc_common_app/utils/utils.dart'; +import 'package:mc_common_app/widgets/button/show_fill_button.dart'; +import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; +import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; +import 'package:mc_common_app/widgets/txt_field.dart'; +import 'package:permission_handler/permission_handler.dart'; +import 'package:provider/provider.dart'; + +class CreateItemPage extends StatefulWidget { + const CreateItemPage({Key? key}) : super(key: key); + + @override + State createState() => _CreateItemPageState(); +} + +class _CreateItemPageState extends State { + String? name, description, price, year, itemImage; + bool isAppointmentAvailable = false; + bool isWorkshopAppointmentAvailable = false; + bool isHomeAppointmentAvailable = false; + bool isDefaultValudDone = false; + + ItemsVM? model; + ItemData? itemData; + + setDefaultData() { + name = itemData!.name; + description = itemData!.description; + price = itemData!.price; + print(itemData!.manufactureDate); + + //TODO: need to discuss with zahoor year and picture + if (itemData!.manufactureDate != null) year = DateHelper.formatAsYearMonthDay(DateHelper.parseStringToDate(itemData!.manufactureDate ?? DateTime.now().toString())); + // itemImage=itemData. + + isAppointmentAvailable = itemData!.isAllowAppointment ?? false; + isWorkshopAppointmentAvailable = itemData!.isAppointmentCompanyLoc ?? false; + isHomeAppointmentAvailable = itemData!.isAppointmentCustomerLoc ?? false; + isDefaultValudDone = true; + } + + @override + Widget build(BuildContext context) { + model ??= context.read(); + itemData ??= ModalRoute.of(context)!.settings.arguments as ItemData; + if (!isDefaultValudDone) setDefaultData(); + return Scaffold( + appBar: const CustomAppBar( + title: "Add Items", + ), + body: Container( + width: double.infinity, + height: double.infinity, + padding: const EdgeInsets.all(20), + child: Column( + children: [ + Expanded( + child: SingleChildScrollView( + child: Column( + children: [ + TxtField( + hint: "Item Name", + value: name, + onChanged: (v) { + name = v; + }, + ), + 12.height, + TxtField( + hint: "Item Description", + value: description, + onChanged: (v) { + description = v; + }, + ), + 12.height, + TxtField( + hint: "Item Price", + value: price, + keyboardType: TextInputType.number, + onChanged: (v) { + price = v; + }, + ), + 12.height, + TxtField( + hint: "Manufacture Year", + value: year, + keyboardType: TextInputType.number, + isNeedClickAll: true, + postfixWidget: const IconButton( + onPressed: null, + icon: Icon(Icons.date_range), + ), + onTap: () async { + year = await Utils.pickDateFromDatePicker(context, firstDate: DateTime(1990), lastDate: DateTime.now()); + setState(() {}); + }, + onChanged: (v) { + year = v; + }, + ), + 12.height, + if (itemImage != null && itemImage!.isNotEmpty) + Column( + children: [ + Image.memory( + base64Decode(itemImage ?? ""), + ).toContainer( + isEnabledBorder: true, + paddingAll: 12, + ), + 12.height, + ], + ), + InkWell( + onTap: () async { + bool isPermissionsAvailable = await requestPermissionGranted(context, Permission.storage); + if (isPermissionsAvailable && model != null) { + itemImage = await model!.selectFile() ?? ""; + setState(() {}); + } + }, + child: Container( + width: double.infinity, + height: 45, + decoration: BoxDecoration( + color: Colors.transparent, + border: Border.all(color: MyColors.greyACColor, width: 2), + borderRadius: const BorderRadius.all(Radius.circular(0)), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const Icon( + Icons.attach_file, + size: 18, + color: MyColors.darkPrimaryColor, + ), + 8.width, + const Text( + "Attach Item Image", + style: TextStyle( + color: MyColors.darkPrimaryColor, + ), + ), + const Icon( + Icons.attach_file, + size: 18, + color: Colors.transparent, + ), + ], + ), + ), + ), + 20.height, + CheckBoxWithTitleDescription( + isSelected: isAppointmentAvailable, + title: 'Available for appointment', + description: 'This option will allow customer to book appointment for these services', + onSelection: (bool v) { + setState(() { + isAppointmentAvailable = v; + // isWorkshopAppointmentAvailable = v; + }); + }, + ), + 12.height, + if (isAppointmentAvailable) + CheckBoxWithTitleDescription( + isSelected: isWorkshopAppointmentAvailable, + title: 'Allow Workshop service', + description: 'This option will show to customer that you can avail this service on workshop or not.', + onSelection: (bool v) { + setState(() { + isWorkshopAppointmentAvailable = v; + }); + }, + ), + 12.height, + if (isAppointmentAvailable) + CheckBoxWithTitleDescription( + isSelected: isHomeAppointmentAvailable, + title: 'Allow home services', + description: 'This option will allow customer to book appointment at their desired location', + onSelection: (bool v) { + setState(() { + isHomeAppointmentAvailable = v; + }); + }, + ), + 12.height, + ], + ), + ), + ), + ShowFillButton( + title: (itemData!.isUpdate ?? false) ? "Update Item" : "Create Item", + maxWidth: double.infinity, + onPressed: () async { + if (validation()) { + if (!(itemData?.isUpdate ?? false)) { + Map map = { + "name": name, + "price": price, + "description": description, + "itemImage": itemImage ?? "", + "companyID": 1, + "manufactureDate": year, + "serviceProviderServiceID": itemData!.serviceProviderServiceId, + "isActive": true, + "isAllowAppointment": isAppointmentAvailable, + "isAppointmentCompanyLoc": isWorkshopAppointmentAvailable, + "isAppointmentCustomerLoc": isHomeAppointmentAvailable + }; + Utils.showLoading(context); + MResponse mResponse = await model!.createServiceItem(map); + Utils.hideLoading(context); + if (mResponse.messageStatus == 1) { + model!.getServiceItems(itemData!.serviceProviderServiceId ?? 0); + } + Utils.showToast(mResponse.message ?? ""); + pop(context); + } else { + Map map = { + "id": itemData!.id, + "name": name, + "price": price, + "description": description, + "itemImage": itemImage ?? "", + "companyID": 1, + "manufactureDate": year, + "serviceProviderServiceID": itemData!.serviceProviderServiceId, + "isActive": true, + "isAllowAppointment": isAppointmentAvailable, + "isAppointmentCompanyLoc": isWorkshopAppointmentAvailable, + "isAppointmentCustomerLoc": isHomeAppointmentAvailable + }; + Utils.showLoading(context); + MResponse mResponse = await model!.updateServiceItem(map); + Utils.hideLoading(context); + if (mResponse.messageStatus == 1) { + model!.getServiceItems(itemData!.serviceProviderServiceId ?? 0); + } + Utils.showToast(mResponse.message ?? ""); + pop(context); + } + } + }, + ), + ], + ), + ), + ); + } + + bool validation() { + bool valid = true; + if (name == null || name!.length < 3) { + Utils.showToast("Please add valid item name"); + valid = false; + } else if (description == null || description!.length < 3) { + Utils.showToast("Please add valid item description"); + valid = false; + } else if (price == null) { + Utils.showToast("Please add valid item price"); + valid = false; + } else if (year == null) { + Utils.showToast("Please add valid year"); + valid = false; + } + return valid; + } +} diff --git a/lib/views/settings/services/create_services_page2.dart b/lib/views/settings/services/create_services_page2.dart new file mode 100644 index 0000000..6ed72fe --- /dev/null +++ b/lib/views/settings/services/create_services_page2.dart @@ -0,0 +1,234 @@ +// import 'package:car_provider_app/common/widget/checkbox_with_title_desc.dart'; +// import 'package:car_provider_app/view_models/service_view_model.dart'; +// import 'package:easy_localization/easy_localization.dart'; +// +// import 'package:flutter/material.dart'; +// +// import 'package:car_provider_app/generated/locale_keys.g.dart'; +// +// import 'package:car_provider_app/view_models/branch_view_model.dart'; +// import 'package:mc_common_app/classes/app_state.dart'; +// import 'package:mc_common_app/extensions/int_extensions.dart'; +// import 'package:mc_common_app/extensions/string_extensions.dart'; +// import 'package:mc_common_app/models/m_response.dart'; +// import 'package:mc_common_app/models/model/branch2.dart'; +// import 'package:mc_common_app/theme/colors.dart'; +// import 'package:mc_common_app/utils/enums.dart'; +// import 'package:mc_common_app/utils/navigator.dart'; +// import 'package:mc_common_app/utils/utils.dart'; +// import 'package:mc_common_app/widgets/button/show_fill_button.dart'; +// import 'package:mc_common_app/widgets/common_widgets/app_bar.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/txt_field.dart'; +// +// import 'package:provider/provider.dart'; +// +// class CreateServicesPage2 extends StatelessWidget { +// ServiceProviderBranch? serviceProviderBranch; +// +// CreateServicesPage2(this.serviceProviderBranch, {Key? key}) : super(key: key); +// bool isAppointmentAvailable = false; +// bool isHomeAppointmentAvailable = false; +// int serviceRage = 0; +// int chargersPerKm = 0; +// +// @override +// Widget build(BuildContext context) { +// ServiceVM branchVM = context.read(); +// +// // if (serviceProviderBranch != null) { +// // branchVM.categoryDropList.clear(); +// // branchVM.serviceId = -1; +// // branchVM.fetchBranchCategory(EasyLocalization.of(context)?.currentLocale?.countryCode ?? "SA"); +// // } +// // print(AppState().getUser.data!.accessToken); +// +// return Scaffold( +// appBar: CustomAppBar(title: LocaleKeys.defineServices.tr()), +// body: SizedBox( +// width: double.infinity, +// height: double.infinity, +// child: Consumer( +// builder: (context, model, _) { +// return Column( +// children: [ +// Expanded( +// child: SingleChildScrollView( +// child: Padding( +// padding: const EdgeInsets.all(20.0), +// child: Column( +// children: [ +// Text( +// serviceProviderBranch!.branchName ?? "N/A", +// style: const TextStyle( +// fontSize: 12, +// fontWeight: FontWeight.bold, +// ), +// ).toContainer( +// padding: const EdgeInsets.only(left: 8, right: 8, bottom: 12, top: 12), +// backgroundColor: MyColors.textFieldColor, +// borderRadius: 0, +// width: double.infinity, +// ), +// 12.height, +// (model.category != null) +// ? DropdownField( +// (DropValue value) { +// model.categoryId = value.id; +// model.services = null; +// model.serviceId = -1; +// isAppointmentAvailable = false; +// isHomeAppointmentAvailable = false; +// model.fetchServicesByCategoryId(); +// +// // model.setState(ViewState.idle); +// }, +// list: model.categoryDropList, +// hint: LocaleKeys.selectServiceCategory.tr(), +// ) +// : const CircularProgressIndicator(), +// 12.height, +// (model.services != null) +// ? DropdownField( +// (DropValue value) { +// model.serviceId = value.id; +// isAppointmentAvailable = false; +// isHomeAppointmentAvailable = false; +// model.setState(ViewState.idle); +// }, +// list: model.servicesDropList, +// hint: LocaleKeys.defineServices.tr(), +// ) +// : model.categoryId == -1 +// ? Container() +// : const CircularProgressIndicator(), +// 20.height, +// if (model.serviceId != -1) +// Column( +// children: [ +// CheckBoxWithTitleDescription( +// isSelected: isAppointmentAvailable, +// title: 'Available for appointment', +// description: 'This option will allow customer to book appointment for these services', +// onSelection: (bool v) { +// isAppointmentAvailable = v; +// model.setState(ViewState.idle); +// }, +// ), +// 20.height, +// CheckBoxWithTitleDescription( +// isSelected: isHomeAppointmentAvailable, +// title: 'Allow home services', +// description: 'This option will allow customer to book appointment at their desired location', +// onSelection: (bool v) { +// isHomeAppointmentAvailable = v; +// model.setState(ViewState.idle); +// }, +// ), +// 20.height, +// if (isHomeAppointmentAvailable) +// Column( +// children: [ +// TxtField( +// hint: "Home Services Range", +// keyboardType: TextInputType.number, +// postfixWidget: Row( +// mainAxisSize: MainAxisSize.min, +// crossAxisAlignment: CrossAxisAlignment.center, +// mainAxisAlignment: MainAxisAlignment.center, +// children: [ +// "KM".toText(color: MyColors.lightTextColor), +// ], +// ), +// onChanged: (v) { +// if (v.isNotEmpty) { +// serviceRage = int.parse(v); +// } else { +// serviceRage = 0; +// } +// }, +// ), +// 12.height, +// TxtField( +// hint: "Charges per Kilometer", +// keyboardType: TextInputType.number, +// onChanged: (v) { +// if (v.isNotEmpty) { +// chargersPerKm = int.parse(v); +// } else { +// chargersPerKm = 0; +// } +// }, +// ), +// ], +// ), +// ], +// ), +// ], +// ), +// ), +// ), +// ), +// if (model.serviceId != -1) +// ShowFillButton( +// title: LocaleKeys.save.tr(), +// maxWidth: double.infinity, +// margin: const EdgeInsets.all(20), +// onPressed: () { +// createService(context, model); +// }, +// ), +// ], +// ); +// }, +// ), +// ), +// ); +// } +// +// bool checkServicesSelection(BranchVM model) { +// bool isServiceSelected = false; +// try { +// for (var element in model.services!.data!) { +// if (element.isSelected ?? false) isServiceSelected = true; +// } +// } catch (e) { +// isServiceSelected = false; +// } +// +// return isServiceSelected; +// } +// +// createService(BuildContext context, BranchVM model) async { +// List> map = []; +// model.services!.data?.forEach((element) { +// if (model.serviceId == element.id) { +// element.isSelected = true; +// } else { +// element.isSelected = false; +// } +// }); +// +// for (int i = 0; i < model.services!.data!.length; i++) { +// if (model.services!.data![i].isSelected ?? false) { +// var postParams = { +// // "id": services!.data![i].id, +// "providerBranchID": model.branchId, +// "serviceID": model.services!.data![i].id, +// "isAllowAppointment": isAppointmentAvailable, +// "isActive": true, +// "customerLocationRange": serviceRage, +// "rangePricePerKm": chargersPerKm +// }; +// map.add(postParams); +// } +// } +// // print(map); +// Utils.showLoading(context); +// MResponse mResponse = await model.createService(map); +// model.getBranchAndServices(); +// Utils.hideLoading(context); +// Utils.showToast(mResponse.message ?? ""); +// } +// } diff --git a/lib/views/settings/services/create_services_page3.dart b/lib/views/settings/services/create_services_page3.dart new file mode 100644 index 0000000..5aa7ccf --- /dev/null +++ b/lib/views/settings/services/create_services_page3.dart @@ -0,0 +1,272 @@ +import 'package:car_provider_app/common/widget/checkbox_with_title_desc.dart'; +import 'package:car_provider_app/generated/locale_keys.g.dart'; +import 'package:car_provider_app/view_models/service_view_model.dart'; +import 'package:car_provider_app/views/settings/services/services_list_page.dart'; +import 'package:flutter/material.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/models/m_response.dart'; +import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/utils/enums.dart'; +import 'package:mc_common_app/utils/utils.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:easy_localization/easy_localization.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/txt_field.dart'; +import 'package:provider/provider.dart'; + +class CreateServicesPage3 extends StatelessWidget { + CreateBranchModel? branchModel; + + CreateServicesPage3(this.branchModel, {Key? key}) : super(key: key); + + bool isAppointmentAvailable = false; + bool isHomeAppointmentAvailable = false; + int serviceRage = 0; + String chargersPerKm = "0"; + int? categoryId; + int? serviceId = -1; + + @override + Widget build(BuildContext context) { + ServiceVM serviceVM = context.read(); + if (branchModel!.categoryId == null) { + serviceVM.fetchBranchCategory(EasyLocalization.of(context)?.currentLocale?.countryCode ?? "SA"); + } else { + isAppointmentAvailable = branchModel?.serviceProviderService?.isAllowAppointment ?? false; + // isHomeAppointmentAvailable=branchModel.serviceProviderService. + serviceRage = branchModel?.serviceProviderService?.customerLocationRange ?? 0; + if (serviceRage > 0) { + isHomeAppointmentAvailable = true; + } + chargersPerKm = branchModel?.serviceProviderService?.rangePricePerKm ?? "0"; + serviceId = branchModel?.serviceProviderService?.serviceId ?? -1; + } + return Scaffold( + appBar: CustomAppBar(title: LocaleKeys.defineServices.tr()), + body: SizedBox( + width: double.infinity, + height: double.infinity, + child: Consumer( + builder: (context, model, _) { + return Column( + children: [ + Expanded( + child: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + children: [ + Text( + branchModel!.branchName ?? "N/A", + style: const TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + ), + ).toContainer( + padding: const EdgeInsets.only(left: 8, right: 8, bottom: 12, top: 12), + backgroundColor: MyColors.textFieldColor, + borderRadius: 0, + width: double.infinity, + ), + 12.height, + (branchModel!.categoryId != null) + ? Text( + branchModel!.categoryName ?? "N/A", + style: const TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + ), + ).toContainer( + padding: const EdgeInsets.only(left: 8, right: 8, bottom: 12, top: 12), + backgroundColor: MyColors.textFieldColor, + borderRadius: 0, + width: double.infinity, + ) + : (branchModel!.categoryId == null && model.categoryDropList.isNotEmpty) + ? DropdownField( + (DropValue value) async { + categoryId = value.id; + serviceId = -1; + isAppointmentAvailable = false; + isHomeAppointmentAvailable = false; + model.fetchServicesByCategoryId(value.id.toString()); + }, + list: model.categoryDropList, + hint: LocaleKeys.selectServiceCategory.tr(), + ) + : const CircularProgressIndicator(), + 12.height, + branchModel!.serviceProviderService != null + ? Text( + branchModel!.serviceProviderService!.serviceName ?? "N/A", + style: const TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + ), + ).toContainer( + padding: const EdgeInsets.only(left: 8, right: 8, bottom: 12, top: 12), + backgroundColor: MyColors.textFieldColor, + borderRadius: 0, + width: double.infinity, + ) + : model.servicesDropList.isNotEmpty + ? DropdownField( + (DropValue value) { + serviceId = value.id; + isAppointmentAvailable = false; + isHomeAppointmentAvailable = false; + model.setState(ViewState.idle); + }, + list: model.servicesDropList, + hint: LocaleKeys.defineServices.tr(), + ) + : categoryId == null + ? Container() + : const CircularProgressIndicator(), + 12.height, + if (serviceId != -1) + Column( + children: [ + 20.height, + CheckBoxWithTitleDescription( + isSelected: isAppointmentAvailable, + title: 'Available for appointment', + description: 'This option will allow customer to book appointment for these services', + onSelection: (bool v) { + isAppointmentAvailable = v; + model.setState(ViewState.idle); + }, + ), + 20.height, + CheckBoxWithTitleDescription( + isSelected: isHomeAppointmentAvailable, + title: 'Allow home services', + description: 'This option will allow customer to book appointment at their desired location', + onSelection: (bool v) { + isHomeAppointmentAvailable = v; + model.setState(ViewState.idle); + }, + ), + 20.height, + if (isHomeAppointmentAvailable) + Column( + children: [ + TxtField( + hint: "Home Services Range", + keyboardType: TextInputType.number, + value: serviceRage == 0 ? null : serviceRage.toString(), + postfixWidget: Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + "KM".toText(color: MyColors.lightTextColor), + ], + ), + onChanged: (v) { + if (v.isNotEmpty) { + serviceRage = int.parse(v); + } else { + serviceRage = 0; + } + }, + ), + 12.height, + TxtField( + hint: "Charges per Kilometer", + keyboardType: TextInputType.number, + value: chargersPerKm == "0.0" ? null : chargersPerKm, + onChanged: (v) { + if (v.isNotEmpty) { + chargersPerKm = v; + } else { + chargersPerKm = "0"; + } + }, + ), + ], + ), + ], + ), + ], + ), + ), + ), + ), + if (serviceId != -1) + ShowFillButton( + title: LocaleKeys.save.tr(), + maxWidth: double.infinity, + margin: const EdgeInsets.all(20), + onPressed: () { + if (branchModel!.serviceProviderService != null) { + updateService(context, model); + } else { + if (model.services != null) { + createService(context, model); + } + } + }, + ), + ], + ); + }, + ), + ), + ); + } + + createService(BuildContext context, ServiceVM model) async { + List> map = []; + model.services!.data?.forEach((element) { + if (serviceId == element.id) { + element.isSelected = true; + } else { + element.isSelected = false; + } + }); + + for (int i = 0; i < model.services!.data!.length; i++) { + if (model.services!.data![i].isSelected ?? false) { + var postParams = { + // "id": services!.data![i].id, + "providerBranchID": branchModel!.branchId, + "serviceID": model.services!.data![i].id, + "isAllowAppointment": isAppointmentAvailable, + "isActive": true, + "customerLocationRange": serviceRage, + "rangePricePerKm": chargersPerKm + }; + map.add(postParams); + } + } + // print(map); + Utils.showLoading(context); + MResponse mResponse = await model.createService(map); + model.getBranchAndServices(); + Utils.hideLoading(context); + Utils.showToast(mResponse.message ?? ""); + } + + updateService(BuildContext context, ServiceVM model) async { + List> map = [ + { + "id": branchModel!.serviceProviderService!.serviceId.toString(), + "isAllowAppointment": isAppointmentAvailable, + "isActive": true, + "customerLocationRange": serviceRage, + "rangePricePerKm": chargersPerKm + } + ]; + + // print(map); + Utils.showLoading(context); + MResponse mResponse = await model.updateServices(map); + model.getBranchAndServices(); + Utils.hideLoading(context); + Utils.showToast(mResponse.message ?? ""); + } +} diff --git a/lib/views/settings/services/items_list_page.dart b/lib/views/settings/services/items_list_page.dart new file mode 100644 index 0000000..d30ce21 --- /dev/null +++ b/lib/views/settings/services/items_list_page.dart @@ -0,0 +1,136 @@ +import 'package:car_provider_app/common/item_model.dart'; +import 'package:car_provider_app/common/widget/empty_widget.dart'; +import 'package:car_provider_app/config/provider_routes.dart'; +import 'package:car_provider_app/view_models/items_view_model.dart'; +import 'package:flutter/material.dart'; +import 'package:mc_common_app/classes/consts.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/models/model/branch2.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/widgets/button/show_fill_button.dart'; +import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; +import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; +import 'package:provider/provider.dart'; +import 'package:flutter_svg/svg.dart'; + +class ItemsListPage extends StatelessWidget { + ServiceProviderService? serviceProviderService; + + ItemsListPage({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + serviceProviderService ??= ModalRoute.of(context)!.settings.arguments as ServiceProviderService; + context.read().getServiceItems(serviceProviderService!.serviceId ?? 0); + return Scaffold( + appBar: CustomAppBar( + title: serviceProviderService!.serviceName, + ), + body: SizedBox( + width: double.infinity, + height: double.infinity, + child: Column( + children: [ + Expanded( + child: Consumer( + builder: (context, model, _) { + return model.state == ViewState.busy + ? const Center(child: CircularProgressIndicator()) + : model.serviceItems!.data!.isEmpty + ? const EmptyWidget() + : ListView.separated( + itemBuilder: (BuildContext context, int index) { + return SizedBox( + width: double.infinity, + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + model.serviceItems!.data![index].name.toString().toText(fontSize: 16, isBold: true), + 4.height, + showItem("Available for appointment:", (model.serviceItems!.data![index].isAllowAppointment ?? false) ? "Yes" : "No", valueColor: Colors.green), + showItem("Allowing Workshop service:", (model.serviceItems!.data![index].isAppointmentCompanyLoc ?? false) ? "Yes" : "No", valueColor: Colors.green), + showItem("Allowing home service:", (model.serviceItems!.data![index].isAppointmentCustomerLoc ?? false) ? "Yes" : "No", valueColor: Colors.green), + 12.height, + "Service Amount".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + model.serviceItems!.data![index].price!.toText(fontSize: 22, isBold: true), + 2.width, + Padding( + padding: const EdgeInsets.only(bottom: 4), + child: "SAR".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), + ), + ], + ), + ], + ), + ), + Padding( + padding: const EdgeInsets.all(4.0), + child: SvgPicture.asset( + MyAssets.icEdit, + width: 16, + height: 16, + ), + ).onPress(() { + model.serviceItems!.data![index].isUpdate = true; + navigateWithName(context, ProviderAppRoutes.createItem, arguments: model.serviceItems!.data![index]); + }), + ], + ), + ).toWhiteContainer( + width: double.infinity, + allPading: 12, + ); + }, + separatorBuilder: (BuildContext context, int index) { + return 12.height; + }, + padding: const EdgeInsets.all(20), + itemCount: model.serviceItems!.data!.length, + ); + }, + ), + ), + ShowFillButton( + title: "Add Item", + maxWidth: double.infinity, + margin: const EdgeInsets.all(20), + onPressed: () { + navigateWithName( + context, + ProviderAppRoutes.createItem, + arguments: ItemData( + serviceProviderServiceId: serviceProviderService!.serviceId, + ), + ); + }, + ), + ], + ), + ), + ); + } + + Widget showItem(String item, String value, {Color valueColor = Colors.black}) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + item.toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), + 4.width, + value.toText(fontSize: 12, color: valueColor, isBold: true), + ], + ); + } +} diff --git a/lib/views/settings/services/services_list_page.dart b/lib/views/settings/services/services_list_page.dart new file mode 100644 index 0000000..750e362 --- /dev/null +++ b/lib/views/settings/services/services_list_page.dart @@ -0,0 +1,176 @@ +import 'package:car_provider_app/common/widget/empty_widget.dart'; +import 'package:car_provider_app/config/provider_routes.dart'; +import 'package:flutter/material.dart'; +import 'package:mc_common_app/classes/consts.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/models/model/branch2.dart'; +import 'package:mc_common_app/models/profile/categroy.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/widgets/common_widgets/app_bar.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/tab/menu_tabs.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:mc_common_app/widgets/tab/role_type_tab.dart'; + +class CreateBranchModel { + String branchId; + String branchName; + String? categoryId; + String? categoryName; + ServiceProviderService? serviceProviderService; + + CreateBranchModel({required this.branchId, required this.branchName, this.categoryId, this.categoryName, this.serviceProviderService}); +} + +class ServicesListPage extends StatefulWidget { + const ServicesListPage({Key? key}) : super(key: key); + + @override + State createState() => _ServicesListPageState(); +} + +class _ServicesListPageState extends State { + int selectedTap = 0; + int selectedService = ServiceStatus.approvedOrActive.index; + + @override + Widget build(BuildContext context) { + CategoryData categoryData = ModalRoute.of(context)!.settings.arguments as CategoryData; + List? services = []; + if (selectedService == ServiceStatus.approvedOrActive.index) { + services = categoryData.services!.where((i) => i.serviceStatus == selectedService + 1).toList(); + } else { + services = categoryData.services!.where((i) => i.serviceStatus != selectedService + 1).toList(); + } + + return Scaffold( + appBar: const CustomAppBar( + title: "Services", + ), + body: SizedBox( + width: double.infinity, + child: Column( + children: [ + Padding( + padding: const EdgeInsets.only(left: 20, right: 20, top: 20), + child: RoleTypeTab( + selectedTap, + [ + DropValue(0, "Active", ""), + DropValue(1, "Requested", ""), + ], + width: (MediaQuery.of(context).size.width / 2) - 26, + onSelect: (DropValue value) { + setState(() { + selectedTap = value.id; + if (selectedTap == 0) { + selectedService = ServiceStatus.approvedOrActive.index; + } else { + selectedService = 1; + } + }); + }, + ), + ), + 10.height, + Expanded( + child: services.isEmpty + ? const EmptyWidget() + : ListView.separated( + itemBuilder: (context, index) { + return SizedBox( + width: double.infinity, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Row( + children: [ + Expanded(child: services![index].serviceName.toString().toText(fontSize: 16, isBold: true)), + Padding( + padding: const EdgeInsets.all(4.0), + child: SvgPicture.asset( + MyAssets.icEdit, + width: 16, + height: 16, + ), + ).onPress(() { + navigateWithName( + context, + ProviderAppRoutes.createServices3, + arguments: CreateBranchModel( + branchId: categoryData.branchId ?? "", + branchName: categoryData.branchName ?? "", + categoryId: categoryData.id.toString(), + categoryName: categoryData.categoryName, + serviceProviderService: services![index], + ), + ); + }), + ], + ), + Row( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + 4.height, + showItem("Available for appointment:", "Yes", valueColor: Colors.green), + showItem("Allowing home service:", (services[index].isAllowAppointment ?? false) ? "Yes" : "No", valueColor: Colors.green), + showItem("Home service range:", services[index].customerLocationRange.toString()), + showItem("Charges per KM:", services[index].rangePricePerKm.toString()), + ], + ), + ), + const Icon( + Icons.arrow_forward_rounded, + size: 16, + ), + ], + ), + ], + ), + ) + .toWhiteContainer( + width: double.infinity, + allPading: 12, + ) + .onPress( + () { + navigateWithName(context, ProviderAppRoutes.itemsList, arguments: services![index]); + }, + ); + }, + separatorBuilder: (context, index) { + return 12.height; + }, + padding: const EdgeInsets.only(left: 20, right: 20, bottom: 20, top: 10), + itemCount: services.length, + ), + ), + ], + ), + ), + ); + } + + Widget showItem(String item, String value, {Color valueColor = Colors.black}) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + item.toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), + 4.width, + value.toText(fontSize: 12, color: valueColor, isBold: true), + ], + ); + } +} diff --git a/lib/views/subscriptions/my_subscritions_page.dart b/lib/views/subscriptions/my_subscritions_page.dart index 8136a13..df26870 100644 --- a/lib/views/subscriptions/my_subscritions_page.dart +++ b/lib/views/subscriptions/my_subscritions_page.dart @@ -1,14 +1,21 @@ +import 'package:car_provider_app/view_models/subscriptions_view_model.dart'; import 'package:car_provider_app/views/subscriptions/widget/subscriptions_card.dart'; import 'package:flutter/material.dart'; +import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; +import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart'; +import 'package:mc_common_app/widgets/tab/menu_tabs.dart'; +import 'package:provider/provider.dart'; class MySubscriptionsPage extends StatelessWidget { const MySubscriptionsPage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { + context.read().getMySubscriptions(AppState().getUser.data?.userInfo?.providerId.toString() ?? ""); return Scaffold( appBar: const CustomAppBar( title: "My Subscriptions", @@ -16,15 +23,33 @@ class MySubscriptionsPage extends StatelessWidget { body: SizedBox( width: double.infinity, height: double.infinity, - child: Column( - children: [ - 21.height, - SubscriptionsCard( - isSubscribed: true, - backgroundColor: MyColors.darkIconColor, - ), - ], - ), + child: Consumer(builder: (context, model, _) { + return model.state == ViewState.busy + ? const Center(child: CircularProgressIndicator()) + : SingleChildScrollView( + child: Column( + children: [ + 21.height, + ListView.separated( + itemBuilder: (BuildContext context, int index) { + return SubscriptionsCard( + model.allSubscriptions.data![index], + isSubscribed: model.allSubscriptions.data![index].isSubscribed ?? false, + backgroundColor: MyColors.darkIconColor, + ); + }, + separatorBuilder: (BuildContext context, int index) { + return 21.height; + }, + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: model.allSubscriptions.data!.length, + ), + 21.height, + ], + ), + ); + }), ), ); } diff --git a/lib/views/subscriptions/subscriptions_page.dart b/lib/views/subscriptions/subscriptions_page.dart index 8fd12a0..38cd5a1 100644 --- a/lib/views/subscriptions/subscriptions_page.dart +++ b/lib/views/subscriptions/subscriptions_page.dart @@ -1,16 +1,21 @@ +import 'package:car_provider_app/view_models/subscriptions_view_model.dart'; import 'package:car_provider_app/views/subscriptions/widget/subscriptions_card.dart'; import 'package:flutter/material.dart'; +import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart'; import 'package:mc_common_app/widgets/tab/menu_tabs.dart'; +import 'package:provider/provider.dart'; class SubscriptionsPage extends StatelessWidget { const SubscriptionsPage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { + context.read().getAllAvailableSubscriptions(null); return Scaffold( appBar: const CustomAppBar( title: "Subscriptions", @@ -18,27 +23,44 @@ class SubscriptionsPage extends StatelessWidget { body: SizedBox( width: double.infinity, height: double.infinity, - child: Column( - children: [ - 21.height, - MenuTabs( - 0, - [ - DropValue(0, "1 Month", ""), - DropValue(1, "2 Month", ""), - DropValue(2, "3 Month", ""), - ], - selectedColor: MyColors.primaryColor, - onSelect: (DropValue selectedValue) {}, - ), - 21.height, - SubscriptionsCard( - isSubscribed: true, - ), - 21.height, - SubscriptionsCard() - ], - ), + child: Consumer(builder: (context, model, _) { + return model.state == ViewState.busy + ? const Center(child: CircularProgressIndicator()) + : SingleChildScrollView( + child: Column( + children: [ + 21.height, + MenuTabs( + model.selectedIndex, + model.monthlyTabs, + selectedColor: MyColors.primaryColor, + onSelect: (DropValue selectedValue) { + model.selectedMothlyTab = selectedValue; + // model.selectedIndex = selectedIndex; + model.filterSubscriptions(); + model.setState(ViewState.idle); + }, + ), + 21.height, + ListView.separated( + itemBuilder: (BuildContext context, int index) { + return SubscriptionsCard( + model.tempSubscriptions[index], + isSubscribed: model.tempSubscriptions[index].isSubscribed ?? false, + ); + }, + separatorBuilder: (BuildContext context, int index) { + return 21.height; + }, + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: model.tempSubscriptions.length, + ), + 21.height, + ], + ), + ); + }), ), ); } diff --git a/lib/views/subscriptions/widget/subscriptions_card.dart b/lib/views/subscriptions/widget/subscriptions_card.dart index 1675d58..95564d3 100644 --- a/lib/views/subscriptions/widget/subscriptions_card.dart +++ b/lib/views/subscriptions/widget/subscriptions_card.dart @@ -1,16 +1,19 @@ +import 'package:car_provider_app/common/subscription_model.dart'; import 'package:flutter/material.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/utils/date_helper.dart'; import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; class SubscriptionsCard extends StatelessWidget { + Subscription subscription; bool isSubscribed; Color? backgroundColor; late Color textColor; - SubscriptionsCard({Key? key, this.isSubscribed = false, this.backgroundColor}) : super(key: key); + SubscriptionsCard(this.subscription, {Key? key, this.isSubscribed = false, this.backgroundColor}) : super(key: key); @override Widget build(BuildContext context) { @@ -21,10 +24,10 @@ class SubscriptionsCard extends StatelessWidget { Row( children: [ Expanded( - child: "Silver Plan".toText( - fontSize: 18, - color: textColor, - ), + child: subscription.name.toString().toText( + fontSize: 18, + color: textColor, + ), ), if (isSubscribed) Row( @@ -54,9 +57,9 @@ class SubscriptionsCard extends StatelessWidget { ], ), 6.height, - showItem("Ads:", "10"), - showItem("Users:", "20"), - showItem("Branches:", "5"), + showItem("Ads:", subscription.numberOfAds.toString()), + showItem("Users:", subscription.numberOfSubUsers.toString()), + showItem("Branches:", subscription.numberOfBranches.toString()), 14.height, Row( crossAxisAlignment: CrossAxisAlignment.center, @@ -67,13 +70,13 @@ class SubscriptionsCard extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.end, children: [ - "30,000".toText( - fontSize: 26, - isBold: true, - color: textColor, - ), + subscription.price.toString().toText( + fontSize: 26, + isBold: true, + color: textColor, + ), 2.width, - "SAR/Month".toText( + "${subscription.currency}/Month".toText( color: MyColors.lightTextColor, fontSize: 16, ), @@ -88,9 +91,10 @@ class SubscriptionsCard extends StatelessWidget { color: textColor, ), 4.width, - const Icon( + Icon( Icons.arrow_forward, size: 16, + color: textColor, ) ], ) @@ -99,7 +103,7 @@ class SubscriptionsCard extends StatelessWidget { if (isSubscribed) Row( children: [ - "Expires on 3 Mar, 2023".toText( + "Expires on ${DateHelper.formatAsDayMonthYear(subscription.dateEnd)}".toText( fontSize: 14, color: textColor, ), diff --git a/pubspec.lock b/pubspec.lock index 3957802..e781b07 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -13,10 +13,10 @@ packages: dependency: transitive description: name: async - sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dev" source: hosted - version: "2.10.0" + version: "2.11.0" auto_size_text: dependency: transitive description: @@ -77,10 +77,10 @@ packages: dependency: transitive description: name: characters - sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.3.0" clock: dependency: transitive description: @@ -93,10 +93,10 @@ packages: dependency: transitive description: name: collection - sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.17.1" cross_file: dependency: transitive description: @@ -121,14 +121,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.5" + dropdown_button2: + dependency: transitive + description: + name: dropdown_button2 + sha256: "193e97bfe9fd3d89317bddb6129653781fa9b62d99811d49f633e67ea449a62c" + url: "https://pub.dev" + source: hosted + version: "2.1.0" easy_localization: dependency: transitive description: name: easy_localization - sha256: "6a2e99fa0bfe5765bf4c6ca9b137d5de2c75593007178c5e4cd2ae985f870080" + sha256: f30e9b20ed4d1b890171c30241d9b9c43efe21fee55dee7bd68f94daf269ea75 url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2-dev.2" easy_logger: dependency: transitive description: @@ -433,18 +441,18 @@ packages: dependency: transitive description: name: intl - sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91" + sha256: a3715e3bc90294e971cb7dc063fbf3cd9ee0ebf8604ffeafabd9e6f16abbdbe6 url: "https://pub.dev" source: hosted - version: "0.17.0" + version: "0.18.0" js: dependency: transitive description: name: js - sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 url: "https://pub.dev" source: hosted - version: "0.6.5" + version: "0.6.7" lints: dependency: transitive description: @@ -457,10 +465,42 @@ packages: dependency: transitive description: name: local_auth - sha256: d3fece0749101725b03206f84a7dab7aaafb702dbbd09131ff8d8173259a9b19 + sha256: "0cf238be2bfa51a6c9e7e9cfc11c05ea39f2a3a4d3e5bb255d0ebc917da24401" + url: "https://pub.dev" + source: hosted + version: "2.1.6" + local_auth_android: + dependency: transitive + description: + name: local_auth_android + sha256: c5e48c4a67fc0e5dd9b5725cc8766b67e2da9a54155c82c6e2ea4a0d1cf9ef93 url: "https://pub.dev" source: hosted - version: "1.1.11" + version: "1.0.28" + local_auth_ios: + dependency: transitive + description: + name: local_auth_ios + sha256: "503a938c4edde6b244c6ee3b1e2e675ddb7e37e79d5056658dbed1997cf04785" + url: "https://pub.dev" + source: hosted + version: "1.1.2" + local_auth_platform_interface: + dependency: transitive + description: + name: local_auth_platform_interface + sha256: "9e160d59ef0743e35f1b50f4fb84dc64f55676b1b8071e319ef35e7f3bc13367" + url: "https://pub.dev" + source: hosted + version: "1.0.7" + local_auth_windows: + dependency: transitive + description: + name: local_auth_windows + sha256: "19323b75ab781d5362dbb15dcb7e0916d2431c7a6dbdda016ec9708689877f73" + url: "https://pub.dev" + source: hosted + version: "1.0.8" logger: dependency: transitive description: @@ -473,10 +513,10 @@ packages: dependency: transitive description: name: matcher - sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" url: "https://pub.dev" source: hosted - version: "0.12.13" + version: "0.12.15" material_color_utilities: dependency: transitive description: @@ -496,10 +536,10 @@ packages: dependency: transitive description: name: meta - sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.9.1" nested: dependency: transitive description: @@ -520,10 +560,10 @@ packages: dependency: transitive description: name: path - sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" url: "https://pub.dev" source: hosted - version: "1.8.2" + version: "1.8.3" path_drawing: dependency: transitive description: @@ -837,10 +877,10 @@ packages: dependency: transitive description: name: test_api - sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb url: "https://pub.dev" source: hosted - version: "0.4.16" + version: "0.5.1" typed_data: dependency: transitive description: @@ -962,5 +1002,5 @@ packages: source: hosted version: "6.2.2" sdks: - dart: ">=2.18.0 <3.0.0" + dart: ">=3.0.0-0 <4.0.0" flutter: ">=3.3.0"