Services merging in Schedules (In Progress)

pull/3/head
FaizHashmiCS22 3 years ago
parent 436befd111
commit 533952e14e

@ -1,10 +1,12 @@
import 'package:car_customer_app/repositories/provider_repo.dart'; import 'package:car_customer_app/repositories/provider_repo.dart';
import 'package:car_customer_app/repositories/schedule_repo.dart';
import 'package:mc_common_app/config/dependencies.dart'; import 'package:mc_common_app/config/dependencies.dart';
class CustomerDependencies { class CustomerDependencies {
static void addDependencies() { static void addDependencies() {
AppDependencies.addDependencies(); AppDependencies.addDependencies();
injector.registerSingleton<ProviderRepo>(() => ProviderRepoImp()); injector.registerSingleton<ProviderRepo>(() => ProviderRepoImp());
injector.registerSingleton<ScheduleRepo>(() => ScheduleRepoImp());
} }
} }

@ -1,6 +1,8 @@
import 'package:car_customer_app/views/appointments/appointment_detail_view.dart'; import 'package:car_customer_app/views/appointments/appointment_detail_view.dart';
import 'package:car_customer_app/views/appointments/book_appointment_services_view.dart'; import 'package:car_customer_app/views/appointments/book_appointment_services_view.dart';
import 'package:car_customer_app/views/appointments/book_appointments_item_view.dart';
import 'package:car_customer_app/views/appointments/pick_items_view.dart'; import 'package:car_customer_app/views/appointments/pick_items_view.dart';
import 'package:car_customer_app/views/appointments/review_appointment_view.dart';
import 'package:car_customer_app/views/dashboard/dashboard_page.dart'; import 'package:car_customer_app/views/dashboard/dashboard_page.dart';
import 'package:car_customer_app/views/provider/branch_detail_page.dart'; import 'package:car_customer_app/views/provider/branch_detail_page.dart';
import 'package:car_customer_app/views/provider/provider_profile_page.dart'; import 'package:car_customer_app/views/provider/provider_profile_page.dart';
@ -21,6 +23,8 @@ class CustomerAppRoutes {
AppRoutes.adsDetailView: (context) => AdsDetailView(adDetails: ModalRoute.of(context)!.settings.arguments as AdDetailsModel), AppRoutes.adsDetailView: (context) => AdsDetailView(adDetails: ModalRoute.of(context)!.settings.arguments as AdDetailsModel),
AppRoutes.createAdView: (context) => CreateAdView(), AppRoutes.createAdView: (context) => CreateAdView(),
AppRoutes.bookAppointmenServicesView: (context) => BookAppointmentServicesView(), AppRoutes.bookAppointmenServicesView: (context) => BookAppointmentServicesView(),
AppRoutes.bookAppointmentsItemView: (context) => BookAppointmentsItemView(),
AppRoutes.reviewAppointmentView: (context) => ReviewAppointment(),
AppRoutes.paymentMethodsView: (context) => PaymentMethodsView(), AppRoutes.paymentMethodsView: (context) => PaymentMethodsView(),
AppRoutes.branchDetailPage: (context) => BranchDetailPage(branchDetailModel: ModalRoute.of(context)!.settings.arguments as BranchDetailModel), AppRoutes.branchDetailPage: (context) => BranchDetailPage(branchDetailModel: ModalRoute.of(context)!.settings.arguments as BranchDetailModel),
AppRoutes.providerProfilePage: (context) => ProviderProfilePage(providerId: ModalRoute.of(context)!.settings.arguments as int), AppRoutes.providerProfilePage: (context) => ProviderProfilePage(providerId: ModalRoute.of(context)!.settings.arguments as int),

@ -1,6 +1,7 @@
import 'package:car_customer_app/config/customer_dependencies.dart'; import 'package:car_customer_app/config/customer_dependencies.dart';
import 'package:car_customer_app/config/customer_routes.dart'; import 'package:car_customer_app/config/customer_routes.dart';
import 'package:car_customer_app/repositories/provider_repo.dart'; import 'package:car_customer_app/repositories/provider_repo.dart';
import 'package:car_customer_app/repositories/schedule_repo.dart';
import 'package:car_customer_app/view_models/appointments_view_model.dart'; import 'package:car_customer_app/view_models/appointments_view_model.dart';
import 'package:car_customer_app/view_models/dashboard_view_model.dart'; import 'package:car_customer_app/view_models/dashboard_view_model.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
@ -26,7 +27,6 @@ import 'package:provider/provider.dart';
import 'package:provider/single_child_widget.dart'; import 'package:provider/single_child_widget.dart';
import 'package:sizer/sizer.dart'; import 'package:sizer/sizer.dart';
//test commit //test commit
Future<void> main() async { Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
@ -56,6 +56,7 @@ Future<void> main() async {
), ),
ChangeNotifierProvider<AppointmentsVM>( ChangeNotifierProvider<AppointmentsVM>(
create: (_) => AppointmentsVM( create: (_) => AppointmentsVM(
scheduleRepo: injector.get<ScheduleRepo>(),
providerRepo: injector.get<ProviderRepo>(), providerRepo: injector.get<ProviderRepo>(),
commonServices: injector.get<CommonAppServices>(), commonServices: injector.get<CommonAppServices>(),
commonRepo: injector.get<CommonRepo>(), commonRepo: injector.get<CommonRepo>(),

@ -12,7 +12,7 @@ import 'package:mc_common_app/models/services/item_model.dart';
abstract class ProviderRepo { abstract class ProviderRepo {
Future<List<BranchDetailModel>> getAllNearBranchAndServices(); Future<List<BranchDetailModel>> getAllNearBranchAndServices();
Future<List<ServiceItemModel>> getServiceItems(int serviceId); Future<List<ItemData>> getServiceItems(int serviceId);
Future<ProviderProfileModel> getBranchAndServices(int providerId); Future<ProviderProfileModel> getBranchAndServices(int providerId);
} }
@ -29,7 +29,7 @@ class ProviderRepoImp implements ProviderRepo {
} }
@override @override
Future<List<ServiceItemModel>> getServiceItems(int serviceId) async { Future<List<ItemData>> getServiceItems(int serviceId) async {
var queryParameters = { var queryParameters = {
"ServiceProviderServiceID": serviceId.toString(), "ServiceProviderServiceID": serviceId.toString(),
}; };
@ -40,7 +40,7 @@ class ProviderRepoImp implements ProviderRepo {
token: appState.getUser.data!.accessToken, token: appState.getUser.data!.accessToken,
queryParameters: queryParameters, queryParameters: queryParameters,
); );
List<ServiceItemModel> serviceItems = List.generate(adsGenericModel.data.length, (index) => ServiceItemModel.fromJson(adsGenericModel.data[index])); List<ItemData> serviceItems = List.generate(adsGenericModel.data.length, (index) => ItemData.fromJson(adsGenericModel.data[index]));
return serviceItems; return serviceItems;
} }

@ -0,0 +1,70 @@
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/generic_resp_model.dart';
import 'package:mc_common_app/models/m_response.dart';
import 'package:mc_common_app/models/provider_branches_models/profile/services.dart';
import 'package:mc_common_app/models/schedule_model.dart';
abstract class ScheduleRepo {
Future<Services> getAllServices(String branchId);
Future<MResponse> createSchedule(Map map);
Future<MResponse> addServicesInSchedule(Map map);
Future<MResponse> updateSchedule(Map map);
Future<List<ScheduleData>> getSchedules(String branchId);
Future<MResponse> updateServicesInSchedule(Map map);
}
class ScheduleRepoImp implements ScheduleRepo {
@override
Future<Services> getAllServices(String branchId) async {
Map<String, dynamic> map = {"ProviderBranchID": branchId};
String t = AppState().getUser.data!.accessToken ?? "";
return await injector.get<ApiClient>().getJsonForObject((json) => Services.fromJson(json), ApiConsts.getServicesOfBranch, token: t, queryParameters: map);
}
@override
Future<MResponse> createSchedule(Map map) async {
String t = AppState().getUser.data!.accessToken ?? "";
return await injector.get<ApiClient>().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.createSchedule, map, token: t);
}
@override
Future<MResponse> addServicesInSchedule(Map map) async {
String t = AppState().getUser.data!.accessToken ?? "";
return await injector.get<ApiClient>().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.createGroup, map, token: t);
}
@override
Future<List<ScheduleData>> getSchedules(String branchId) async {
Map<String, dynamic> map = {"ServiceProviderBranchID": branchId};
String t = AppState().getUser.data!.accessToken ?? "";
GenericRespModel adsGenericModel = await injector.get<ApiClient>().getJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.getSchedule,
token: t,
queryParameters: map,
);
return List.generate(adsGenericModel.data.length, (index) => ScheduleData.fromJson(adsGenericModel.data[index]));
}
@override
Future<MResponse> updateSchedule(Map map) async {
String t = AppState().getUser.data!.accessToken ?? "";
return await injector.get<ApiClient>().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.updateSchedule, map, token: t);
}
@override
Future<MResponse> updateServicesInSchedule(Map map) async {
String t = AppState().getUser.data!.accessToken ?? "";
return await injector.get<ApiClient>().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.updateGroup, map, token: t);
}
}

