Appointment Implementation 1.1

mirza_dev
Mirza.Shafique@cloudsolutions.com.sa 2 years ago
parent b437bf4c91
commit e4e1b0a3c4

@ -0,0 +1,14 @@
## For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
#
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx1024m -XX:MaxPermSize=256m
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
#
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
#Wed Dec 13 16:00:22 AST 2023
org.gradle.jvmargs=-Xmx2048M -Dkotlin.daemon.jvm.options\="-Xmx2048M"

@ -0,0 +1,44 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '11.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_ios_podfile_setup
target 'Runner' do
use_frameworks!
use_modular_headers!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
target 'RunnerTests' do
inherit! :search_paths
end
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
end
end

@ -0,0 +1,286 @@
import 'package:car_provider_app/view_models/service_view_model.dart';
import 'package:car_provider_app/views/appoinments/widget/select_items_sheet.dart';
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/config/dependencies.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/appointments_models/appointment_list_model.dart';
import 'package:mc_common_app/models/general_models/m_response.dart';
import 'package:mc_common_app/models/services_models/item_model.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/view_models/appointments_view_model.dart';
import 'package:mc_common_app/widgets/bottom_sheet.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
import 'package:mc_common_app/widgets/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';
import 'package:easy_localization/easy_localization.dart';
import '../../generated/locale_keys.g.dart';
import '../dashboard/widget/appointment_slider_widget.dart';
import '../settings/schedule/widgets/chips_picker_item.dart';
class AddNewServiceAppointmentPage extends StatelessWidget {
AppointmentListModel appointmentListModel;
AddNewServiceAppointmentPage(this.appointmentListModel, {Key? key})
: super(key: key);
DropValue? category;
DropValue? service;
List<ItemData> selectedList = [];
List<PickerItem>? pickedItems;
@override
Widget build(BuildContext context) {
ServiceVM serviceVM = context.read<ServiceVM>();
serviceVM.fetchBranchCategory(
EasyLocalization.of(context)?.currentLocale?.countryCode ?? "SA");
return Scaffold(
appBar: const CustomAppBar(
title: "Add Service",
),
body: Padding(
padding: const EdgeInsets.all(21.0),
child: Column(
children: [
AppointmentSliderWidget(
appointmentListModel: appointmentListModel,
isNeedTotalPayment: true,
isNeedToShowItems: true,
isNeedToShowToMoreText: false,
onTap: () {},
),
12.height,
Expanded(
child: Consumer<ServiceVM>(
builder: (context, model, _) {
return Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Select services you want to add".toText(
fontSize: 18,
isBold: true,
),
12.height,
Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
model.categoryDropList.isNotEmpty
? DropdownField(
(DropValue value) async {
category = value;
service = null;
model.fetchProviderServices(
appointmentListModel.branchId
.toString(),
value.id.toString());
},
dropdownValue: category,
list: model.categoryDropList,
hint:
LocaleKeys.selectServiceCategory.tr(),
)
: const Center(
child: CircularProgressIndicator(),
),
12.height,
model.servicesDropList.isNotEmpty
? DropdownField(
(DropValue value) {
service = value;
pickedItems = null;
model.setState(ViewState.idle);
showMyBottomSheet(
context,
child: SelectItemsSheet(
serviceId: service?.id ?? 0,
onSelectItems:
(List<ItemData> selectedList) {
this.selectedList.clear();
this.selectedList = selectedList;
pickedItems = [];
for (var element
in selectedList) {
pickedItems!.add(
PickerItem(
id: element.id ?? 0,
title:
element.name ?? ""),
);
}
model.notifyListeners();
},
),
);
},
dropdownValue: service,
list: model.servicesDropList,
hint: LocaleKeys.defineServices.tr(),
)
: category == null
? Container()
: model.services != null &&
model.servicesDropList.isEmpty
? const Text("No Service Found")
: const CircularProgressIndicator(),
12.height,
(service != null &&
pickedItems != null &&
pickedItems!.length > 0)
? ChipsPickerItem(
hint: 'Select Items',
itemsList: [...pickedItems ?? []],
onClick: () {
showMyBottomSheet(
context,
child: SelectItemsSheet(
serviceId: service?.id ?? 0,
list: pickedItems,
onSelectItems:
(List<ItemData> selectedList) {
pickedItems = [];
for (var element
in selectedList) {
pickedItems!.add(
PickerItem(
id: element.id ?? 0,
title:
element.name ?? ""),
);
}
model.notifyListeners();
},
),
);
},
)
: service != null
? const Text("No Item Selected Yet")
: const SizedBox(),
if ((service != null &&
pickedItems != null &&
pickedItems!.length > 0))
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
16.height,
"Total Additional Amount".toText(
fontSize: 14,
isBold: true,
color: MyColors.lightTextColor,
),
Row(
crossAxisAlignment:
CrossAxisAlignment.end,
children: [
calculatePrice().toString().toText(
fontSize: 29,
isBold: true,
),
2.width,
"SAR".toText(
fontSize: 16,
isBold: true,
color: MyColors.lightTextColor,
),
],
),
],
),
],
),
],
).toWhiteContainer(width: double.infinity, allPading: 12),
Row(
children: [
Expanded(
child: ShowFillButton(
title: "Cancel",
maxWidth: double.infinity,
isFilled: false,
txtColor: MyColors.redColor,
borderColor: MyColors.redColor,
onPressed: () {},
),
),
12.width,
Expanded(
child: ShowFillButton(
title: "Add",
maxWidth: double.infinity,
onPressed: () async {
if (pickedItems != null &&
pickedItems!.length > 0) {
List<int> items = [];
pickedItems?.forEach((element) {
items.add(element.id);
});
Utils.showLoading(context);
var postParams = {
"providerBranchID":
appointmentListModel.branchId,
"appointmentID": appointmentListModel.id,
"serviceItemID": items
};
MResponse res = await serviceVM
.addNewServiceInAppointment(postParams);
_updateAppointment(context,
appointmentListModel.branchId ?? 0);
Utils.hideLoading(context);
if (res.messageStatus == 1) {
Utils.showToast(
"Items are added Successfully");
pop(context);
} else {
Utils.showToast(res.message.toString());
}
} else {
Utils.showToast("Please select items");
}
},
),
),
],
),
],
);
},
),
),
],
),
),
);
}
Future<void> _updateAppointment(BuildContext context, int branchId) async {
await context.read<AppointmentsVM>().getProviderMyAppointments({
"ServiceProviderID": injector
.get<AppState>()
.getUser
.data
?.userInfo
?.providerId
.toString() ??
"0",
"ProviderBranchID": branchId.toString(),
}, isNeedToRebuild: true);
}
double calculatePrice() {
double total = 0;
for (var element in selectedList) {
total = total + double.parse(element.price ?? "0");
}
return total;
}
}

