diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro index e4e65227..68b506a1 100644 --- a/android/app/proguard-rules.pro +++ b/android/app/proguard-rules.pro @@ -3,7 +3,7 @@ -keep class com.twilio.common.** { *; } -keepattributes InnerClasses --keep class com.ejada.** { *; } +#-keep class com.ejada.** { *; } -keep class org.webrtc.** { *; } -keep class com.builttoroam.devicecalendar.** { *; } diff --git a/android/gradle.properties b/android/gradle.properties index 023d116a..0e253cc0 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,5 +1,6 @@ #org.gradle.jvmargs=-xmx4608m android.enableR8=true +android.enableR8.fullMode=true android.enableJetifier=true android.useDeprecatedNdk=true org.gradle.jvmargs=-Xmx4096m -XX:MaxMetaspaceSize=1024m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 5c20ab0f..f0e3c730 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -2067,5 +2067,8 @@ "importantNotice": "تنبيه هام", "appDecommissionedText": "تم إيقاف هذا الإصدار من تطبيق الحبيب الطبي.\nللاستمرار في الاستفادة من الخدمات الصحية والسجلات الطبية، يرجى تحميل التطبيق الجديد.", "appDecommissionedSubText": "نعتذر بشدة عن الإزعاج الناتج عن هذا الانتقال.", - "downloadApp": "حمل التطبيق" + "downloadApp": "حمل التطبيق", + "unread": "غير مقروء", + "read": "مقروءة", + "pendingMedicalReportRequest": "لديك بالفعل طلب معلّق للحصول على تقرير طبي خاص بهذا الموعد. يرجى الانتظار حتى اكتمال الطلب قبل تقديم طلب جديد." } diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index e968d84c..06a2742c 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -2057,7 +2057,10 @@ "importantNotice": "Important Notice", "appDecommissionedText": "This version of our healthcare application has been officially discontinued. To ensure uninterrupted access to your clinical records, we are transitioning all patients back to our main platform.", "appDecommissionedSubText": "We sincerely apologize for the inconvenience of this transition.", - "downloadApp": "Download App" + "downloadApp": "Download App", + "unread": "Unread", + "read": "Read", + "pendingMedicalReportRequest": "You already have a pending medical report request for this appointment. Please wait for the request to be completed before submitting a new one." } diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index 07198caa..1bccb154 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -210,7 +210,7 @@ class ApiClientImp implements ApiClient { } // body['TokenID'] = "@dm!n"; - // body['PatientID'] = 7000792; + // body['PatientID'] = 1009156; // body['PatientID'] = 53320; // body['PatientTypeID'] = 1; // body['PatientOutSA'] = 0; diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index 85de77e5..3cac224b 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -324,6 +324,12 @@ class ApiConsts { static final String appIpAddress = "10.20.10.20"; static final String appGeneralId = "Cs2020@2016\$2958"; static final String sessionID = 'TMRhVmkGhOsvamErw'; + + // Notification Center GUIDs - Configure these values as per your notification center setup + static final String notificationCenterAppGUID = "SzFwWjI0TjhmSjZreDVsNmc3SDRSdWlxUG1h"; + static final String notificationServiceGUID_Login = "D8BD5C76-4B50-4122-81D0-C3AA25DB08A2"; + static final String notificationServiceGUID_Registration = "690D3595-A1E1-489A-B9AB-6270E83AD6ED"; + static final String notificationServiceGUID_FamilyFile = "318285E4-6221-4A66-8FAF-2265D2B4B24C"; } // PACKAGES and OFFERS diff --git a/lib/core/utils/request_utils.dart b/lib/core/utils/request_utils.dart index 62399abd..b7691eb5 100644 --- a/lib/core/utils/request_utils.dart +++ b/lib/core/utils/request_utils.dart @@ -75,6 +75,12 @@ class RequestUtils { } request.isRegister = false; } + + request.notificationCenterAppGUID = ApiConsts.notificationCenterAppGUID; + request.notificationCenterAppServiceGUID = isForRegister + ? ApiConsts.notificationServiceGUID_Registration + : ApiConsts.notificationServiceGUID_Login; + return request; } @@ -148,6 +154,12 @@ class RequestUtils { } request.deviceTypeID = request.searchType; + + request.notificationCenterAppGUID = ApiConsts.notificationCenterAppGUID; + request.notificationCenterAppServiceGUID = (registeredData != null && registeredData.isRegister == true) + ? ApiConsts.notificationServiceGUID_Registration + : ApiConsts.notificationServiceGUID_Login; + return request; } @@ -220,6 +232,13 @@ class RequestUtils { request.familyRegionID = zipCode == CountryEnum.saudiArabia.countryCode ? 1 : 2; } + request.notificationCenterAppGUID = ApiConsts.notificationCenterAppGUID; + request.notificationCenterAppServiceGUID = isFormFamilyFile + ? ApiConsts.notificationServiceGUID_FamilyFile + : isForRegister + ? ApiConsts.notificationServiceGUID_Registration + : ApiConsts.notificationServiceGUID_Login; + return request; } diff --git a/lib/features/authentication/authentication_repo.dart b/lib/features/authentication/authentication_repo.dart index 291e4a9b..1c95d99a 100644 --- a/lib/features/authentication/authentication_repo.dart +++ b/lib/features/authentication/authentication_repo.dart @@ -222,6 +222,8 @@ class AuthenticationRepoImp implements AuthenticationRepo { if (isRegister) { newRequest["activationCode"] = activationCode ?? "0000"; newRequest["isSilentLogin"] = activationCode == null; + newRequest.remove("NotificationCenterAppGUID"); + newRequest.remove("NotificationCenterAppSeviceGUID"); } else { newRequest.activationCode = activationCode ?? "0000"; newRequest.isSilentLogin = activationCode == null; diff --git a/lib/features/authentication/authentication_view_model.dart b/lib/features/authentication/authentication_view_model.dart index a00100c6..e5324525 100644 --- a/lib/features/authentication/authentication_view_model.dart +++ b/lib/features/authentication/authentication_view_model.dart @@ -1519,7 +1519,9 @@ class AuthenticationViewModel extends ChangeNotifier { LoaderBottomSheet.hideLoader(); if (apiResponse.data["MessageStatus"] == 1) { LoaderBottomSheet.showLoader(loadingText: "Your medical file has been created successfully. \nPlease proceed to login."); - //TODO: Here We Need to Show a Dialog Of Something in the case of Success. + // Reset registration payload and clear healthId so subsequent logins hit the login endpoint + _appState.getUserRegistrationPayload.healthId = null; + _appState.setUserRegistrationPayload = RegistrationDataModelPayload(); await clearDefaultInputValues(); // This will Clear All Default Values Of User. Future.delayed(Duration(seconds: 1), () { LoaderBottomSheet.hideLoader(); diff --git a/lib/features/authentication/models/request_models/send_activation_request_model.dart b/lib/features/authentication/models/request_models/send_activation_request_model.dart index 6e2ddb93..840227ea 100644 --- a/lib/features/authentication/models/request_models/send_activation_request_model.dart +++ b/lib/features/authentication/models/request_models/send_activation_request_model.dart @@ -31,6 +31,8 @@ class SendActivationRequest { int? familyRegionID; bool? isPatientExcluded; String? turnstileToken; + String? notificationCenterAppGUID; + String? notificationCenterAppServiceGUID; SendActivationRequest( {this.patientMobileNumber, @@ -64,7 +66,10 @@ class SendActivationRequest { this.status, this.familyRegionID, this.isPatientExcluded, - this.turnstileToken}); + this.turnstileToken, + this.notificationCenterAppGUID, + this.notificationCenterAppServiceGUID +}); SendActivationRequest.fromJson(Map json) { patientMobileNumber = json['PatientMobileNumber']; @@ -99,6 +104,8 @@ class SendActivationRequest { familyRegionID = json['FamilyRegionID']; isPatientExcluded = json['IsPatientExcluded']; turnstileToken = json['TurnstileToken']; + notificationCenterAppGUID = json['NotificationCenterAppGUID']; + notificationCenterAppServiceGUID = json['NotificationCenterAppSeviceGUID']; } Map toJson() { @@ -141,6 +148,8 @@ class SendActivationRequest { if (turnstileToken != null) { data['TurnstileToken'] = turnstileToken; } + data['NotificationCenterAppGUID'] = notificationCenterAppGUID; + data['NotificationCenterAppSeviceGUID'] = notificationCenterAppServiceGUID; return data; } } diff --git a/lib/features/book_appointments/book_appointments_repo.dart b/lib/features/book_appointments/book_appointments_repo.dart index a705d84a..caf97cb8 100644 --- a/lib/features/book_appointments/book_appointments_repo.dart +++ b/lib/features/book_appointments/book_appointments_repo.dart @@ -37,7 +37,7 @@ abstract class BookAppointmentsRepo { Future>> getDoctorFreeSlots(int clinicID, int projectID, int doctorId, bool isBookingForLiveCare, {bool continueDentalPlan = false, Function(dynamic)? onSuccess, Function(String)? onError}); - Future>> cancelAppointment({required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel}); + Future>> cancelAppointment({required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, bool isReschedule = false}); Future>> insertSpecificAppointment( {required int docID, @@ -483,12 +483,12 @@ class BookAppointmentsRepoImp implements BookAppointmentsRepo { } @override - Future> cancelAppointment({required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel}) async { + Future> cancelAppointment({required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, bool isReschedule = false}) async { Map requestBody = { "AppointmentID": patientAppointmentHistoryResponseModel.appointmentNo, "ClinicID": patientAppointmentHistoryResponseModel.clinicID, "ProjectID": patientAppointmentHistoryResponseModel.projectID, - "CancelToReschadual": false, + "CancelToReschadual": isReschedule, "EndTime": patientAppointmentHistoryResponseModel.endTime, "StartTime": patientAppointmentHistoryResponseModel.startTime, "DoctorID": patientAppointmentHistoryResponseModel.doctorID, diff --git a/lib/features/book_appointments/book_appointments_view_model.dart b/lib/features/book_appointments/book_appointments_view_model.dart index a4530eee..5865a829 100644 --- a/lib/features/book_appointments/book_appointments_view_model.dart +++ b/lib/features/book_appointments/book_appointments_view_model.dart @@ -948,8 +948,8 @@ class BookAppointmentsViewModel extends ChangeNotifier { ); } - Future cancelAppointment({required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, Function(dynamic)? onSuccess, Function(String)? onError}) async { - final result = await bookAppointmentsRepo.cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel); + Future cancelAppointment({required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, bool isReschedule = false, Function(dynamic)? onSuccess, Function(String)? onError}) async { + final result = await bookAppointmentsRepo.cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel, isReschedule: isReschedule); result.fold( (failure) async => await errorHandlerService.handleError(failure: failure), @@ -1011,7 +1011,7 @@ class BookAppointmentsViewModel extends ChangeNotifier { appointmentDate: apiResponse.data["SameClinicApptList"][0]['AppointmentDate'], ); - await cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel).then((val) async { + await cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel, isReschedule: true).then((val) async { // LoaderBottomSheet.hideLoader(); Future.delayed(Duration(milliseconds: 50)).then((value) async {}); // LoaderBottomSheet.showLoader(loadingText: LocaleKeys.bookingYourAppointment.tr()); @@ -1069,7 +1069,7 @@ class BookAppointmentsViewModel extends ChangeNotifier { // loadingText: LocaleKeys.reschedulingAppo.tr(context: navigationService.navigatorKey.currentContext!), loadingText: LocaleKeys.loadingText.tr(context: navigationService.navigatorKey.currentContext!), ); - await cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel).then((val) async { + await cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel, isReschedule: true).then((val) async { LoaderBottomSheet.hideLoader(); Future.delayed(Duration(milliseconds: 50)).then((value) async {}); LoaderBottomSheet.showLoader(loadingText: LocaleKeys.bookingYourAppointment.tr()); @@ -1174,7 +1174,7 @@ class BookAppointmentsViewModel extends ChangeNotifier { isCloseButtonVisible: false, isDismissible: false, isFullScreen: false); - await cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel).then((val) async { + await cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel, isReschedule: true).then((val) async { navigationService.pop(); Future.delayed(Duration(milliseconds: 50)).then((value) async {}); LoaderBottomSheet.showLoader(loadingText: LocaleKeys.bookingYourAppointment.tr()); diff --git a/lib/features/medical_file/medical_file_view_model.dart b/lib/features/medical_file/medical_file_view_model.dart index 29f653ec..f3a4e2e8 100644 --- a/lib/features/medical_file/medical_file_view_model.dart +++ b/lib/features/medical_file/medical_file_view_model.dart @@ -864,4 +864,17 @@ class MedicalFileViewModel extends ChangeNotifier { print("❌ Error updating family member profile image in cache: $e"); } } + + bool checkExistingMedicalReportStatus(PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel) { + bool hasExistingRequest = false; + + for (var report in patientMedicalReportRequestedList) { + if (report.clinicID == patientAppointmentHistoryResponseModel.clinicID && report.doctorID == patientAppointmentHistoryResponseModel.doctorID) { + hasExistingRequest = true; + break; + } + } + + return hasExistingRequest; + } } diff --git a/lib/features/my_appointments/my_appointments_repo.dart b/lib/features/my_appointments/my_appointments_repo.dart index 87fb2ec2..ef3cd283 100644 --- a/lib/features/my_appointments/my_appointments_repo.dart +++ b/lib/features/my_appointments/my_appointments_repo.dart @@ -44,7 +44,7 @@ abstract class MyAppointmentsRepo { Future>> generateAppointmentQR({required int clinicID, required int projectID, required String appointmentNo, required int isFollowUp}); - Future>> cancelAppointment({required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel}); + Future>> cancelAppointment({required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, bool isReschedule = false}); Future>> confirmAppointment({required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel}); @@ -341,12 +341,12 @@ class MyAppointmentsRepoImp implements MyAppointmentsRepo { } @override - Future> cancelAppointment({required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel}) async { + Future> cancelAppointment({required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, bool isReschedule = false}) async { Map requestBody = { "AppointmentID": patientAppointmentHistoryResponseModel.appointmentNo, "ClinicID": patientAppointmentHistoryResponseModel.clinicID, "ProjectID": patientAppointmentHistoryResponseModel.projectID, - "CancelToReschadual": false, + "CancelToReschadual": isReschedule, "EndTime": patientAppointmentHistoryResponseModel.endTime, "StartTime": patientAppointmentHistoryResponseModel.startTime, "DoctorID": patientAppointmentHistoryResponseModel.doctorID, diff --git a/lib/features/my_appointments/my_appointments_view_model.dart b/lib/features/my_appointments/my_appointments_view_model.dart index b2b990db..f040fd82 100644 --- a/lib/features/my_appointments/my_appointments_view_model.dart +++ b/lib/features/my_appointments/my_appointments_view_model.dart @@ -639,8 +639,8 @@ class MyAppointmentsViewModel extends ChangeNotifier { ); } - Future cancelAppointment({required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, Function(dynamic)? onSuccess, Function(String)? onError}) async { - final result = await myAppointmentsRepo.cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel); + Future cancelAppointment({required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, bool isReschedule = false, Function(dynamic)? onSuccess, Function(String)? onError}) async { + final result = await myAppointmentsRepo.cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel, isReschedule: isReschedule); result.fold( // (failure) async => await errorHandlerService.handleError(failure: failure), diff --git a/lib/features/notifications/notifications_view_model.dart b/lib/features/notifications/notifications_view_model.dart index 85049ec9..0f3cc160 100644 --- a/lib/features/notifications/notifications_view_model.dart +++ b/lib/features/notifications/notifications_view_model.dart @@ -13,11 +13,16 @@ class NotificationsViewModel extends ChangeNotifier { ErrorHandlerService errorHandlerService; List notificationsList = []; + List readdNotificationsList = []; + List unreadNotificationsList = []; + List allNotificationsList = []; int currentPage = 0; int pagingSize = 50; int notificationStatusID = 2; // Default to status 2 (e.g., unread) + int selectedNotificationsTabIndex = 0; + NotificationsViewModel({ required this.notificationsRepo, required this.errorHandlerService, @@ -35,6 +40,18 @@ class NotificationsViewModel extends ChangeNotifier { notifyListeners(); } + void onNotificationTabChange(int index) { + selectedNotificationsTabIndex = index; + if (index == 0) { + notificationsList = allNotificationsList; + } else if (index == 1) { + notificationsList = unreadNotificationsList; + } else if (index == 2) { + notificationsList = readdNotificationsList; + } + notifyListeners(); + } + setNotificationStatusID(int statusID) { notificationStatusID = statusID; notificationsList.clear(); @@ -49,6 +66,9 @@ class NotificationsViewModel extends ChangeNotifier { }) async { isNotificationsLoading = true; unreadNotificationsCount = 0; + + notificationsList.clear(); + notifyListeners(); final result = await notificationsRepo.getAllNotifications( @@ -80,17 +100,37 @@ class NotificationsViewModel extends ChangeNotifier { hasMoreNotifications = false; } - notificationsList.addAll(newNotifications); - for (var notification in notificationsList) { - if (notification.isRead == false) { - unreadNotificationsCount++; + try { + notificationsList.addAll(newNotifications); + + // allNotificationsList.clear(); + // readdNotificationsList.clear(); + // unreadNotificationsList.clear(); + + // for (var notification in notificationsList) { + // if (notification.isRead == false) { + // unreadNotificationsCount++; + // unreadNotificationsList.add(notification); + // } else { + // readdNotificationsList.add(notification); + // } + // } + + // Filter out the items directly without a loop + unreadNotificationsList = notificationsList.where((n) => n.isRead == false).toList(); + readdNotificationsList = notificationsList.where((n) => n.isRead == true).toList(); + + // Calculate count based on the new list length + unreadNotificationsCount = unreadNotificationsList.length; + + currentPage++; + allNotificationsList = notificationsList; + notifyListeners(); + if (onSuccess != null) { + onSuccess(apiResponse); } - } - currentPage++; - - notifyListeners(); - if (onSuccess != null) { - onSuccess(apiResponse); + } catch (ex) { + print(ex.toString()); } } }, diff --git a/lib/features/occasion_theme/occasion_config_model.dart b/lib/features/occasion_theme/occasion_config_model.dart index 03bf9392..bf9d713f 100644 --- a/lib/features/occasion_theme/occasion_config_model.dart +++ b/lib/features/occasion_theme/occasion_config_model.dart @@ -68,6 +68,11 @@ class OccasionConfigModel { enabled: (json['enabled'] as bool?) ?? false, startDate: _parseDate(json['start_date']), endDate: _parseDate(json['end_date']), + + // enabled: true, + // startDate: _parseDate("2026-09-30T00:00:00Z"), + // endDate: _parseDate("2026-10-07T00:00:00Z"), + primaryColorHex: json['primary_color'] as String?, backgroundOpacityImage: json['background_opacity_image'] as String?, backgroundImageOpacity: (json['background_image_opacity'] as num?)?.toDouble() ?? 1.0, diff --git a/lib/features/payfort/payfort_view_model.dart b/lib/features/payfort/payfort_view_model.dart index c4f96857..7b6b8b7d 100644 --- a/lib/features/payfort/payfort_view_model.dart +++ b/lib/features/payfort/payfort_view_model.dart @@ -578,4 +578,27 @@ class PayfortViewModel extends ChangeNotifier { ); } + Future addApplePayPayfortResponse(dynamic paymentMap) async { + PayfortResponseInsertModel payfortResponseInsertModel = PayfortResponseInsertModel(); + + payfortResponseInsertModel.fortId = paymentMap['fort_id'] ?? ""; + payfortResponseInsertModel.commandType = paymentMap['command'] ?? ""; + payfortResponseInsertModel.amount = num.tryParse(paymentMap['amount'] ?? "0") ?? 0; + payfortResponseInsertModel.sadadOLP = ""; + payfortResponseInsertModel.paymentOption = paymentMap['payment_option'] ?? ""; + payfortResponseInsertModel.customerIP = paymentMap['customer_ip'] ?? ""; + payfortResponseInsertModel.eCI = paymentMap['eci'] ?? ""; + payfortResponseInsertModel.responseMessage = paymentMap['response_message'] ?? ""; + payfortResponseInsertModel.cardNumber = paymentMap['card_number'] ?? ""; + payfortResponseInsertModel.cardBin = paymentMap['card_bin'] ?? ""; + payfortResponseInsertModel.installmentsNumber = int.tryParse(paymentMap['installments_number'] ?? "0") ?? 0; + payfortResponseInsertModel.status = paymentMap['status'] ?? ""; + payfortResponseInsertModel.merchantRef = paymentMap['merchant_reference'] ?? ""; + payfortResponseInsertModel.isRefund = false; + payfortResponseInsertModel.remmeberMe = true; + payfortResponseInsertModel.reconciliationReference = ""; + + payfortResponseInsert(payfortResponseInsertModel: payfortResponseInsertModel); + } + } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 67aacc0e..30e3bc0a 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -2036,5 +2036,8 @@ abstract class LocaleKeys { static const appDecommissionedText = 'appDecommissionedText'; static const appDecommissionedSubText = 'appDecommissionedSubText'; static const downloadApp = 'downloadApp'; + static const unread = 'unread'; + static const read = 'read'; + static const pendingMedicalReportRequest = 'pendingMedicalReportRequest'; } diff --git a/lib/presentation/appointments/appointment_details_page.dart b/lib/presentation/appointments/appointment_details_page.dart index 7d1d3f91..874c97c6 100644 --- a/lib/presentation/appointments/appointment_details_page.dart +++ b/lib/presentation/appointments/appointment_details_page.dart @@ -338,6 +338,7 @@ class _AppointmentDetailsPageState extends State { myAppointmentsViewModel.updateListWRTTab(0); await myAppointmentsViewModel.cancelAppointment( patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel, + isReschedule: false, onSuccess: (apiResponse) async { LoaderBottomSheet.hideLoader(); myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true); diff --git a/lib/presentation/appointments/appointment_payment_page.dart b/lib/presentation/appointments/appointment_payment_page.dart index ffa9b723..bef2df93 100644 --- a/lib/presentation/appointments/appointment_payment_page.dart +++ b/lib/presentation/appointments/appointment_payment_page.dart @@ -748,7 +748,8 @@ class _AppointmentPaymentPageState extends State { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - (myAppointmentsVM.patientAppointmentShareResponseModel!.isCash ?? true) + // (myAppointmentsVM.patientAppointmentShareResponseModel!.isCash ?? true) + (true) ? Container( height: 50.h, decoration: ShapeDecoration( @@ -1282,6 +1283,7 @@ class _AppointmentPaymentPageState extends State { currency: appState.getAuthenticatedUser()!.outSa! == 0 ? "SAR" : "AED", onFailed: (failureResult) async { log("failureResult: ${failureResult.message.toString()}"); + payfortViewModel.addApplePayPayfortResponse(failureResult.response); LoaderBottomSheet.hideLoader(); showCommonBottomSheetWithoutHeight( context, @@ -1292,10 +1294,94 @@ class _AppointmentPaymentPageState extends State { ); }, onSucceeded: (successResult) async { + payfortViewModel.addApplePayPayfortResponse(successResult); LoaderBottomSheet.hideLoader(); log("successResult: ${successResult.responseMessage.toString()}"); selectedPaymentMethod = successResult.paymentOption ?? "VISA"; checkPaymentStatus(); + + // LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingPaymentStatusPleaseWait.tr(context: context)); + // await myAppointmentsViewModel.createAdvancePayment( + // paymentMethodName: selectedPaymentMethod, + // projectID: widget.patientAppointmentHistoryResponseModel.projectID, + // clinicID: widget.patientAppointmentHistoryResponseModel.clinicID, + // appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo.toString(), + // payedAmount: num.parse(myAppointmentsViewModel.patientAppointmentShareResponseModel!.patientShareWithTax!.toString()), + // paymentReference: successResult.fortId!, + // patientID: appState.getAuthenticatedUser()!.patientId.toString(), + // patientType: appState.getAuthenticatedUser()!.patientType!, + // onSuccess: (value) async { + // print(value); + // await myAppointmentsViewModel.addAdvanceNumberRequest( + // advanceNumber: Utils.isVidaPlusProject(widget.patientAppointmentHistoryResponseModel.projectID) + // ? value.data['OnlineCheckInAppointments'][0]['AdvanceNumber_VP'].toString() + // : value.data['OnlineCheckInAppointments'][0]['AdvanceNumber'].toString(), + // paymentReference: successResult.fortId!, + // appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo.toString(), + // onSuccess: (value) async { + // if (widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment!) { + // //TODO: Implement LiveCare Check-In API Call + // await myAppointmentsViewModel.insertLiveCareVIDARequest( + // clientRequestID: transID, + // patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel, + // onSuccess: (apiResponse) { + // Future.delayed(Duration(milliseconds: 500), () { + // myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true); + // myAppointmentsViewModel.initAppointmentsViewModel(); + // myAppointmentsViewModel.getPatientAppointments(true, false); + // + // getIt.get().setIsWalletAmountToBeLoaded(true); + // getIt.get().initHabibWalletProvider(); + // getIt.get().getPatientBalanceAmount(); + // + // LoaderBottomSheet.hideLoader(); + // Navigator.pushAndRemoveUntil( + // context, + // CustomPageRoute( + // page: LandingNavigation(), + // ), + // (r) => false); + // }); + // }, + // onError: (error) {}); + // } else { + // await myAppointmentsViewModel.generateAppointmentQR( + // clinicID: widget.patientAppointmentHistoryResponseModel.clinicID, + // projectID: widget.patientAppointmentHistoryResponseModel.projectID, + // appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo.toString(), + // isFollowUp: myAppointmentsViewModel.patientAppointmentShareResponseModel!.isFollowup!, + // onSuccess: (apiResponse) { + // Future.delayed(Duration(milliseconds: 500), () { + // myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true); + // myAppointmentsViewModel.initAppointmentsViewModel(); + // myAppointmentsViewModel.getPatientAppointments(true, false); + // + // getIt.get().setIsWalletAmountToBeLoaded(true); + // getIt.get().initHabibWalletProvider(); + // getIt.get().getPatientBalanceAmount(); + // + // LoaderBottomSheet.hideLoader(); + // Navigator.pushAndRemoveUntil( + // context, + // CustomPageRoute( + // page: LandingNavigation(), + // ), + // (r) => false); + // }); + // }); + // } + // }); + // }, + // onError: (err) { + // LoaderBottomSheet.hideLoader(); + // showCommonBottomSheetWithoutHeight( + // context, + // child: Utils.getErrorWidget(loadingText: err.toString()), + // callBackFunc: () {}, + // isFullScreen: false, + // isCloseButtonVisible: true, + // ); + // }); }, // projectId: appo.projectID, // serviceTypeEnum: ServiceTypeEnum.appointmentPayment, diff --git a/lib/presentation/appointments/widgets/appointment_card.dart b/lib/presentation/appointments/widgets/appointment_card.dart index 1eeb842c..b9a2f26f 100644 --- a/lib/presentation/appointments/widgets/appointment_card.dart +++ b/lib/presentation/appointments/widgets/appointment_card.dart @@ -448,7 +448,17 @@ class _AppointmentCardState extends State { if (widget.isForFeedback) { widget.contactUsViewModel!.setPatientFeedbackSelectedAppointment(widget.patientAppointmentHistoryResponseModel); } else { - widget.medicalFileViewModel!.setSelectedMedicalReportAppointment(widget.patientAppointmentHistoryResponseModel); + if(!widget.medicalFileViewModel!.checkExistingMedicalReportStatus(widget.patientAppointmentHistoryResponseModel)) { + widget.medicalFileViewModel!.setSelectedMedicalReportAppointment(widget.patientAppointmentHistoryResponseModel); + } else { + showCommonBottomSheetWithoutHeight( + context, + child: Utils.getErrorWidget(loadingText: LocaleKeys.pendingMedicalReportRequest.tr(context: context)), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + } } Navigator.pop(context, false); } else { diff --git a/lib/presentation/book_appointment/livecare/immediate_livecare_payment_page.dart b/lib/presentation/book_appointment/livecare/immediate_livecare_payment_page.dart index 9d30f976..b205063c 100644 --- a/lib/presentation/book_appointment/livecare/immediate_livecare_payment_page.dart +++ b/lib/presentation/book_appointment/livecare/immediate_livecare_payment_page.dart @@ -1077,6 +1077,7 @@ class _ImmediateLiveCarePaymentPageState extends State { currency: appState.getAuthenticatedUser()!.outSa! == 0 ? "SAR" : "AED", onFailed: (failureResult) async { log("failureResult: ${failureResult.message.toString()}"); + payfortViewModel.addApplePayPayfortResponse(failureResult.response); showCommonBottomSheetWithoutHeight( context, child: Utils.getErrorWidget(loadingText: failureResult.message.toString()), @@ -677,6 +678,7 @@ class _WalletPaymentConfirmPageState extends State { }, onSucceeded: (successResult) async { log("successResult: ${successResult.responseMessage.toString()}"); + payfortViewModel.addApplePayPayfortResponse(successResult); selectedPaymentMethod = successResult.paymentOption ?? "VISA"; checkPaymentStatus(); }, diff --git a/lib/presentation/hmg_services/services_page.dart b/lib/presentation/hmg_services/services_page.dart index 582fd6fc..34fc268f 100644 --- a/lib/presentation/hmg_services/services_page.dart +++ b/lib/presentation/hmg_services/services_page.dart @@ -72,7 +72,7 @@ class _ServicesPageState extends State { LocaleKeys.emergencyServices.tr(), "", AppAssets.emergency_services_icon, - bgColor: AppColors.primaryRedColor, + bgColor: AppColors.primaryRedColorBase, true, route: null, onTap: () async { // if (getIt.get().isAuthenticated) { diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index 8644655d..9d401fac 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.dart @@ -437,6 +437,7 @@ class _LandingPageState extends State { : SizedBox.shrink(), ]).onPress(() async { if (appState.isAuthenticated) { + notificationsViewModel.onNotificationTabChange(0); notificationsViewModel.setNotificationStatusID(2); notificationsViewModel.getAllNotifications(); Navigator.of(context).push( diff --git a/lib/presentation/medical_file/medical_file_page.dart b/lib/presentation/medical_file/medical_file_page.dart index 629ff15c..add423d8 100644 --- a/lib/presentation/medical_file/medical_file_page.dart +++ b/lib/presentation/medical_file/medical_file_page.dart @@ -280,7 +280,7 @@ class _MedicalFilePageState extends State { AppCustomChipWidget( icon: AppAssets.blood_icon, labelText: appState.getUserBloodGroup.isEmpty ? "N/A" : appState.getUserBloodGroup, - iconColor: AppColors.primaryRedColor, + iconColor: AppColors.primaryRedColorBase, labelPadding: EdgeInsetsDirectional.only(start: -6.w, end: 6.w), padding: EdgeInsets.zero, ), diff --git a/lib/presentation/medical_file/widgets/medical_report_card.dart b/lib/presentation/medical_file/widgets/medical_report_card.dart index 1a43b83b..905823b4 100644 --- a/lib/presentation/medical_file/widgets/medical_report_card.dart +++ b/lib/presentation/medical_file/widgets/medical_report_card.dart @@ -84,15 +84,15 @@ class MedicalReportCard extends StatelessWidget { ), ); }, - backgroundColor: AppColors.lightRedButtonColor, - borderColor: AppColors.lightRedButtonColor, + backgroundColor: AppColors.secondaryLightRedColor, + borderColor: AppColors.secondaryLightRedColor, textColor: AppColors.primaryRedColor, iconColor: AppColors.primaryRedColor, fontSize: 14.f, - // fontWeight: FontWeight.w600, isBold: true, borderRadius: 12.r, height: 40.h, + iconSize: 18.f, ).toShimmer2(isShow: isLoading), ], ), diff --git a/lib/presentation/medical_file/widgets/patient_sick_leave_card.dart b/lib/presentation/medical_file/widgets/patient_sick_leave_card.dart index f06e6a0e..2bb879b5 100644 --- a/lib/presentation/medical_file/widgets/patient_sick_leave_card.dart +++ b/lib/presentation/medical_file/widgets/patient_sick_leave_card.dart @@ -122,7 +122,7 @@ class PatientSickLeaveCard extends StatelessWidget { }); }, backgroundColor: AppColors.secondaryLightRedColor, - borderColor: AppColors.secondaryLightRedColor, + borderColor: AppColors.transparent, textColor: AppColors.primaryRedColor, fontSize: 14.f, isBold: true, diff --git a/lib/presentation/medical_report/medical_report_request_page.dart b/lib/presentation/medical_report/medical_report_request_page.dart index 47a2df32..859a6b2f 100644 --- a/lib/presentation/medical_report/medical_report_request_page.dart +++ b/lib/presentation/medical_report/medical_report_request_page.dart @@ -2,6 +2,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.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/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'; @@ -26,8 +27,9 @@ class MedicalReportRequestPage extends StatelessWidget { isClose: true, child: Column( children: [ - ListView.separated( - padding: EdgeInsets.only(top: 24.h), + medicalFileViewModel.patientMedicalReportAppointmentHistoryList.isNotEmpty + ? ListView.separated( + padding: EdgeInsets.only(top: 24.h), shrinkWrap: true, physics: NeverScrollableScrollPhysics(), itemCount: medicalFileViewModel.patientMedicalReportAppointmentHistoryList.length, @@ -57,7 +59,8 @@ class MedicalReportRequestPage extends StatelessWidget { ); }, separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h), - ), + ) + : Utils.getNoDataWidget(context), SizedBox(height: 24.h), ], ), diff --git a/lib/presentation/medical_report/medical_reports_page.dart b/lib/presentation/medical_report/medical_reports_page.dart index e1ac3969..33f9e6e3 100644 --- a/lib/presentation/medical_report/medical_reports_page.dart +++ b/lib/presentation/medical_report/medical_reports_page.dart @@ -50,42 +50,7 @@ class _MedicalReportsPageState extends State { child: Consumer(builder: (context, medicalFileVM, child) { return Column( children: [ - SizedBox(height: 16.h), - // Status filter tabs - // Row( - // children: [ - // CustomButton( - // text: LocaleKeys.byClinic.tr(context: context), - // onPressed: () { - // medicalFileVM.setIsMedicalReportsSortByClinic(true); - // }, - // backgroundColor: medicalFileVM.isMedicalReportsSortByClinic ? AppColors.bgRedLightColor : AppColors.whiteColor, - // borderColor: medicalFileVM.isMedicalReportsSortByClinic ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2), - // textColor: medicalFileVM.isMedicalReportsSortByClinic ? AppColors.primaryRedColor : AppColors.blackColor, - // fontSize: 12, - // isBold: true, - // borderRadius: 10, - // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - // height: 40.h, - // ), - // SizedBox(width: 8.h), - // CustomButton( - // text: LocaleKeys.byHospital.tr(context: context), - // onPressed: () { - // medicalFileVM.setIsMedicalReportsSortByClinic(false); - // }, - // backgroundColor: medicalFileVM.isMedicalReportsSortByClinic ? AppColors.whiteColor : AppColors.bgRedLightColor, - // borderColor: medicalFileVM.isMedicalReportsSortByClinic ? AppColors.textColor.withValues(alpha: 0.2) : AppColors.primaryRedColor, - // textColor: medicalFileVM.isMedicalReportsSortByClinic ? AppColors.blackColor : AppColors.primaryRedColor, - // fontSize: 12, - // isBold: true, - // borderRadius: 10, - // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - // height: 40.h, - // ), - // ], - // ).paddingSymmetrical(24.h, 0.h), - SizedBox(height: 8.h), + SizedBox(height: 24.h), Row( children: [ CustomButton( @@ -404,6 +369,7 @@ class _MedicalReportsPageState extends State { showCommonBottomSheetWithoutHeight(context, child: Utils.getSuccessWidget(loadingText: LocaleKeys.yourMedicalReportRequestSubmittedSuccessfully.tr(context: context)), callBackFunc: () async{ + medicalFileViewModel.setIsMedicalReportsDataNeedsReloading(true); medicalFileViewModel.setIsPatientMedicalReportsLoading(true); medicalFileViewModel.onMedicalReportTabChange(0); medicalFileViewModel.getPatientMedicalReportList(); diff --git a/lib/presentation/my_family/widget/family_cards.dart b/lib/presentation/my_family/widget/family_cards.dart index a52f2ca6..362aada0 100644 --- a/lib/presentation/my_family/widget/family_cards.dart +++ b/lib/presentation/my_family/widget/family_cards.dart @@ -475,7 +475,7 @@ class _FamilyCardsState extends State { ? Wrap(direction: Axis.horizontal, spacing: 4.h, runSpacing: 4.h, children: [ AppCustomChipWidget( icon: AppAssets.file_icon, - richText: "${LocaleKeys.fileno.tr(context: context)}: ${profile.responseId}".toText10(isBold: true), + richText: "${profile.responseId}".toText10(isBold: true), labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: 6.w), ), AppCustomChipWidget( @@ -489,7 +489,7 @@ class _FamilyCardsState extends State { : SizedBox( height: 4.h, ), - Spacer(), + SizedBox(height: 8.h), widget.isForWalletRecharge ? CustomButton( height: 40.h, diff --git a/lib/presentation/notifications/notifications_list_page.dart b/lib/presentation/notifications/notifications_list_page.dart index 77f9a20a..eb1af696 100644 --- a/lib/presentation/notifications/notifications_list_page.dart +++ b/lib/presentation/notifications/notifications_list_page.dart @@ -17,6 +17,7 @@ import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart'; import 'package:hmg_patient_app_new/presentation/notifications/notification_details_page.dart'; 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:provider/provider.dart'; import 'package:intl/intl.dart'; import 'dart:ui' as ui; @@ -51,6 +52,54 @@ class _NotificationsListPageState extends State { child: Consumer(builder: (context, notificationsVM, child) { return Column( children: [ + Row( + children: [ + CustomButton( + text: LocaleKeys.all.tr(context: context), + onPressed: () { + notificationsVM.onNotificationTabChange(0); + }, + backgroundColor: notificationsVM.selectedNotificationsTabIndex == 0 ? AppColors.bgRedLightColor : AppColors.whiteColor, + borderColor: notificationsVM.selectedNotificationsTabIndex == 0 ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2), + textColor: notificationsVM.selectedNotificationsTabIndex == 0 ? AppColors.primaryRedColor : AppColors.blackColor, + fontSize: 12, + isBold: true, + borderRadius: 10, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 40.h, + ), + SizedBox(width: 8.h), + CustomButton( + text: LocaleKeys.unread.tr(context: context), + onPressed: () { + notificationsVM.onNotificationTabChange(1); + }, + backgroundColor: notificationsVM.selectedNotificationsTabIndex == 1 ? AppColors.bgRedLightColor : AppColors.whiteColor, + borderColor: notificationsVM.selectedNotificationsTabIndex == 1 ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2), + textColor: notificationsVM.selectedNotificationsTabIndex == 1 ? AppColors.primaryRedColor : AppColors.blackColor, + fontSize: 12, + isBold: true, + borderRadius: 10, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 40.h, + ), + SizedBox(width: 8.h), + CustomButton( + text: LocaleKeys.read.tr(context: context), + onPressed: () { + notificationsVM.onNotificationTabChange(2); + }, + backgroundColor: notificationsVM.selectedNotificationsTabIndex == 2 ? AppColors.bgRedLightColor : AppColors.whiteColor, + borderColor: notificationsVM.selectedNotificationsTabIndex == 2 ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2), + textColor: notificationsVM.selectedNotificationsTabIndex == 2 ? AppColors.primaryRedColor : AppColors.blackColor, + fontSize: 12, + isBold: true, + borderRadius: 10, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 40.h, + ), + ], + ).paddingSymmetrical(24.h, 0.h), Container( margin: EdgeInsets.symmetric(vertical: 24.h), decoration: RoundedRectangleBorder().toSmoothCornerDecoration( diff --git a/lib/presentation/todo_section/ancillary_order_payment_page.dart b/lib/presentation/todo_section/ancillary_order_payment_page.dart index 365dff2b..e6665037 100644 --- a/lib/presentation/todo_section/ancillary_order_payment_page.dart +++ b/lib/presentation/todo_section/ancillary_order_payment_page.dart @@ -819,6 +819,7 @@ class _AncillaryOrderPaymentPageState extends State { applePayShaRequestPhrase: payfortViewModel.payfortProjectDetailsRespModel!.shaRequest, currency: appState.getAuthenticatedUser()!.outSa! == 0 ? "SAR" : "AED", onFailed: (failureResult) async { + payfortViewModel.addApplePayPayfortResponse(failureResult.response); log("failureResult: ${failureResult.message.toString()}"); LoaderBottomSheet.hideLoader(); showCommonBottomSheetWithoutHeight( @@ -830,6 +831,7 @@ class _AncillaryOrderPaymentPageState extends State { ); }, onSucceeded: (successResult) async { + payfortViewModel.addApplePayPayfortResponse(successResult); LoaderBottomSheet.hideLoader(); log("successResult: ${successResult.responseMessage.toString()}"); selectedPaymentMethod = successResult.paymentOption ?? "VISA"; diff --git a/lib/widgets/in_app_browser/InAppBrowser.dart b/lib/widgets/in_app_browser/InAppBrowser.dart index fe08fbbe..5eaa313c 100644 --- a/lib/widgets/in_app_browser/InAppBrowser.dart +++ b/lib/widgets/in_app_browser/InAppBrowser.dart @@ -307,12 +307,13 @@ class MyInAppBrowser extends InAppBrowser { form = form.replaceFirst('CUSTNAME_VALUE', patientName); form = form.replaceFirst('CUSTID_VALUE', patientID.toString()); + form = form.replaceFirst('APPOINTMENT_DATE_VALUE', appoDate); + form = form.replaceFirst('APPOINTMENT_NO_VALUE', appoNo.toString()); + form = form.replaceFirst('DOCTOR_ID_VALUE', doctorID.toString()); + form = form.replaceFirst('CLINIC_ID_VALUE', clinicID.toString()); + if (isLiveCareAppo) { form = form.replaceFirst('IS_SCHEDULE_VALUE', "true"); - form = form.replaceFirst('APPOINTMENT_DATE_VALUE', appoDate); - form = form.replaceFirst('APPOINTMENT_NO_VALUE', appoNo.toString()); - form = form.replaceFirst('DOCTOR_ID_VALUE', doctorID.toString()); - form = form.replaceFirst('CLINIC_ID_VALUE', clinicID.toString()); } var bytes = utf8.encode(form); @@ -363,6 +364,10 @@ class MyInAppBrowser extends InAppBrowser { '' + '' + '' + + '' + + '' + + '' + + '' + '' + '' + '' +