Merge branch 'master' into haroon_dev

pull/204/head
haroon amjad 1 day ago
commit 444e7b562f

@ -752,6 +752,11 @@
"erConsultation": "تتيح لك هذه الخدمة إجراء استشارة افتراضية عبر الإنترنت عبر مكالمة فيديو مباشرة مع الطبيب من أي مكان وفي أي وقت.",
"myInvoice": "القائمة",
"invoiceList": "فواتيري",
"allInvoices": "كل الفواتير",
"hospitals": "المستشفيات",
"clinics": "العيادات",
"doctors": "الأطباء",
"selectDoctor": "اختر الطبيب",
"thisItemIsNotAvailable": "هذا العنصر غير متوفر",
"beforeAfterImages": "صور قبل وبعد",
"clinicAcceptLivecare": "لا حاجة للانتظار أو الزيارة يمكنك الآن الحصول على استشارة طبية عبر مكالمة فيديو (لايف كير) في اسم العيادة وسيتصل بك الطبيب على الفور",

@ -744,6 +744,11 @@
"erConsultation": "This service allows you to make an online virtual consultation via video call directly with the doctor from anywhere at any time.",
"myInvoice": "List",
"invoiceList": "My Invoice",
"allInvoices": "All Invoices",
"hospitals": "Hospitals",
"clinics": "Clinics",
"doctors": "Doctors",
"selectDoctor": "Select Doctor",
"thisItemIsNotAvailable": "This item is not available",
"beforeAfterImages": "Before & After Images",
"clinicAcceptLivecare": "No need to wait or visit You can now get medical consultation via Video call (LiveCare service) in The name of the clinic clinic and the doctor will contact you immediately",

@ -315,7 +315,13 @@ class AuthenticationRepoImp implements AuthenticationRepo {
}
if (appState.getSuperUserID == responseID) {
// switchRequest['LoginType'] = 0;
switchRequest['PatientIdentificationID'] = "";
// switchRequest["PatientID"] = responseID;
// switchRequest["SuperUser"] = responseID;
// switchRequest["PatientID"] = appState.getAuthenticatedUser()?.patientId ?? 0;
// switchRequest["PatientMobileNumber"] = newRequest.patientMobileNumber?.toString().startsWith('0') == true ? newRequest.patientMobileNumber.toString() : '0${newRequest.patientMobileNumber}';
switchRequest.removeWhere((key, value) => ['NationalID', 'isDentalAllowedBackend', 'ProjectOutSA', 'ForRegisteration'].contains(key));
}
}