@ -0,0 +1,273 @@
import 'package:car_provider_app/config/provider_routes.dart';
import 'package:car_provider_app/views/dashboard/widget/appointment_slider_widget.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/config/dependencies.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/provider_branches_models/branch_detail_model.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/date_helper.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/view_models/appointments_view_model.dart';
import 'package:mc_common_app/widgets/common_widgets/categories_list.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.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/widgets/common_widgets/app_bar.dart';
import 'package:percent_indicator/percent_indicator.dart';
import 'package:provider/provider.dart';
class AppointmentPage extends StatelessWidget {
BranchDetailModel branch;
String date = "";
AppointmentPage({
required this.branch,
Key? key,
}) : super(key: key);
GlobalKey<RefreshIndicatorState> refreshIndicatorKey =
GlobalKey<RefreshIndicatorState>();
Future<void> _pullRefresh(BuildContext context) async {
await context.read<AppointmentsVM>().getAppointmentSlotsInfo(
context: context,
map: {
"ProviderBranchID": branch.id.toString(),
"FromDate": date,
"ToDate": date
},
isNeedToRebuild: true,
);
await context.read<AppointmentsVM>().getProviderMyAppointments({
"ServiceProviderID": injector
.get<AppState>()
.getUser
.data
?.userInfo
?.providerId
.toString() ??
"0",
"ProviderBranchID": branch.id.toString(),
"FromDate": date,
"DateTo": date,
});
}
@override
Widget build(BuildContext context) {
date = DateHelper.formatAsYearMonthDay(DateTime.now());
context.read<AppointmentsVM>().setupProviderAppointmentFilter();
_pullRefresh(context);
context.read<AppointmentsVM>().selectedBranch = branch.id ?? 0;
return Scaffold(
appBar: CustomAppBar(
profileImageUrl: MyAssets.carBanner,
title: branch.branchName,
),
body: SizedBox(
width: double.infinity,
height: double.infinity,
child: Consumer(builder: (BuildContext context,
AppointmentsVM appointmentsVM, Widget? child) {
if (appointmentsVM.state == ViewState.busy) {
return const Center(child: CircularProgressIndicator());
} else {
return RefreshIndicator(
onRefresh: () => _pullRefresh(context),
key: refreshIndicatorKey,
child: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
child: Column(
children: [
progressWidget(context, appointmentsVM),
FiltersList(
filterList: appointmentsVM.appointmentsFilterOptions,
padding: const EdgeInsets.symmetric(horizontal: 18),
onFilterTapped: (index, selectedFilterId) {
appointmentsVM.applyFilterOnAppointmentsVM(
appointmentStatusEnum:
selectedFilterId.toAppointmentStatusEnum(),
isNeedCustomerFilter: true,
);
},
),
if (appointmentsVM.myFilteredAppointments2.isEmpty)
Padding(
padding: const EdgeInsets.symmetric(vertical: 12),
child: "No Appointment Found".toText(),
),
ListView.separated(
itemBuilder: (context, index) {
return AppointmentSliderWidget(
appointmentListModel:
appointmentsVM.myFilteredAppointments2[index],
isNeedTotalPayment: false,
onTap: () {
context
.read<AppointmentsVM>()
.selectedAppointmentIndex = index;
navigateWithName(
context,
ProviderAppRoutes.appointmentDetailList,
// arguments: appointmentsVM
// .myFilteredAppointments2[index]
// .customerAppointmentList,
);
},
);
},
separatorBuilder: (context, snapchat) {
return 21.height;
},
itemCount: appointmentsVM.myFilteredAppointments2.length,
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: const EdgeInsets.all(21),
),
],
),
),
);
}
}),
),
);
}
Widget progressWidget(BuildContext context, AppointmentsVM appointmentsVM) {
double percent = (appointmentsVM.appointmentSlots?.occupiedSlots ??
0.0 / (appointmentsVM.appointmentSlots?.totalSlots ?? 0.0))
.toDouble() *
100;
return Column(
children: [
Row(
children: [
Expanded(
child: "Slots Overview".toText(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
Row(
children: [
date.toText(
fontWeight: FontWeight.bold,
),
const Icon(
Icons.keyboard_arrow_down_outlined,
size: 16,
),
],
)
.toContainer(
backgroundColor: MyColors.lightGreyEAColor,
borderRadius: 100,
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 6,
),
)
.onPress(() async {
date = await Utils.pickDateFromDatePicker(
context,
firstDate: null,
);
_pullRefresh(context);
// context.read<AppointmentsVM>().notifyListeners();
}),
],
),
24.height,
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
width: 14,
height: 14,
color: MyColors.lightGreyEAColor,
),
4.width,
"Empty: ".toText(
fontSize: 8,
color: Colors.white,
),
(appointmentsVM.appointmentSlots?.emptySlots ?? 0)
.toString()
.toText(
fontSize: 9,
fontWeight: FontWeight.bold,
color: Colors.white,
),
],
).toContainer(
backgroundColor: MyColors.darkIconColor,
),
8.height,
Row(
children: [
Container(
width: 14,
height: 14,
color: MyColors.darkPrimaryColor,
),
4.width,
"Occupied: ".toText(
fontSize: 8,
color: Colors.white,
),
(appointmentsVM.appointmentSlots?.occupiedSlots ?? 0)
.toString()
.toText(
fontSize: 9,
fontWeight: FontWeight.bold,
color: Colors.white,
),
],
).toContainer(
backgroundColor: MyColors.darkIconColor,
),
],
),
CircularPercentIndicator(
radius: 60.0,
lineWidth: 12.0,
percent: percent,
circularStrokeCap: CircularStrokeCap.round,
center: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
"Total Slots".toText(
fontSize: 13,
fontWeight: FontWeight.bold,
),
(appointmentsVM.appointmentSlots?.totalSlots ?? 0)
.toString()
.toText(
fontSize: 24,
fontWeight: FontWeight.bold,
),
],
),
backgroundColor: MyColors.lightGreyEAColor,
progressColor: MyColors.darkPrimaryColor,
),
],
)
],
).toWhiteContainer(
width: double.infinity,
pading: const EdgeInsets.all(12),
margin: const EdgeInsets.all(21),
);
}
}

