Compare commits

...

11 Commits

Author SHA1 Message Date
Faiz Hashmi 29567119e6 12 feb,2025 9 months ago
Faiz Hashmi 14024def24 Quick Fixes 9 months ago
Faiz Hashmi 0ed41736b2 Quick Fixes 10 months ago
Faiz Hashmi f9b559fe23 Merge branch 'aamir_dev' into faiz_development 10 months ago
Faiz Hashmi 6fb586c3b4 Quick Fixes 10 months ago
Faiz Hashmi 8a93c82b22 Quick Fixes 10 months ago
Faiz Hashmi 8bed0df13a Merge remote-tracking branch 'origin/faiz_dev' into faiz_development 10 months ago
Faiz Hashmi 02bf2d6b2f Quick Fixes 10 months ago
Faiz Hashmi 40500614d3 Merge remote-tracking branch 'origin/faiz_dev' into faiz_development 10 months ago
Faiz Hashmi 44ae05f9e7 Quick Fixes 10 months ago
Faiz Hashmi b621556158 Quick Fixes 10 months ago

@ -16,10 +16,29 @@
or higher if your app targets Android 14 (API level 34) or higher. -->
<uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />
<queries>
<!-- If your app checks for SMS support -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="sms" />
</intent>
<!-- If your app checks for call support -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="tel" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="mailto" />
</intent>
</queries>
<application
android:icon="@mipmap/ic_launcher"
android:extractNativeLibs="true"
android:icon="@mipmap/ic_launcher"
android:label="Provider">
<activity
android:name=".MainActivity"
@ -56,6 +75,7 @@
</intent-filter>
</activity>
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="AIzaSyCyDbWUM9d_sBUGIE8PcuShzPaqO08NSC8" />

@ -140,14 +140,16 @@ Future<void> main() async {
),
),
ChangeNotifierProvider<ShippingManagementVM>(
create: (_) => ShippingManagementVM(
shippingRepo: injector.get<ShippingRepo>(),
commonRepo: injector.get<CommonRepo>(),
)),
create: (_) => ShippingManagementVM(
shippingRepo: injector.get<ShippingRepo>(),
commonRepo: injector.get<CommonRepo>(),
),
),
ChangeNotifierProvider<SettingOptionsVM>(
create: (_) => SettingOptionsVM(
settingOptionsRepo: injector.get<SettingOptionsRepo>(),
)),
create: (_) => SettingOptionsVM(
settingOptionsRepo: injector.get<SettingOptionsRepo>(),
),
),
],
child: const MyApp(),
).setupLocale());

