From 877f73b3842ae7c50a7d9afa3463a0e476fe31ce Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Thu, 23 Apr 2026 15:45:46 +0300 Subject: [PATCH] Notification permission added on app launch, appointment invoice download option added, HMG Wallet added in medical file page --- lib/core/utils/push_notification_handler.dart | 6 +- .../my_appointments/my_appointments_repo.dart | 41 ++++++++++ .../my_appointments_view_model.dart | 74 +++++++++++++++++++ .../appointment_details_page.dart | 26 +++++++ .../medical_file/medical_file_page.dart | 12 +++ 5 files changed, 158 insertions(+), 1 deletion(-) diff --git a/lib/core/utils/push_notification_handler.dart b/lib/core/utils/push_notification_handler.dart index 23cb4f51..48cc69ee 100644 --- a/lib/core/utils/push_notification_handler.dart +++ b/lib/core/utils/push_notification_handler.dart @@ -364,6 +364,8 @@ class PushNotificationHandler { init(BuildContext context) async { this.context = context; + await requestPermissions(); + if (Platform.isIOS) { voIPKit.getVoIPToken().then((value) { print("🎈 APNS VOIP KIT TOKEN: $value"); @@ -452,7 +454,9 @@ class PushNotificationHandler { sound: true, ); if (permission.authorizationStatus == AuthorizationStatus.denied) return; - } else {} + } else { + final permission = await FirebaseMessaging.instance.requestPermission(); + } try { FirebaseMessaging.instance.getInitialMessage().then((RemoteMessage? message) async { diff --git a/lib/features/my_appointments/my_appointments_repo.dart b/lib/features/my_appointments/my_appointments_repo.dart index eeef41e4..553491e1 100644 --- a/lib/features/my_appointments/my_appointments_repo.dart +++ b/lib/features/my_appointments/my_appointments_repo.dart @@ -16,6 +16,7 @@ import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/ import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_share_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_queue_details_response_model.dart'; +import 'package:hmg_patient_app_new/features/my_invoices/models/get_invoices_list_response_model.dart'; import 'package:hmg_patient_app_new/services/logger_service.dart'; import 'models/req_model/appointment_rate_req_model.dart'; @@ -89,6 +90,8 @@ abstract class MyAppointmentsRepo { required int clinicID, required int appointmentNo, }); + + Future>>> getAppointmentInvoice(num appointmentNum); } class MyAppointmentsRepoImp implements MyAppointmentsRepo { @@ -1142,4 +1145,42 @@ class MyAppointmentsRepoImp implements MyAppointmentsRepo { return Left(UnknownFailure(e.toString())); } } + + @override + Future>>> getAppointmentInvoice(num appointmentNum) async { + Map mapDevice = {"AppointmentNo": appointmentNum}; + + try { + GenericApiModel>? apiResponse; + Failure? failure; + await apiClient.post( + GET_ALL_APPOINTMENTS_FOR_DENTAL_CLINIC, + body: mapDevice, + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + try { + final list = response['List_AllInvoices']; + + final invoicesList = list.map((item) => GetInvoicesListResponseModel.fromJson(item as Map)).toList().cast(); + + apiResponse = GenericApiModel>( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: null, + data: invoicesList, + ); + } catch (e) { + failure = DataParsingFailure(e.toString()); + } + }, + ); + 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/features/my_appointments/my_appointments_view_model.dart b/lib/features/my_appointments/my_appointments_view_model.dart index cb52a19d..2fda0505 100644 --- a/lib/features/my_appointments/my_appointments_view_model.dart +++ b/lib/features/my_appointments/my_appointments_view_model.dart @@ -2,6 +2,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:get_it/get_it.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/utils/calender_utils_new.dart'; import 'package:hmg_patient_app_new/core/utils/date_util.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; @@ -17,6 +18,8 @@ import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/ import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_queue_details_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_repo.dart'; import 'package:hmg_patient_app_new/features/my_appointments/utils/appointment_type.dart'; +import 'package:hmg_patient_app_new/features/my_invoices/models/get_invoices_list_response_model.dart'; +import 'package:hmg_patient_app_new/features/my_invoices/my_invoices_repo.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/insurance/insurance_home_page.dart'; import 'package:hmg_patient_app_new/services/error_handler_service.dart'; @@ -25,6 +28,7 @@ import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; 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:open_filex/open_filex.dart'; class MyAppointmentsViewModel extends ChangeNotifier { int selectedTabIndex = 0; @@ -1519,4 +1523,74 @@ class MyAppointmentsViewModel extends ChangeNotifier { ); } } + + Future getAppointmentInvoice({required num appointmentNum, Function(dynamic)? onSuccess, Function(String)? onError}) async { + String? downloadInvoicePDFBase64 = ""; + final result = await myAppointmentsRepo.getAppointmentInvoice(appointmentNum); + + result.fold( + (failure) async { + if (onError != null) { + onError(failure.message ?? "Unknown error"); + } + }, + (apiResponse) async { + if (apiResponse.messageStatus == 2) { + if (onError != null) { + onError(apiResponse.errorMessage ?? "Unknown error"); + } + // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); + } else if (apiResponse.messageStatus == 1) { + if (apiResponse.data!.isNotEmpty) { + GetInvoicesListResponseModel getInvoicesListResponseModel = apiResponse.data!.first; + final result = await getIt + .get() + .downloadInvoice(setupId: getInvoicesListResponseModel.setupId!, invoiceNo: getInvoicesListResponseModel.invoiceNo!, projectID: getInvoicesListResponseModel.projectId!); + + result.fold( + (failure) async { + if (onError != null) { + onError(failure.message); + } + }, + (apiResponse) async { + if (apiResponse.messageStatus == 2) { + // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); + } else if (apiResponse.messageStatus == 1) { + if (apiResponse.data != null && apiResponse.data!.isNotEmpty) { + downloadInvoicePDFBase64 = apiResponse.data!; + String path = await Utils.createFileFromString(downloadInvoicePDFBase64!, "pdf"); + try { + OpenFilex.open(path); + } catch (ex) { + showCommonBottomSheetWithoutHeight( + GetIt.instance().navigatorKey.currentContext!, + child: Utils.getErrorWidget(loadingText: "Cannot open file"), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + } + } else { + downloadInvoicePDFBase64 = ""; + } + if (onSuccess != null) { + onSuccess(apiResponse); + } + } + }, + ); + } else { + showCommonBottomSheetWithoutHeight( + GetIt.instance().navigatorKey.currentContext!, + child: Utils.getErrorWidget(loadingText: "Cannot open invoice"), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + } + } + }, + ); + } } diff --git a/lib/presentation/appointments/appointment_details_page.dart b/lib/presentation/appointments/appointment_details_page.dart index 87ca5e93..c7da6d47 100644 --- a/lib/presentation/appointments/appointment_details_page.dart +++ b/lib/presentation/appointments/appointment_details_page.dart @@ -1020,6 +1020,32 @@ class _AppointmentDetailsPageState extends State { ), ); }), + MedicalFileCard( + label: LocaleKeys.viewInvoiceDetails.tr(context: context), + textColor: AppColors.blackColor, + backgroundColor: AppColors.whiteColor, + svgIcon: AppAssets.invoices_list_icon, + isLargeText: true, + iconSize: 36.w, + ).onPress(() { + LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingInvoiceDetails.tr(context: context)); + myAppointmentsViewModel.getAppointmentInvoice( + appointmentNum: widget.patientAppointmentHistoryResponseModel.appointmentNo, + onSuccess: (val) { + LoaderBottomSheet.hideLoader(); + }, + onError: (err) { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight( + context, + child: Utils.getErrorWidget(loadingText: err), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + }, + ); + }), myAppointmentsVM.isAppointmentRatedResponseLoading ? MedicalFileCard( label: "Medical File", diff --git a/lib/presentation/medical_file/medical_file_page.dart b/lib/presentation/medical_file/medical_file_page.dart index 86807150..63b23ea3 100644 --- a/lib/presentation/medical_file/medical_file_page.dart +++ b/lib/presentation/medical_file/medical_file_page.dart @@ -46,6 +46,8 @@ import 'package:hmg_patient_app_new/presentation/ask_doctor/ask_doctor_page.dart import 'package:hmg_patient_app_new/presentation/book_appointment/book_appointment_page.dart'; import 'package:hmg_patient_app_new/presentation/book_appointment/doctor_profile_page.dart'; import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/appointment_calendar.dart'; +import 'package:hmg_patient_app_new/presentation/habib_wallet/habib_wallet_page.dart'; +import 'package:hmg_patient_app_new/presentation/habib_wallet/recharge_wallet_page.dart'; import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart'; import 'package:hmg_patient_app_new/presentation/insurance/insurance_approvals_page.dart'; import 'package:hmg_patient_app_new/presentation/insurance/insurance_home_page.dart'; @@ -1233,6 +1235,16 @@ class _MedicalFilePageState extends State { ), ); }), + MedicalFileCard( + label: LocaleKeys.habibWallet.tr(context: context), + textColor: AppColors.blackColor, + backgroundColor: AppColors.whiteColor, + svgIcon: AppAssets.wallet, + isLargeText: true, + iconSize: 36.w, + ).onPress(() { + Navigator.of(context).push(CustomPageRoute(page: HabibWalletPage())); + }), ], ).paddingSymmetrical(0.w, 0.0), SizedBox(height: 16.h),