@ -0,0 +1,159 @@
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/config/dependencies.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/models/general_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/navigator.dart';
import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/view_models/appointments_view_model.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
import '../../config/provider_routes.dart';
import '../dashboard/widget/appointment_slider_widget.dart';
import 'package:provider/provider.dart';
class MergeAppointmentListPage extends StatelessWidget {
MergeAppointmentListPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: const CustomAppBar(
title: "Select Appointments",
),
body: SizedBox(
width: double.infinity,
height: double.infinity,
child: Consumer(
builder: (BuildContext context, AppointmentsVM appointmentsVM,
Widget? child) {
return Column(
children: [
Expanded(
child: Column(
children: [
Expanded(
child: (appointmentsVM.state == ViewState.busy)
? const Center(child: CircularProgressIndicator())
: ListView.separated(
itemBuilder: (context, index) {
return AppointmentSliderWidget(
appointmentListModel: appointmentsVM
.myFilteredAppointments2[appointmentsVM
.selectedAppointmentIndex]
.customerAppointmentList![index],
isNeedTotalPayment: true,
isSelectable: true,
isNeedToShowAppointmentStatus: true,
isNeedToShowMergeStatus: true,
onTap: () {
appointmentsVM
.updateCheckBoxInMergeRequest(index);
},
);
},
separatorBuilder: (context, snapchat) {
return 21.height;
},
itemCount: appointmentsVM
.myFilteredAppointments2[
appointmentsVM.selectedAppointmentIndex]
.customerAppointmentList!
.length,
padding: const EdgeInsets.all(21),
),
),
],
),
),
ShowFillButton(
title: "Merge Appointments",
maxWidth: double.infinity,
margin: const EdgeInsets.all(21),
txtColor: appointmentsVM.inNeedToEnableMergeButton
? MyColors.white
: MyColors.black,
backgroundColor: appointmentsVM.inNeedToEnableMergeButton
? MyColors.primaryColor
: MyColors.greyButtonColor,
onPressed: () async {
Utils.showLoading(context);
List<int> appointmentIDs = [];
for (var element in appointmentsVM
.myFilteredAppointments2[
appointmentsVM.selectedAppointmentIndex]
.customerAppointmentList!) {
if (element.isSelected ?? false) {
appointmentIDs.add(element.id ?? 0);
}
}
Map<String, dynamic> map = {
"serviceProviderID": injector
.get<AppState>()
.getUser
.data
?.userInfo
?.providerId
.toString() ??
"0",
"serviceProviderBranchID": appointmentsVM
.myFilteredAppointments2[
appointmentsVM.selectedAppointmentIndex]
.branchId,
"serviceAppointmentIDs": appointmentIDs
};
try {
MResponse response =
await appointmentsVM.createMergeAppointment(map);
Utils.hideLoading(context);
if (response.messageStatus == 1) {
Utils.showToast(
"Appointment Merge is Successfully done");
_updateAppointment(
context,
appointmentsVM
.myFilteredAppointments2[
appointmentsVM.selectedAppointmentIndex]
.branchId ??
0);
pop(context);
pop(context);
} else {
Utils.showToast(response.message.toString());
}
} catch (e) {
Utils.showToast(e.toString());
Utils.hideLoading(context);
}
},
),
],
);
},
),
),
);
}
Future<void> _updateAppointment(BuildContext context, int branchId) async {
await context.read<AppointmentsVM>().getProviderMyAppointments({
"ServiceProviderID": injector
.get<AppState>()
.getUser
.data
?.userInfo
?.providerId
.toString() ??
"0",
"ProviderBranchID": branchId.toString(),
}, isNeedToRebuild: true);
}
}