@ -1,16 +1,14 @@
import 'dart:async';
import 'dart:developer';
import 'package:car_provider_app/views/dashboard/widget/general_appointment_widget.dart';
import 'package:car_provider_app/views/branch_management/schedule/widgets/chips_picker_item.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/widgets.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_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/config/dependency_injection.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/appointments_models/appointment_list_model.dart';
@ -26,6 +24,7 @@ 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/empty_widget.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:mc_common_app/widgets/txt_field.dart';
import 'package:provider/provider.dart';
import 'package:easy_localization/easy_localization.dart';
@ -107,102 +106,162 @@ class _AddNewServiceAppointmentPageState extends State<AddNewServiceAppointmentP
),
12.height,
Consumer<ServiceVM>(
builder: (context, serviceVm, _) {
builder: (context, ServiceVM serviceVm, _) {
return Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.selectServicestoAdd.tr().toText(
fontSize: 18,
isBold: true,
),
12.height,
Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
serviceVm.categoryDropList.isNotEmpty
? DropdownField(
(DropValue value) async {
category = value;
service = null;
serviceVm.fetchProviderServices(widget.appointmentListModel.branchId.toString(), value.id.toString());
},
dropdownValue: category,
list: serviceVm.categoryDropList,
hint: LocaleKeys.selectServiceCategory.tr(),
)
: const Center(
child: CircularProgressIndicator(),
),
12.height,
serviceVm.servicesDropList.isNotEmpty
? DropdownField(
(DropValue value) {
service = value;
pickedItems = null;
serviceVm.setState(ViewState.idle);
openItemsSelectionBottomSheet();
},
dropdownValue: service,
list: serviceVm.servicesDropList,
hint: LocaleKeys.defineServices.tr(),
)
: category == null
? Container()
: serviceVm.services != null && serviceVm.servicesDropList.isEmpty
? EmptyWidget(text: LocaleKeys.noServicesAvailable.tr())
: const CircularProgressIndicator(),
12.height,
(service != null && pickedItems != null && pickedItems!.isNotEmpty)
? ChipsPickerItem(
hint: LocaleKeys.selectItems.tr(),
itemsList: [...pickedItems ?? []],
onClick: () {
openItemsSelectionBottomSheet();
},
)
: service != null
? EmptyWidget(text: LocaleKeys.noItemSelectedYet.tr())
: const SizedBox(),
if ((service != null && pickedItems != null && pickedItems!.isNotEmpty))
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
16.height,
LocaleKeys.totalAdditionalAmount.tr().toText(
fontSize: 14,
isBold: true,
color: MyColors.lightTextColor,
),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
totalPrice.toString().toText(
fontSize: 29,
isBold: true,
),
2.width,
LocaleKeys.sar
.tr()
.toText(
fontSize: 16,
isBold: true,
color: MyColors.lightTextColor,
)
.paddingOnly(bottom: 5),
],
),
10.height,
],
),
],
LocaleKeys.customService.tr().toText(fontSize: 18),
8.width,
Center(
child: Checkbox(
value: serviceVm.customServiceEnabledStatus,
onChanged: (value) {
serviceVm.updateCustomServiceEnabledStatus(value ?? false); // update the status
},
activeColor: MyColors.darkPrimaryColor,
checkColor: MyColors.white,
fillColor: serviceVm.customServiceEnabledStatus ? WidgetStateProperty.all(MyColors.darkPrimaryColor) : WidgetStateProperty.all(MyColors.white),
),
),
],
).toWhiteContainer(width: double.infinity, allPading: 12),
),
5.height,
if (serviceVm.customServiceEnabledStatus) ...[
LocaleKeys.addServiceDetails.tr().toText(fontSize: 16),
12.height,
Column(
children: [
8.height,
TxtField(
value: serviceVm.customServiceTitle,
errorValue: serviceVm.customServiceTitleError,
hint: LocaleKeys.serviceName.tr(),
onChanged: (v) => serviceVm.updateCustomServiceTitle(v),
),
8.height,
TxtField(
postfixWidget: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
LocaleKeys.sar.tr().toText(fontWeight: MyFonts.Medium, fontSize: 15, color: borderColor, textAlign: TextAlign.center),
],
),
value: serviceVm.customServicePrice,
errorValue: serviceVm.customServicePriceError,
keyboardType: TextInputType.number,
numbersOnly: true,
hint: LocaleKeys.price.tr(),
onChanged: (v) => serviceVm.updateCustomServicePrice(v),
),
8.height,
TxtField(
postfixWidget: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
"%".toText(fontWeight: MyFonts.Medium, fontSize: 15, color: borderColor, textAlign: TextAlign.center),
],
),
isNeedClickAll: true,
isBackgroundEnabled: true,
hint: '',
onTap: () {},
value: serviceVm.customerServiceTax,
errorValue: '',
keyboardType: TextInputType.number,
numbersOnly: true,
onChanged: (v) => serviceVm.updateCustomerServiceTax(v),
),
],
),
] else ...[
LocaleKeys.selectServiceDetails.tr().toText(fontSize: 16),
12.height,
Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
serviceVm.categoryDropList.isNotEmpty
? DropdownField(
(DropValue value) async {
category = value;
service = null;
serviceVm.fetchProviderServices(widget.appointmentListModel.branchId.toString(), value.id.toString());
},
dropdownValue: category,
list: serviceVm.categoryDropList,
hint: LocaleKeys.selectServiceCategory.tr(),
)
: const Center(
child: CircularProgressIndicator(),
),
12.height,
serviceVm.servicesDropList.isNotEmpty
? DropdownField(
(DropValue value) {
service = value;
pickedItems = null;
serviceVm.setState(ViewState.idle);
openItemsSelectionBottomSheet();
},
dropdownValue: service,
list: serviceVm.servicesDropList,
hint: LocaleKeys.defineServices.tr(),
)
: category == null
? Container()
: serviceVm.services != null && serviceVm.servicesDropList.isEmpty
? EmptyWidget(text: LocaleKeys.noServicesAvailable.tr())
: const CircularProgressIndicator(),
12.height,
(service != null && pickedItems != null && pickedItems!.isNotEmpty)
? ChipsPickerItem(
hint: LocaleKeys.selectItems.tr(),
itemsList: [...pickedItems ?? []],
onClick: () {
openItemsSelectionBottomSheet();
},
)
: service != null
? EmptyWidget(text: LocaleKeys.noItemSelectedYet.tr())
: const SizedBox(),
if ((service != null && pickedItems != null && pickedItems!.isNotEmpty))
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
16.height,
LocaleKeys.totalAdditionalAmount.tr().toText(
fontSize: 14,
isBold: true,
color: MyColors.lightTextColor,
),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
totalPrice.toString().toText(
fontSize: 29,
isBold: true,
),
2.width,
LocaleKeys.sar
.tr()
.toText(
fontSize: 16,
isBold: true,
color: MyColors.lightTextColor,
)
.paddingOnly(bottom: 5),
],
),
10.height,
],
),
],
),
],
],
);
).toWhiteContainer(width: double.infinity, allPading: 12);
},
),
55.height,
@ -226,6 +285,7 @@ class _AddNewServiceAppointmentPageState extends State<AddNewServiceAppointmentP
if (pickedItems != null && pickedItems!.isNotEmpty) {
pickedItems!.clear();
}
serviceVM!.resetCustomServiceForm();
pop(context);
},
),
@ -236,29 +296,55 @@ class _AddNewServiceAppointmentPageState extends State<AddNewServiceAppointmentP
title: LocaleKeys.add.tr(),
maxWidth: double.infinity,
onPressed: () async {
if (pickedItems != null && pickedItems!.isNotEmpty) {
List<int> items = [];
pickedItems?.forEach((element) {
items.add(element.id);
});
Map<String, dynamic> postParams = {};
if (serviceVM!.customServiceEnabledStatus) {
if (serviceVM!.isCustomServiceDetailValidated()) {
postParams = {
"providerBranchID": widget.appointmentListModel.branchId,
"appointmentID": widget.appointmentListModel.id,
"serviceItemsFreeText": [
{
"name": serviceVM!.customServiceTitle,
"price": serviceVM!.customServicePrice,
"tax": serviceVM!.customerServiceTax,
}
],
};
} else {
return;
}
} else {
if (pickedItems != null && pickedItems!.isNotEmpty) {
List<int> items = [];
pickedItems?.forEach((element) {
items.add(element.id);
});
postParams = {
"providerBranchID": widget.appointmentListModel.branchId,
"appointmentID": widget.appointmentListModel.id,
"serviceItemID": items,
};
} else {
Utils.showToast(LocaleKeys.pleaseSelectItems.tr());
return;
}
}
try {
Utils.showLoading(context);
var postParams = {
"providerBranchID": widget.appointmentListModel.branchId,
"appointmentID": widget.appointmentListModel.id,
"serviceItemID": items,
};
GenericRespModel res = await serviceVM!.addNewServiceInAppointment(postParams);
_updateAppointment(context, widget.appointmentListModel.branchId ?? 0);
Utils.hideLoading(context);
if (res.messageStatus == 1) {
serviceVM!.resetCustomServiceForm();
_updateAppointment(context, widget.appointmentListModel.branchId ?? 0);
Utils.showToast(LocaleKeys.itemsAddedSuccessfully.tr());
pop(context);
pop(context);
} else {
Utils.showToast(res.message.toString());
}
} else {
Utils.showToast(LocaleKeys.pleaseSelectItems.tr());
} catch (e) {
Utils.showToast(e.toString());
Utils.hideLoading(context);
}
},
),
@ -273,6 +359,10 @@ class _AddNewServiceAppointmentPageState extends State<AddNewServiceAppointmentP
}
Future<void> _updateAppointment(BuildContext context, int branchId) async {
await context.read<AppointmentsVM>().getMyAppointmentsForProvider(branchID: branchId);
await context.read<AppointmentsVM>().applyFilterOnAppointmentsVMForProviders(
branchID: branchId,
appointmentStatusEnum: AppointmentStatusEnum.allAppointments,
isNeedCustomerFilter: true,
);
}
}

