From 5a402b45b74377d8235c3b418f5a5a37643d357c Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Wed, 8 Apr 2026 16:17:37 +0300 Subject: [PATCH 01/11] color update --- .../lab_result_via_clinic/lab_ai_analysis_detailed_page.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/presentation/lab/lab_result_via_clinic/lab_ai_analysis_detailed_page.dart b/lib/presentation/lab/lab_result_via_clinic/lab_ai_analysis_detailed_page.dart index 8d25ef37..8c4dfc33 100644 --- a/lib/presentation/lab/lab_result_via_clinic/lab_ai_analysis_detailed_page.dart +++ b/lib/presentation/lab/lab_result_via_clinic/lab_ai_analysis_detailed_page.dart @@ -336,7 +336,7 @@ class _LabAiAnalysisDetailedPageState extends State { if (priority == null) return AppColors.primaryRedColor; switch (priority.toLowerCase()) { case 'high': - return Color(0xFFED1C2B).withOpacity(.10); + return AppColors.secondaryLightRedColor; case 'medium' || 'moderate': return AppColors.lightGreenButtonColor; case 'low': From bb274e80c1e0fae5149fb9b313cba311e21d440d Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Wed, 8 Apr 2026 18:09:42 +0300 Subject: [PATCH 02/11] updates --- .../appointments/widgets/appointment_doctor_card.dart | 6 ++++-- .../book_appointment/widgets/doctor_card.dart | 10 ++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/presentation/appointments/widgets/appointment_doctor_card.dart b/lib/presentation/appointments/widgets/appointment_doctor_card.dart index 5de06455..b8a0ec8a 100644 --- a/lib/presentation/appointments/widgets/appointment_doctor_card.dart +++ b/lib/presentation/appointments/widgets/appointment_doctor_card.dart @@ -142,8 +142,10 @@ class AppointmentDoctorCard extends StatelessWidget { ], ), ), - Utils.buildSvgWithAssets(icon: AppAssets.doctor_profile_icon, width: 20.h, height: 20.h, fit: BoxFit.scaleDown).onPress(() async { - DoctorsListResponseModel selectedDoctor = DoctorsListResponseModel(); + patientAppointmentHistoryResponseModel.isLiveCareAppointment! + ? SizedBox.shrink() + : Utils.buildSvgWithAssets(icon: AppAssets.doctor_profile_icon, width: 20.h, height: 20.h, fit: BoxFit.scaleDown).onPress(() async { + DoctorsListResponseModel selectedDoctor = DoctorsListResponseModel(); selectedDoctor.doctorID = patientAppointmentHistoryResponseModel.doctorID; selectedDoctor.doctorImageURL = patientAppointmentHistoryResponseModel.doctorImageURL; selectedDoctor.name = patientAppointmentHistoryResponseModel.doctorNameObj; diff --git a/lib/presentation/book_appointment/widgets/doctor_card.dart b/lib/presentation/book_appointment/widgets/doctor_card.dart index 11042a57..7b9ce848 100644 --- a/lib/presentation/book_appointment/widgets/doctor_card.dart +++ b/lib/presentation/book_appointment/widgets/doctor_card.dart @@ -159,10 +159,12 @@ class DoctorCard extends StatelessWidget { ], ), ), - Expanded( - flex: 1, - child: Utils.buildSvgWithAssets(icon: AppAssets.doctor_profile_icon, width: 20.h, height: 20.h, fit: BoxFit.scaleDown).toShimmer2(isShow: isLoading), - ), + (doctorsListResponseModel.isLiveCare ?? true) + ? SizedBox.shrink() + : Expanded( + flex: 1, + child: Utils.buildSvgWithAssets(icon: AppAssets.doctor_profile_icon, width: 20.h, height: 20.h, fit: BoxFit.scaleDown).toShimmer2(isShow: isLoading), + ), ], ), SizedBox(height: 16.h), From f8df84177de39c05e55c6e8d978d4b691a40c7f2 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Wed, 8 Apr 2026 18:29:33 +0300 Subject: [PATCH 03/11] update --- assets/langs/ar-SA.json | 6 +++--- lib/presentation/my_family/widget/family_cards.dart | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 822b73dd..dac6aeb4 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -694,7 +694,7 @@ "retouch": "روتوش", "bikini": "بيكيني", "totalMinutes": "إجمالي الدقائق", - "feedback": "ملاحظات", + "feedback": "رأيك يهمنا", "likeToHear": "نود سماع ملاحظاتك، ومخاوفك بشأن خدمات الرعاية الصحية وتجربة الخدمات الإلكترونية. يرجى استخدام النموذج أدناه", "emptySubject": "يرجى إدخال الموضوع", "emptyMessage": "يرجى إدخال الرسالة", @@ -702,10 +702,10 @@ "complainAppo": "شكوى بخصوص الموعد", "complainAppoAlt": "شكوى بدون موعد", "messageType": "نوع الرسالة", - "feedbackType": "نوع الملاحظات", + "feedbackType": "نوع الرسالة", "compliment": "تقدير", "suggestion": "اقتراح", - "yourFeedback": "تم إرسال ملاحظاتك", + "yourFeedback": "تم إرسال رأيك", "selectPart": "يرجى اختيار الجزء الذي تشتكي منه", "number": "رقم", "notClassified": "غير مصنف", diff --git a/lib/presentation/my_family/widget/family_cards.dart b/lib/presentation/my_family/widget/family_cards.dart index 39344f30..16609a03 100644 --- a/lib/presentation/my_family/widget/family_cards.dart +++ b/lib/presentation/my_family/widget/family_cards.dart @@ -199,7 +199,7 @@ class _FamilyCardsState extends State { children: [ AppCustomChipWidget( icon: AppAssets.file_icon, - richText: "${LocaleKeys.fileno.tr(context: context)}: ${appState.getAuthenticatedUser()!.patientId}".toText10(isEnglishOnly: true), + richText: "${LocaleKeys.fileno.tr(context: context)}: ${appState.getAuthenticatedUser()!.patientId}".toText10(isBold: true), labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: 6.w), ), AppCustomChipWidget( From b33a559305b208c3227239b2d88ddc8a6a47b0c1 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Wed, 8 Apr 2026 19:06:22 +0300 Subject: [PATCH 04/11] Dental workflow implemented --- lib/core/api_consts.dart | 3 ++- lib/features/book_appointments/book_appointments_repo.dart | 5 +++-- .../book_appointments/book_appointments_view_model.dart | 3 +-- lib/presentation/authentication/saved_login_screen.dart | 1 + 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index 9a16cdbc..d8fc9cc7 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -475,7 +475,8 @@ var GET_ACTIVE_APPOINTMENTS_LIST_URL = "Services/Doctors.svc/Rest/Dr_GetAppointm var GET_DOCTORS_LIST_URL = "Services/Doctors.svc/REST/SearchDoctorsByTime"; //URL to dental doctors list -var GET_DENTAL_DOCTORS_LIST_URL = "Services/Doctors.svc/REST/Dental_DoctorChiefComplaintMapping"; +// var GET_DENTAL_DOCTORS_LIST_URL = "Services/Doctors.svc/REST/Dental_DoctorChiefComplaintMapping"; +var GET_DENTAL_DOCTORS_LIST_URL = "Services/Doctors.svc/REST/Dental_DoctorChiefComplaintMapping_Nearest"; //URL to get doctor free slots var GET_DOCTOR_FREE_SLOTS = "Services/Doctors.svc/REST/GetDoctorFreeSlots"; diff --git a/lib/features/book_appointments/book_appointments_repo.dart b/lib/features/book_appointments/book_appointments_repo.dart index 7a984399..0db37274 100644 --- a/lib/features/book_appointments/book_appointments_repo.dart +++ b/lib/features/book_appointments/book_appointments_repo.dart @@ -86,7 +86,7 @@ abstract class BookAppointmentsRepo { {required int projectID, required int clinicID, required int patientID, Function(dynamic)? onSuccess, Function(String)? onError}); Future>>> getDentalChiefComplaintDoctorsList(int projectID, int chiefComplaintID, - {Function(dynamic)? onSuccess, Function(String)? onError}); + {bool isGetNearestAppointments, Function(dynamic)? onSuccess, Function(String)? onError}); Future>>> getLaserClinics(int laserCategoryID, int projectID, int languageID, {Function(dynamic)? onSuccess, Function(String)? onError}); @@ -877,12 +877,13 @@ class BookAppointmentsRepoImp implements BookAppointmentsRepo { @override Future>>> getDentalChiefComplaintDoctorsList(int projectID, int chiefComplaintID, - {Function(dynamic)? onSuccess, Function(String)? onError}) async { + {bool isGetNearestAppointments = false, Function(dynamic)? onSuccess, Function(String)? onError}) async { Map mapDevice = { "ProjectID": projectID, "ChiefComplaintID": chiefComplaintID, "isDentalAllowedBackend": true, "IsPublicRequest": true, + "IsGetNearAppointment": isGetNearestAppointments }; try { diff --git a/lib/features/book_appointments/book_appointments_view_model.dart b/lib/features/book_appointments/book_appointments_view_model.dart index 647b8632..7ac6ae45 100644 --- a/lib/features/book_appointments/book_appointments_view_model.dart +++ b/lib/features/book_appointments/book_appointments_view_model.dart @@ -1471,12 +1471,11 @@ class BookAppointmentsViewModel extends ChangeNotifier { } Future getDentalChiefComplaintDoctorsList({int projectID = 0, Function(dynamic)? onSuccess, Function(String)? onError}) async { - setIsNearestAppointmentSelected(false); doctorsList.clear(); notifyListeners(); projectID = currentlySelectedHospitalFromRegionFlow != null ? int.parse(currentlySelectedHospitalFromRegionFlow!) : projectID; - final result = await bookAppointmentsRepo.getDentalChiefComplaintDoctorsList(projectID, selectedChiefComplaintID); + final result = await bookAppointmentsRepo.getDentalChiefComplaintDoctorsList(projectID, selectedChiefComplaintID, isGetNearestAppointments: isNearestAppointmentSelected); result.fold( (failure) async { diff --git a/lib/presentation/authentication/saved_login_screen.dart b/lib/presentation/authentication/saved_login_screen.dart index 4659972e..ffa5f529 100644 --- a/lib/presentation/authentication/saved_login_screen.dart +++ b/lib/presentation/authentication/saved_login_screen.dart @@ -288,6 +288,7 @@ class _SavedLogin extends State { child: CustomButton( text: LocaleKeys.guest.tr(), onPressed: () { + authVm.setIsInitialLoginNavigated(true); Navigator.pushAndRemoveUntil( context, CustomPageRoute( From ad0cbe1e21fe14ba1293f056702b598b90904537 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Wed, 8 Apr 2026 21:35:03 +0300 Subject: [PATCH 05/11] updates --- .../appointments/widgets/appointment_doctor_card.dart | 4 ++-- .../book_appointment/select_doctor_page.dart | 9 +++++---- lib/presentation/home/landing_page.dart | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/presentation/appointments/widgets/appointment_doctor_card.dart b/lib/presentation/appointments/widgets/appointment_doctor_card.dart index b8a0ec8a..474878ef 100644 --- a/lib/presentation/appointments/widgets/appointment_doctor_card.dart +++ b/lib/presentation/appointments/widgets/appointment_doctor_card.dart @@ -267,7 +267,7 @@ class AppointmentDoctorCard extends StatelessWidget { fontSize: 14.f, isBold: true, borderRadius: 12.r, - height: 40.h, + height: 46.h, icon: AppAssets.appointment_calendar_icon, iconColor: AppColors.primaryRedColor, iconSize: 16.h, @@ -286,7 +286,7 @@ class AppointmentDoctorCard extends StatelessWidget { fontSize: 14.f, isBold: true, borderRadius: 12.r, - height: 40.h, + height: 46.h, icon: AppAssets.cancel, iconColor: AppColors.whiteColor, iconSize: 16.h, diff --git a/lib/presentation/book_appointment/select_doctor_page.dart b/lib/presentation/book_appointment/select_doctor_page.dart index de2e2ae8..d9012573 100644 --- a/lib/presentation/book_appointment/select_doctor_page.dart +++ b/lib/presentation/book_appointment/select_doctor_page.dart @@ -220,8 +220,9 @@ class _SelectDoctorPageState extends State { ], ).paddingSymmetrical(0.h, 0.h), if (bookAppointmentsViewModel.isGetDocForHealthCal && bookAppointmentsVM.showSortFilterButtons) SizedBox(height: 16.h), - bookAppointmentsVM.doctorsListGrouped.isNotEmpty - ? Row( + // bookAppointmentsVM.doctorsListGrouped.isNotEmpty + // ? + Row( mainAxisSize: MainAxisSize.max, children: [ Column( @@ -243,8 +244,8 @@ class _SelectDoctorPageState extends State { }, ), ], - ) - : SizedBox.shrink(), + ), + // : SizedBox.shrink(), ListView.separated( padding: EdgeInsets.only(top: 16.h), shrinkWrap: true, diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index 371fe892..1d7e3777 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.dart @@ -188,7 +188,7 @@ class _LandingPageState extends State { // Refresh Appointments Data myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true); myAppointmentsViewModel.initAppointmentsViewModel(); - myAppointmentsViewModel.getPatientAppointments(true, false); + myAppointmentsViewModel.getPatientAppointments(true, true); // Refresh Appointments Data habibWalletVM.initHabibWalletProvider(); From d1e0ec31e6bdac438d2f4c70e6cf12d7e7871c78 Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Thu, 9 Apr 2026 08:36:36 +0300 Subject: [PATCH 06/11] radiology ai lab analysis & lab ai analysis api end points updates. --- lib/core/app_state.dart | 14 ++++++++++++++ .../authentication/authentication_repo.dart | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/core/app_state.dart b/lib/core/app_state.dart index a5a8d72a..d02aa946 100644 --- a/lib/core/app_state.dart +++ b/lib/core/app_state.dart @@ -249,4 +249,18 @@ class AppState { _userSwitchPayloads.clear(); _childSwitchCounter = 0; } + + void clearChildUsersKeepSuperUser() { + // Keep the super user payload + final superUserPayload = _userSwitchPayloads['superUser']; + + // Clear all payloads + _userSwitchPayloads.clear(); + _childSwitchCounter = 0; + + // Restore super user if it existed + if (superUserPayload != null) { + _userSwitchPayloads['superUser'] = superUserPayload; + } + } } diff --git a/lib/features/authentication/authentication_repo.dart b/lib/features/authentication/authentication_repo.dart index 39d8e3ee..c355819e 100644 --- a/lib/features/authentication/authentication_repo.dart +++ b/lib/features/authentication/authentication_repo.dart @@ -314,7 +314,7 @@ class AuthenticationRepoImp implements AuthenticationRepo { requestBody['PatientIdentificationID'] = ""; requestBody.removeWhere((key, value) => ['NationalID', 'isDentalAllowedBackend', 'ForRegisteration'].contains(key)); appState.setIsChildLoggedIn = false; - appState.clearUserSwitchPayloads(); + appState.clearChildUsersKeepSuperUser(); } } else { appState.setIsChildLoggedIn = true; From 74479850f53e6955bf7258f322b89e08263c28dc Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Thu, 9 Apr 2026 09:57:59 +0300 Subject: [PATCH 07/11] radiology ai lab analysis & lab ai analysis api end points updates. --- lib/presentation/my_family/widget/family_cards.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/presentation/my_family/widget/family_cards.dart b/lib/presentation/my_family/widget/family_cards.dart index 39344f30..3a647674 100644 --- a/lib/presentation/my_family/widget/family_cards.dart +++ b/lib/presentation/my_family/widget/family_cards.dart @@ -319,7 +319,6 @@ class _FamilyCardsState extends State { final profile = widget.profileViewList![index]; final isActive = (profile.responseId == appState.getAuthenticatedUser()?.patientId); final isParentUser = appState.getAuthenticatedUser()?.isParentUser ?? false; - print(jsonEncode(appState.getUserSwitchPayloads)); final isSuperUser = appState.getUserSwitchPayloads; // TODO: canSwitch functionality is currently disabled - set to true to allow all switches // Original logic: final canSwitch = isParentUser || (!isParentUser && profile.responseId == appState.getSuperUserID); From 39cbee029aed1f85fce5cead4d0fe078f56e7f05 Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Thu, 9 Apr 2026 10:18:15 +0300 Subject: [PATCH 08/11] radiology ai lab analysis & lab ai analysis api end points updates. --- lib/features/authentication/authentication_view_model.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/features/authentication/authentication_view_model.dart b/lib/features/authentication/authentication_view_model.dart index 7e753722..733118ca 100644 --- a/lib/features/authentication/authentication_view_model.dart +++ b/lib/features/authentication/authentication_view_model.dart @@ -641,8 +641,8 @@ class AuthenticationViewModel extends ChangeNotifier { _appState.addUserSwitchPayload(activation.list!.first.toJson(), isSuperUser: true); } } else { - _appState.setSuperUserID = _appState.getAuthenticatedUser()?.patientId; - // _appState.setIsChildLoggedIn = false; + var allUsersPayload = _appState.getUserSwitchPayloads; + _appState.setSuperUserID = allUsersPayload['superUser']?['PatientID']; activation.list!.first.isParentUser = true; _appState.addUserSwitchPayload(activation.list!.first.toJson(), isSuperUser: true); } From 5b443299723ebfad0a82b0775262c3a4a9915fc7 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Thu, 9 Apr 2026 10:50:27 +0300 Subject: [PATCH 09/11] updates --- assets/images/svg/invoice_list_icon.svg | 5 + assets/langs/ar-SA.json | 4 +- assets/langs/en-US.json | 4 +- lib/core/api_consts.dart | 5 +- lib/core/app_assets.dart | 1 + .../my_appointments/my_appointments_repo.dart | 6 +- .../my_appointments_view_model.dart | 1 + lib/generated/locale_keys.g.dart | 2 + .../widgets/appointment_card.dart | 260 +++++++++--------- .../widgets/appointment_doctor_card.dart | 2 +- .../ask_doctor_request_type_select.dart | 21 +- .../authentication/saved_login_screen.dart | 2 +- .../book_appointment_page.dart | 8 +- .../home/data/landing_page_data.dart | 10 + .../home/widgets/small_service_card.dart | 8 + .../my_invoices/my_invoices_list.dart | 94 +++++-- .../widgets/invoice_list_card.dart | 3 +- .../widgets/preferred_language_widget.dart | 6 +- lib/widgets/app_language_change.dart | 2 +- lib/widgets/common_bottom_sheet.dart | 2 +- 20 files changed, 268 insertions(+), 178 deletions(-) create mode 100644 assets/images/svg/invoice_list_icon.svg diff --git a/assets/images/svg/invoice_list_icon.svg b/assets/images/svg/invoice_list_icon.svg new file mode 100644 index 00000000..6b9e698f --- /dev/null +++ b/assets/images/svg/invoice_list_icon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index dac6aeb4..b39a0518 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -1691,5 +1691,7 @@ "generateAiAnalysisRadResult": "بإنشاء تحليل الذكاء الاصطناعي لهذا التقرير", "grantLocationPermission": "يرجى منح إذن الوصول إلى الموقع من إعدادات التطبيق للحصول على نتائج أفضل.", "NoBookedAppointments": "لا توجد مواعيد محجوزة", - "aiDisclaimerRad": "سيتم مشاركة بيانات نتائج الأشعة الخاصة بك بشكل آمن مع محلل الذكاء الاصطناعي لدينا لتحليلها. يساعد هذا في توفير رؤى صحية مخصصة. هل ترغب في المتابعة؟" + "aiDisclaimerRad": "سيتم مشاركة بيانات نتائج الأشعة الخاصة بك بشكل آمن مع محلل الذكاء الاصطناعي لدينا لتحليلها. يساعد هذا في توفير رؤى صحية مخصصة. هل ترغب في المتابعة؟", + "sendingAskDrRequest": "جارٍ إرسال الطلب...", + "askDrRequestSentSuccess": "تم إرسال الطلب بنجاح، وسيتواصل معك الطبيب قريباً." } diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 27a67857..c3869831 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -1683,5 +1683,7 @@ "generateAiAnalysisRadResult": "Generate AI analysis for this result", "grantLocationPermission": "Please grant location permission from app settings to see better results.", "NoBookedAppointments": "No Booked Appointments", - "aiDisclaimerRad": "Your radiology result data will be securely shared with our AI Analyzer for analysis. This helps provide personalized health insights. Do you want to proceed?" + "aiDisclaimerRad": "Your radiology result data will be securely shared with our AI Analyzer for analysis. This helps provide personalized health insights. Do you want to proceed?", + "sendingAskDrRequest": "Sending Request...", + "askDrRequestSentSuccess": "Request has been sent successfully, The doctor will get back to you soon." } diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index d8fc9cc7..1e08f792 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -25,6 +25,7 @@ class ApiConsts { static String GET_TAMARA_PAYMENT_STATUS = 'https://mdlaboratories.com/tamaralive/api/OnlineTamara/order_status?orderid='; static String QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail"; + // static String QLINE_URL = "https://qline.hmg.com/api/PatientCall/PatientInQueue_Detail"; static String CHAT_URL = "https://chat.hmg.com/Index.aspx?RequestedId="; @@ -44,7 +45,7 @@ class ApiConsts { GET_TAMARA_INSTALLMENTS_URL = "https://mdlaboratories.com/tamaralive/Home/GetInstallments"; GET_TAMARA_PAYMENT_STATUS = 'https://mdlaboratories.com/tamaralive/api/OnlineTamara/order_status?orderid='; rcBaseUrl = 'https://rc.hmg.com/'; - QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail"; + QLINE_URL = "https://qline.hmg.com/api/PatientCall/PatientInQueue_Detail"; CHAT_URL = "https://chat.hmg.com/Index.aspx?RequestedId="; break; case AppEnvironmentTypeEnum.dev: @@ -80,7 +81,7 @@ class ApiConsts { GET_TAMARA_INSTALLMENTS_URL = "https://epharmacy.hmg.com/tamara/Home/getinstallments"; GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid='; rcBaseUrl = 'https://rc.hmg.com/'; - QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail"; + QLINE_URL = "https://qline.hmg.com/api/PatientCall/PatientInQueue_Detail"; CHAT_URL = "https://chat.hmg.com/geneysChat/Index.aspx?RequestedId="; break; case AppEnvironmentTypeEnum.qa: diff --git a/lib/core/app_assets.dart b/lib/core/app_assets.dart index 21280f45..70f4b5d3 100644 --- a/lib/core/app_assets.dart +++ b/lib/core/app_assets.dart @@ -357,6 +357,7 @@ class AppAssets { static const String biometricLockIcon = '$svgBasePath/biometric_lock_icon.svg'; static const String imageIcon = '$svgBasePath/image_icon.svg'; static const String appointmentRatingIcon = '$svgBasePath/appointment_rating_icon.svg'; + static const String invoiceListIcon = '$svgBasePath/invoice_list_icon.svg'; // PNGS // static const String hmgLogo = '$pngBasePath/hmg_logo.png'; diff --git a/lib/features/my_appointments/my_appointments_repo.dart b/lib/features/my_appointments/my_appointments_repo.dart index 45c28c45..2c9391a4 100644 --- a/lib/features/my_appointments/my_appointments_repo.dart +++ b/lib/features/my_appointments/my_appointments_repo.dart @@ -77,7 +77,7 @@ abstract class MyAppointmentsRepo { Future>> sendDoctorRate( int rate, int appointmentNo, int projectID, int doctorID, int clinicID, String note, String appoDate, String docName, String projectName, String clinicName); - Future>>> getPatientAppointmentQueueDetails({required int appointmentNo, required int patientID}); + Future>>> getPatientAppointmentQueueDetails({required int appointmentNo, required int patientID, required int clinicID}); Future>> convertPatientToCash({required int projectID}); @@ -833,8 +833,8 @@ class MyAppointmentsRepoImp implements MyAppointmentsRepo { } @override - Future>>> getPatientAppointmentQueueDetails({required int appointmentNo, required int patientID}) async { - Map mapDevice = {"appointmentNo": appointmentNo, "patientID": patientID, "apiKey": "EE17D21C7943485D9780223CCE55DCE5"}; + Future>>> getPatientAppointmentQueueDetails({required int appointmentNo, required int patientID, required int clinicID}) async { + Map mapDevice = {"appointmentNo": appointmentNo, "patientID": patientID, "ClinicID": clinicID, "apiKey": "EE17D21C7943485D9780223CCE55DCE5"}; try { GenericApiModel>? apiResponse; Failure? failure; diff --git a/lib/features/my_appointments/my_appointments_view_model.dart b/lib/features/my_appointments/my_appointments_view_model.dart index bc0bfc74..5db21aee 100644 --- a/lib/features/my_appointments/my_appointments_view_model.dart +++ b/lib/features/my_appointments/my_appointments_view_model.dart @@ -932,6 +932,7 @@ class MyAppointmentsViewModel extends ChangeNotifier { notifyListeners(); final result = await myAppointmentsRepo.getPatientAppointmentQueueDetails( + clinicID: patientArrivedAppointmentsHistoryList.first.clinicID, appointmentNo: patientArrivedAppointmentsHistoryList.first.appointmentNo, patientID: patientArrivedAppointmentsHistoryList.first.patientID); isAppointmentQueueDetailsLoading = false; diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 29656b23..dc0aeb6c 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -1683,5 +1683,7 @@ abstract class LocaleKeys { static const grantLocationPermission = 'grantLocationPermission'; static const NoBookedAppointments = 'NoBookedAppointments'; static const aiDisclaimerRad = 'aiDisclaimerRad'; + static const sendingAskDrRequest = 'sendingAskDrRequest'; + static const askDrRequestSentSuccess = 'askDrRequestSentSuccess'; } diff --git a/lib/presentation/appointments/widgets/appointment_card.dart b/lib/presentation/appointments/widgets/appointment_card.dart index fb24f689..4f50bae9 100644 --- a/lib/presentation/appointments/widgets/appointment_card.dart +++ b/lib/presentation/appointments/widgets/appointment_card.dart @@ -243,88 +243,88 @@ class AppointmentCard extends StatelessWidget { (patientAppointmentHistoryResponseModel.isExecludeDoctor ?? false) || !Utils.isClinicAllowedForRebook(patientAppointmentHistoryResponseModel.clinicID ?? 0))) && AppointmentType.isArrived(patientAppointmentHistoryResponseModel)) { - if (((patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false) && - DateTime.now().difference(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate)).inDays <= 15)) { - return Row( - children: [ - Expanded( - flex: 6, - child: CustomButton( - text: LocaleKeys.askDoctor.tr(context: context), - onPressed: () async { - LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingDoctorAvailability.tr(context: context)); - await myAppointmentsViewModel.isDoctorAvailable( - projectID: patientAppointmentHistoryResponseModel.projectID, - doctorId: patientAppointmentHistoryResponseModel.doctorID, - clinicId: patientAppointmentHistoryResponseModel.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: patientAppointmentHistoryResponseModel, - ), - callBackFunc: () {}, - isFullScreen: false, - isCloseButtonVisible: true, - ); - }); - } else { - print("Doctor is not available"); - } - }); - }, - backgroundColor: AppColors.secondaryLightRedColor, - borderColor: AppColors.secondaryLightRedColor, - textColor: AppColors.primaryRedColor, - fontSize: (isFoldable || isTablet) ? 12.f : 14.f, - fontWeight: FontWeight.w600, - borderRadius: 12.r, - padding: EdgeInsets.symmetric(horizontal: 10.w), - // height: isTablet || isFoldable ? 46.h : 40.h, - height: 40.h, - icon: AppAssets.ask_doctor_icon, - iconColor: AppColors.primaryRedColor, - iconSize: 16.h, - ), - ), - SizedBox(width: 8.h), - Expanded( - flex: 1, - child: Container( - height: (isFoldable || isTablet) ? 50.h : 40.h, - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.textColor, - borderRadius: 10.h, - side: BorderSide( - color: AppColors.textColor, - width: 1.2, - ), - ), - child: Transform.flip( - flipX: appState.isArabic(), - child: Utils.buildSvgWithAssets( - icon: AppAssets.forward_arrow_icon, - iconColor: AppColors.whiteColor, - width: 24.w, - height: 24.h, - fit: BoxFit.contain, - ), - ), - ).toShimmer2(isShow: isLoading).onPress(() { - _goToDetails(context); - }), - ), - ], - ); - } else { - return CustomButton( - text: isFromMedicalReport ? LocaleKeys.selectAppointment.tr(context: context) : LocaleKeys.viewDetails.tr(context: context), + // if (((patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false) && + // DateTime.now().difference(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate)).inDays <= 15)) { + // return Row( + // children: [ + // Expanded( + // flex: 6, + // child: CustomButton( + // text: LocaleKeys.askDoctor.tr(context: context), + // onPressed: () async { + // LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingDoctorAvailability.tr(context: context)); + // await myAppointmentsViewModel.isDoctorAvailable( + // projectID: patientAppointmentHistoryResponseModel.projectID, + // doctorId: patientAppointmentHistoryResponseModel.doctorID, + // clinicId: patientAppointmentHistoryResponseModel.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: patientAppointmentHistoryResponseModel, + // ), + // callBackFunc: () {}, + // isFullScreen: false, + // isCloseButtonVisible: true, + // ); + // }); + // } else { + // print("Doctor is not available"); + // } + // }); + // }, + // backgroundColor: AppColors.secondaryLightRedColor, + // borderColor: AppColors.secondaryLightRedColor, + // textColor: AppColors.primaryRedColor, + // fontSize: (isFoldable || isTablet) ? 12.f : 14.f, + // fontWeight: FontWeight.w600, + // borderRadius: 12.r, + // padding: EdgeInsets.symmetric(horizontal: 10.w), + // // height: isTablet || isFoldable ? 46.h : 40.h, + // height: 40.h, + // icon: AppAssets.ask_doctor_icon, + // iconColor: AppColors.primaryRedColor, + // iconSize: 16.h, + // ), + // ), + // SizedBox(width: 8.h), + // Expanded( + // flex: 1, + // child: Container( + // height: (isFoldable || isTablet) ? 50.h : 40.h, + // decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + // color: AppColors.textColor, + // borderRadius: 10.h, + // side: BorderSide( + // color: AppColors.textColor, + // width: 1.2, + // ), + // ), + // child: Transform.flip( + // flipX: appState.isArabic(), + // child: Utils.buildSvgWithAssets( + // icon: AppAssets.forward_arrow_icon, + // iconColor: AppColors.whiteColor, + // width: 24.w, + // height: 24.h, + // fit: BoxFit.contain, + // ), + // ), + // ).toShimmer2(isShow: isLoading).onPress(() { + // _goToDetails(context); + // }), + // ), + // ], + // ); + // } else { + return CustomButton( + text: isFromMedicalReport ? LocaleKeys.selectAppointment.tr(context: context) : LocaleKeys.viewDetails.tr(context: context), onPressed: () { if (isFromMedicalReport) { if (isForFeedback) { @@ -359,7 +359,7 @@ class AppointmentCard extends StatelessWidget { iconColor: AppColors.primaryRedColor, iconSize: 16.h, ); - } + // } } else { if (isFromMedicalReport) { if (isForEyeMeasurements) { @@ -446,53 +446,53 @@ class AppointmentCard extends StatelessWidget { } Widget _getArrivedButton(BuildContext context) { - final isRecent = DateTime.now().difference(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate)).inDays <= 15; - - if (isRecent) { - return CustomButton( - text: LocaleKeys.askDoctor.tr(context: context), - onPressed: () async { - LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingDoctorAvailability.tr(context: context)); - await myAppointmentsViewModel.isDoctorAvailable( - projectID: patientAppointmentHistoryResponseModel.projectID, - doctorId: patientAppointmentHistoryResponseModel.doctorID, - clinicId: patientAppointmentHistoryResponseModel.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: patientAppointmentHistoryResponseModel, - ), - callBackFunc: () {}, - isFullScreen: false, - isCloseButtonVisible: true, - ); - }); - } else { - print("Doctor is not available"); - } - }); - }, - backgroundColor: AppColors.secondaryLightRedColor, - borderColor: AppColors.secondaryLightRedColor, - textColor: AppColors.primaryRedColor, - fontSize: (isFoldable || isTablet) ? 12.f : 14.f, - fontWeight: FontWeight.w600, - borderRadius: 12.r, - padding: EdgeInsets.symmetric(horizontal: 10.w), - // height: isTablet || isFoldable ? 46.h : 40.h, - height: 40.h, - icon: AppAssets.ask_doctor_icon, - iconColor: AppColors.primaryRedColor, - iconSize: 16.h, - ); - } + // final isRecent = DateTime.now().difference(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate)).inDays <= 15; + // + // if (isRecent) { + // return CustomButton( + // text: LocaleKeys.askDoctor.tr(context: context), + // onPressed: () async { + // LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingDoctorAvailability.tr(context: context)); + // await myAppointmentsViewModel.isDoctorAvailable( + // projectID: patientAppointmentHistoryResponseModel.projectID, + // doctorId: patientAppointmentHistoryResponseModel.doctorID, + // clinicId: patientAppointmentHistoryResponseModel.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: patientAppointmentHistoryResponseModel, + // ), + // callBackFunc: () {}, + // isFullScreen: false, + // isCloseButtonVisible: true, + // ); + // }); + // } else { + // print("Doctor is not available"); + // } + // }); + // }, + // backgroundColor: AppColors.secondaryLightRedColor, + // borderColor: AppColors.secondaryLightRedColor, + // textColor: AppColors.primaryRedColor, + // fontSize: (isFoldable || isTablet) ? 12.f : 14.f, + // fontWeight: FontWeight.w600, + // borderRadius: 12.r, + // padding: EdgeInsets.symmetric(horizontal: 10.w), + // // height: isTablet || isFoldable ? 46.h : 40.h, + // height: 40.h, + // icon: AppAssets.ask_doctor_icon, + // iconColor: AppColors.primaryRedColor, + // iconSize: 16.h, + // ); + // } return CustomButton( borderSide: BorderSide( diff --git a/lib/presentation/appointments/widgets/appointment_doctor_card.dart b/lib/presentation/appointments/widgets/appointment_doctor_card.dart index 474878ef..4b5df07b 100644 --- a/lib/presentation/appointments/widgets/appointment_doctor_card.dart +++ b/lib/presentation/appointments/widgets/appointment_doctor_card.dart @@ -126,7 +126,7 @@ class AppointmentDoctorCard extends StatelessWidget { DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false, )}" - .toText10(isEnglishOnly: true), + .toText10(isBold: true), ), ), AppCustomChipWidget( diff --git a/lib/presentation/appointments/widgets/ask_doctor_request_type_select.dart b/lib/presentation/appointments/widgets/ask_doctor_request_type_select.dart index 35b15399..bf74863a 100644 --- a/lib/presentation/appointments/widgets/ask_doctor_request_type_select.dart +++ b/lib/presentation/appointments/widgets/ask_doctor_request_type_select.dart @@ -1,5 +1,6 @@ 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_assets.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; @@ -10,6 +11,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/my_appointments_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/services/navigation_service.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; @@ -95,8 +97,8 @@ class AskDoctorRequestTypeSelect extends StatelessWidget { child: CustomButton( text: LocaleKeys.confirm.tr(), onPressed: () async { - Navigator.pop(context); - LoaderBottomSheet.showLoader(loadingText: "Sending Request..."); + Navigator.of(context).pop(); + LoaderBottomSheet.showLoader(loadingText: LocaleKeys.sendingAskDrRequest.tr(context: context)); await myAppointmentsViewModel.sendAskDocCallRequest( patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel, requestType: selectedParameterCodeValue.toString(), @@ -104,17 +106,10 @@ class AskDoctorRequestTypeSelect extends StatelessWidget { userMobileNumber: myAppointmentsViewModel.appState.getAuthenticatedUser()!.mobileNumber!, onSuccess: (val) { LoaderBottomSheet.hideLoader(); - showCommonBottomSheetWithoutHeight( - context, - child: Utils.getSuccessWidget(loadingText: "Request has been sent successfully, you will be contacted soon."), - callBackFunc: () { - Navigator.of(context).pop(); - }, - title: "", - isCloseButtonVisible: true, - isDismissible: false, - isFullScreen: false, - ); + showCommonBottomSheetWithoutHeight(GetIt.instance().navigatorKey.currentContext!, + child: Padding(padding: EdgeInsets.symmetric(horizontal: 24.h), child: Utils.getSuccessWidget(loadingText: LocaleKeys.askDrRequestSentSuccess.tr())), callBackFunc: () { + Navigator.of(context).pop(); + }, title: "", isCloseButtonVisible: false, isDismissible: false, isFullScreen: false, isAutoDismiss: true); }, onError: (errMessage) { LoaderBottomSheet.hideLoader(); diff --git a/lib/presentation/authentication/saved_login_screen.dart b/lib/presentation/authentication/saved_login_screen.dart index ffa5f529..6d326939 100644 --- a/lib/presentation/authentication/saved_login_screen.dart +++ b/lib/presentation/authentication/saved_login_screen.dart @@ -92,7 +92,7 @@ class _SavedLogin extends State { Container( padding: EdgeInsets.all(16.h), - decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: false, isCustomShadow: [ + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: false, isCustomShadow: [ BoxShadow(color: Color(0x0D000000), blurRadius: 16.h, offset: Offset(0, 0), spreadRadius: 5.h), ]), child: Column( diff --git a/lib/presentation/book_appointment/book_appointment_page.dart b/lib/presentation/book_appointment/book_appointment_page.dart index bbc88214..47c4f968 100644 --- a/lib/presentation/book_appointment/book_appointment_page.dart +++ b/lib/presentation/book_appointment/book_appointment_page.dart @@ -355,10 +355,10 @@ class _BookAppointmentPageState extends State { return Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ - Utils.buildSvgWithAssets(icon: AppAssets.add_new_family_icon, height: 64.h, width: 64.h), - SizedBox( - width: 80.w, - child: LocaleKeys.add.tr(context: context).toText12( + Utils.buildSvgWithAssets(icon: AppAssets.add_new_family_icon, height: 64.h, width: 64.h, applyThemeColor: false), + SizedBox( + width: 80.w, + child: LocaleKeys.add.tr(context: context).toText12( color: AppColors.textColor, isBold: true, isCenter: true, diff --git a/lib/presentation/home/data/landing_page_data.dart b/lib/presentation/home/data/landing_page_data.dart index 33b12855..00142c23 100644 --- a/lib/presentation/home/data/landing_page_data.dart +++ b/lib/presentation/home/data/landing_page_data.dart @@ -142,6 +142,16 @@ class LandingPageData { textColor: AppColors.blackColor, isBold: false, ), + ServiceCardData( + serviceName: "my_invoice", + icon: AppAssets.invoiceListIcon, + title: LocaleKeys.invoiceList, + subtitle: LocaleKeys.myDoctorSubtitle, + backgroundColor: AppColors.whiteColor, + iconColor: AppColors.blackColor, + textColor: AppColors.blackColor, + isBold: false, + ), ]; static List get getServiceCardsList => [ diff --git a/lib/presentation/home/widgets/small_service_card.dart b/lib/presentation/home/widgets/small_service_card.dart index ff834204..45023c3b 100644 --- a/lib/presentation/home/widgets/small_service_card.dart +++ b/lib/presentation/home/widgets/small_service_card.dart @@ -16,6 +16,7 @@ import 'package:hmg_patient_app_new/presentation/health_calculators_and_converts import 'package:hmg_patient_app_new/presentation/insurance/insurance_home_page.dart'; import 'package:hmg_patient_app_new/presentation/lab/lab_orders_page.dart'; import 'package:hmg_patient_app_new/presentation/medical_file/patient_sickleaves_list_page.dart'; +import 'package:hmg_patient_app_new/presentation/my_invoices/my_invoices_list.dart'; import 'package:hmg_patient_app_new/presentation/parking/paking_page.dart'; import 'package:hmg_patient_app_new/presentation/prescriptions/prescriptions_list_page.dart'; import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; @@ -92,6 +93,13 @@ class SmallServiceCard extends StatelessWidget { ), ); break; + case "my_invoice": + Navigator.of(context).push( + CustomPageRoute( + page: MyInvoicesList(), + ), + ); + break; case "prescriptions": Navigator.of(context).push( CustomPageRoute( diff --git a/lib/presentation/my_invoices/my_invoices_list.dart b/lib/presentation/my_invoices/my_invoices_list.dart index a935f0d1..5a8e9c70 100644 --- a/lib/presentation/my_invoices/my_invoices_list.dart +++ b/lib/presentation/my_invoices/my_invoices_list.dart @@ -20,6 +20,7 @@ import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.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'; import 'package:provider/provider.dart'; import '../../widgets/buttons/custom_button.dart'; @@ -215,23 +216,36 @@ class _MyInvoicesListState extends State { 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!, + if (Utils.isVidaPlusProject(myInvoicesVM.allInvoicesList[index].projectId ?? 0)) { + LoaderBottomSheet.showLoader(loadingText: LocaleKeys.sendingEmailPleaseWait.tr(context: context)); + await myInvoicesViewModel.sendInvoiceEmail( + appointmentNo: myInvoicesVM.allInvoicesList[index].appointmentNo!, + projectID: myInvoicesVM.allInvoicesList[index].projectId!, + onSuccess: (val) { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight(context, + child: Utils.getSuccessWidget(loadingText: LocaleKeys.emailSentSuccessfullyMessage.tr(context: context)), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + isAutoDismiss: true); + }, + onError: (err) { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight( + context, + child: Utils.getErrorWidget(loadingText: err), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + }); + } else { + LoaderBottomSheet.showLoader(loadingText: LocaleKeys.loadingText.tr(context: context)); + myInvoicesViewModel.downloadInvoicePDF( + setupId: myInvoicesVM.allInvoicesList[index].setupId!, 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( @@ -241,8 +255,56 @@ class _MyInvoicesListState extends State { isFullScreen: false, isCloseButtonVisible: true, ); - }); + }, + onSuccess: (value) async { + LoaderBottomSheet.hideLoader(); + if (myInvoicesViewModel.downloadInvoicePDFBase64!.isNotEmpty) { + String path = await Utils.createFileFromString(myInvoicesViewModel.downloadInvoicePDFBase64!, "pdf"); + try { + OpenFilex.open(path); + } catch (ex) { + showCommonBottomSheetWithoutHeight( + context, + child: Utils.getErrorWidget(loadingText: "Cannot open file"), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + } + } + }, + ); + } }, + // 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, + // ); + // }); + // }, ), ), ), diff --git a/lib/presentation/my_invoices/widgets/invoice_list_card.dart b/lib/presentation/my_invoices/widgets/invoice_list_card.dart index 3aacb85c..42d2fd92 100644 --- a/lib/presentation/my_invoices/widgets/invoice_list_card.dart +++ b/lib/presentation/my_invoices/widgets/invoice_list_card.dart @@ -140,7 +140,8 @@ class InvoiceListCard extends StatelessWidget { ), SizedBox(height: 16.h), CustomButton( - text: LocaleKeys.viewInvoiceDetails.tr(context: context), + // text: LocaleKeys.viewInvoiceDetails.tr(context: context), + text: Utils.isVidaPlusProject(getInvoicesListResponseModel.projectId ?? 0) ? LocaleKeys.sendEmail.tr(context: context) : LocaleKeys.downloadInvoice.tr(context: context), onPressed: () { if (onTap != null) { onTap!(); diff --git a/lib/presentation/profile_settings/widgets/preferred_language_widget.dart b/lib/presentation/profile_settings/widgets/preferred_language_widget.dart index 5b6fe7f9..4cecc651 100644 --- a/lib/presentation/profile_settings/widgets/preferred_language_widget.dart +++ b/lib/presentation/profile_settings/widgets/preferred_language_widget.dart @@ -47,9 +47,9 @@ class _PreferredLanguageWidgetState extends State { decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true), child: Column( children: [ - languageItem("English", "2"), - 1.divider, languageItem("العربية", "1"), + 1.divider, + languageItem("English", "2"), ], ), ), @@ -104,7 +104,7 @@ class _PreferredLanguageWidgetState extends State { }, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, ), - title.toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1, fontFamily: _value == "1" ? 'GESSTwo' : 'Poppins').expanded, + title.toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1, fontFamily: _value == "1" ? 'CairoArabic' : 'Poppins').expanded, ], ).paddingOnly(left: 16, right: 16).onPress(() { setState(() { diff --git a/lib/widgets/app_language_change.dart b/lib/widgets/app_language_change.dart index a6769b3e..f041cd85 100644 --- a/lib/widgets/app_language_change.dart +++ b/lib/widgets/app_language_change.dart @@ -103,7 +103,7 @@ class _AppLanguageChangeState extends State { }, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, ), - title.toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1, fontFamily: _value == "ar" ? 'GESSTwo' : 'Poppins').expanded, + title.toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1, fontFamily: _value == "ar" ? 'CairoArabic' : 'Poppins').expanded, ], ).paddingOnly(left: 16, right: 16).onPress(() { setState(() { diff --git a/lib/widgets/common_bottom_sheet.dart b/lib/widgets/common_bottom_sheet.dart index 85d50b48..d47971d7 100644 --- a/lib/widgets/common_bottom_sheet.dart +++ b/lib/widgets/common_bottom_sheet.dart @@ -238,7 +238,7 @@ void showCommonBottomSheetWithoutHeight( duration: Duration(milliseconds: 500), reverseDuration: Duration(milliseconds: 300), ), - constraints: BoxConstraints(maxWidth: MediaQuery.sizeOf(context).width //MediaQuery.of(context).size.width, // Full width + constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width //MediaQuery.of(context).size.width, // Full width ), context: context, isScrollControlled: true, From f472bd49f43d733ea0c3cd7af1a8ff15bbe306da Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Thu, 9 Apr 2026 11:26:24 +0300 Subject: [PATCH 10/11] Updates --- .../appointment_details_page.dart | 6 ++-- .../widgets/appointment_card.dart | 34 +++++++++++++++++-- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/lib/presentation/appointments/appointment_details_page.dart b/lib/presentation/appointments/appointment_details_page.dart index 31cd5403..c668ebff 100644 --- a/lib/presentation/appointments/appointment_details_page.dart +++ b/lib/presentation/appointments/appointment_details_page.dart @@ -912,9 +912,9 @@ class _AppointmentDetailsPageState extends State { ], ).paddingOnly(left: 16.h, top: 24.h, right: 16.h, bottom: 0.h), AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel) - ? - (widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment! || - widget.patientAppointmentHistoryResponseModel.isExecludeDoctor! || + ? (!(widget.patientAppointmentHistoryResponseModel.isActiveDoctor ?? true) || + widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment! || + widget.patientAppointmentHistoryResponseModel.isExecludeDoctor! || !Utils.isClinicAllowedForRebook(widget.patientAppointmentHistoryResponseModel.clinicID)) ? SizedBox.shrink() : CustomButton( diff --git a/lib/presentation/appointments/widgets/appointment_card.dart b/lib/presentation/appointments/widgets/appointment_card.dart index 4f50bae9..0542f76d 100644 --- a/lib/presentation/appointments/widgets/appointment_card.dart +++ b/lib/presentation/appointments/widgets/appointment_card.dart @@ -390,8 +390,9 @@ class AppointmentCard extends StatelessWidget { ); } } - return Row( - children: [ + return (patientAppointmentHistoryResponseModel.isActiveDoctor ?? true) + ? Row( + children: [ Expanded( flex: 6, child: (AppointmentType.isArrived(patientAppointmentHistoryResponseModel) @@ -441,7 +442,34 @@ class AppointmentCard extends StatelessWidget { }), ), ], - ); + ) + : CustomButton( + text: LocaleKeys.viewDetails.tr(context: context), + onPressed: () { + Navigator.of(context) + .push( + CustomPageRoute( + page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel), + ), + ) + .then((_) { + myAppointmentsViewModel.initAppointmentsViewModel(); + myAppointmentsViewModel.getPatientAppointments(true, false); + }); + }, + backgroundColor: AppColors.secondaryLightRedColor, + borderColor: AppColors.secondaryLightRedColor, + textColor: AppColors.primaryRedColor, + fontSize: (isFoldable || isTablet) ? 12.f : 14.f, + fontWeight: FontWeight.w600, + borderRadius: 12.r, + padding: EdgeInsets.symmetric(horizontal: 10.w), + // height: isTablet || isFoldable ? 46.h : 40.h, + height: 40.h, + icon: isFromMedicalReport ? AppAssets.checkmark_icon : null, + iconColor: AppColors.primaryRedColor, + iconSize: 16.h, + ); } } From 6a687f4ff63303211646d30a3f8401fd79607b13 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Thu, 9 Apr 2026 12:37:45 +0300 Subject: [PATCH 11/11] Updates & fixes --- .../patient_queue_details_response_model.dart | 7 +++- .../my_appointments/my_appointments_repo.dart | 3 +- .../my_appointments_view_model.dart | 31 +++++++++++++- lib/presentation/home/landing_page.dart | 41 +++++++++++++++++-- 4 files changed, 74 insertions(+), 8 deletions(-) diff --git a/lib/features/my_appointments/models/resp_models/patient_queue_details_response_model.dart b/lib/features/my_appointments/models/resp_models/patient_queue_details_response_model.dart index c36b9ec5..8ad174ff 100644 --- a/lib/features/my_appointments/models/resp_models/patient_queue_details_response_model.dart +++ b/lib/features/my_appointments/models/resp_models/patient_queue_details_response_model.dart @@ -6,6 +6,7 @@ class PatientQueueDetails { String? roomNo; String? calledOn; bool? servingNow; + int? isClinicConfigured; PatientQueueDetails( {this.patientID, @@ -14,7 +15,7 @@ class PatientQueueDetails { this.callType, this.roomNo, this.calledOn, - this.servingNow}); + this.servingNow, this.isClinicConfigured}); PatientQueueDetails.fromJson(Map json) { patientID = json['patientID']; @@ -24,10 +25,11 @@ class PatientQueueDetails { roomNo = json['roomNo']; calledOn = json['calledOn']; servingNow = json['servingNow']; + isClinicConfigured = json['isClinicConfigured']; } Map toJson() { - final Map data = new Map(); + final Map data = Map(); data['patientID'] = this.patientID; data['patientName'] = this.patientName; data['queueNo'] = this.queueNo; @@ -35,6 +37,7 @@ class PatientQueueDetails { data['roomNo'] = this.roomNo; data['calledOn'] = this.calledOn; data['servingNow'] = this.servingNow; + data['isClinicConfigured'] = this.isClinicConfigured; return data; } } diff --git a/lib/features/my_appointments/my_appointments_repo.dart b/lib/features/my_appointments/my_appointments_repo.dart index 2c9391a4..7344bc22 100644 --- a/lib/features/my_appointments/my_appointments_repo.dart +++ b/lib/features/my_appointments/my_appointments_repo.dart @@ -834,7 +834,7 @@ class MyAppointmentsRepoImp implements MyAppointmentsRepo { @override Future>>> getPatientAppointmentQueueDetails({required int appointmentNo, required int patientID, required int clinicID}) async { - Map mapDevice = {"appointmentNo": appointmentNo, "patientID": patientID, "ClinicID": clinicID, "apiKey": "EE17D21C7943485D9780223CCE55DCE5"}; + Map mapDevice = {"appointmentNo": appointmentNo, "patientID": patientID, "clinicID": clinicID, "apiKey": "EE17D21C7943485D9780223CCE55DCE5"}; try { GenericApiModel>? apiResponse; Failure? failure; @@ -842,6 +842,7 @@ class MyAppointmentsRepoImp implements MyAppointmentsRepo { failure = failureType; }, onSuccess: (response, statusCode, {messageStatus, errorMessage}) { try { + // final list = response['data']; final list = response['data']; final queueList = list.map((item) => PatientQueueDetails.fromJson(item as Map)).toList().cast(); diff --git a/lib/features/my_appointments/my_appointments_view_model.dart b/lib/features/my_appointments/my_appointments_view_model.dart index 5db21aee..a6f306ba 100644 --- a/lib/features/my_appointments/my_appointments_view_model.dart +++ b/lib/features/my_appointments/my_appointments_view_model.dart @@ -929,6 +929,7 @@ class MyAppointmentsViewModel extends ChangeNotifier { //TODO: Discuss With Haroon, Is the User Has no data it return No Element Bad State; isPatientHasQueueAppointment = false; isAppointmentQueueDetailsLoading = true; + patientQueueDetailsList.clear(); notifyListeners(); final result = await myAppointmentsRepo.getPatientAppointmentQueueDetails( @@ -949,8 +950,32 @@ class MyAppointmentsViewModel extends ChangeNotifier { onError!(apiResponse.errorMessage!); } else if (apiResponse.messageStatus == 1) { if (apiResponse.data != null && apiResponse.data!.isNotEmpty) { - isPatientHasQueueAppointment = true; patientQueueDetailsList = apiResponse.data!; + + if (patientQueueDetailsList.first.isClinicConfigured == 1) { + isPatientHasQueueAppointment = true; + for (var element in patientQueueDetailsList) { + if (element.patientID == patientArrivedAppointmentsHistoryList.first.patientID) { + currentPatientQueueDetails = element; + currentQueueStatus = element.callType!; + // currentQueueStatus = 2; + break; + } + } + // patientQueueDetailsList.first.callType = 1; + patientQueueDetailsList.removeWhere((element) => element.patientID == patientArrivedAppointmentsHistoryList.first.patientID); + } else { + isPatientHasQueueAppointment = false; + } + } else { + isPatientHasQueueAppointment = false; + } + + if (apiResponse.data != null && apiResponse.data!.isNotEmpty) { + patientQueueDetailsList = apiResponse.data!; + + // if (patientQueueDetailsList.first.isClinicConfigured == 1) { + isPatientHasQueueAppointment = true; for (var element in patientQueueDetailsList) { if (element.patientID == patientArrivedAppointmentsHistoryList.first.patientID) { currentPatientQueueDetails = element; @@ -960,8 +985,10 @@ class MyAppointmentsViewModel extends ChangeNotifier { } } // patientQueueDetailsList.first.callType = 1; - patientQueueDetailsList.removeWhere((element) => element.patientID == patientArrivedAppointmentsHistoryList.first.patientID); + // } else { + // isPatientHasQueueAppointment = false; + // } } else { isPatientHasQueueAppointment = false; } diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index 1d7e3777..3f2dcaf6 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.dart @@ -104,9 +104,13 @@ class _LandingPageState extends State { final ScrollController _horizontalScrollController = ScrollController(); + final ScrollController _scrollController = ScrollController(); + double _scrollOpacity = 0.0; + @override void dispose() { _horizontalScrollController.dispose(); + _scrollController.dispose(); super.dispose(); } @@ -122,6 +126,17 @@ class _LandingPageState extends State { showQuickLogin(context); }); } + + _scrollController.addListener(() { + final scrollOffset = _scrollController.offset; + final newOpacity = (scrollOffset / 50).clamp(0.0, 1.0); + if (_scrollOpacity != newOpacity) { + setState(() { + _scrollOpacity = newOpacity; + }); + } + }); + scheduleMicrotask(() async { if (!appState.isAuthenticated) { // LoaderBottomSheet.showLoader(); @@ -203,6 +218,7 @@ class _LandingPageState extends State { } }, child: SingleChildScrollView( + controller: _scrollController, physics: const AlwaysScrollableScrollPhysics(), padding: EdgeInsets.only( top: (appState.isAuthenticated && !insuranceVM.isInsuranceLoading && insuranceVM.isInsuranceExpired && insuranceVM.isInsuranceExpiryBannerShown) @@ -701,8 +717,8 @@ class _LandingPageState extends State { itemBuilder: (context, index) { return AnimationConfiguration.staggeredList( position: index, - duration: const Duration(milliseconds: 1000), - child: SlideAnimation( + duration: const Duration(milliseconds: 500), + child: SlideAnimation( horizontalOffset: 100.0, child: FadeInAnimation( child: SmallServiceCard( @@ -833,6 +849,25 @@ class _LandingPageState extends State { ), ), ), + AnimatedOpacity( + opacity: _scrollOpacity, + duration: Duration(milliseconds: 200), + child: Container( + height: MediaQuery.paddingOf(context).top + 10.h, + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + AppColors.scaffoldBgColor, + AppColors.scaffoldBgColor.withValues(alpha: 0.9), + AppColors.scaffoldBgColor.withValues(alpha: 0.0), + ], + stops: [0.0, 0.7, 1.0], + ), + ), + ), + ), (appState.isAuthenticated && !insuranceVM.isInsuranceLoading && insuranceVM.isInsuranceExpired && insuranceVM.isInsuranceExpiryBannerShown) ? Container( height: MediaQuery.paddingOf(context).top + 50.h, @@ -1042,7 +1077,7 @@ class _LandingPageState extends State { // Queue Card: Currently serving section Widget _buildServingNowSection() { if (myAppointmentsViewModel.patientQueueDetailsList.isEmpty) { - return SizedBox(height: 12.h); + return SizedBox(height: 24.h); } final servingQueue = myAppointmentsViewModel.patientQueueDetailsList.first;