@ -0,0 +1,144 @@
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/services_models/item_model.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';
import '../../settings/schedule/widgets/chips_picker_item.dart';
class SelectItemsSheet extends StatelessWidget {
int serviceId;
Function(List<ItemData>) onSelectItems;
List<PickerItem>? list;
SelectItemsSheet(
{Key? key,
required this.serviceId,
required this.onSelectItems,
this.list})
: super(key: key);
@override
Widget build(BuildContext context) {
context.read<ItemsVM>().getServiceItems(serviceId,list: list);
return SizedBox(
width: double.infinity,
height: MediaQuery.of(context).size.height / 1.4,
child: Column(
children: [
Expanded(
child: Consumer<ItemsVM>(
builder: (_, model, child) {
return Padding(
padding: const EdgeInsets.only(left: 20, right: 20, top: 6),
child: Column(
children: [
Row(
children: [
Expanded(
child: "Select Items"
.toText(fontSize: 24, isBold: true),
),
Center(
child: (model.serviceItems == null
? "0"
: model.serviceItems!.data!
.where((element) =>
element.isUpdateOrSelected == 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 Items",
onChanged: (v) {},
),
12.height,
Expanded(
child: model.serviceItems?.data == null
? const Center(child: CircularProgressIndicator())
: model.serviceItems?.data!.length == 0
? Center(child: "No Item Found".toText())
: ListView.separated(
itemBuilder:
(BuildContext context, int index) {
return Row(
children: [
Checkbox(
value: model
.serviceItems!
.data![index]
.isUpdateOrSelected,
onChanged: (bool? v) {
model.serviceItems!.data![index]
.isUpdateOrSelected = v;
model.notifyListeners();
},
),
12.width,
Expanded(
child: model.serviceItems!
.data![index].name!
.toText(),
),
],
);
},
separatorBuilder:
(BuildContext context, int index) {
return const Divider(
height: 1,
);
},
itemCount:
model.serviceItems?.data?.length ?? 0,
),
),
],
),
);
},
),
),
ShowFillButton(
title: 'Add Selected Items',
maxWidth: double.infinity,
margin: const EdgeInsets.all(20),
onPressed: () {
if (context.read<ItemsVM>().serviceItems != null) {
List<ItemData> list = [];
context.read<ItemsVM>().serviceItems!.data!.forEach((element) {
if (element.isUpdateOrSelected ?? false) {
list.add(element);
}
});
onSelectItems(list);
}
Navigator.pop(context);
},
)
],
),
);
}
}

@ -0,0 +1,185 @@
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/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/extensions/extensions_widget.dart';
import 'package:mc_common_app/widgets/txt_field.dart';
class ShowCollectPaymentSheet extends StatelessWidget {
Function() onClickYes;
Function() onClickNo;
ShowCollectPaymentSheet(
{required this.onClickYes, required this.onClickNo, Key? key})
: super(key: key);
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(left: 21, right: 21, bottom: 21, top: 12),
child: Column(
children: [
"Do you want to collect the money before providing services?".toText(
fontSize: 24,
isBold: true,
),
21.height,
Row(
children: [
Expanded(
child: ShowFillButton(
title: "Yes",
onPressed: onClickYes,
),
),
12.width,
Expanded(
child: ShowFillButton(
title: "No",
isFilled: false,
txtColor: MyColors.darkPrimaryColor,
onPressed: onClickNo,
),
),
],
),
],
),
);
}
}
class Reason {
String title;
bool isSelected;
Reason(this.title, this.isSelected);
}
class CancelAppointmentReasonSheet extends StatefulWidget {
Function(String) onCancelClick;
CancelAppointmentReasonSheet({required this.onCancelClick, Key? key})
: super(key: key);
@override
State<CancelAppointmentReasonSheet> createState() =>
_CancelAppointmentReasonSheetState();
}
class _CancelAppointmentReasonSheetState
extends State<CancelAppointmentReasonSheet> {
String reason = "";
List<Reason> reasonList = [
Reason("Operational Issue", true),
Reason("Material Issue", false),
Reason("The customer no longer responding", false),
Reason("Other", false),
];
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.only(left: 21, right: 21, top: 12, bottom: 21),
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Reason".toText(fontSize: 24, isBold: true),
ListView.separated(
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.only(top: 12, bottom: 12),
child: Row(
children: [
Container(
width: 14,
height: 14,
decoration: BoxDecoration(
color: reasonList[index].isSelected
? MyColors.darkPrimaryColor
: Colors.transparent,
borderRadius: BorderRadius.circular(122),
border: Border.all(
color: reasonList[index].isSelected
? MyColors.darkPrimaryColor
: borderColor,
width: 1),
),
child: const Icon(
Icons.done,
size: 12,
color: Colors.white,
),
),
12.width,
reasonList[index].title.toText(isBold: true)
],
),
).onPress(() {
for (var element in reasonList) {
element.isSelected = false;
}
setState(() {
reason = reasonList[index].title;
reasonList[index].isSelected = true;
});
});
},
separatorBuilder: (context, index) {
return Container(
width: double.infinity,
height: 1,
color: MyColors.borderColor,
);
},
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: reasonList.length,
),
if (reason == "Other")
TxtField(
hint: "Type Here...",
maxLines: 5,
onChanged: (v) {
reason = v;
},
),
12.height,
Row(
children: [
Expanded(
child: ShowFillButton(
title: "No",
isFilled: false,
txtColor: MyColors.darkPrimaryColor,
onPressed: () {
pop(context);
},
),
),
12.width,
Expanded(
child: ShowFillButton(
title: "Yes",
onPressed: () {
if (reason.isEmpty || reason == "Other") {
Utils.showToast("Please Select Reason");
} else {
widget.onCancelClick(reason);
pop(context);
}
},
),
),
],
)
],
),
);
}
}