@ -1,8 +1,12 @@
import 'dart:developer';
import 'package:car_customer_app/repositories/provider_repo.dart'; import 'package:car_customer_app/repositories/provider_repo.dart';
import 'package:car_customer_app/repositories/schedule_repo.dart';
import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart'; import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart';
import 'package:mc_common_app/models/provider_branches_models/branch_detail_model.dart'; import 'package:mc_common_app/models/provider_branches_models/branch_detail_model.dart';
import 'package:mc_common_app/models/provider_branches_models/provider_profile_model.dart'; import 'package:mc_common_app/models/provider_branches_models/provider_profile_model.dart';
import 'package:mc_common_app/models/schedule_model.dart';
import 'package:mc_common_app/models/services/item_model.dart'; import 'package:mc_common_app/models/services/item_model.dart';
import 'package:mc_common_app/models/services/service_model.dart'; import 'package:mc_common_app/models/services/service_model.dart';
import 'package:mc_common_app/models/widgets_models.dart'; import 'package:mc_common_app/models/widgets_models.dart';
@ -16,20 +20,29 @@ class AppointmentsVM extends BaseVM {
final CommonRepo commonRepo; final CommonRepo commonRepo;
final CommonAppServices commonServices; final CommonAppServices commonServices;
final ProviderRepo providerRepo; final ProviderRepo providerRepo;
final ScheduleRepo scheduleRepo;
AppointmentsVM({required this.commonServices, required this.providerRepo, required this.commonRepo}); AppointmentsVM({required this.commonServices, required this.scheduleRepo, required this.providerRepo, required this.commonRepo});
bool isFetchingLists = false; bool isFetchingLists = false;
List<AppointmentListModel> myAppointments = []; List<AppointmentListModel> myAppointments = [];
List<FilterListModel> appointmentsFilterOptions = []; List<FilterListModel> appointmentsFilterOptions = [];
List<ScheduleData> availableSchedules = [];
bool isFetchingServices = false; bool isFetchingServices = false;
List<DropValue> branchCategories = []; List<DropValue> branchCategories = [];
bool isHomeTapped = false; bool isHomeTapped = false;
Future<void> getSchedulesByBranchId() async {
availableSchedules = await scheduleRepo.getSchedules(selectedBranchModel!.id!.toString());
log("schedules: ${availableSchedules.toString()}");
notifyListeners();
}
void updateIsHomeTapped(bool value) { void updateIsHomeTapped(bool value) {
isHomeTapped = value; isHomeTapped = value;
notifyListeners(); notifyListeners();
@ -39,38 +52,38 @@ class AppointmentsVM extends BaseVM {
void updatePickedHomeLocation(String value) { void updatePickedHomeLocation(String value) {
pickedHomeLocation = value; pickedHomeLocation = value;
pickHomeLocationError = "";
notifyListeners(); notifyListeners();
} }
SelectionModel branchSelectedCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); SelectionModel branchSelectedCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
void updateProviderCategoryId(SelectionModel id) async { void updateProviderCategoryId(SelectionModel id) {
branchSelectedCategoryId = id; branchSelectedCategoryId = id;
await getProviderServices(id.selectedId); getBranchServices(categoryId: branchSelectedCategoryId.selectedId);
notifyListeners(); notifyListeners();
} }
List<ServiceModel> branchServices = []; List<FilterListModel> providersFilterOptions = [];
List<BranchDetailModel> nearbyBranches = [];
BranchDetailModel? selectedBranchModel;
SelectionModel branchSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); List<ServiceModel> branchServices = [];
ServiceModel? currentServiceSelection;
void updateBranchServiceId(SelectionModel id) async { void updateBranchServiceId(SelectionModel id) async {
branchSelectedServiceId = id; branchSelectedServiceId = id;
currentServiceSelection = branchServices.firstWhere((element) => element.serviceProviderServiceId == id.selectedId);
notifyListeners(); notifyListeners();
} }
getProviderServices(int categoryId) async { resetCategorySelectionBottomSheet() {
branchSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); selectedSubServicesCounter = 0;
branchSelectedCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
isHomeTapped = false; isHomeTapped = false;
pickedHomeLocation = ""; branchSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
if (categoryId != -1) { currentServiceSelection = null;
isFetchingServices = true;
notifyListeners();
// branchServices = await commonRepo.getProviderServices(categoryId: categoryId);
isFetchingServices = false;
notifyListeners();
}
} }
populateAppointmentsFilterList() { populateAppointmentsFilterList() {
@ -101,11 +114,39 @@ class AppointmentsVM extends BaseVM {
notifyListeners(); notifyListeners();
} }
List<FilterListModel> providersFilterOptions = []; updateSelectedBranch(BranchDetailModel branchDetailModel) {
List<BranchDetailModel> nearbyBranches = []; selectedBranchModel = branchDetailModel;
List<ServiceItemModel> serviceItems = []; getBranchCategories();
notifyListeners();
}
List<ItemData> serviceItems = [];
List<ItemData> selectedServiceItems = [];
ProviderProfileModel? providerProfileModel; ProviderProfileModel? providerProfileModel;
int selectedSubServicesCounter = 0;
updateSelectedSubServicesCounter(int value) {
selectedSubServicesCounter = value;
notifyListeners();
}
onItemUpdateOrSelected(int index, bool selected, int itemId) {
serviceItems[index].isUpdateOrSelected = selected;
if (selected) {
selectedSubServicesCounter = selectedSubServicesCounter + 1;
updateSelectedSubServicesCounter(selectedSubServicesCounter);
selectSubServicesError = "";
currentServiceSelection!.serviceItems!.add(serviceItems[index]);
}
if (!selected) {
selectedSubServicesCounter = selectedSubServicesCounter - 1;
updateSelectedSubServicesCounter(selectedSubServicesCounter);
currentServiceSelection!.serviceItems!.removeWhere((element) => element.id == itemId);
}
notifyListeners();
}
populateProvidersFilterList() { populateProvidersFilterList() {
providersFilterOptions.clear(); providersFilterOptions.clear();
providersFilterOptions = [ providersFilterOptions = [
@ -128,7 +169,6 @@ class AppointmentsVM extends BaseVM {
notifyListeners(); notifyListeners();
} }
//Create new branch
getAllNearBranches({bool isNeedToRebuild = false}) async { getAllNearBranches({bool isNeedToRebuild = false}) async {
//TODO: needs to lat,long into API //TODO: needs to lat,long into API
nearbyBranches.clear(); nearbyBranches.clear();
@ -137,7 +177,7 @@ class AppointmentsVM extends BaseVM {
setState(ViewState.idle); setState(ViewState.idle);
} }
Future<List<ServiceItemModel>> getServiceItems(int serviceId) async { Future<List<ItemData>> getServiceItems(int serviceId) async {
serviceItems.clear(); serviceItems.clear();
serviceItems = await providerRepo.getServiceItems(serviceId); serviceItems = await providerRepo.getServiceItems(serviceId);
setState(ViewState.idle); setState(ViewState.idle);
@ -151,8 +191,9 @@ class AppointmentsVM extends BaseVM {
} }
String pickHomeLocationError = ""; String pickHomeLocationError = "";
String selectSubServicesError = "";
SelectionModel branchServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); SelectionModel branchSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
bool isCategoryAlreadyPresent(int id) { bool isCategoryAlreadyPresent(int id) {
final contain = branchCategories.where((element) => element.id == id); final contain = branchCategories.where((element) => element.id == id);
@ -163,7 +204,7 @@ class AppointmentsVM extends BaseVM {
} }
void getBranchCategories() async { void getBranchCategories() async {
for (var value in branchServices) { for (var value in selectedBranchModel!.branchServices!) {
if (!isCategoryAlreadyPresent(value.categoryId!)) { if (!isCategoryAlreadyPresent(value.categoryId!)) {
branchCategories.add(DropValue(value.categoryId!, value.categoryName!, "")); branchCategories.add(DropValue(value.categoryId!, value.categoryName!, ""));
} }
@ -171,24 +212,24 @@ class AppointmentsVM extends BaseVM {
notifyListeners(); notifyListeners();
} }
getBranchServices(int categoryId) async { getBranchServices({required int categoryId}) async {
branchServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); branchSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
isHomeTapped = false; isHomeTapped = false;
pickedHomeLocation = ""; pickedHomeLocation = "";
pickHomeLocationError = ""; pickHomeLocationError = "";
if (categoryId != -1) { if (categoryId != -1) {
isFetchingServices = true; isFetchingServices = true;
notifyListeners(); // notifyListeners();
branchServices = getFilteredBranchServices(categoryId: categoryId, branchId: 6); branchServices = getFilteredBranchServices(categoryId: categoryId);
isFetchingServices = false; isFetchingServices = false;
notifyListeners(); notifyListeners();
} }
} }
List<ServiceModel> getFilteredBranchServices({required int branchId, required int categoryId}) { List<ServiceModel> getFilteredBranchServices({required int categoryId}) {
// List<BranchServices> filteredServices = nearbyBranchesList.where((element) => element) List<ServiceModel> filteredServices = selectedBranchModel!.branchServices!.where((element) => element.categoryId == categoryId).toList();
return []; log("returning: ${filteredServices.toString()}");
return filteredServices;
} }
void updatePickHomeLocationError(String value) { void updatePickHomeLocationError(String value) {
@ -197,7 +238,7 @@ class AppointmentsVM extends BaseVM {
} }
bool isServiceSelectionValidated() { bool isServiceSelectionValidated() {
if (branchServiceId.selectedId == -1) { if (branchSelectedServiceId.selectedId == -1) {
return false; return false;
} }
@ -209,4 +250,24 @@ class AppointmentsVM extends BaseVM {
} }
return true; return true;
} }
bool onSubServicesNextPressed() {
for (var value in serviceItems) {
if (value.isUpdateOrSelected!) {
return true;
}
}
selectSubServicesError = "Please select at least one sub service";
notifyListeners();
return false;
}
void mergeServiceInAvailableSchedule() {
for (var schedule in availableSchedules) {
for (var service in schedule.scheduleServices!) {
if (branchSelectedServiceId.selectedId == service.serviceId) {}
schedule.selectedServices!.add(currentServiceSelection!);
}
}
}
} }

@ -5,6 +5,9 @@ import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/routes.dart'; import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/schedule_model.dart';
import 'package:mc_common_app/models/services/item_model.dart';
import 'package:mc_common_app/models/services/service_model.dart';
import 'package:mc_common_app/models/widgets_models.dart'; import 'package:mc_common_app/models/widgets_models.dart';
import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/navigator.dart'; import 'package:mc_common_app/utils/navigator.dart';
@ -148,15 +151,16 @@ class BookAppointmentServicesView extends StatelessWidget {
10.height, 10.height,
ListView.builder( ListView.builder(
shrinkWrap: true, shrinkWrap: true,
itemCount: 20, itemCount: appointmentsVM.availableSchedules.where((element) => element.selectedServices!.isNotEmpty).toList().length,
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int scheduleIndex) {
ScheduleData scheduleData = appointmentsVM.availableSchedules.where((element) => element.selectedServices!.isNotEmpty).toList()[scheduleIndex];
return Column( return Column(
children: [ children: [
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Expanded( Expanded(
child: "Mechanic".toText(fontSize: 16, isBold: true), child: "Schedule: ${scheduleData.scheduleName}".toText(fontSize: 20, isBold: true),
), ),
Align( Align(
alignment: Alignment.topRight, alignment: Alignment.topRight,
@ -164,60 +168,84 @@ class BookAppointmentServicesView extends StatelessWidget {
).onPress(() {}), ).onPress(() {}),
], ],
), ),
Builder(builder: (context) { if (true) ...[
return Column( 5.height,
crossAxisAlignment: CrossAxisAlignment.start, Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
if (true) ...[ ("Available Slots").toText(fontSize: 14, isBold: true),
Row( ],
crossAxisAlignment: CrossAxisAlignment.start, ),
5.height,
SizedBox(
width: double.infinity,
child: BuildTimeSlots(
timeSlots: _dummySlots,
onPressed: (index) => null,
),
),
],
20.height,
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ListView.separated(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: scheduleData.selectedServices!.length,
itemBuilder: (BuildContext context, int serviceIndex) {
ServiceModel selectedService = scheduleData.selectedServices![serviceIndex];
return Column(
children: [ children: [
"Service Location: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), Row(
("Home").toText(fontSize: 12, isBold: true).expand(),
],
),
8.height,
Column(
children: List.generate(
5,
(index) => Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
"Gear Kit: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), Expanded(
("200 SAR").toText(fontSize: 12, isBold: true).expand(), child: "${selectedService.serviceDescription}".toText(fontSize: 15, isBold: true),
),
], ],
), ),
), if (true) ...[
), Row(
8.height, crossAxisAlignment: CrossAxisAlignment.start,
Row( children: [
crossAxisAlignment: CrossAxisAlignment.end, "Service Location: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
children: [ ("Home").toText(fontSize: 12, isBold: true).expand(),
"120".toText(fontSize: 29, isBold: true), ],
2.width, ),
"SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5), 8.height,
Icon( Column(
Icons.arrow_drop_down, children: List.generate(scheduleData.selectedServices![serviceIndex].serviceItems!.length, (itemIndex) {
size: 30, ItemData itemData = selectedService.serviceItems![itemIndex];
) return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"${itemData.name}: ".toText(fontSize: 13, color: MyColors.lightTextColor, isBold: true),
("${itemData.price}").toText(fontSize: 13, isBold: true).expand(),
],
);
}),
),
8.height,
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
"120".toText(fontSize: 29, isBold: true),
2.width,
"SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5),
Icon(
Icons.arrow_drop_down,
size: 30,
)
],
).onPress(() => priceBreakDownClicked(context)),
],
], ],
).onPress(() => priceBreakDownClicked(context)), );
], },
if (true) ...[ separatorBuilder: (BuildContext context, int index) => Divider(thickness: 2),
8.height, )
("Available Slots").toText(fontSize: 14, isBold: true), ],
5.height, ),
SizedBox(
width: double.infinity,
child: BuildTimeSlots(
timeSlots: _dummySlots,
onPressed: (index) => null,
),
),
],
],
);
}),
], ],
).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10)); ).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10));
}, },