@ -55,28 +55,26 @@ class AppointmentDetailListPage extends StatelessWidget {
return ListView.separated(
itemBuilder: (context, index) {
if (customerID == 0) {
customerID = appointmentsVM.myFilteredAppointments2[appointmentsVM.selectedAppointmentIndex].customerAppointmentList![index].customerID ?? 0;
customerID = appointmentsVM.myFilteredAppointmentsForProvider[appointmentsVM.selectedAppointmentIndex].customerAppointmentList![index].customerID ?? 0;
}
if (customerName.isEmpty) {
customerName = appointmentsVM.myFilteredAppointments2[appointmentsVM.selectedAppointmentIndex].customerAppointmentList![index].customerName ?? "";
customerName = appointmentsVM.myFilteredAppointmentsForProvider[appointmentsVM.selectedAppointmentIndex].customerAppointmentList![index].customerName ?? "";
}
return GeneralAppointmentWidget(
appointmentListModel: appointmentsVM.myFilteredAppointments2[appointmentsVM.selectedAppointmentIndex].customerAppointmentList![index],
appointmentListModel: appointmentsVM.myFilteredAppointmentsForProvider[appointmentsVM.selectedAppointmentIndex].customerAppointmentList![index],
isNeedTotalPayment: true,
isNeedToShowAppointmentStatus: true,
isNeedToShowMergeStatus: appointmentsVM.myFilteredAppointments2[appointmentsVM.selectedAppointmentIndex].customerAppointmentList![index].isMerged ?? false,
isNeedToShowMergeStatus: appointmentsVM.myFilteredAppointmentsForProvider[appointmentsVM.selectedAppointmentIndex].customerAppointmentList![index].isMerged ?? false,
onTap: () {
appointmentsVM.selectedAppointmentId = appointmentsVM.myFilteredAppointments2[appointmentsVM.selectedAppointmentIndex].customerAppointmentList![index].id ?? 0;
appointmentsVM.selectedAppointmentId = appointmentsVM.myFilteredAppointmentsForProvider[appointmentsVM.selectedAppointmentIndex].customerAppointmentList![index].id ?? 0;
appointmentsVM.selectedAppointmentSubIndex = index;
navigateWithName(context, AppRoutes.updateAppointmentPage,
arguments: appointmentsVM.myFilteredAppointments2[appointmentsVM.selectedAppointmentIndex].customerAppointmentList![index]);
arguments: appointmentsVM.myFilteredAppointmentsForProvider[appointmentsVM.selectedAppointmentIndex].customerAppointmentList![index]);
},
);
},
separatorBuilder: (context, snapchat) {
return 21.height;
},
itemCount: appointmentsVM.myFilteredAppointments2[appointmentsVM.selectedAppointmentIndex].customerAppointmentList!.length,
separatorBuilder: (context, snapchat) => 21.height,
itemCount: appointmentsVM.myFilteredAppointmentsForProvider[appointmentsVM.selectedAppointmentIndex].customerAppointmentList!.length,
padding: const EdgeInsets.all(21),
);
}