@ -0,0 +1,170 @@
import 'package:geolocator/geolocator.dart';
import 'package:car_provider_app/config/provider_routes.dart';
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/general_models/m_response.dart';
import 'package:mc_common_app/models/provider_branches_models/branch_detail_model.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/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/tab/role_type_tab.dart';
import '../../../generated/locale_keys.g.dart';
import '../../../view_models/service_view_model.dart';
import 'package:provider/provider.dart';
import 'package:flutter_svg/flutter_svg.dart';
class BranchAppointmentFragment extends StatelessWidget {
bool isNeedAppBar;
VoidCallback onBackButtonTapped;
BranchAppointmentFragment(
{Key? key, this.isNeedAppBar = true, required this.onBackButtonTapped})
: super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: !isNeedAppBar
? null
: CustomAppBar(
title: "Appointments",
onBackButtonTapped: onBackButtonTapped,
),
body: SizedBox(
width: double.infinity,
height: double.infinity,
child: Column(
children: [
Padding(
padding: const EdgeInsets.only(left: 21, right: 21, top: 21),
child: RoleTypeTab(
context.watch<ServiceVM>().selectedBranchStatus == 3
? 0
: context.watch<ServiceVM>().selectedBranchStatus,
[
DropValue(3, "Active", ""),
DropValue(1, "Requested", ""),
],
onSelect: (DropValue value) {
context.read<ServiceVM>().updateSelectedBranchType(value.id);
},
),
),
Expanded(
child: Consumer<ServiceVM>(
builder: (context, model, _) {
if (model.state == ViewState.busy) {
return const Center(child: CircularProgressIndicator());
} else {
List<BranchDetailModel> branches = [];
if (model.branches!.data != null) {
branches = model.branches!.data!.serviceProviderBranch!
.where((element) =>
model.selectedBranchStatus == element.statusId)
.toList();
}
return branches.isEmpty
? Center(child: Text(LocaleKeys.no_branch.tr()))
: ListView.separated(
itemBuilder: (context, index) {
return Row(
children: [
Container(
width: 74,
height: 50,
decoration: const BoxDecoration(
color: MyColors.darkPrimaryColor,
borderRadius:
BorderRadius.all(Radius.circular(8)),
),
padding: const EdgeInsets.all(6),
child: SvgPicture.asset(
MyAssets.icBranches,
color: Colors.white,
),
),
12.width,
Expanded(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.start,
children: [
Row(
children: [
const Icon(
Icons.place,
size: 12,
color: MyColors.darkPrimaryColor,
),
Geolocator.distanceBetween(
AppState()
.currentLocation
.latitude,
AppState()
.currentLocation
.latitude,
double.parse(branches[index]
.latitude ??
"0"),
double.parse(branches[index]
.longitude ??
"0"))
.toStringAsFixed(2)
.toText(
fontSize: 12,
color:
MyColors.darkPrimaryColor,
)
],
),
Text(
branches[index].branchName ?? "",
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
),
),
"Tap to view".toText(
fontSize: 10,
color: MyColors.grey70Color),
],
),
),
12.width,
],
).toContainer().onPress(() async {
branches[index].countryID =
model.branches!.data!.countryID;
branches[index].countryName =
model.branches!.data!.countryName;
navigateWithName(
context, ProviderAppRoutes.appointment,
arguments: branches[index]);
});
},
separatorBuilder: (context, index) {
return 12.height;
},
itemCount: branches.length,
padding: const EdgeInsets.all(12),
);
}
},
),
),
],
),
),
);
}
}
Loading…
Cancel
Save