From 001808488c9ee29d431f421ca256c53cbb7e6e45 Mon Sep 17 00:00:00 2001 From: faizatflutter Date: Mon, 12 Jan 2026 11:30:01 +0300 Subject: [PATCH] Added 'send report to email' feature --- .../health_trackers/health_trackers_repo.dart | 127 ++++- lib/main.dart | 1 + .../health_tracker_detail_page.dart | 183 ++++++- .../health_trackers_view_model.dart | 104 ++++ .../medical_file/medical_file_page.dart | 456 +++++++++--------- 5 files changed, 644 insertions(+), 227 deletions(-) diff --git a/lib/features/health_trackers/health_trackers_repo.dart b/lib/features/health_trackers/health_trackers_repo.dart index e6930f9..2a64fc4 100644 --- a/lib/features/health_trackers/health_trackers_repo.dart +++ b/lib/features/health_trackers/health_trackers_repo.dart @@ -39,6 +39,11 @@ abstract class HealthTrackersRepo { required int lineItemNo, }); + /// Send blood sugar report by email. + Future>> sendBloodSugarReportByEmail({ + required String email, + }); + // ==================== BLOOD PRESSURE ==================== /// Get blood pressure result averages (week, month, year). Future>> getBloodPressureResultAverage(); @@ -68,6 +73,11 @@ abstract class HealthTrackersRepo { required int lineItemNo, }); + /// Send blood pressure report by email. + Future>> sendBloodPressureReportByEmail({ + required String email, + }); + // ==================== WEIGHT MEASUREMENT ==================== /// Get weight measurement result averages (week, month, year). Future>> getWeightMeasurementResultAverage(); @@ -94,6 +104,11 @@ abstract class HealthTrackersRepo { Future>> deactivateWeightMeasurementStatus({ required int lineItemNo, }); + + /// Send weight report by email. + Future>> sendWeightReportByEmail({ + required String email, + }); } class HealthTrackersRepoImp implements HealthTrackersRepo { @@ -322,6 +337,42 @@ class HealthTrackersRepoImp implements HealthTrackersRepo { } } + @override + Future>> sendBloodSugarReportByEmail({ + required String email, + }) async { + try { + GenericApiModel? apiResponse; + Failure? failure; + + Map body = { + 'To': email, + }; + + await apiClient.post( + ApiConsts.sendAverageBloodSugarReport, + body: body, + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + apiResponse = GenericApiModel( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: errorMessage, + data: response, + ); + }, + ); + + if (failure != null) return Left(failure!); + if (apiResponse == null) return Left(ServerFailure("Unknown error")); + return Right(apiResponse!); + } catch (e) { + return Left(UnknownFailure(e.toString())); + } + } + // ==================== BLOOD PRESSURE METHODS ==================== @override @@ -538,6 +589,42 @@ class HealthTrackersRepoImp implements HealthTrackersRepo { } } + @override + Future>> sendBloodPressureReportByEmail({ + required String email, + }) async { + try { + GenericApiModel? apiResponse; + Failure? failure; + + Map body = { + 'To': email, + }; + + await apiClient.post( + ApiConsts.sendAverageBloodPressureReport, + body: body, + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + apiResponse = GenericApiModel( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: errorMessage, + data: response, + ); + }, + ); + + if (failure != null) return Left(failure!); + if (apiResponse == null) return Left(ServerFailure("Unknown error")); + return Right(apiResponse!); + } catch (e) { + return Left(UnknownFailure(e.toString())); + } + } + // ==================== WEIGHT MEASUREMENT METHODS ==================== @override @@ -715,9 +802,7 @@ class HealthTrackersRepoImp implements HealthTrackersRepo { } @override - Future>> deactivateWeightMeasurementStatus({ - required int lineItemNo, - }) async { + Future>> deactivateWeightMeasurementStatus({required int lineItemNo}) async { try { GenericApiModel? apiResponse; Failure? failure; @@ -749,4 +834,40 @@ class HealthTrackersRepoImp implements HealthTrackersRepo { return Left(UnknownFailure(e.toString())); } } + + @override + Future>> sendWeightReportByEmail({ + required String email, + }) async { + try { + GenericApiModel? apiResponse; + Failure? failure; + + Map body = { + 'To': email, + }; + + await apiClient.post( + ApiConsts.sendAverageBodyWeightReport, + body: body, + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + apiResponse = GenericApiModel( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: errorMessage, + data: response, + ); + }, + ); + + if (failure != null) return Left(failure!); + if (apiResponse == null) return Left(ServerFailure("Unknown error")); + return Right(apiResponse!); + } catch (e) { + return Left(UnknownFailure(e.toString())); + } + } } diff --git a/lib/main.dart b/lib/main.dart index f0537b3..5091572 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -219,3 +219,4 @@ class MyApp extends StatelessWidget { } } // flutter pub run easy_localization:generate -S assets/langs -f keys -o locale_keys.g.dart + diff --git a/lib/presentation/health_trackers/health_tracker_detail_page.dart b/lib/presentation/health_trackers/health_tracker_detail_page.dart index a2b82ec..9443f12 100644 --- a/lib/presentation/health_trackers/health_tracker_detail_page.dart +++ b/lib/presentation/health_trackers/health_tracker_detail_page.dart @@ -2,6 +2,7 @@ import 'package:fl_chart/fl_chart.dart'; import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_export.dart'; +import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/common_models/data_points.dart'; import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/enums.dart'; @@ -9,8 +10,6 @@ import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/route_extensions.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; -import 'package:hmg_patient_app_new/features/health_trackers/models/blood_pressure/week_blood_pressure_result_average.dart'; -import 'package:hmg_patient_app_new/features/health_trackers/models/blood_pressure/year_blood_pressure_result_average.dart'; import 'package:hmg_patient_app_new/features/health_trackers/models/blood_sugar/week_diabetic_result_average.dart'; import 'package:hmg_patient_app_new/features/health_trackers/models/blood_sugar/year_diabetic_result_average.dart'; import 'package:hmg_patient_app_new/features/health_trackers/models/weight/week_weight_measurement_result_average.dart'; @@ -22,7 +21,10 @@ import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; +import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; import 'package:hmg_patient_app_new/widgets/graph/custom_graph.dart'; +import 'package:hmg_patient_app_new/widgets/input_widget.dart'; +import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; import 'package:provider/provider.dart'; import 'package:shimmer/shimmer.dart'; @@ -1028,7 +1030,182 @@ class _HealthTrackerDetailPageState extends State { } void onSendEmailPressed(BuildContext context) async { - // TODO: Implement send email functionality + _showEmailInputBottomSheet(context); + } + + /// Show email input bottom sheet + void _showEmailInputBottomSheet(BuildContext context) { + final viewModel = context.read(); + final appState = getIt.get(); + final dialogService = getIt.get(); + + // Get user's email from authenticated user + final userEmail = appState.getAuthenticatedUser()?.emailAddress ?? ''; + + // Create email controller and pre-fill if available + final emailController = TextEditingController(text: userEmail); + + dialogService.showFamilyBottomSheetWithoutHWithChild( + label: "Send Report by Email".needTranslation, + message: "", + child: _buildEmailInputContent( + context: context, + emailController: emailController, + viewModel: viewModel, + dialogService: dialogService, + ), + onOkPressed: () {}, + ); + } + + /// Build email input content + Widget _buildEmailInputContent({ + required BuildContext context, + required TextEditingController emailController, + required HealthTrackersViewModel viewModel, + required DialogService dialogService, + }) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Enter your email address to receive the report".needTranslation.toText14( + color: AppColors.textColor, + weight: FontWeight.w400, + ), + SizedBox(height: 16.h), + + // Email Input Field using TextInputWidget + TextInputWidget( + padding: EdgeInsets.symmetric(horizontal: 8.w), + labelText: "Email Address".needTranslation, + hintText: "Enter email address".needTranslation, + controller: emailController, + keyboardType: TextInputType.emailAddress, + isEnable: true, + isBorderAllowed: true, + isAllowRadius: true, + ), + + SizedBox(height: 24.h), + + // Send Button + Row( + children: [ + Expanded( + child: CustomButton( + height: 56.h, + text: "Send Report".needTranslation, + onPressed: () { + _sendEmailReport( + context: context, + email: emailController.text.trim(), + viewModel: viewModel, + dialogService: dialogService, + ); + }, + textColor: AppColors.whiteColor, + ), + ), + ], + ), + ], + ); + } + + /// Send email report based on tracker type + Future _sendEmailReport({ + required BuildContext context, + required String email, + required HealthTrackersViewModel viewModel, + required DialogService dialogService, + }) async { + // Validate email + if (email.isEmpty) { + dialogService.showErrorBottomSheet( + message: "Please enter your email address".needTranslation, + ); + return; + } + + // Basic email validation + final emailRegex = RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$'); + if (!emailRegex.hasMatch(email)) { + dialogService.showErrorBottomSheet( + message: "Please enter a valid email address".needTranslation, + ); + return; + } + + // Close the email input bottom sheet + Navigator.of(context).pop(); + + // Call appropriate email function based on tracker type + switch (widget.trackerType) { + case HealthTrackerTypeEnum.bloodSugar: + LoaderBottomSheet.showLoader(loadingText: "Please wait".needTranslation); + await viewModel.sendBloodSugarReportByEmail( + email: email, + onSuccess: () { + LoaderBottomSheet.hideLoader(); + + _showSuccessMessage(context, dialogService); + }, + onFailure: (error) { + LoaderBottomSheet.hideLoader(); + dialogService.showErrorBottomSheet(message: error); + }, + ); + break; + + case HealthTrackerTypeEnum.bloodPressure: + LoaderBottomSheet.showLoader(loadingText: "Please wait".needTranslation); + + await viewModel.sendBloodPressureReportByEmail( + email: email, + onSuccess: () { + LoaderBottomSheet.hideLoader(); + + _showSuccessMessage(context, dialogService); + }, + onFailure: (error) { + LoaderBottomSheet.hideLoader(); + + dialogService.showErrorBottomSheet(message: error); + }, + ); + break; + + case HealthTrackerTypeEnum.weightTracker: + LoaderBottomSheet.showLoader(loadingText: "Please wait".needTranslation); + await viewModel.sendWeightReportByEmail( + email: email, + onSuccess: () { + LoaderBottomSheet.hideLoader(); + + _showSuccessMessage(context, dialogService); + }, + onFailure: (error) { + LoaderBottomSheet.hideLoader(); + + dialogService.showErrorBottomSheet(message: error); + }, + ); + break; + } + } + + /// Show success message + void _showSuccessMessage(BuildContext context, DialogService dialogService) { + showCommonBottomSheetWithoutHeight( + context, + child: Utils.getSuccessWidget( + loadingText: "Report has been sent to your email successfully".needTranslation, + ), + callBackFunc: () {}, + isCloseButtonVisible: false, + isDismissible: true, + isFullScreen: false, + ); } Widget _buildPageShimmer() { diff --git a/lib/presentation/health_trackers/health_trackers_view_model.dart b/lib/presentation/health_trackers/health_trackers_view_model.dart index 059c11e..ce1bdf2 100644 --- a/lib/presentation/health_trackers/health_trackers_view_model.dart +++ b/lib/presentation/health_trackers/health_trackers_view_model.dart @@ -388,6 +388,41 @@ class HealthTrackersViewModel extends ChangeNotifier { } } + /// Send weight report by email + Future sendWeightReportByEmail({ + required String email, + Function()? onSuccess, + Function(String error)? onFailure, + }) async { + try { + final result = await healthTrackersRepo.sendWeightReportByEmail( + email: email, + ); + + bool success = false; + + result.fold( + (failure) { + errorHandlerService.handleError(failure: failure); + if (onFailure != null) onFailure("Failed to send report by email"); + }, + (apiModel) { + success = true; + if (onSuccess != null) onSuccess(); + }, + ); + + notifyListeners(); + + return success; + } catch (e) { + log('Error in sendWeightReportByEmail: $e'); + + if (onFailure != null) onFailure("An error occurred"); + return false; + } + } + // ==================== BLOOD PRESSURE TRACKING METHODS ==================== /// Fetch blood pressure averages and results @@ -554,6 +589,41 @@ class HealthTrackersViewModel extends ChangeNotifier { } } + /// Send blood pressure report by email + Future sendBloodPressureReportByEmail({ + required String email, + Function()? onSuccess, + Function(String error)? onFailure, + }) async { + try { + final result = await healthTrackersRepo.sendBloodPressureReportByEmail( + email: email, + ); + + bool success = false; + + result.fold( + (failure) { + errorHandlerService.handleError(failure: failure); + if (onFailure != null) onFailure("Failed to send report by email"); + }, + (apiModel) { + success = true; + if (onSuccess != null) onSuccess(); + }, + ); + + notifyListeners(); + + return success; + } catch (e) { + log('Error in sendBloodPressureReportByEmail: $e'); + + if (onFailure != null) onFailure("An error occurred"); + return false; + } + } + // ==================== BLOOD SUGAR (DIABETIC) TRACKING METHODS ==================== /// Fetch blood sugar averages and results @@ -746,6 +816,40 @@ class HealthTrackersViewModel extends ChangeNotifier { } } + /// Send blood sugar report by email + Future sendBloodSugarReportByEmail({ + required String email, + Function()? onSuccess, + Function(String error)? onFailure, + }) async { + try { + final result = await healthTrackersRepo.sendBloodSugarReportByEmail( + email: email, + ); + + bool success = false; + + result.fold( + (failure) { + errorHandlerService.handleError(failure: failure); + if (onFailure != null) onFailure("Failed to send report by email"); + }, + (apiModel) { + success = true; + if (onSuccess != null) onSuccess(); + }, + ); + + notifyListeners(); + + return success; + } catch (e) { + log('Error in sendBloodSugarReportByEmail: $e'); + if (onFailure != null) onFailure("An error occurred"); + return false; + } + } + // Validation method String? _validateBloodSugarEntry(String dateTime) { // Validate blood sugar value diff --git a/lib/presentation/medical_file/medical_file_page.dart b/lib/presentation/medical_file/medical_file_page.dart index f705993..554131a 100644 --- a/lib/presentation/medical_file/medical_file_page.dart +++ b/lib/presentation/medical_file/medical_file_page.dart @@ -7,10 +7,11 @@ import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_export.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/date_util.dart'; import 'package:hmg_patient_app_new/core/utils/size_config.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/route_extensions.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart'; @@ -234,9 +235,9 @@ class _MedicalFilePageState extends State { labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: 6.w), onChipTap: () { navigationService.pushPage( - page: FamilyMedicalScreen( - profiles: medicalFileViewModel.patientFamilyFiles, - onSelect: (FamilyFileResponseModelLists p1) {}, + page: FamilyMedicalScreen( + profiles: medicalFileViewModel.patientFamilyFiles, + onSelect: (FamilyFileResponseModelLists p1) {}, ), ); }, @@ -279,7 +280,8 @@ class _MedicalFilePageState extends State { iconColor: insuranceVM.isInsuranceExpired ? AppColors.primaryRedColor : AppColors.successColor, textColor: insuranceVM.isInsuranceExpired ? AppColors.primaryRedColor : AppColors.successColor, iconSize: 12.w, - backgroundColor: insuranceVM.isInsuranceExpired ? AppColors.primaryRedColor.withOpacity(0.1) : AppColors.successColor.withOpacity(0.1), + backgroundColor: + insuranceVM.isInsuranceExpired ? AppColors.primaryRedColor.withOpacity(0.1) : AppColors.successColor.withOpacity(0.1), labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: 6.w), ); }), @@ -381,9 +383,7 @@ class _MedicalFilePageState extends State { width: hmgServicesVM.vitalSignCurrentPage == index ? 24.w : 8.w, height: 8.h, decoration: BoxDecoration( - color: hmgServicesVM.vitalSignCurrentPage == index - ? AppColors.primaryRedColor - : AppColors.dividerColor, + color: hmgServicesVM.vitalSignCurrentPage == index ? AppColors.primaryRedColor : AppColors.dividerColor, borderRadius: BorderRadius.circular(4.r), ), ), @@ -587,7 +587,8 @@ class _MedicalFilePageState extends State { ? Container( padding: EdgeInsets.all(12.w), width: MediaQuery.of(context).size.width, - decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 12.r, hasShadow: false), + decoration: + RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 12.r, hasShadow: false), child: Column( children: [ Utils.buildSvgWithAssets(icon: AppAssets.home_calendar_icon, width: 32.h, height: 32.h), @@ -624,57 +625,58 @@ class _MedicalFilePageState extends State { itemCount: myAppointmentsVM.patientAppointmentsHistoryList.length, itemBuilder: (context, index) { return AnimationConfiguration.staggeredList( - position: index, - duration: const Duration(milliseconds: 500), - child: SlideAnimation( - horizontalOffset: 100.0, - child: FadeInAnimation( - child: AnimatedContainer( - duration: const Duration(milliseconds: 300), - curve: Curves.easeInOut, - child: MedicalFileAppointmentCard( - patientAppointmentHistoryResponseModel: myAppointmentsVM.patientAppointmentsHistoryList[index], - myAppointmentsViewModel: myAppointmentsViewModel, - onRescheduleTap: () { - openDoctorScheduleCalendar(myAppointmentsVM.patientAppointmentsHistoryList[index]); - }, - onAskDoctorTap: () async { - LoaderBottomSheet.showLoader(loadingText: "Checking doctor availability...".needTranslation); - await myAppointmentsViewModel.isDoctorAvailable( - projectID: myAppointmentsVM.patientAppointmentsHistoryList[index].projectID, - doctorId: myAppointmentsVM.patientAppointmentsHistoryList[index].doctorID, - clinicId: myAppointmentsVM.patientAppointmentsHistoryList[index].clinicID, - onSuccess: (value) async { - if (value) { - await myAppointmentsViewModel.getAskDoctorRequestTypes(onSuccess: (val) { + position: index, + duration: const Duration(milliseconds: 500), + child: SlideAnimation( + horizontalOffset: 100.0, + child: FadeInAnimation( + child: AnimatedContainer( + duration: const Duration(milliseconds: 300), + curve: Curves.easeInOut, + child: MedicalFileAppointmentCard( + patientAppointmentHistoryResponseModel: myAppointmentsVM.patientAppointmentsHistoryList[index], + myAppointmentsViewModel: myAppointmentsViewModel, + onRescheduleTap: () { + openDoctorScheduleCalendar(myAppointmentsVM.patientAppointmentsHistoryList[index]); + }, + onAskDoctorTap: () async { + LoaderBottomSheet.showLoader(loadingText: "Checking doctor availability...".needTranslation); + await myAppointmentsViewModel.isDoctorAvailable( + projectID: myAppointmentsVM.patientAppointmentsHistoryList[index].projectID, + doctorId: myAppointmentsVM.patientAppointmentsHistoryList[index].doctorID, + clinicId: myAppointmentsVM.patientAppointmentsHistoryList[index].clinicID, + onSuccess: (value) async { + if (value) { + await myAppointmentsViewModel.getAskDoctorRequestTypes(onSuccess: (val) { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight( + context, + title: LocaleKeys.askDoctor.tr(context: context), + child: AskDoctorRequestTypeSelect( + askDoctorRequestTypeList: myAppointmentsViewModel.askDoctorRequestTypeList, + myAppointmentsViewModel: myAppointmentsViewModel, + patientAppointmentHistoryResponseModel: + myAppointmentsVM.patientAppointmentsHistoryList[index], + ), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + }); + } else { LoaderBottomSheet.hideLoader(); - showCommonBottomSheetWithoutHeight( - context, - title: LocaleKeys.askDoctor.tr(context: context), - child: AskDoctorRequestTypeSelect( - askDoctorRequestTypeList: myAppointmentsViewModel.askDoctorRequestTypeList, - myAppointmentsViewModel: myAppointmentsViewModel, - patientAppointmentHistoryResponseModel: myAppointmentsVM.patientAppointmentsHistoryList[index], - ), - callBackFunc: () {}, - isFullScreen: false, - isCloseButtonVisible: true, - ); - }); - } else { + print("Doctor is not available"); + } + }, + onError: (_) { LoaderBottomSheet.hideLoader(); - print("Doctor is not available"); - } - }, - onError: (_) { - LoaderBottomSheet.hideLoader(); - }, - ); - }, + }, + ); + }, + ), ), ), - ), - )); + )); }, separatorBuilder: (BuildContext cxt, int index) => SizedBox(width: 12.h), ), @@ -733,116 +735,125 @@ class _MedicalFilePageState extends State { child: Column( children: [ ListView.separated( - itemCount: prescriptionVM.patientPrescriptionOrders.length <= 2 ? prescriptionVM.patientPrescriptionOrders.length : 2, + itemCount: + prescriptionVM.patientPrescriptionOrders.length <= 2 ? prescriptionVM.patientPrescriptionOrders.length : 2, shrinkWrap: true, padding: EdgeInsets.only(left: 0, right: 8.w), physics: NeverScrollableScrollPhysics(), itemBuilder: (context, index) { return AnimationConfiguration.staggeredList( - position: index, - duration: const Duration(milliseconds: 500), - child: SlideAnimation( - verticalOffset: 100.0, - child: FadeInAnimation( - child: Row( - children: [ - Image.network( - prescriptionVM.patientPrescriptionOrders[index].doctorImageURL!, - width: 40.w, - height: 40.h, - fit: BoxFit.cover, - ).circle(100.r), - SizedBox(width: 16.w), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - prescriptionVM.patientPrescriptionOrders[index].doctorName!.toText16(isBold: true), - SizedBox(height: 4.h), - Wrap( - direction: Axis.horizontal, - spacing: 3.w, - runSpacing: 4.w, - children: [ - AppCustomChipWidget(labelText: prescriptionVM.patientPrescriptionOrders[index].clinicDescription!), - AppCustomChipWidget( - icon: AppAssets.doctor_calendar_icon, - labelText: DateUtil.formatDateToDate( - DateUtil.convertStringToDate(prescriptionVM.patientPrescriptionOrders[index].appointmentDate), - false, + position: index, + duration: const Duration(milliseconds: 500), + child: SlideAnimation( + verticalOffset: 100.0, + child: FadeInAnimation( + child: Row( + children: [ + Image.network( + prescriptionVM.patientPrescriptionOrders[index].doctorImageURL!, + width: 40.w, + height: 40.h, + fit: BoxFit.cover, + ).circle(100.r), + SizedBox(width: 16.w), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + prescriptionVM.patientPrescriptionOrders[index].doctorName!.toText16(isBold: true), + SizedBox(height: 4.h), + Wrap( + direction: Axis.horizontal, + spacing: 3.w, + runSpacing: 4.w, + children: [ + AppCustomChipWidget( + labelText: prescriptionVM.patientPrescriptionOrders[index].clinicDescription!), + AppCustomChipWidget( + icon: AppAssets.doctor_calendar_icon, + labelText: DateUtil.formatDateToDate( + DateUtil.convertStringToDate( + prescriptionVM.patientPrescriptionOrders[index].appointmentDate), + false, + ), ), - ), - ], - ), - ], + ], + ), + ], + ), ), - ), - // SizedBox(width: 40.h), - Transform.flip( - flipX: appState.isArabic(), - child: Utils.buildSvgWithAssets( - icon: AppAssets.forward_arrow_icon_small, width: 15.w, height: 15.h, fit: BoxFit.contain, iconColor: AppColors.textColor)), - ], - ).onPress(() { - prescriptionVM.setPrescriptionsDetailsLoading(); - Navigator.of(context).push( - CustomPageRoute( - page: PrescriptionDetailPage(isFromAppointments: false, prescriptionsResponseModel: prescriptionVM.patientPrescriptionOrders[index]), - ), - ); - }), - ), - )); - }, - separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h), - ), - SizedBox(height: 16.h), - const Divider(color: AppColors.dividerColor), - SizedBox(height: 16.h), - Row( - children: [ - Expanded( - child: CustomButton( - text: "All Prescriptions".needTranslation, - onPressed: () { - Navigator.of(context).push( - CustomPageRoute( - page: PrescriptionsListPage(), - ), - ); - }, - backgroundColor: AppColors.secondaryLightRedColor, - borderColor: AppColors.secondaryLightRedColor, - textColor: AppColors.primaryRedColor, - fontSize: 12.f, - fontWeight: FontWeight.w500, - borderRadius: 12.r, - height: 40.h, - icon: AppAssets.requests, - iconColor: AppColors.primaryRedColor, - iconSize: 16.w, - ), + // SizedBox(width: 40.h), + Transform.flip( + flipX: appState.isArabic(), + child: Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon_small, + width: 15.w, + height: 15.h, + fit: BoxFit.contain, + iconColor: AppColors.textColor)), + ], + ).onPress(() { + prescriptionVM.setPrescriptionsDetailsLoading(); + Navigator.of(context).push( + CustomPageRoute( + page: PrescriptionDetailPage( + isFromAppointments: false, + prescriptionsResponseModel: prescriptionVM.patientPrescriptionOrders[index]), + ), + ); + }), + ), + )); + }, + separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h), + ), + SizedBox(height: 16.h), + const Divider(color: AppColors.dividerColor), + SizedBox(height: 16.h), + Row( + children: [ + Expanded( + child: CustomButton( + text: "All Prescriptions".needTranslation, + onPressed: () { + Navigator.of(context).push( + CustomPageRoute( + page: PrescriptionsListPage(), + ), + ); + }, + backgroundColor: AppColors.secondaryLightRedColor, + borderColor: AppColors.secondaryLightRedColor, + textColor: AppColors.primaryRedColor, + fontSize: 12.f, + fontWeight: FontWeight.w500, + borderRadius: 12.r, + height: 40.h, + icon: AppAssets.requests, + iconColor: AppColors.primaryRedColor, + iconSize: 16.w, ), - SizedBox(width: 6.w), - Expanded( - child: CustomButton( - text: "All Medications".needTranslation, - onPressed: () {}, - backgroundColor: AppColors.secondaryLightRedColor, - borderColor: AppColors.secondaryLightRedColor, - textColor: AppColors.primaryRedColor, - fontSize: 12.f, - fontWeight: FontWeight.w500, - borderRadius: 12.h, - height: 40.h, - icon: AppAssets.all_medications_icon, - iconColor: AppColors.primaryRedColor, - iconSize: 16.h, - ), + ), + SizedBox(width: 6.w), + Expanded( + child: CustomButton( + text: "All Medications".needTranslation, + onPressed: () {}, + backgroundColor: AppColors.secondaryLightRedColor, + borderColor: AppColors.secondaryLightRedColor, + textColor: AppColors.primaryRedColor, + fontSize: 12.f, + fontWeight: FontWeight.w500, + borderRadius: 12.h, + height: 40.h, + icon: AppAssets.all_medications_icon, + iconColor: AppColors.primaryRedColor, + iconSize: 16.h, ), - ], - ), - ], + ), + ], + ), + ], ), ), ).paddingSymmetrical(0.w, 0.h) @@ -896,7 +907,10 @@ class _MedicalFilePageState extends State { fit: BoxFit.cover, ).circle(100).toShimmer2(isShow: true, radius: 50.r), SizedBox(height: 8.h), - ("Dr. John Smith Smith Smith").toString().toText12(fontWeight: FontWeight.w500, isCenter: true, maxLine: 2).toShimmer2(isShow: true), + ("Dr. John Smith Smith Smith") + .toString() + .toText12(fontWeight: FontWeight.w500, isCenter: true, maxLine: 2) + .toShimmer2(isShow: true), ], ) : myAppointmentsVM.patientMyDoctorsList.isEmpty @@ -923,58 +937,58 @@ class _MedicalFilePageState extends State { shrinkWrap: true, itemBuilder: (context, index) { return AnimationConfiguration.staggeredList( - position: index, - duration: const Duration(milliseconds: 1000), - child: SlideAnimation( - horizontalOffset: 100.0, - child: FadeInAnimation( - child: SizedBox( - // width: 80.w, - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Image.network( - myAppointmentsVM.patientMyDoctorsList[index].doctorImageURL!, - width: 64.w, - height: 64.h, - fit: BoxFit.cover, - ).circle(100).toShimmer2(isShow: false, radius: 50.r), - SizedBox(height: 8.h), - Expanded( - child: (myAppointmentsVM.patientMyDoctorsList[index].doctorName) - .toString() - .toText12(fontWeight: FontWeight.w500, isCenter: true, maxLine: 2) - .toShimmer2(isShow: false), - ), - ], - ), - ).onPress(() async { - bookAppointmentsViewModel.setSelectedDoctor(DoctorsListResponseModel( - clinicID: myAppointmentsVM.patientMyDoctorsList[index].clinicID, - projectID: myAppointmentsVM.patientMyDoctorsList[index].projectID, - doctorID: myAppointmentsVM.patientMyDoctorsList[index].doctorID, - )); - LoaderBottomSheet.showLoader(); - await bookAppointmentsViewModel.getDoctorProfile(onSuccess: (dynamic respData) { - LoaderBottomSheet.hideLoader(); - Navigator.of(context).push( - CustomPageRoute( - page: DoctorProfilePage(), - ), - ); - }, onError: (err) { - LoaderBottomSheet.hideLoader(); - showCommonBottomSheetWithoutHeight( - context, - child: Utils.getErrorWidget(loadingText: err), - callBackFunc: () {}, - isFullScreen: false, - isCloseButtonVisible: true, - ); - }); - }), - ), - )); + position: index, + duration: const Duration(milliseconds: 1000), + child: SlideAnimation( + horizontalOffset: 100.0, + child: FadeInAnimation( + child: SizedBox( + // width: 80.w, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Image.network( + myAppointmentsVM.patientMyDoctorsList[index].doctorImageURL!, + width: 64.w, + height: 64.h, + fit: BoxFit.cover, + ).circle(100).toShimmer2(isShow: false, radius: 50.r), + SizedBox(height: 8.h), + Expanded( + child: (myAppointmentsVM.patientMyDoctorsList[index].doctorName) + .toString() + .toText12(fontWeight: FontWeight.w500, isCenter: true, maxLine: 2) + .toShimmer2(isShow: false), + ), + ], + ), + ).onPress(() async { + bookAppointmentsViewModel.setSelectedDoctor(DoctorsListResponseModel( + clinicID: myAppointmentsVM.patientMyDoctorsList[index].clinicID, + projectID: myAppointmentsVM.patientMyDoctorsList[index].projectID, + doctorID: myAppointmentsVM.patientMyDoctorsList[index].doctorID, + )); + LoaderBottomSheet.showLoader(); + await bookAppointmentsViewModel.getDoctorProfile(onSuccess: (dynamic respData) { + LoaderBottomSheet.hideLoader(); + Navigator.of(context).push( + CustomPageRoute( + page: DoctorProfilePage(), + ), + ); + }, onError: (err) { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight( + context, + child: Utils.getErrorWidget(loadingText: err), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + }); + }), + ), + )); }, separatorBuilder: (BuildContext cxt, int index) => SizedBox(width: 8.h), ), @@ -1083,9 +1097,14 @@ class _MedicalFilePageState extends State { text: "${LocaleKeys.updateInsurance.tr(context: context)} ${LocaleKeys.updateInsuranceSubtitle.tr(context: context)}", onPressed: () { insuranceViewModel.setIsInsuranceUpdateDetailsLoading(true); - insuranceViewModel.getPatientInsuranceDetailsForUpdate( - appState.getAuthenticatedUser()!.patientId.toString(), appState.getAuthenticatedUser()!.patientIdentificationNo.toString()); - showCommonBottomSheetWithoutHeight(context, child: PatientInsuranceCardUpdateCard(), callBackFunc: () {}, title: "", isCloseButtonVisible: false, isFullScreen: false); + insuranceViewModel.getPatientInsuranceDetailsForUpdate(appState.getAuthenticatedUser()!.patientId.toString(), + appState.getAuthenticatedUser()!.patientIdentificationNo.toString()); + showCommonBottomSheetWithoutHeight(context, + child: PatientInsuranceCardUpdateCard(), + callBackFunc: () {}, + title: "", + isCloseButtonVisible: false, + isFullScreen: false); }, backgroundColor: AppColors.bgGreenColor.withOpacity(0.20), borderColor: AppColors.bgGreenColor.withOpacity(0.0), @@ -1282,7 +1301,7 @@ class _MedicalFilePageState extends State { svgIcon: AppAssets.blood_sugar_icon, isLargeText: true, iconSize: 36.w, - ).onPress(() {}), + ).onPress(() => context.navigateWithName(AppRoutes.healthTrackerDetailPage, arguments: HealthTrackerTypeEnum.bloodSugar)), MedicalFileCard( label: "Blood Pressure".needTranslation, textColor: AppColors.blackColor, @@ -1290,7 +1309,7 @@ class _MedicalFilePageState extends State { svgIcon: AppAssets.lab_result_icon, isLargeText: true, iconSize: 36.w, - ).onPress(() {}), + ).onPress(() => context.navigateWithName(AppRoutes.healthTrackerDetailPage, arguments: HealthTrackerTypeEnum.bloodPressure)), MedicalFileCard( label: "Weight Tracker".needTranslation, textColor: AppColors.blackColor, @@ -1298,7 +1317,7 @@ class _MedicalFilePageState extends State { svgIcon: AppAssets.weight_tracker_icon, isLargeText: true, iconSize: 36.w, - ).onPress(() {}), + ).onPress(() => context.navigateWithName(AppRoutes.healthTrackerDetailPage, arguments: HealthTrackerTypeEnum.weightTracker)), ], ).paddingSymmetrical(0.w, 0.0), SizedBox(height: 16.h), @@ -1547,7 +1566,6 @@ class _MedicalFilePageState extends State { ], ), SizedBox(height: 14.h), - Container( padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 6.h), decoration: BoxDecoration( @@ -1585,7 +1603,6 @@ class _MedicalFilePageState extends State { ), ), SizedBox(height: 8.h), - Align( alignment: AlignmentDirectional.centerEnd, child: Utils.buildSvgWithAssets( @@ -1603,6 +1620,3 @@ class _MedicalFilePageState extends State { ); } } - - -