@ -1,9 +1,5 @@
import 'dart:async';
import 'package:car_provider_app/config/provider_routes.dart';
import 'package:car_provider_app/views/dashboard/widget/general_appointment_widget.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/config/dependency_injection.dart';
import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
@ -14,7 +10,7 @@ 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/common_widgets/filters_list.dart';
import 'package:mc_common_app/widgets/empty_widget.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:flutter/material.dart';
@ -40,12 +36,16 @@ class _AppointmentPageState extends State<AppointmentPage> {
GlobalKey<RefreshIndicatorState> refreshIndicatorKey = GlobalKey<RefreshIndicatorState>();
Future<void> _pullRefresh(BuildContext context) async {
await appointmentsVM.getAppointmentSlotsInfo(
context: context,
branchID: widget.branch.id!,
isNeedToRebuild: true,
);
await appointmentsVM.getAppointmentsBasedOnFiltersForProviders(branchID: widget.branch.id!);
var futures = <Future<void>>[
appointmentsVM.getAppointmentSlotsInfo(branchID: widget.branch.id!),
appointmentsVM.applyFilterOnAppointmentsVMForProviders(
appointmentStatusEnum: AppointmentStatusEnum.allAppointments,
isNeedCustomerFilter: true,
),
];
// Wait for both futures to complete
await Future.wait(futures);
}
@override
@ -88,28 +88,36 @@ class _AppointmentPageState extends State<AppointmentPage> {
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,
);
},
return RefreshIndicator(
onRefresh: () => _pullRefresh(context),
key: refreshIndicatorKey,
child: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
child: Column(
children: [
slotDetailsWidget(context, appointmentsVM),
FiltersList(
filterList: appointmentsVM.appointmentsFilterOptions,
padding: const EdgeInsets.symmetric(horizontal: 18),
onFilterTapped: (index, selectedFilterId) {
if (appointmentsVM.isAppointmentLoading) {
return;
}
appointmentsVM.applyFilterOnAppointmentsVMForProviders(
appointmentStatusEnum: selectedFilterId.toAppointmentStatusEnum(),
isNeedCustomerFilter: true,
);
},
),
if (appointmentsVM.isAppointmentLoading) ...[
const Column(
children: [
SizedBox(height: 50),
Center(child: CircularProgressIndicator()),
],
),
if (appointmentsVM.myFilteredAppointments2.isEmpty)
] else ...[
if (appointmentsVM.myFilteredAppointmentsForProvider.isEmpty)
EmptyWidget(
spacerWidget: const SizedBox(height: 25),
text: LocaleKeys.noAppointmentFound.tr(),
@ -119,38 +127,38 @@ class _AppointmentPageState extends State<AppointmentPage> {
itemBuilder: (context, index) {
return GeneralAppointmentWidget(
isNeedToShowItems: true,
appointmentListModel: appointmentsVM.myFilteredAppointments2[index],
appointmentListModel: appointmentsVM.myFilteredAppointmentsForProvider[index],
isNeedTotalPayment: false,
onTap: () {
appointmentsVM.selectedAppointmentIndex = index;
navigateWithName(
context,
AppRoutes.appointmentDetailList,
// arguments: appointmentsVM
// .myFilteredAppointments2[index]
// .customerAppointmentList,
);
},
);
},
separatorBuilder: (context, snapchat) => 21.height,
itemCount: appointmentsVM.myFilteredAppointments2.length,
itemCount: appointmentsVM.myFilteredAppointmentsForProvider.length,
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: const EdgeInsets.all(21),
),
],
],
),
],
),
);
}
),
);
}),
),
);
}
Widget progressWidget(BuildContext context, AppointmentsVM appointmentsVM) {
Widget slotDetailsWidget(BuildContext context, AppointmentsVM appointmentsVM) {
if (appointmentsVM.isSlotsLoading) {
return const SizedBox(height: 200, child: Center(child: CircularProgressIndicator()));
}
double percent = 0.0;
if (appointmentsVM.appointmentSlots != null) {
percent = appointmentsVM.appointmentSlots!.occupiedSlots / appointmentsVM.appointmentSlots!.totalSlots;
@ -184,14 +192,13 @@ class _AppointmentPageState extends State<AppointmentPage> {
vertical: 6,
),
)
.onPress(() async {
String date = await Utils.pickDateFromDatePicker(
context,
firstDate: null,
);
appointmentsVM.selectedDateForAppointments = date;
_pullRefresh(context);
}),
.onPress(
() async {
String date = await Utils.pickDateFromDatePicker(context, firstDate: DateTime(2023));
appointmentsVM.selectedDateForAppointments = date;
await appointmentsVM.getAppointmentSlotsInfo(branchID: widget.branch.id!);
},
),
],
),
24.height,
@ -209,7 +216,7 @@ class _AppointmentPageState extends State<AppointmentPage> {
color: MyColors.lightGreyEAColor,
),
4.width,
(LocaleKeys.empty.tr() + ":").toText(
("${LocaleKeys.empty.tr()}:").toText(
fontSize: 8,
color: Colors.white,
),
@ -231,7 +238,7 @@ class _AppointmentPageState extends State<AppointmentPage> {
color: MyColors.darkPrimaryColor,
),
4.width,
(LocaleKeys.occupied.tr() + ":").toText(
("${LocaleKeys.occupied.tr()}:").toText(
fontSize: 8,
color: Colors.white,
),

@ -42,7 +42,7 @@ class MergeAppointmentListPage extends StatelessWidget {
: ListView.separated(
itemBuilder: (context, index) {
return GeneralAppointmentWidget(
appointmentListModel: appointmentsVM.myFilteredAppointments2[appointmentsVM.selectedAppointmentIndex].customerAppointmentList![index],
appointmentListModel: appointmentsVM.myFilteredAppointmentsForProvider[appointmentsVM.selectedAppointmentIndex].customerAppointmentList![index],
isNeedTotalPayment: true,
isSelectable: true,
isNeedToShowAppointmentStatus: true,
@ -55,7 +55,7 @@ class MergeAppointmentListPage extends StatelessWidget {
separatorBuilder: (context, snapchat) {
return 21.height;
},
itemCount: appointmentsVM.myFilteredAppointments2[appointmentsVM.selectedAppointmentIndex].customerAppointmentList!.length,
itemCount: appointmentsVM.myFilteredAppointmentsForProvider[appointmentsVM.selectedAppointmentIndex].customerAppointmentList!.length,
padding: const EdgeInsets.all(21),
),
),
@ -72,14 +72,14 @@ class MergeAppointmentListPage extends StatelessWidget {
Utils.showLoading(context);
List<int> appointmentIDs = [];
for (var element in appointmentsVM.myFilteredAppointments2[appointmentsVM.selectedAppointmentIndex].customerAppointmentList!) {
for (var element in appointmentsVM.myFilteredAppointmentsForProvider[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,
"serviceProviderBranchID": appointmentsVM.myFilteredAppointmentsForProvider[appointmentsVM.selectedAppointmentIndex].branchId,
"serviceAppointmentIDs": appointmentIDs
};
@ -89,7 +89,7 @@ class MergeAppointmentListPage extends StatelessWidget {
if (response.messageStatus == 1) {
Utils.showToast(LocaleKeys.appointmentMergeSuccessfully.tr());
_updateAppointment(context, appointmentsVM.myFilteredAppointments2[appointmentsVM.selectedAppointmentIndex].branchId ?? 0);
_updateAppointment(context, appointmentsVM.myFilteredAppointmentsForProvider[appointmentsVM.selectedAppointmentIndex].branchId ?? 0);
pop(context);
pop(context);
@ -111,6 +111,10 @@ class MergeAppointmentListPage extends StatelessWidget {
}
Future<void> _updateAppointment(BuildContext context, int branchId) async {
await context.read<AppointmentsVM>().getMyAppointmentsForProvider(branchID: branchId);
await context.read<AppointmentsVM>().applyFilterOnAppointmentsVMForProviders(
branchID: branchId,
appointmentStatusEnum: AppointmentStatusEnum.allAppointments,
isNeedCustomerFilter: true,
);
}
}

@ -37,7 +37,7 @@ class _UpdateAppointmentPageState extends State<UpdateAppointmentPage> {
width: double.infinity,
height: double.infinity,
child: Consumer(builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) {
appointmentListModel = appointmentsVM.myFilteredAppointments2[appointmentsVM.selectedAppointmentIndex].customerAppointmentList![appointmentsVM.selectedAppointmentSubIndex];
appointmentListModel = appointmentsVM.myFilteredAppointmentsForProvider[appointmentsVM.selectedAppointmentIndex].customerAppointmentList![appointmentsVM.selectedAppointmentSubIndex];
if (appointmentsVM.state == ViewState.busy) {
return const Center(child: CircularProgressIndicator());
} else {
@ -313,6 +313,10 @@ class _UpdateAppointmentPageState extends State<UpdateAppointmentPage> {
}
Future<void> _updateAppointment(BuildContext context, int branchId) async {
await context.read<AppointmentsVM>().getMyAppointmentsForProvider(branchID: branchId);
await context.read<AppointmentsVM>().applyFilterOnAppointmentsVMForProviders(
branchID: branchId,
appointmentStatusEnum: AppointmentStatusEnum.allAppointments,
isNeedCustomerFilter: true,
);
}
}

@ -23,7 +23,7 @@ import 'package:easy_localization/easy_localization.dart';
class SchedulesListPage extends StatefulWidget {
final String? branchId;
const SchedulesListPage(this.branchId, {Key? key}) : super(key: key);
const SchedulesListPage(this.branchId, {super.key});
@override
State<SchedulesListPage> createState() => _SchedulesListPageState();
@ -161,7 +161,7 @@ class _SchedulesListPageState extends State<SchedulesListPage> {
onPressed: () {
navigateWithName(context, AppRoutes.addSchedule, arguments: ScheduleData(branchId: widget.branchId ?? ""));
},
),
),
],
),
),

@ -47,7 +47,6 @@ class _CreateServicesPage3State extends State<CreateServicesPage3> {
int? serviceId = -1;
DropValue? category;
DropValue? service;
bool isEditDisabled = false;
bool isServiceActive = false;
@ -374,38 +373,46 @@ class _CreateServicesPage3State extends State<CreateServicesPage3> {
}
}
Future<bool> updateServiceStatus(BuildContext context, bool value) async {
Future<bool> updateServiceStatus(BuildContext context, bool isServiceActive) async {
try {
final serviceVM = context.read<ServiceVM>();
List<AppointmentBasicDetailsModel> list = await serviceVM.getAppointmentsByServiceID(
context: context,
branchId: int.parse(widget.branchModel!.branchId),
serviceId: widget.branchModel!.serviceProviderService!.serviceProviderServiceId!,
);
List<int> providerServiceIds = [];
providerServiceIds.add(widget.branchModel!.serviceProviderService!.serviceProviderServiceId!);
List<AppointmentBasicDetailsModel> list = [];
if (!isServiceActive) {
list = await serviceVM.getAppointmentsByCategoryOrService(
context: context,
branchId: int.parse(widget.branchModel!.branchId),
serviceId: widget.branchModel!.serviceProviderService!.serviceProviderServiceId!,
categoryId: -1, // -1 means it check appointment by by service
);
}
if (list.isEmpty) {
List<int> providerServiceIds = [];
providerServiceIds.add(widget.branchModel!.serviceProviderService!.serviceProviderServiceId!);
bool status = await serviceVM.updateServiceStatus(
context: context,
serviceStatusEnum: value ? ServiceStatusEnum.approvedOrActive : ServiceStatusEnum.deactivated,
serviceStatusEnum: isServiceActive ? ServiceStatusEnum.approvedOrActive : ServiceStatusEnum.deactivated,
branchId: int.parse(widget.branchModel!.branchId),
providerServiceIds: providerServiceIds,
);
return status;
} else {
serviceVM.buildDealNotCompletedBottomSheetOptions(
serviceVM.cannotDeactivateServiceOrCategoryBottomSheet(
mainContext: context,
appointments: list,
branchName: widget.branchModel!.branchName,
isService: true,
);
return !isServiceActive;
}
return value;
} catch (e) {
Utils.hideLoading(context);
log(e.toString());
Utils.showToast(e.toString());
return value;
return !isServiceActive;
}
}
}

@ -1,6 +1,5 @@
import 'dart:async';
import 'dart:developer';
import 'package:car_provider_app/views/branch_management/services/duplication/sheet/approved_branches_list_sheet.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/cupertino.dart';
@ -11,6 +10,7 @@ import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/appointments_models/appointment_basic_detail_model.dart';
import 'package:mc_common_app/models/provider_branches_models/profile/categroy.dart';
import 'package:mc_common_app/models/services_models/service_model.dart';
import 'package:mc_common_app/theme/colors.dart';
@ -20,10 +20,8 @@ import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/view_models/service_view_model.dart';
import 'package:mc_common_app/widgets/bottom_sheet.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
import 'package:mc_common_app/widgets/common_widgets/categories_list.dart';
import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart';
import 'package:mc_common_app/widgets/common_widgets/filters_list.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:mc_common_app/widgets/tab/role_type_tab.dart';
import 'package:provider/provider.dart';
class CreateBranchModel {
@ -105,7 +103,7 @@ class _ServicesListPageState extends State<ServicesListPage> {
),
8.width,
Expanded(
flex: 10,
flex: 8,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
@ -117,18 +115,20 @@ class _ServicesListPageState extends State<ServicesListPage> {
],
),
// 5.height,
Container(
child: ("${LocaleKeys.branchName.tr()}: ${categoryData.branchName}").toText(
fontSize: 12,
color: MyColors.lightTextColor,
),
Row(
children: [
Flexible(
child: ("${LocaleKeys.branchName.tr()}: ${categoryData.branchName}").toText(
fontSize: 12,
color: MyColors.lightTextColor,
),
),
],
),
if (categoryData.services != null) ...[
Container(
child: ("${LocaleKeys.totalNumberOfServices.tr()} ${categoryData.services!.length}").toText(
fontSize: 12,
color: MyColors.lightTextColor,
),
("${LocaleKeys.totalNumberOfServices.tr()} ${categoryData.services!.length}").toText(
fontSize: 12,
color: MyColors.lightTextColor,
),
],
],
@ -137,9 +137,10 @@ class _ServicesListPageState extends State<ServicesListPage> {
Expanded(
flex: 4,
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
LocaleKeys.active.tr().toText(fontSize: 16),
8.width,
5.height,
Container(
width: 50,
height: 30,
@ -161,6 +162,7 @@ class _ServicesListPageState extends State<ServicesListPage> {
isCategoryActive: value,
categoryId: categoryData.id!,
branchId: int.parse(categoryData.branchId!),
branchName: categoryData.branchName ?? "",
);
if (status) {
@ -179,17 +181,36 @@ class _ServicesListPageState extends State<ServicesListPage> {
).toWhiteContainer(width: double.infinity, allPading: 12);
}
Future<bool> updateCategoryStatus({required bool isCategoryActive, required int categoryId, required int branchId}) async {
log("isCategoryActive: $isCategoryActive");
final serviceVM = context.read<ServiceVM>();
bool status = await serviceVM.updateCategoryStatus(
context: context,
serviceStatusEnum: isCategoryActive ? ServiceStatusEnum.approvedOrActive : ServiceStatusEnum.deactivated,
branchId: branchId,
categoryId: categoryId,
);
return status;
Future<bool> updateCategoryStatus({required bool isCategoryActive, required int categoryId, required int branchId, required String branchName}) async {
try {
final serviceVM = context.read<ServiceVM>();
List<AppointmentBasicDetailsModel> list = [];
if (isCategoryActive) {
list = await serviceVM.getAppointmentsByCategoryOrService(
context: context,
branchId: branchId,
serviceId: -1, // -1 means check appointment by CategoryId
categoryId: categoryId,
);
}
if (list.isEmpty) {
bool status = await serviceVM.updateCategoryStatus(
context: context,
serviceStatusEnum: isCategoryActive ? ServiceStatusEnum.approvedOrActive : ServiceStatusEnum.deactivated,
branchId: branchId,
categoryId: categoryId,
);
return status;
} else {
serviceVM.cannotDeactivateServiceOrCategoryBottomSheet(mainContext: context, appointments: list, branchName: branchName, isService: false);
return !isCategoryActive;
}
} catch (e) {
Utils.hideLoading(context);
log(e.toString());
Utils.showToast(e.toString());
return !isCategoryActive;
}
}
@override

@ -1,222 +0,0 @@
// import 'package:car_provider_app/config/provider_routes.dart';
// import 'package:car_provider_app/views/dashboard/widget/general_appointment_widget.dart';
// import 'package:mc_common_app/classes/app_state.dart';
// import 'package:mc_common_app/config/dependency_injection.dart';
// import 'package:mc_common_app/extensions/string_extensions.dart';
// import 'package:mc_common_app/generated/locale_keys.g.dart';
// import 'package:mc_common_app/theme/colors.dart';
// import 'package:mc_common_app/utils/date_helper.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/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';
// import 'package:easy_localization/easy_localization.dart';
//
// class AppointmentFragment extends StatelessWidget {
// String date = "";
// final VoidCallback onBackButtonTapped;
//
// AppointmentFragment({Key? key, required this.onBackButtonTapped}) : super(key: key);
//
// GlobalKey<RefreshIndicatorState> refreshIndicatorKey = GlobalKey<RefreshIndicatorState>();
//
// Future<void> _pullRefresh(BuildContext context) async {
// await context.read<AppointmentsVM>().getMyAppointmentsForProvider({"ServiceProviderID": injector.get<AppState>().getUser.data?.userInfo?.providerId.toString() ?? "0"});
// }
//
// @override
// Widget build(BuildContext context) {
// date = DateHelper.formatAsDayMonthYear(DateTime.now());
// return Scaffold(
// appBar: CustomAppBar(
// //profileImageUrl: MyAssets.carBanner,
// title: LocaleKeys.appointments.tr(),
// onBackButtonTapped: onBackButtonTapped,
// actions: [
// IconButton(
// onPressed: () {},
// icon: const Icon(Icons.search),
// ),
// 10.width,
// ],
// ),
// body: SizedBox(
// width: double.infinity,
// height: double.infinity,
// child: Consumer(builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) {
// return RefreshIndicator(
// onRefresh: () => _pullRefresh(context),
// key: refreshIndicatorKey,
// child: SingleChildScrollView(
// physics: const AlwaysScrollableScrollPhysics(),
// child: Column(
// children: [
// progressWidget(context),
// FiltersList(
// filterList: appointmentsVM.appointmentsFilterOptions,
// padding: const EdgeInsets.symmetric(horizontal: 18),
// onFilterTapped: (index, selectedFilterId) {
// appointmentsVM.applyFilterOnAppointmentsVM(
// appointmentStatusEnum: selectedFilterId.toAppointmentStatusEnum(),
// );
// },
// ),
// ListView.separated(
// itemBuilder: (context, index) {
// return AppointmentSliderWidget(
// appointmentListModel: appointmentsVM.myFilteredAppointments2[index],
// isNeedTotalPayment: false,
// onTap: () {
// 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) {
// 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,
// );
// 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,
// ),
// "8".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,
// ),
// "54".toText(
// fontSize: 9,
// fontWeight: FontWeight.bold,
// color: Colors.white,
// ),
// ],
// ).toContainer(
// backgroundColor: MyColors.darkIconColor,
// ),
// ],
// ),
// CircularPercentIndicator(
// radius: 60.0,
// lineWidth: 12.0,
// percent: 0.7,
// circularStrokeCap: CircularStrokeCap.round,
// center: Column(
// mainAxisAlignment: MainAxisAlignment.center,
// children: [
// "Total Slots".toText(
// fontSize: 13,
// fontWeight: FontWeight.bold,
// ),
// "24".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),
// );
// }
// }

@ -54,7 +54,7 @@ class GeneralAppointmentWidget extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.start,
children: [
showServices(
"${appointmentListModel.appointmentServicesList!.first.providerServiceDescription} - ${appointmentListModel.appointmentServicesList!.first.serviceId}",
"${appointmentListModel.appointmentServicesList!.first.providerServiceName} ${appointmentListModel.appointmentServicesList!.first.serviceId != 0 ? '- ${appointmentListModel.appointmentServicesList!.first.serviceId}' : ""}",
MyAssets.modificationsIcon,
),
if (isNeedToShowItems) ...itemsList,
@ -77,7 +77,9 @@ class GeneralAppointmentWidget extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
showServices(
"${appointmentListModel.appointmentServicesList![index].providerServiceDescription} - ${appointmentListModel.appointmentServicesList![index].serviceId}", MyAssets.modificationsIcon),
"${appointmentListModel.appointmentServicesList![index].providerServiceName} ${appointmentListModel.appointmentServicesList![index].serviceId != 0 ? '- ${appointmentListModel.appointmentServicesList![index].serviceId}' : ""}",
MyAssets.modificationsIcon,
),
if (isNeedToShowItems) ...itemsList,
],
).paddingOnly(bottom: 6);
@ -231,7 +233,7 @@ class GeneralAppointmentWidget extends StatelessWidget {
),
),
if (!isNeedTotalPayment)
if (appointmentListModel.customerAppointmentList!.length > 1)
if (appointmentListModel.customerAppointmentList != null && appointmentListModel.customerAppointmentList!.length > 1)
"${appointmentListModel.customerAppointmentList!.length - 1}+ Appointments".toText(fontSize: 8).toContainer(
borderRadius: 15,
backgroundColor: MyColors.lightGreyEAColor,

@ -15,7 +15,7 @@ import 'package:provider/provider.dart';
import 'package:easy_localization/easy_localization.dart';
class ServiceProviderWidget extends StatelessWidget {
const ServiceProviderWidget({Key? key}) : super(key: key);
const ServiceProviderWidget({super.key});
@override
Widget build(BuildContext context) {
@ -28,9 +28,9 @@ class ServiceProviderWidget extends StatelessWidget {
return const Center(child: CircularProgressIndicator());
} else {
return serviceVM.branches == null || serviceVM.branches!.data == null
? Center(child: LocaleKeys.noBranchFound.tr().toText(fontSize: 16, color: MyColors.lightTextColor, fontWeight: MyFonts.Medium))
? Center(child: LocaleKeys.noBranchFound.tr().toText(fontSize: 16, color: MyColors.lightTextColor))
: serviceVM.homePageBranches.isEmpty
? Center(child: LocaleKeys.no_branch.tr().toText(fontSize: 16, color: MyColors.lightTextColor, fontWeight: MyFonts.Medium))
? Center(child: LocaleKeys.no_branch.tr().toText(fontSize: 16, color: MyColors.lightTextColor))
: ListView.builder(
itemCount: serviceVM.homePageBranches.length,
scrollDirection: Axis.horizontal,

@ -41,8 +41,8 @@ dependencies:
mc_common_app:
# path: D:\Development\car_common_app
path: /Users/aamir/StudioProjects/car_common_app
# path: /Users/faizhashmi/Development/Projects/MyProjects/CloudSolutions/car_common_app
path: /Volumes/Data/Projects/Flutter/car_common_app
# path: /Users/aamir/StudioProjects/car_common_app

Loading…
Cancel
Save