@ -4,7 +4,10 @@ import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/services/item_model.dart';
import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/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/button/show_fill_button.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
@ -33,7 +36,7 @@ class BookAppointmentsItemView extends StatelessWidget {
width: double.infinity, width: double.infinity,
color: MyColors.darkTextColor, color: MyColors.darkTextColor,
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: "3 Items Selected".toText(fontSize: 16, color: MyColors.white).horPaddingMain(), child: "${appointmentsVM.selectedSubServicesCounter} Item(s) Selected".toText(fontSize: 16, color: MyColors.white).horPaddingMain(),
), ),
16.height, 16.height,
Column( Column(
@ -53,33 +56,46 @@ class BookAppointmentsItemView extends StatelessWidget {
Divider(), Divider(),
], ],
).horPaddingMain(), ).horPaddingMain(),
ListView.separated( appointmentsVM.serviceItems.isEmpty
separatorBuilder: (BuildContext context, int index) => Divider(), ? Expanded(child: Center(child: "No Items to show.".toText(fontSize: 16, color: MyColors.lightTextColor)))
itemCount: 20, : ListView.separated(
itemBuilder: (BuildContext context, int index) { separatorBuilder: (BuildContext context, int index) => Divider(),
return ServiceItemWithPriceCheckBox( itemCount: appointmentsVM.serviceItems.length,
description: "Some description about the sub-services", itemBuilder: (BuildContext context, int index) {
title: "Engine Check", ItemData itemData = appointmentsVM.serviceItems[index];
isSelected: true, return ServiceItemWithPriceCheckBox(
onSelection: (bool value) {}, description: "Some description about the sub-services",
priceWidget: Row( title: itemData.name!,
crossAxisAlignment: CrossAxisAlignment.end, isSelected: itemData.isUpdateOrSelected!,
children: [ onSelection: (bool value) {
// TODO: This Price will be decided according to the service selected appointmentsVM.onItemUpdateOrSelected(index, !itemData.isUpdateOrSelected!, itemData!.id!);
150.toString().toText(fontSize: 30, isBold: true), },
"SAR".toText(fontSize: 15, isBold: true, color: MyColors.lightTextColor).paddingOnly(bottom: 5), priceWidget: Row(
], crossAxisAlignment: CrossAxisAlignment.end,
), children: [
); // TODO: This Price will be decided according to the service selected
}, itemData.price!.split(".").first.toText(fontSize: 30, isBold: true),
).expand(), " SAR".toText(fontSize: 15, isBold: true, color: MyColors.lightTextColor).paddingOnly(bottom: 5),
],
),
);
},
).expand(),
Column( Column(
children: [ children: [
Divider( Divider(
height: 1, height: 1,
thickness: 0.7, thickness: 0.7,
), ),
16.height, 8.height,
if (appointmentsVM.selectSubServicesError != "")
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
appointmentsVM.selectSubServicesError.toText(fontSize: 14, color: Colors.red),
],
).paddingOnly(right: 10),
8.height,
Row( Row(
children: [ children: [
Expanded( Expanded(
@ -87,7 +103,10 @@ class BookAppointmentsItemView extends StatelessWidget {
txtColor: MyColors.black, txtColor: MyColors.black,
maxHeight: 55, maxHeight: 55,
title: "Cancel", title: "Cancel",
onPressed: () {}, onPressed: () {
appointmentsVM.resetCategorySelectionBottomSheet();
pop(context);
},
backgroundColor: MyColors.greyButtonColor, backgroundColor: MyColors.greyButtonColor,
), ),
), ),
@ -96,8 +115,22 @@ class BookAppointmentsItemView extends StatelessWidget {
child: ShowFillButton( child: ShowFillButton(
maxHeight: 55, maxHeight: 55,
title: "Next", title: "Next",
onPressed: () {}, onPressed: () async {
backgroundColor: MyColors.darkPrimaryColor, bool resp = appointmentsVM.onSubServicesNextPressed();
if (resp) {
Utils.showLoading(context);
if (appointmentsVM.availableSchedules.isEmpty) {
await appointmentsVM.getSchedulesByBranchId();
}
appointmentsVM.mergeServiceInAvailableSchedule();
Utils.hideLoading(context);
pop(context);
pop(context);
appointmentsVM.resetCategorySelectionBottomSheet();
}
},
backgroundColor: !appointmentsVM.isServiceSelectionValidated() ? MyColors.lightTextColor.withOpacity(0.6) : MyColors.primaryColor,
), ),
), ),
], ],

@ -62,19 +62,27 @@ class AppointmentServicePickBottomSheet extends StatelessWidget {
builder: (context) { builder: (context) {
List<DropValue> serviceCategories = []; List<DropValue> serviceCategories = [];
for (var element in appointmentsVM.branchServices) { for (var element in appointmentsVM.branchServices) {
serviceCategories.add(DropValue(element.serviceProviderServiceId ?? 0, element.serviceProviderServiceId.toString(), "")); if (element.categoryId == appointmentsVM.branchSelectedCategoryId.selectedId) {
serviceCategories.add(DropValue(
element.serviceProviderServiceId ?? 0,
element.serviceDescription!,
"",
));
}
} }
return DropdownField( return DropdownField(
(DropValue value) => appointmentsVM.updateBranchServiceId(SelectionModel(selectedId: value.id, selectedOption: value.value, itemPrice: value.subValue)), (DropValue value) => appointmentsVM.updateBranchServiceId(SelectionModel(selectedId: value.id, selectedOption: value.value, itemPrice: value.subValue)),
list: serviceCategories, list: serviceCategories,
hint: "Select Services", hint: "Select Service",
dropdownValue: dropdownValue: appointmentsVM.branchSelectedServiceId.selectedId != -1
appointmentsVM.branchServiceId.selectedId != -1 ? DropValue(appointmentsVM.branchServiceId.selectedId, appointmentsVM.branchServiceId.selectedOption, "") : null, ? DropValue(appointmentsVM.branchSelectedServiceId.selectedId, appointmentsVM.branchSelectedServiceId.selectedOption, "")
: null,
); );
}, },
), ),
], ],
if (appointmentsVM.branchServiceId.selectedId != -1 && !appointmentsVM.isFetchingServices) ...[ if (appointmentsVM.branchSelectedServiceId.selectedId != -1 && !appointmentsVM.isFetchingServices) ...[
16.height, 16.height,
Row( Row(
children: [ children: [
@ -171,6 +179,7 @@ class AppointmentServicePickBottomSheet extends StatelessWidget {
onPressed: () { onPressed: () {
bool isValidated = appointmentsVM.isServiceSelectionValidated(); bool isValidated = appointmentsVM.isServiceSelectionValidated();
if (isValidated) { if (isValidated) {
appointmentsVM.getServiceItems(appointmentsVM.branchSelectedServiceId.selectedId);
navigateWithName(context, AppRoutes.bookAppointmentsItemView); navigateWithName(context, AppRoutes.bookAppointmentsItemView);
} }
}, },

@ -53,6 +53,7 @@ class BranchesFragment extends StatelessWidget {
itemCount: model.nearbyBranches.length, itemCount: model.nearbyBranches.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
BranchDetailModel branchDetailModel = model.nearbyBranches[index]; BranchDetailModel branchDetailModel = model.nearbyBranches[index];
return ProviderDetailsCard( return ProviderDetailsCard(
onCardTapped: () { onCardTapped: () {
navigateWithName(context, AppRoutes.branchDetailPage, arguments: branchDetailModel); navigateWithName(context, AppRoutes.branchDetailPage, arguments: branchDetailModel);
@ -62,7 +63,7 @@ class BranchesFragment extends StatelessWidget {
providerLocation: branchDetailModel.distanceKm.toString() + " KM", providerLocation: branchDetailModel.distanceKm.toString() + " KM",
providerName: branchDetailModel.serviceProviderName ?? "", providerName: branchDetailModel.serviceProviderName ?? "",
providerRatings: "4.9", providerRatings: "4.9",
items: branchDetailModel.branchServices, services: branchDetailModel.branchServices,
); );
}, },
separatorBuilder: (context, index) { separatorBuilder: (context, index) {

@ -1,3 +1,4 @@
import 'package:car_customer_app/view_models/appointments_view_model.dart';
import 'package:car_customer_app/views/provider/sheet/items_list_sheet.dart'; import 'package:car_customer_app/views/provider/sheet/items_list_sheet.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -13,6 +14,7 @@ import 'package:mc_common_app/widgets/bottom_sheet.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart'; import 'package:mc_common_app/widgets/button/show_fill_button.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart';
class BranchDetailPage extends StatefulWidget { class BranchDetailPage extends StatefulWidget {
final BranchDetailModel branchDetailModel; final BranchDetailModel branchDetailModel;
@ -28,7 +30,7 @@ class _BranchDetailPageState extends State<BranchDetailPage> {
void initState() { void initState() {
// TODO: implement initState // TODO: implement initState
super.initState(); super.initState();
if (widget.branchDetailModel.branchServices!.length > 0) widget.branchDetailModel.branchServices?.first.isExpanded = true; if (widget.branchDetailModel.branchServices!.length > 0) widget.branchDetailModel.branchServices?.first.isExpandedOrSelected = true;
} }
@override @override
@ -151,6 +153,7 @@ class _BranchDetailPageState extends State<BranchDetailPage> {
margin: EdgeInsets.all(21), margin: EdgeInsets.all(21),
onPressed: () { onPressed: () {
navigateWithName(context, AppRoutes.bookAppointmenServicesView); navigateWithName(context, AppRoutes.bookAppointmenServicesView);
context.read<AppointmentsVM>().updateSelectedBranch(widget.branchDetailModel);
}, },
).toContainer( ).toContainer(
paddingAll: 0, paddingAll: 0,
@ -192,13 +195,13 @@ class _BranchDetailPageState extends State<BranchDetailPage> {
], ],
onExpansionChanged: (value) { onExpansionChanged: (value) {
setState(() { setState(() {
widget.branchDetailModel.branchServices![index].isExpanded = value; widget.branchDetailModel.branchServices![index].isExpandedOrSelected = value;
}); });
}, },
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
collapsedBackgroundColor: Colors.transparent, collapsedBackgroundColor: Colors.transparent,
initiallyExpanded: widget.branchDetailModel.branchServices![index].isExpanded, initiallyExpanded: widget.branchDetailModel.branchServices![index].isExpandedOrSelected,
trailing: widget.branchDetailModel.branchServices![index].isExpanded ? Icon(Icons.keyboard_arrow_up) : Icon(Icons.keyboard_arrow_down), trailing: widget.branchDetailModel.branchServices![index].isExpandedOrSelected ? Icon(Icons.keyboard_arrow_up) : Icon(Icons.keyboard_arrow_down),
); );
}, },
separatorBuilder: (context, index) { separatorBuilder: (context, index) {

@ -92,7 +92,7 @@ class _ProviderProfilePageState extends State<ProviderProfilePage> {
providerLocation: model.providerProfileModel!.serviceProviderBranch![index].distanceKm.toString() + " KM", providerLocation: model.providerProfileModel!.serviceProviderBranch![index].distanceKm.toString() + " KM",
providerName: model.providerProfileModel!.serviceProviderBranch![index].serviceProviderName ?? "", providerName: model.providerProfileModel!.serviceProviderBranch![index].serviceProviderName ?? "",
providerRatings: "4.9", providerRatings: "4.9",
items: model.providerProfileModel!.serviceProviderBranch![index].branchServices, services: model.providerProfileModel!.serviceProviderBranch![index].branchServices,
); );
}, },
separatorBuilder: (context, index) { separatorBuilder: (context, index) {

@ -35,7 +35,7 @@ class _ItemsListSheetState extends State<ItemsListSheet> {
: ListView.separated( : ListView.separated(
itemCount: appointmentsVM.serviceItems.length, itemCount: appointmentsVM.serviceItems.length,
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
ServiceItemModel serviceItemModel = appointmentsVM.serviceItems[index]; ItemData serviceItemModel = appointmentsVM.serviceItems[index];
return SizedBox( return SizedBox(
width: double.infinity, width: double.infinity,
child: Row( child: Row(
@ -47,7 +47,7 @@ class _ItemsListSheetState extends State<ItemsListSheet> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
serviceItemModel.name.toString().toText(fontSize: 16, isBold: true), serviceItemModel.toString().toText(fontSize: 16, isBold: true),
4.height, 4.height,
showItem("Available for appointment:", (serviceItemModel.isAllowAppointment ?? false) ? "Yes" : "No", valueColor: Colors.green), showItem("Available for appointment:", (serviceItemModel.isAllowAppointment ?? false) ? "Yes" : "No", valueColor: Colors.green),
showItem("Allowing Workshop service:", (serviceItemModel.isAppointmentCompanyLoc ?? false) ? "Yes" : "No", valueColor: Colors.green), showItem("Allowing Workshop service:", (serviceItemModel.isAppointmentCompanyLoc ?? false) ? "Yes" : "No", valueColor: Colors.green),

Loading…
Cancel
Save