@ -387,7 +387,8 @@ class LabViewModel extends ChangeNotifier {
LoaderBottomSheet.hideLoader();
if (apiResponse.messageStatus == 2) {
} else if (apiResponse.messageStatus == 1) {
var recentThree = sort(apiResponse.data!);
var sortedResult = sort(apiResponse.data!);
var recentThree = sortedResult.take(3).toList();
mainLabResults = recentThree;
double highRefrenceValue = double.negativeInfinity;
@ -395,11 +396,12 @@ class LabViewModel extends ChangeNotifier {
double lowRefenceValue = double.infinity;
String? flagForLowReferenceRange;
recentThree.reversed.forEach((element) {
sortedResult.take(3).toList().reversed.forEach((element) {
try {
var dateTime = DateUtil.convertStringToDate(element.verifiedOnDateTime!);
var resultValue = double.parse(element.resultValue!);
var transformedValue = transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag ?? "");
// var transformedValue = transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag ?? "");
var transformedValue = resultValue;
if (resultValue > maxY) {
maxY = resultValue;
maxX = maxY;
@ -431,9 +433,9 @@ class LabViewModel extends ChangeNotifier {
highRefrenceValue = maxY;
lowRefenceValue = minY;
}
//
if (minY > lowRefenceValue) {
minY = lowRefenceValue - 25;
minY = lowRefenceValue - getInterval();
}
this.flagForHighReferenceRange = flagForHighReferenceRange;
@ -442,12 +444,16 @@ class LabViewModel extends ChangeNotifier {
lowTransformedReferenceValue = double.parse(transformValueInRange(lowRefenceValue, flagForLowReferenceRange ?? "").toStringAsFixed(1));
this.highRefrenceValue = double.parse(highRefrenceValue.toStringAsFixed(1));
this.lowRefenceValue = double.parse(lowRefenceValue.toStringAsFixed(1));
if (maxY < highRefrenceValue) {
if(maxY<highRefrenceValue){
maxY = highRefrenceValue;
maxX = maxY;
}
maxY += 25;
minY -= 25;
// if (maxY < highRefrenceValue) {
// minY = highRefrenceValue - getInterval();
// }
// maxY += 25;
// minY -= 25;
LabResult recentResult = recentThree.first;
recentResult.uOM = unitOfMeasure;
checkIfGraphShouldBeDisplayed(recentResult);
@ -464,6 +470,17 @@ class LabViewModel extends ChangeNotifier {
},
);
}
num getInterval() {
// return .1;
var maxX = maxY;
if(maxX<1) return .2;
if(maxX >=1.0 && maxX < 5.0) return .3;
if(maxX >=5.0 && maxX < 10.0) return 1.5;
if(maxX >=10.0 && maxX < 50.0) return 2.5;
if(maxX >=50.0 && maxX < 100.0) return 5;
if(maxX >=100.0 && maxX < 200.0) return 10;
return 15;
}
void checkIfGraphShouldBeDisplayed(LabResult recentResult) {
shouldShowGraph = recentResult.checkIfGraphShouldBeDisplayed();
@ -586,7 +603,8 @@ class LabViewModel extends ChangeNotifier {
try {
var dateTime = DateUtil.convertStringToDate(element.verifiedOnDateTime!);
var resultValue = double.parse(element.resultValue!);
var transformedValue = transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag ?? "");
// var transformedValue = transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag ?? "");
var transformedValue = double.parse(element.resultValue!);
if (resultValue > maxY) {
maxY = resultValue;
}

@ -5,6 +5,8 @@ import 'package:hmg_patient_app_new/features/my_invoices/my_invoices_repo.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
enum InvoiceFilterType { all, hospital, clinic, doctor }
class MyInvoicesViewModel extends ChangeNotifier {
bool isInvoicesListLoading = false;
bool isInvoiceDetailsLoading = false;
@ -14,13 +16,23 @@ class MyInvoicesViewModel extends ChangeNotifier {
NavigationService navServices;
List<GetInvoicesListResponseModel> allInvoicesList = [];
List<GetInvoicesListResponseModel> _originalInvoicesList = [];
InvoiceFilterType currentFilter = InvoiceFilterType.all;
late GetInvoiceDetailsResponseModel invoiceDetailsResponseModel;
// Filter bottom sheet properties
List<String> filterDisplayList = [];
List<String> _filterOriginalList = [];
TextEditingController filterSearchController = TextEditingController();
String? selectedFilterItem;
MyInvoicesViewModel({required this.myInvoicesRepo, required this.errorHandlerService, required this.navServices});
setInvoicesListLoading() {
isInvoicesListLoading = true;
allInvoicesList.clear();
_originalInvoicesList.clear();
currentFilter = InvoiceFilterType.all;
notifyListeners();
}
@ -41,9 +53,10 @@ class MyInvoicesViewModel extends ChangeNotifier {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
allInvoicesList = apiResponse.data!;
_originalInvoicesList = apiResponse.data!;
_originalInvoicesList.sort((a, b) => b.appointmentDate!.compareTo(a.appointmentDate!));
allInvoicesList = List.from(_originalInvoicesList);
isInvoicesListLoading = false;
allInvoicesList.sort((a, b) => b.appointmentDate!.compareTo(a.appointmentDate!));
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
@ -99,4 +112,128 @@ class MyInvoicesViewModel extends ChangeNotifier {
},
);
}
void filterInvoices(InvoiceFilterType filterType) {
currentFilter = filterType;
switch (filterType) {
case InvoiceFilterType.all:
allInvoicesList = List.from(_originalInvoicesList);
break;
case InvoiceFilterType.hospital:
allInvoicesList = _originalInvoicesList.where((invoice) {
return invoice.projectName != null && invoice.projectName!.isNotEmpty;
}).toList();
// Group by hospital (projectName) and sort
allInvoicesList.sort((a, b) {
int projectComparison = (a.projectName ?? '').compareTo(b.projectName ?? '');
if (projectComparison != 0) return projectComparison;
return b.appointmentDate!.compareTo(a.appointmentDate!);
});
break;
case InvoiceFilterType.clinic:
allInvoicesList = _originalInvoicesList.where((invoice) {
return invoice.clinicName != null && invoice.clinicName!.isNotEmpty;
}).toList();
// Group by clinic (clinicName) and sort
allInvoicesList.sort((a, b) {
int clinicComparison = (a.clinicName ?? '').compareTo(b.clinicName ?? '');
if (clinicComparison != 0) return clinicComparison;
return b.appointmentDate!.compareTo(a.appointmentDate!);
});
break;
case InvoiceFilterType.doctor:
allInvoicesList = _originalInvoicesList.where((invoice) {
return invoice.doctorName != null && invoice.doctorName!.isNotEmpty;
}).toList();
// Group by doctor (doctorName) and sort
allInvoicesList.sort((a, b) {
int doctorComparison = (a.doctorName ?? '').compareTo(b.doctorName ?? '');
if (doctorComparison != 0) return doctorComparison;
return b.appointmentDate!.compareTo(a.appointmentDate!);
});
break;
}
notifyListeners();
}
void filterInvoicesByHospital(String hospitalName) {
currentFilter = InvoiceFilterType.hospital;
allInvoicesList = _originalInvoicesList
.where((invoice) => invoice.projectName == hospitalName)
.toList();
allInvoicesList.sort((a, b) => b.appointmentDate!.compareTo(a.appointmentDate!));
notifyListeners();
}
void filterInvoicesByClinic(String clinicName) {
currentFilter = InvoiceFilterType.clinic;
allInvoicesList = _originalInvoicesList
.where((invoice) => invoice.clinicName == clinicName)
.toList();
allInvoicesList.sort((a, b) => b.appointmentDate!.compareTo(a.appointmentDate!));
notifyListeners();
}
void filterInvoicesByDoctor(String doctorName) {
currentFilter = InvoiceFilterType.doctor;
allInvoicesList = _originalInvoicesList
.where((invoice) => invoice.doctorName == doctorName)
.toList();
allInvoicesList.sort((a, b) => b.appointmentDate!.compareTo(a.appointmentDate!));
notifyListeners();
}
List<GetInvoicesListResponseModel> getOriginalInvoicesList() {
return _originalInvoicesList;
}
// Filter bottom sheet methods
void prepareFilterList(InvoiceFilterType filterType) {
Set<String> uniqueItems = {};
for (var invoice in _originalInvoicesList) {
String? itemName;
if (filterType == InvoiceFilterType.hospital) {
itemName = invoice.projectName;
} else if (filterType == InvoiceFilterType.clinic) {
itemName = invoice.clinicName;
} else if (filterType == InvoiceFilterType.doctor) {
itemName = invoice.doctorName;
}
if (itemName != null && itemName.isNotEmpty) {
uniqueItems.add(itemName);
}
}
_filterOriginalList = uniqueItems.toList()..sort();
filterDisplayList = List.from(_filterOriginalList);
filterSearchController.clear();
selectedFilterItem = null;
notifyListeners();
}
void searchFilterItems(String query) {
if (query.isEmpty) {
filterDisplayList = List.from(_filterOriginalList);
} else {
filterDisplayList = _filterOriginalList
.where((item) => item.toLowerCase().contains(query.toLowerCase()))
.toList();
}
notifyListeners();
}
void clearFilterSearch() {
filterSearchController.clear();
filterDisplayList = List.from(_filterOriginalList);
notifyListeners();
}
void selectFilterItem(String item) {
selectedFilterItem = item;
notifyListeners();
}
}

@ -751,6 +751,11 @@ abstract class LocaleKeys {
static const erConsultation = 'erConsultation';
static const myInvoice = 'myInvoice';
static const invoiceList = 'invoiceList';
static const allInvoices = 'allInvoices';
static const hospitals = 'hospitals';
static const clinics = 'clinics';
static const doctors = 'doctors';
static const selectDoctor = 'selectDoctor';
static const thisItemIsNotAvailable = 'thisItemIsNotAvailable';
static const beforeAfterImages = 'beforeAfterImages';
static const clinicAcceptLivecare = 'clinicAcceptLivecare';

@ -328,20 +328,20 @@ class LabResultDetails extends StatelessWidget {
},
leftLabelFormatter: (value) {
value = double.parse(value.toStringAsFixed(1));
// return leftLabels(value.toStringAsFixed(2));
if (value == labmodel.highRefrenceValue) {
return leftLabels(LocaleKeys.high.tr());
}
if (value == labmodel.lowRefenceValue) {
return leftLabels(LocaleKeys.low.tr());
}
return leftLabels(value.toStringAsFixed(2));
// if (value == labmodel.highRefrenceValue) {
// return leftLabels(LocaleKeys.high.tr());
// }
//
// if (value == labmodel.lowRefenceValue) {
// return leftLabels(LocaleKeys.low.tr());
// }
return SizedBox.shrink();
// }
},
graphColor: AppColors.blackColor,
graphShadowColor: Colors.transparent,
graphColor: AppColors.graphGridColor,
graphShadowColor: AppColors.graphGridColor.withOpacity(.5),
graphGridColor: graphColor.withOpacity(.4),
bottomLabelFormatter: (value, data) {
if (data.isEmpty) return SizedBox.shrink();
@ -373,7 +373,7 @@ class LabResultDetails extends StatelessWidget {
ranges.add(HorizontalRangeAnnotation(
y1: model.minY,
y2: model.lowRefenceValue,
color: AppColors.highAndLow.withOpacity(0.05),
color: Colors.transparent,
));
ranges.add(HorizontalRangeAnnotation(
@ -385,7 +385,7 @@ class LabResultDetails extends StatelessWidget {
ranges.add(HorizontalRangeAnnotation(
y1: model.highRefrenceValue,
y2: model.maxY,
color: AppColors.criticalLowAndHigh.withOpacity(0.05),
color: Colors.transparent,
));
return ranges;
}
@ -414,15 +414,17 @@ class LabResultDetails extends StatelessWidget {
}
double? getInterval(LabViewModel labmodel) {
return .1;
// var maxX = labmodel.maxY;
// if(maxX<1) return .5;
// if(maxX >1 && maxX < 5) return 1;
// if(maxX >5 && maxX < 10) return 5;
// if(maxX >10 && maxX < 50) return 10;
// if(maxX >50 && maxX < 100) return 20;
// if(maxX >100 && maxX < 200) return 30;
// return 50;
// return .1;
var maxX = labmodel.maxY;
if(maxX<1) return .3;
if(maxX >1 && maxX <= 5) return .7;
if(maxX >5 && maxX <= 10) return 2.5;
if(maxX >10 && maxX <= 50) return 5;
if(maxX >50 && maxX <= 100) return 10;
if(maxX >100 && maxX <= 200) return 30;
if(maxX >200 && maxX <= 300) return 50;
if(maxX >300 && maxX <= 400) return 100;
return 200 ;
}
Widget getLabDescription(BuildContext context) {

@ -13,6 +13,7 @@ import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_card.dart';
import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart';
import 'package:hmg_patient_app_new/presentation/my_invoices/my_invoices_details_page.dart';
import 'package:hmg_patient_app_new/presentation/my_invoices/widgets/invoice_filter_bottom_sheet.dart';
import 'package:hmg_patient_app_new/presentation/my_invoices/widgets/invoice_list_card.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
@ -21,6 +22,8 @@ import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:provider/provider.dart';
import '../../widgets/buttons/custom_button.dart';
class MyInvoicesList extends StatefulWidget {
const MyInvoicesList({super.key});
@ -40,6 +43,75 @@ class _MyInvoicesListState extends State<MyInvoicesList> {
super.initState();
}
void _showHospitalFilterBottomSheet(BuildContext context) {
myInvoicesViewModel.prepareFilterList(InvoiceFilterType.hospital);
showCommonBottomSheetWithoutHeight(
title: LocaleKeys.selectHospital.tr(context: context),
context,
child: InvoiceFilterBottomSheet(
title: LocaleKeys.hospital.tr(context: context),
onItemSelected: (selectedHospital) {
Navigator.pop(context);
myInvoicesViewModel.filterInvoicesByHospital(selectedHospital);
},
),
isFullScreen: false,
isCloseButtonVisible: true,
hasBottomPadding: false,
backgroundColor: AppColors.bottomSheetBgColor,
callBackFunc: () {
myInvoicesViewModel.clearFilterSearch();
},
);
}
void _showClinicFilterBottomSheet(BuildContext context) {
myInvoicesViewModel.prepareFilterList(InvoiceFilterType.clinic);
showCommonBottomSheetWithoutHeight(
title: LocaleKeys.selectClinic.tr(context: context),
context,
child: InvoiceFilterBottomSheet(
title: LocaleKeys.clinic.tr(context: context),
onItemSelected: (selectedClinic) {
Navigator.pop(context);
myInvoicesViewModel.filterInvoicesByClinic(selectedClinic);
},
),
isFullScreen: false,
isCloseButtonVisible: true,
hasBottomPadding: false,
backgroundColor: AppColors.bottomSheetBgColor,
callBackFunc: () {
myInvoicesViewModel.clearFilterSearch();
},
);
}
void _showDoctorFilterBottomSheet(BuildContext context) {
myInvoicesViewModel.prepareFilterList(InvoiceFilterType.doctor);
showCommonBottomSheetWithoutHeight(
title: LocaleKeys.selectDoctor.tr(context: context),
context,
child: InvoiceFilterBottomSheet(
title: LocaleKeys.doctor.tr(context: context),
onItemSelected: (selectedDoctor) {
Navigator.pop(context);
myInvoicesViewModel.filterInvoicesByDoctor(selectedDoctor);
},
),
isFullScreen: false,
isCloseButtonVisible: true,
hasBottomPadding: false,
backgroundColor: AppColors.bottomSheetBgColor,
callBackFunc: () {
myInvoicesViewModel.clearFilterSearch();
},
);
}
@override
Widget build(BuildContext context) {
myInvoicesViewModel = Provider.of<MyInvoicesViewModel>(context, listen: false);
@ -50,62 +122,133 @@ class _MyInvoicesListState extends State<MyInvoicesList> {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 24.h),
SizedBox(height: 16.h),
Row(
children: [
CustomButton(
text: LocaleKeys.allInvoices.tr(context: context),
onPressed: () {
myInvoicesViewModel.filterInvoices(InvoiceFilterType.all);
},
backgroundColor: myInvoicesVM.currentFilter == InvoiceFilterType.all ? AppColors.bgRedLightColor : AppColors.whiteColor,
borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.all ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2),
textColor: myInvoicesVM.currentFilter == InvoiceFilterType.all ? AppColors.primaryRedColor : AppColors.blackColor,
fontSize: 12,
fontWeight: FontWeight.w500,
borderRadius: 10,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h,
),
SizedBox(width: 8.h),
CustomButton(
text: LocaleKeys.hospitals.tr(context: context),
onPressed: () {
if (myInvoicesVM.allInvoicesList.isEmpty) return;
_showHospitalFilterBottomSheet(context);
},
backgroundColor: myInvoicesVM.currentFilter == InvoiceFilterType.hospital ? AppColors.bgRedLightColor : AppColors.whiteColor,
borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.hospital ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2),
textColor: myInvoicesVM.currentFilter == InvoiceFilterType.hospital ? AppColors.primaryRedColor : AppColors.blackColor,
fontSize: 12,
fontWeight: FontWeight.w500,
borderRadius: 10,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h,
),
SizedBox(width: 8.h),
CustomButton(
text: LocaleKeys.clinics.tr(context: context),
onPressed: () {
if (myInvoicesVM.allInvoicesList.isEmpty) return;
_showClinicFilterBottomSheet(context);
},
backgroundColor: myInvoicesVM.currentFilter == InvoiceFilterType.clinic ? AppColors.bgRedLightColor : AppColors.whiteColor,
borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.clinic ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2),
textColor: myInvoicesVM.currentFilter == InvoiceFilterType.clinic ? AppColors.primaryRedColor : AppColors.blackColor,
fontSize: 12,
fontWeight: FontWeight.w500,
borderRadius: 10,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h,
),
SizedBox(width: 8.h),
CustomButton(
text: LocaleKeys.doctors.tr(context: context),
onPressed: () {
if (myInvoicesVM.allInvoicesList.isEmpty) return;
_showDoctorFilterBottomSheet(context);
},
backgroundColor: myInvoicesVM.currentFilter == InvoiceFilterType.doctor ? AppColors.bgRedLightColor : AppColors.whiteColor,
borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.doctor ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2),
textColor: myInvoicesVM.currentFilter == InvoiceFilterType.doctor ? AppColors.primaryRedColor : AppColors.blackColor,
fontSize: 12,
fontWeight: FontWeight.w500,
borderRadius: 10,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h,
),
],
).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 16.h),
ListView.builder(
itemCount: myInvoicesVM.isInvoicesListLoading ? 4 : myInvoicesVM.allInvoicesList.isEmpty ? 1 : myInvoicesVM.allInvoicesList.length,
itemCount: myInvoicesVM.isInvoicesListLoading
? 4
: myInvoicesVM.allInvoicesList.isEmpty
? 1
: myInvoicesVM.allInvoicesList.length,
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: EdgeInsetsGeometry.zero,
itemBuilder: (context, index) {
return myInvoicesVM.isInvoicesListLoading
? LabResultItemView(
onTap: () {},
labOrder: null,
index: index,
isLoading: true,
)
: myInvoicesVM.allInvoicesList.isNotEmpty ? AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 500),
child: SlideAnimation(
verticalOffset: 100.0,
child: FadeInAnimation(
child: AnimatedContainer(
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
child: InvoiceListCard(
getInvoicesListResponseModel: myInvoicesVM.allInvoicesList[index],
onTap: () async {
myInvoicesVM.setInvoiceDetailLoading();
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingInvoiceDetails.tr(context: context));
await myInvoicesVM.getInvoiceDetails(
appointmentNo: myInvoicesVM.allInvoicesList[index].appointmentNo!,
invoiceNo: myInvoicesVM.allInvoicesList[index].invoiceNo!,
projectID: myInvoicesVM.allInvoicesList[index].projectID!,
onSuccess: (val) {
LoaderBottomSheet.hideLoader();
Navigator.of(context).push(
CustomPageRoute(
page: MyInvoicesDetailsPage(getInvoiceDetailsResponseModel: myInvoicesVM.invoiceDetailsResponseModel, getInvoicesListResponseModel: myInvoicesVM.allInvoicesList[index],),
),
);
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
},
? LabResultItemView(onTap: () {}, labOrder: null, index: index, isLoading: true)
: myInvoicesVM.allInvoicesList.isNotEmpty
? AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 500),
child: SlideAnimation(
verticalOffset: 100.0,
child: FadeInAnimation(
child: AnimatedContainer(
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
child: InvoiceListCard(
getInvoicesListResponseModel: myInvoicesVM.allInvoicesList[index],
onTap: () async {
myInvoicesVM.setInvoiceDetailLoading();
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingInvoiceDetails.tr(context: context));
await myInvoicesVM.getInvoiceDetails(
appointmentNo: myInvoicesVM.allInvoicesList[index].appointmentNo!,
invoiceNo: myInvoicesVM.allInvoicesList[index].invoiceNo!,
projectID: myInvoicesVM.allInvoicesList[index].projectID!,
onSuccess: (val) {
LoaderBottomSheet.hideLoader();
Navigator.of(context).push(
CustomPageRoute(
page: MyInvoicesDetailsPage(
getInvoiceDetailsResponseModel: myInvoicesVM.invoiceDetailsResponseModel,
getInvoicesListResponseModel: myInvoicesVM.allInvoicesList[index],
),
),
);
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
},
),
),
),
),
),
),
) : Utils.getNoDataWidget(context);
)
: Utils.getNoDataWidget(context);
}).paddingSymmetrical(24.w, 0.h),
],
);

@ -0,0 +1,133 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/core/utils/debouncer.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/my_invoices/my_invoices_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/input_widget.dart';
import 'package:provider/provider.dart';
class InvoiceFilterBottomSheet extends StatelessWidget {
final Function(String) onItemSelected;
final String title;
const InvoiceFilterBottomSheet({
super.key,
required this.onItemSelected,
required this.title,
});
@override
Widget build(BuildContext context) {
final debouncer = Debouncer(milliseconds: 500);
return Consumer<MyInvoicesViewModel>(
builder: (context, vm, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextInputWidget(
labelText: LocaleKeys.search.tr(context: context),
hintText: "Search $title",
controller: vm.filterSearchController,
onChange: (value) {
debouncer.run(() {
vm.searchFilterItems(value ?? "");
});
},
isEnable: true,
prefix: null,
autoFocus: false,
isBorderAllowed: false,
keyboardType: TextInputType.text,
isAllowLeadingIcon: true,
selectionType: SelectionTypeEnum.search,
padding: EdgeInsets.symmetric(
vertical: ResponsiveExtension(10).h,
horizontal: ResponsiveExtension(15).h,
),
),
SizedBox(height: 24.h),
SizedBox(
height: MediaQuery.sizeOf(context).height * 0.4,
child: vm.filterDisplayList.isEmpty
? Center(
child: Text(
"No $title found",
style: TextStyle(
fontSize: 16,
color: AppColors.greyTextColor,
),
),
)
: ListView.separated(
itemBuilder: (_, index) {
final item = vm.filterDisplayList[index];
return FilterListItem(
itemName: item,
).onPress(() {
vm.selectFilterItem(item);
onItemSelected(item);
});
},
separatorBuilder: (_, __) => SizedBox(height: 16.h),
itemCount: vm.filterDisplayList.length,
),
),
],
);
},
);
}
}
class FilterListItem extends StatelessWidget {
final String itemName;
const FilterListItem({super.key, required this.itemName});
AppState get appState => getIt.get<AppState>();
@override
Widget build(BuildContext context) {
return DecoratedBox(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: false,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
itemName,
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 16,
color: AppColors.blackColor,
),
),
),
Transform.flip(
flipX: appState.isArabic(),
child: Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon_small,
iconColor: AppColors.blackColor,
width: 18.h,
height: 13.h,
fit: BoxFit.contain,
),
),
],
).paddingSymmetrical(16.h, 16.h),
);
}
}

@ -257,7 +257,7 @@ class CustomGraph extends StatelessWidget {
isCurved: true,
isStrokeCapRound: true,
isStrokeJoinRound: true,
barWidth: 2,
barWidth: 3,
gradient: LinearGradient(
colors: [resolvedGraphColor, resolvedGraphColor],
begin: Alignment.centerLeft,

Loading…
Cancel
Save