From 63fd82407e4e1d3805b801148ad3792cf41cafe8 Mon Sep 17 00:00:00 2001 From: faizatflutter Date: Tue, 28 Apr 2026 14:40:18 +0300 Subject: [PATCH] Symptoms checker flow updates and Design Fixes on Fold --- lib/core/api/api_client.dart | 4 +- lib/core/api_consts.dart | 42 +++- .../symptoms_checker_repo.dart | 12 +- .../symptoms_checker_view_model.dart | 54 ++++- .../book_appointment/doctor_profile_page.dart | 212 ++++++++++-------- .../widgets/appointment_calendar.dart | 4 +- .../health_calculator_detailed_page.dart | 78 +++---- .../health_calculators_page.dart | 43 ++-- .../widgets/blood_cholesterol.dart | 53 +++-- .../widgets/triglycerides.dart | 58 ++--- .../organ_selector_screen.dart | 28 ++- .../symptoms_checker/triage_screen.dart | 67 ++++-- .../pages/height_selection_page.dart | 21 +- .../widgets/height_scale.dart | 9 +- .../ancillary_procedures_details_page.dart | 44 +--- lib/widgets/appbar/collapsing_list_view.dart | 56 +++-- 16 files changed, 444 insertions(+), 341 deletions(-) diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index 34f56efe..5172f77b 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -17,7 +17,6 @@ import 'package:hmg_patient_app_new/services/navigation_service.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:http/http.dart' as http; - abstract class ApiClient { static final NavigationService _navigationService = getIt.get(); @@ -209,7 +208,7 @@ class ApiClientImp implements ApiClient { // body['PatientOutSA'] = 0; // body['SessionID'] = "45786230487560q"; - //VIP Patient: 1181868 + //VIP Patient: 1181868body: // body['IdentificationNo'] = "2235558844"; // body['MobileNo'] = "966533147722"; @@ -244,6 +243,7 @@ class ApiClientImp implements ApiClient { http.Response response; try { response = await http.post(Uri.parse(url.trim()), body: requestBody, headers: headers); + debugPrint("response: ${response.body}", wrapWidth: 2048); } on SocketException catch (e) { final message = e.message.contains('Connection reset by peer') ? LocaleKeys.networkConnectionReset.tr() : LocaleKeys.networkErrorMessage.tr(); onFailure(message, -1, failureType: ConnectivityFailure(message)); diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index 29c690e1..a8f8c2fb 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -11,8 +11,14 @@ class ApiConsts { static String baseUrl = 'https://hmgwebservices.com/'; // HIS API URL PROD static String rcBaseUrl = 'https://rc.hmg.com/'; // dRC API URL PROD - static String hmgPharmacyApiBaseUrl = 'https://hmgpharmacyapi.hmg.com/'; // dRC API URL PROD - static String symptomsCheckerApi = '${hmgPharmacyApiBaseUrl}symptomsapi/api/SymptomChecker'; // dRC API URL PROD + static String hmgPharmacyApiBaseUrl = 'https://hmgpharmacyapi.hmg.com/'; // symptoms API URL PROD + static String symptomsCheckerApiUAT = '${hmgPharmacyApiBaseUrl}symptomsapi/api/SymptomChecker'; // dRC API URL PROD + static String symptomsCheckerApiLive = '${hmgPharmacyApiBaseUrl}symptomsapi_live/api/SymptomChecker'; // dRC API URL PROD + static String symptomsCheckerApi = '${hmgPharmacyApiBaseUrl}symptomsapi_live/api/SymptomChecker'; // dRC API URL PROD + + // Symptoms Checker Credentials + static String symptomsCheckerUsername = 'mobile_user'; + static String symptomsCheckerPassword = '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92'; static var payFortEnvironment = FortEnvironment.production; static var applePayMerchantId = "merchant.com.hmgwebservices"; @@ -25,6 +31,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="; @@ -47,6 +54,10 @@ class ApiConsts { rcBaseUrl = 'https://rc.hmg.com/'; QLINE_URL = "https://qline.hmg.com/api/PatientCall/PatientInQueue_Detail"; CHAT_URL = "https://chat.hmg.com/Index.aspx?RequestedId="; + symptomsCheckerApi = symptomsCheckerApiLive; + symptomsCheckerUsername = 'mobile_user'; + symptomsCheckerPassword = '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92'; + break; case AppEnvironmentTypeEnum.dev: baseUrl = "https://uat.hmgwebservices.com/"; @@ -59,6 +70,10 @@ class ApiConsts { rcBaseUrl = 'https://rc.hmg.com/uat/'; QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail"; CHAT_URL = "https://chat.hmg.com/geneysChat/Index.aspx?RequestedId="; + symptomsCheckerApi = symptomsCheckerApiUAT; + symptomsCheckerUsername = 'guest_user'; + symptomsCheckerPassword = '123456'; + break; case AppEnvironmentTypeEnum.uat: baseUrl = "https://uat.hmgwebservices.com/"; @@ -71,6 +86,10 @@ class ApiConsts { rcBaseUrl = 'https://rc.hmg.com/uat/'; QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail"; CHAT_URL = "https://chat.hmg.com/geneysChat/Index.aspx?RequestedId="; + symptomsCheckerApi = symptomsCheckerApiUAT; + symptomsCheckerUsername = 'guest_user'; + symptomsCheckerPassword = '123456'; + break; case AppEnvironmentTypeEnum.preProd: baseUrl = "https://webservices.hmg.com/"; @@ -83,6 +102,10 @@ class ApiConsts { rcBaseUrl = 'https://rc.hmg.com/'; QLINE_URL = "https://qline.hmg.com/api/PatientCall/PatientInQueue_Detail"; CHAT_URL = "https://chat.hmg.com/geneysChat/Index.aspx?RequestedId="; + symptomsCheckerApi = symptomsCheckerApiUAT; + symptomsCheckerUsername = 'guest_user'; + symptomsCheckerPassword = '123456'; + break; case AppEnvironmentTypeEnum.qa: baseUrl = "https://uat.hmgwebservices.com/"; @@ -95,6 +118,10 @@ class ApiConsts { rcBaseUrl = 'https://rc.hmg.com/uat/'; QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail"; CHAT_URL = "https://chat.hmg.com/geneysChat/Index.aspx?RequestedId="; + symptomsCheckerApi = symptomsCheckerApiUAT; + symptomsCheckerUsername = 'guest_user'; + symptomsCheckerPassword = '123456'; + break; case AppEnvironmentTypeEnum.staging: baseUrl = "https://uat.hmgwebservices.com/"; @@ -107,6 +134,10 @@ class ApiConsts { rcBaseUrl = 'https://rc.hmg.com/uat/'; QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail"; CHAT_URL = "https://chat.hmg.com/geneysChat/Index.aspx?RequestedId="; + symptomsCheckerApi = symptomsCheckerApiUAT; + symptomsCheckerUsername = 'guest_user'; + symptomsCheckerPassword = '123456'; + break; } } @@ -189,7 +220,6 @@ class ApiConsts { static final createEReferral = "Services/Patients.svc/REST/CreateEReferral"; static final getEReferrals = "Services/Patients.svc/REST/GetEReferrals"; - //WATER CONSUMPTION static String h2oGetUserProgress = "Services/H2ORemainder.svc/REST/H2O_GetUserProgress"; static String h2oInsertUserActivity = "Services/H2ORemainder.svc/REST/H2O_InsertUserActivity"; @@ -235,6 +265,7 @@ class ApiConsts { static String getPatientBloodGroup = "services/PatientVarification.svc/REST/BloodDonation_GetBloodGroupDetails"; static String getPatientBloodAgreement = "Services/PatientVarification.svc/REST/CheckUserAgreementForBloodDonation"; static String getPatientBloodTypeNew = "Services/Patients.svc/REST/HIS_GetPatientBloodType_New"; + // static String getAiOverViewLabOrders = "Services/Patients.svc/REST/HMGAI_Lab_Analyze_Orders_API"; // static String getAiOverViewLabOrder = "Services/Patients.svc/REST/HMGAI_Lab_Analyzer_API"; @@ -806,7 +837,8 @@ var GET_CUSTOMER_INFO = "VerifyCustomer"; //Pharmacy -var GET_PHARMACY_CATEGORISE = 'categories?fields=id,name,namen,description,image,localized_names,display_order,parent_category_id,is_leaf&parent_id=0'; +var GET_PHARMACY_CATEGORISE = + 'categories?fields=id,name,namen,description,image,localized_names,display_order,parent_category_id,is_leaf&parent_id=0'; var GET_OFFERS_CATEGORISE = 'discountcategories'; var GET_OFFERS_PRODUCTS = 'offerproducts/'; var GET_CATEGORISE_PARENT = 'categories?fields=id,name,namen,description,image,localized_names,display_order,parent_category_id,is_leaf&parent_id='; @@ -834,7 +866,7 @@ var FILTERED_PRODUCTS = 'products?categoryids='; var GET_DOCTOR_LIST_CALCULATION = "Services/Doctors.svc/REST/GetCallculationDoctors"; // var GET_ALL_APPOINTMENTS_FOR_DENTAL_CLINIC = "Services/Patients.svc/REST/GetDentalAppointments"; -var GET_ALL_APPOINTMENTS_FOR_DENTAL_CLINIC ='Services/Patients.svc/REST/GetAllInvoices'; +var GET_ALL_APPOINTMENTS_FOR_DENTAL_CLINIC = 'Services/Patients.svc/REST/GetAllInvoices'; var GET_DENTAL_APPOINTMENT_INVOICE = "Services/Patients.svc/REST/HIS_eInvoiceForDentalByAppointmentNo"; var SEND_DENTAL_APPOINTMENT_INVOICE_EMAIL = "Services/Notifications.svc/REST/SendInvoiceForDental"; diff --git a/lib/features/symptoms_checker/symptoms_checker_repo.dart b/lib/features/symptoms_checker/symptoms_checker_repo.dart index 499a1c59..f8282418 100644 --- a/lib/features/symptoms_checker/symptoms_checker_repo.dart +++ b/lib/features/symptoms_checker/symptoms_checker_repo.dart @@ -17,6 +17,7 @@ abstract class SymptomsCheckerRepo { Future>> getUserDetails({ required String userName, required String password, + String? fileNo, }); Future>> getBodySymptomsByName({ @@ -70,8 +71,17 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo { Future>> getUserDetails({ required String userName, required String password, + String? fileNo, }) async { - Map body = {"userName": userName, "password": password}; + Map body = { + "userName": userName, + "password": password, + }; + + // Add fileNo only if provided (user is logged in) + if (fileNo != null && fileNo.isNotEmpty) { + body["fileNo"] = fileNo; + } try { GenericApiModel? apiResponse; diff --git a/lib/features/symptoms_checker/symptoms_checker_view_model.dart b/lib/features/symptoms_checker/symptoms_checker_view_model.dart index 8e949533..4aba984d 100644 --- a/lib/features/symptoms_checker/symptoms_checker_view_model.dart +++ b/lib/features/symptoms_checker/symptoms_checker_view_model.dart @@ -76,6 +76,10 @@ class SymptomsCheckerViewModel extends ChangeNotifier { final List> _triageEvidenceList = []; // Store triage evidence with proper format int _triageQuestionCount = 0; // Track number of triage questions answered + // For type=1 questions: single selection across all items + String? _selectedSingleItemId; // Store which item was selected + int? _selectedSingleChoiceIndex; // Store which choice was selected + // Selected risk factors tracking final Set _selectedRiskFactorIds = {}; @@ -170,12 +174,35 @@ class SymptomsCheckerViewModel extends ChangeNotifier { return _selectedTriageChoicesByItemId[itemId]; } + /// Check if current question type is single selection (type=1) + bool get isTriageQuestionSingleSelection => currentTriageQuestion?.type == 1; + + /// Check if current question type is multi-item selection (type=2) + bool get isTriageQuestionMultiItem => currentTriageQuestion?.type == 2; + + /// For type=1 questions: check if a specific item-choice combination is selected + bool isTriageSingleOptionSelected(String itemId, int choiceIndex) { + return _selectedSingleItemId == itemId && _selectedSingleChoiceIndex == choiceIndex; + } + + /// Get selected item ID for type=1 questions + String? get selectedSingleItemId => _selectedSingleItemId; + + /// Get selected choice index for type=1 questions + int? get selectedSingleChoiceIndex => _selectedSingleChoiceIndex; + /// Check if all items in current question have been answered bool get areAllTriageItemsAnswered { if (currentTriageQuestion?.items == null || currentTriageQuestion!.items!.isEmpty) { return false; } + // Type 1: Single selection mode - check if any option is selected + if (isTriageQuestionSingleSelection) { + return _selectedSingleItemId != null && _selectedSingleChoiceIndex != null; + } + + // Type 2: Multi-item selection mode - check if all items have answers // Check if we have an answer for each item for (var item in currentTriageQuestion!.items!) { if (item.id != null && !_selectedTriageChoicesByItemId.containsKey(item.id)) { @@ -277,7 +304,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier { } } - toggleZoomOut(){ + toggleZoomOut() { if (_currentZoomScale > _minZoomScale) { _currentZoomScale = (_currentZoomScale - _zoomStep).clamp(_minZoomScale, _maxZoomScale); notifyListeners(); @@ -846,7 +873,21 @@ class SymptomsCheckerViewModel extends ChangeNotifier { /// Select a choice for a specific item (for multi-item questions) void selectTriageChoiceForItem(String itemId, int choiceIndex) { - _selectedTriageChoicesByItemId[itemId] = choiceIndex; + // Type 1: Single selection mode - only one option can be selected across all items + if (isTriageQuestionSingleSelection) { + // If same option clicked again, deselect it + if (_selectedSingleItemId == itemId && _selectedSingleChoiceIndex == choiceIndex) { + _selectedSingleItemId = null; + _selectedSingleChoiceIndex = null; + } else { + // Select new option, clear previous selection + _selectedSingleItemId = itemId; + _selectedSingleChoiceIndex = choiceIndex; + } + } else { + // Type 2: Multi-item selection mode - each item can have one selected option + _selectedTriageChoicesByItemId[itemId] = choiceIndex; + } notifyListeners(); } @@ -854,6 +895,8 @@ class SymptomsCheckerViewModel extends ChangeNotifier { void resetTriageChoice() { _selectedTriageChoiceIndex = null; _selectedTriageChoicesByItemId.clear(); + _selectedSingleItemId = null; + _selectedSingleChoiceIndex = null; _triageQuestionCount++; // Increment question count notifyListeners(); } @@ -1018,12 +1061,17 @@ class SymptomsCheckerViewModel extends ChangeNotifier { Future getSymptomsUserDetails({ required String userName, required String password, + String? fileNo, Function()? onSuccess, Function(String)? onError, }) async { isBodySymptomsLoading = true; notifyListeners(); - final result = await symptomsCheckerRepo.getUserDetails(userName: userName, password: password); + final result = await symptomsCheckerRepo.getUserDetails( + userName: userName, + password: password, + fileNo: fileNo, + ); result.fold( (failure) async { diff --git a/lib/presentation/book_appointment/doctor_profile_page.dart b/lib/presentation/book_appointment/doctor_profile_page.dart index 29e1c824..137aaa09 100644 --- a/lib/presentation/book_appointment/doctor_profile_page.dart +++ b/lib/presentation/book_appointment/doctor_profile_page.dart @@ -1,6 +1,5 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; -import 'package:intl/intl.dart' show NumberFormat; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/dependencies.dart'; @@ -13,8 +12,8 @@ import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_vie import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/appointment_calendar.dart'; import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/doctor_rating_details.dart'; -import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.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:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; @@ -56,7 +55,9 @@ class DoctorProfilePage extends StatelessWidget { doctorID: viewModel.doctorsProfileResponseModel.doctorID ?? 0, isActive: viewModel.isFavouriteDoctor, onSuccess: (response) { - Utils.showToast(viewModel.isFavouriteDoctor ? LocaleKeys.doctorAddedToFavourite.tr(context: context) : LocaleKeys.doctorRemovedFromFavourite.tr(context: context)); + Utils.showToast(viewModel.isFavouriteDoctor + ? LocaleKeys.doctorAddedToFavourite.tr(context: context) + : LocaleKeys.doctorRemovedFromFavourite.tr(context: context)); // Successfully added/removed favorite - refresh the favorites list getIt.get().refreshFavouriteDoctors(); }, @@ -75,7 +76,7 @@ class DoctorProfilePage extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - // SizedBox(height: 24.h), + isFoldable ? SizedBox(height: 24.h) : SizedBox.shrink(), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -87,18 +88,21 @@ class DoctorProfilePage extends StatelessWidget { width: 63.h, height: 63.h, fit: BoxFit.cover, - ).circle(100), + ).circle(100.r), SizedBox(width: 8.h), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( - width: 220.h, - child: ("${bookAppointmentsViewModel.doctorsProfileResponseModel.doctorTitleForProfile} ${bookAppointmentsViewModel.doctorsProfileResponseModel.doctorName}") - .toString() - .toText24(isBold: true), + width: isFoldable ? 250.w : 220.w, + child: + ("${bookAppointmentsViewModel.doctorsProfileResponseModel.doctorTitleForProfile} ${bookAppointmentsViewModel.doctorsProfileResponseModel.doctorName}") + .toString() + .toText24(isBold: true), ), - (bookAppointmentsViewModel.doctorsProfileResponseModel.specialty!.isNotEmpty ? bookAppointmentsViewModel.doctorsProfileResponseModel.specialty!.first : "") + (bookAppointmentsViewModel.doctorsProfileResponseModel.specialty!.isNotEmpty + ? bookAppointmentsViewModel.doctorsProfileResponseModel.specialty!.first + : "") .toString() .toText18(isBold: true, color: AppColors.primaryRedColor), ], @@ -137,12 +141,16 @@ class DoctorProfilePage extends StatelessWidget { children: [ Column( children: [ - Utils.buildSvgWithAssets(icon: AppAssets.doctor_profile_rating_icon, width: 48.w, height: 48.h, fit: BoxFit.contain, applyThemeColor: false), + Utils.buildSvgWithAssets( + icon: AppAssets.doctor_profile_rating_icon, width: 48.w, height: 48.h, fit: BoxFit.contain, applyThemeColor: false), SizedBox(height: 16.h), LocaleKeys.ratings.tr(context: context).toText12(isBold: true, color: AppColors.greyTextColor), - bookAppointmentsViewModel.doctorsProfileResponseModel.decimalDoctorRate - .toString() - .toText16(isBold: true, color: AppColors.textColor, isUnderLine: true, decorationColor: AppColors.textColor, fontFamily: "Poppins"), + bookAppointmentsViewModel.doctorsProfileResponseModel.decimalDoctorRate.toString().toText16( + isBold: true, + color: AppColors.textColor, + isUnderLine: true, + decorationColor: AppColors.textColor, + fontFamily: "Poppins"), ], ).onPress(() { bookAppointmentsViewModel.getDoctorRatingDetails(); @@ -158,11 +166,18 @@ class DoctorProfilePage extends StatelessWidget { SizedBox(width: 36.w), Column( children: [ - Utils.buildSvgWithAssets(icon: AppAssets.doctor_profile_reviews_icon, width: 48.w, height: 48.h, fit: BoxFit.contain, applyThemeColor: false), + Utils.buildSvgWithAssets( + icon: AppAssets.doctor_profile_reviews_icon, width: 48.w, height: 48.h, fit: BoxFit.contain, applyThemeColor: false), SizedBox(height: 16.h), LocaleKeys.reviews.tr(context: context).toText12(isBold: true, color: AppColors.greyTextColor), - NumberFormat.decimalPattern().format(bookAppointmentsViewModel.doctorsProfileResponseModel.noOfPatientsRate ?? 0) - .toText16(isBold: true, color: AppColors.textColor, isUnderLine: true, decorationColor: AppColors.textColor, fontFamily: "Poppins"), + NumberFormat.decimalPattern() + .format(bookAppointmentsViewModel.doctorsProfileResponseModel.noOfPatientsRate ?? 0) + .toText16( + isBold: true, + color: AppColors.textColor, + isUnderLine: true, + decorationColor: AppColors.textColor, + fontFamily: "Poppins"), ], ).onPress(() { bookAppointmentsViewModel.getDoctorRatingDetails(); @@ -182,92 +197,97 @@ class DoctorProfilePage extends StatelessWidget { SizedBox(height: 16.h), LocaleKeys.information.tr(context: context).toText14(isBold: true, color: AppColors.textColor), SizedBox(height: 6.h), - (bookAppointmentsViewModel.doctorsProfileResponseModel.doctorProfileInfo ?? "").trim().toText12(isBold: true, color: AppColors.greyTextColor), + (bookAppointmentsViewModel.doctorsProfileResponseModel.doctorProfileInfo ?? "") + .trim() + .toText12(isBold: true, color: AppColors.greyTextColor), SizedBox(height: 24.h), ], ).paddingSymmetrical(24.h, 0.h), ), ), ), - isDoctorAllowedToBook ? Container( - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 24.h, - hasShadow: true, - ), - child: CustomButton( - text: LocaleKeys.viewAvailableAppointments.tr(), - onPressed: () async { - bookAppointmentsViewModel.selectedDoctor.speciality = bookAppointmentsViewModel.doctorsProfileResponseModel.specialty; - bookAppointmentsViewModel.selectedDoctor.specialityN = bookAppointmentsViewModel.doctorsProfileResponseModel.specialty; - bookAppointmentsViewModel.selectedDoctor.name = bookAppointmentsViewModel.doctorsProfileResponseModel.doctorName; - bookAppointmentsViewModel.selectedDoctor.doctorImageURL = bookAppointmentsViewModel.doctorsProfileResponseModel.doctorImageURL; - bookAppointmentsViewModel.selectedDoctor.nationalityFlagURL = bookAppointmentsViewModel.doctorsProfileResponseModel.nationalityFlagURL; - bookAppointmentsViewModel.selectedDoctor.clinicName = bookAppointmentsViewModel.doctorsProfileResponseModel.clinicDescription; - bookAppointmentsViewModel.selectedDoctor.projectName = bookAppointmentsViewModel.doctorsProfileResponseModel.projectName; + isDoctorAllowedToBook + ? Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24.h, + hasShadow: true, + ), + child: CustomButton( + text: LocaleKeys.viewAvailableAppointments.tr(), + onPressed: () async { + bookAppointmentsViewModel.selectedDoctor.speciality = bookAppointmentsViewModel.doctorsProfileResponseModel.specialty; + bookAppointmentsViewModel.selectedDoctor.specialityN = bookAppointmentsViewModel.doctorsProfileResponseModel.specialty; + bookAppointmentsViewModel.selectedDoctor.name = bookAppointmentsViewModel.doctorsProfileResponseModel.doctorName; + bookAppointmentsViewModel.selectedDoctor.doctorImageURL = bookAppointmentsViewModel.doctorsProfileResponseModel.doctorImageURL; + bookAppointmentsViewModel.selectedDoctor.nationalityFlagURL = + bookAppointmentsViewModel.doctorsProfileResponseModel.nationalityFlagURL; + bookAppointmentsViewModel.selectedDoctor.clinicName = bookAppointmentsViewModel.doctorsProfileResponseModel.clinicDescription; + bookAppointmentsViewModel.selectedDoctor.projectName = bookAppointmentsViewModel.doctorsProfileResponseModel.projectName; - LoaderBottomSheet.showLoader(); - bookAppointmentsViewModel.isLiveCareSchedule - ? await bookAppointmentsViewModel.getLiveCareDoctorFreeSlots( - isBookingForLiveCare: true, - onSuccess: (dynamic respData) async { - LoaderBottomSheet.hideLoader(); - showCommonBottomSheetWithoutHeight( - title: LocaleKeys.pickADate.tr(), - context, - child: AppointmentCalendar(), - isFullScreen: false, - isCloseButtonVisible: true, - callBackFunc: () {}, - ); - }, - onError: (err) { - LoaderBottomSheet.hideLoader(); - showCommonBottomSheetWithoutHeight( - context, - child: Utils.getErrorWidget(loadingText: err), - callBackFunc: () {}, - isFullScreen: false, - isCloseButtonVisible: true, - ); - }) - : await bookAppointmentsViewModel.getDoctorFreeSlots( - isBookingForLiveCare: false, - onSuccess: (dynamic respData) async { - LoaderBottomSheet.hideLoader(); - showCommonBottomSheetWithoutHeight( - title: LocaleKeys.pickADate.tr() , - context, - child: AppointmentCalendar(), - isFullScreen: false, - isCloseButtonVisible: true, - callBackFunc: () {}, - ); - }, - onError: (err) { - LoaderBottomSheet.hideLoader(); - showCommonBottomSheetWithoutHeight( - context, - child: Utils.getErrorWidget(loadingText: err), - callBackFunc: () {}, - isFullScreen: false, - isCloseButtonVisible: true, - ); - }); - }, - backgroundColor: AppColors.primaryRedColor, - borderColor: AppColors.primaryRedColor, - textColor: Colors.white, - fontSize: 16, - isBold: true, - borderRadius: 12, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 50.h, - icon: AppAssets.calendar, - iconColor: Colors.white, - iconSize: 20.h, - ).paddingSymmetrical(24.h, 24.h), - ) : SizedBox.shrink(), + LoaderBottomSheet.showLoader(); + bookAppointmentsViewModel.isLiveCareSchedule + ? await bookAppointmentsViewModel.getLiveCareDoctorFreeSlots( + isBookingForLiveCare: true, + onSuccess: (dynamic respData) async { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight( + title: LocaleKeys.pickADate.tr(), + context, + child: AppointmentCalendar(), + isFullScreen: false, + isCloseButtonVisible: true, + callBackFunc: () {}, + ); + }, + onError: (err) { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight( + context, + child: Utils.getErrorWidget(loadingText: err), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + }) + : await bookAppointmentsViewModel.getDoctorFreeSlots( + isBookingForLiveCare: false, + onSuccess: (dynamic respData) async { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight( + title: LocaleKeys.pickADate.tr(), + context, + child: AppointmentCalendar(), + isFullScreen: false, + isCloseButtonVisible: true, + callBackFunc: () {}, + ); + }, + onError: (err) { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight( + context, + child: Utils.getErrorWidget(loadingText: err), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + }); + }, + backgroundColor: AppColors.primaryRedColor, + borderColor: AppColors.primaryRedColor, + textColor: Colors.white, + fontSize: 16, + isBold: true, + borderRadius: 12, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 50.h, + icon: AppAssets.calendar, + iconColor: Colors.white, + iconSize: 20.h, + ).paddingSymmetrical(24.h, 24.h), + ) + : SizedBox.shrink(), ], ), ); diff --git a/lib/presentation/book_appointment/widgets/appointment_calendar.dart b/lib/presentation/book_appointment/widgets/appointment_calendar.dart index 0b9d9029..544b55c8 100644 --- a/lib/presentation/book_appointment/widgets/appointment_calendar.dart +++ b/lib/presentation/book_appointment/widgets/appointment_calendar.dart @@ -319,9 +319,9 @@ class _AppointmentCalendarState extends State { if (bookAppointmentsViewModel.isWaitingAppointmentAvailable && DateUtils.isSameDay(dateStart, DateTime.now())) { dayEvents.add(TimeSlot(isoTime: LocaleKeys.waitingAppointment.tr(context: context), start: DateTime.now(), end: DateTime.now(), vidaDate: "")); } - freeSlots.forEach((v) { + for (var v in freeSlots) { if (v.start == dateStartObj) dayEvents.add(v); - }); + } selectedButtonIndex = 0; List> timeList = []; for (var i = 0; i < dayEvents.length; i++) { diff --git a/lib/presentation/health_calculators_and_converts/health_calculator_detailed_page.dart b/lib/presentation/health_calculators_and_converts/health_calculator_detailed_page.dart index 3d8a60ee..3f86e380 100644 --- a/lib/presentation/health_calculators_and_converts/health_calculator_detailed_page.dart +++ b/lib/presentation/health_calculators_and_converts/health_calculator_detailed_page.dart @@ -1,9 +1,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; -import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/enums.dart'; import 'package:hmg_patient_app_new/core/utils/size_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/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/book_appointment/select_clinic_page.dart'; @@ -19,7 +17,6 @@ import 'package:hmg_patient_app_new/presentation/health_calculators_and_converts import 'package:hmg_patient_app_new/presentation/health_calculators_and_converts/widgets/ibw.dart'; import 'package:hmg_patient_app_new/presentation/health_calculators_and_converts/widgets/ovulation.dart'; import 'package:hmg_patient_app_new/presentation/health_calculators_and_converts/widgets/triglycerides.dart'; -import 'package:hmg_patient_app_new/services/dialog_service.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'; @@ -27,11 +24,11 @@ import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:provider/provider.dart'; class HealthCalculatorDetailedPage extends StatefulWidget { - HealthCalculatorsTypeEnum calculatorType; - int? clinicID; - int? calculationID; + final HealthCalculatorsTypeEnum calculatorType; + final int? clinicID; + final int? calculationID; - HealthCalculatorDetailedPage({super.key, required this.calculatorType, this.clinicID, this.calculationID}); + const HealthCalculatorDetailedPage({super.key, required this.calculatorType, this.clinicID, this.calculationID}); @override State createState() => _HealthCalculatorDetailedPageState(); @@ -52,8 +49,8 @@ class _HealthCalculatorDetailedPageState extends State createState() => _HealthCalculatorsPageState(); @@ -34,9 +33,8 @@ class _HealthCalculatorsPageState extends State { @override Widget build(BuildContext context) { - DialogService dialogService = getIt.get(); return CollapsingListView( - isLeading: Navigator.canPop(context), + isLeading: Navigator.canPop(context), title: widget.type == HealthCalConEnum.calculator ? LocaleKeys.healthCalculators.tr(context: context) : LocaleKeys.healthConverters.tr(), child: widget.type == HealthCalConEnum.calculator ? CustomExpandableList( @@ -58,7 +56,8 @@ class _HealthCalculatorsPageState extends State { ), ], theme: ExpandableListTheme.custom( - defaultTrailingIcon: Utils.buildSvgWithAssets(icon: AppAssets.arrow_down, height: 22.h, width: 22.w, iconColor: AppColors.textColor), + defaultTrailingIcon: + Utils.buildSvgWithAssets(icon: AppAssets.arrow_down, height: 22.h, width: 22.w, iconColor: AppColors.textColor), ), ).paddingSymmetrical(16.w, 0.0) // ? Column( @@ -129,7 +128,8 @@ class _HealthCalculatorsPageState extends State { child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Utils.buildSvgWithAssets(icon: AppAssets.bloodSugar, height: 40.h, width: 40.w, fit: BoxFit.none, applyThemeColor: false), + Utils.buildSvgWithAssets( + icon: AppAssets.bloodSugar, height: 40.h, width: 40.w, fit: BoxFit.none, applyThemeColor: false), SizedBox(width: 12.w), Flexible( child: Column( @@ -149,7 +149,8 @@ class _HealthCalculatorsPageState extends State { ), Transform.flip( flipX: getIt.get().isArabic(), - child: Utils.buildSvgWithAssets(icon: AppAssets.arrowRight, width: 24.w, height: 24.h, fit: BoxFit.contain, iconColor: AppColors.textColor), + child: Utils.buildSvgWithAssets( + icon: AppAssets.arrowRight, width: 24.w, height: 24.h, fit: BoxFit.contain, iconColor: AppColors.textColor), ), ], ).paddingAll(16.w)) @@ -166,7 +167,8 @@ class _HealthCalculatorsPageState extends State { child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Utils.buildSvgWithAssets(icon: AppAssets.bloodCholestrol, height: 40.h, width: 40.w, fit: BoxFit.none, applyThemeColor: false), + Utils.buildSvgWithAssets( + icon: AppAssets.bloodCholestrol, height: 40.h, width: 40.w, fit: BoxFit.none, applyThemeColor: false), SizedBox(width: 12.w), Flexible( child: Column( @@ -181,7 +183,8 @@ class _HealthCalculatorsPageState extends State { SizedBox(width: 12.w), Transform.flip( flipX: getIt.get().isArabic(), - child: Utils.buildSvgWithAssets(icon: AppAssets.arrowRight, width: 24.w, height: 24.h, fit: BoxFit.contain, iconColor: AppColors.textColor), + child: Utils.buildSvgWithAssets( + icon: AppAssets.arrowRight, width: 24.w, height: 24.h, fit: BoxFit.contain, iconColor: AppColors.textColor), ), ], ).paddingAll(16.w)) @@ -198,7 +201,8 @@ class _HealthCalculatorsPageState extends State { child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Utils.buildSvgWithAssets(icon: AppAssets.triglycerides, height: 40.h, width: 40.w, fit: BoxFit.none, applyThemeColor: false), + Utils.buildSvgWithAssets( + icon: AppAssets.triglycerides, height: 40.h, width: 40.w, fit: BoxFit.none, applyThemeColor: false), SizedBox(width: 12.w), Flexible( child: Column( @@ -213,7 +217,8 @@ class _HealthCalculatorsPageState extends State { SizedBox(width: 12.w), Transform.flip( flipX: getIt.get().isArabic(), - child: Utils.buildSvgWithAssets(icon: AppAssets.arrowRight, width: 24.w, height: 24.h, fit: BoxFit.contain, iconColor: AppColors.textColor), + child: Utils.buildSvgWithAssets( + icon: AppAssets.arrowRight, width: 24.w, height: 24.h, fit: BoxFit.contain, iconColor: AppColors.textColor), ), ], ).paddingAll(16.w)) @@ -247,7 +252,8 @@ class _HealthCalculatorsPageState extends State { page: HealthCalculatorDetailedPage( calculatorType: type == HealthCalculatorEnum.general ? generalHealthServices[index].type : womenHealthServices[index].type, clinicID: type == HealthCalculatorEnum.general ? generalHealthServices[index].clinicID : womenHealthServices[index].clinicID, - calculationID: type == HealthCalculatorEnum.general ? generalHealthServices[index].calculationID : womenHealthServices[index].calculationID, + calculationID: + type == HealthCalculatorEnum.general ? generalHealthServices[index].calculationID : womenHealthServices[index].calculationID, ), ), ); @@ -341,5 +347,14 @@ class HealthComponentModel { int? clinicID; int? calculationID; - HealthComponentModel({required this.title, this.subTitle, required this.icon, this.iconColor, this.bgColor, this.textColor, required this.type, this.clinicID, this.calculationID}); + HealthComponentModel( + {required this.title, + this.subTitle, + required this.icon, + this.iconColor, + this.bgColor, + this.textColor, + required this.type, + this.clinicID, + this.calculationID}); } diff --git a/lib/presentation/health_calculators_and_converts/widgets/blood_cholesterol.dart b/lib/presentation/health_calculators_and_converts/widgets/blood_cholesterol.dart index 14b956e0..5a835561 100644 --- a/lib/presentation/health_calculators_and_converts/widgets/blood_cholesterol.dart +++ b/lib/presentation/health_calculators_and_converts/widgets/blood_cholesterol.dart @@ -1,14 +1,14 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; -import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; -import 'package:provider/provider.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'; 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/theme/colors.dart'; +import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/health_calculators_and_converts/health_calculator_view_model.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:provider/provider.dart'; class BloodCholesterolWidget extends StatefulWidget { final Function(dynamic result)? onChange; @@ -107,7 +107,7 @@ class _BloodCholesterolWidgetState extends State { ], ), _buildInputField( - label:LocaleKeys.mmol.tr(), + label: LocaleKeys.mmol.tr(), hint: "3.1", controller: _mmolController, focusNode: _mmolFocus, @@ -123,7 +123,7 @@ class _BloodCholesterolWidgetState extends State { Utils.buildSvgWithAssets(icon: AppAssets.globe, width: 18.w, height: 18.w), SizedBox(width: 12.w), Expanded( - child:LocaleKeys.convertBloodcholesterolInfo.tr(context: context).toText12(isBold: true, color: AppColors.inputLabelTextColor), + child: LocaleKeys.convertBloodcholesterolInfo.tr(context: context).toText12(isBold: true, color: AppColors.inputLabelTextColor), ), ], ).paddingSymmetrical(0.w, 16.w), @@ -149,29 +149,26 @@ class _BloodCholesterolWidgetState extends State { isBold: true, color: AppColors.inputLabelTextColor, ), - SizedBox( - height: 40.h, - child: TextField( - controller: controller, - focusNode: focusNode, - keyboardType: const TextInputType.numberWithOptions(decimal: true), - maxLines: 1, - onChanged: onChanged, - cursorHeight: 35.h, - textAlignVertical: TextAlignVertical.center, - decoration: InputDecoration( - border: InputBorder.none, - contentPadding: EdgeInsets.zero, - isCollapsed: true, - hintText: hint, - hintStyle: const TextStyle(color: Colors.grey), - ), - style: TextStyle( - fontSize: 32.f, - fontWeight: FontWeight.bold, - color: Colors.black87, - height: 1.h, - ), + TextField( + controller: controller, + focusNode: focusNode, + keyboardType: const TextInputType.numberWithOptions(decimal: true), + maxLines: 1, + onChanged: onChanged, + cursorHeight: 35.h, + textAlignVertical: TextAlignVertical.center, + decoration: InputDecoration( + border: InputBorder.none, + contentPadding: EdgeInsets.zero, + isCollapsed: true, + hintText: hint, + hintStyle: const TextStyle(color: Colors.grey), + ), + style: TextStyle( + fontSize: 32.f, + fontWeight: FontWeight.bold, + color: Colors.black87, + height: 1.h, ), ), ], diff --git a/lib/presentation/health_calculators_and_converts/widgets/triglycerides.dart b/lib/presentation/health_calculators_and_converts/widgets/triglycerides.dart index dd5eb0f0..724a99eb 100644 --- a/lib/presentation/health_calculators_and_converts/widgets/triglycerides.dart +++ b/lib/presentation/health_calculators_and_converts/widgets/triglycerides.dart @@ -1,14 +1,14 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; -import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; -import 'package:provider/provider.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'; 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/theme/colors.dart'; +import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/health_calculators_and_converts/health_calculator_view_model.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:provider/provider.dart'; class TriglyceridesWidget extends StatefulWidget { final Function(dynamic result)? onChange; @@ -91,7 +91,6 @@ class _TriglyceridesWidgetState extends State { provider.onTriglyceridesMgdlChanged(value); }, ).paddingOnly(top: 16.h), - Row( children: [ const Expanded( @@ -111,7 +110,6 @@ class _TriglyceridesWidgetState extends State { }), ], ), - _buildInputField( label: LocaleKeys.mmol, hint: "1.7", @@ -122,9 +120,7 @@ class _TriglyceridesWidgetState extends State { provider.onTriglyceridesMmolChanged(value); }, ).paddingOnly(bottom: 16.h), - const Divider(height: 1, color: Color(0xFFEEEEEE)), - Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -135,12 +131,10 @@ class _TriglyceridesWidgetState extends State { ), SizedBox(width: 12.w), Expanded( - child: - LocaleKeys.triglycerideInfo.tr() - .toText12( - isBold: true, - color: AppColors.inputLabelTextColor, - ), + child: LocaleKeys.triglycerideInfo.tr().toText12( + isBold: true, + color: AppColors.inputLabelTextColor, + ), ), ], ).paddingSymmetrical(0.w, 16.w), @@ -165,27 +159,23 @@ class _TriglyceridesWidgetState extends State { isBold: true, color: AppColors.inputLabelTextColor, ), - SizedBox( - height: 40.h, - child: TextField( - controller: controller, - focusNode: focusNode, - keyboardType: - const TextInputType.numberWithOptions(decimal: true), - onChanged: onChanged, - cursorHeight: 35.h, - decoration: InputDecoration( - border: InputBorder.none, - contentPadding: EdgeInsets.zero, - isCollapsed: true, - hintText: hint, - hintStyle: const TextStyle(color: Colors.grey), - ), - style: TextStyle( - fontSize: 32.f, - fontWeight: FontWeight.bold, - color: Colors.black87, - ), + TextField( + controller: controller, + focusNode: focusNode, + keyboardType: const TextInputType.numberWithOptions(decimal: true), + onChanged: onChanged, + cursorHeight: 35.h, + decoration: InputDecoration( + border: InputBorder.none, + contentPadding: EdgeInsets.zero, + isCollapsed: true, + hintText: hint, + hintStyle: const TextStyle(color: Colors.grey), + ), + style: TextStyle( + fontSize: 32.f, + fontWeight: FontWeight.bold, + color: Colors.black87, ), ), ], diff --git a/lib/presentation/symptoms_checker/organ_selector_screen.dart b/lib/presentation/symptoms_checker/organ_selector_screen.dart index 9d7f78e8..840a24b6 100644 --- a/lib/presentation/symptoms_checker/organ_selector_screen.dart +++ b/lib/presentation/symptoms_checker/organ_selector_screen.dart @@ -1,5 +1,6 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/api_consts.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_export.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; @@ -46,13 +47,13 @@ class _OrganSelectorPageState extends State { Future _checkAndShowTutorial() async { // final hasSeenTutorial = cacheService.getBool(key: CacheConst.organSelectorTutorialShown) ?? false; // if (!hasSeenTutorial) { - // Show tutorial after a short delay to ensure the screen is fully built - await Future.delayed(const Duration(milliseconds: 500)); - if (mounted) { - setState(() { - _showTutorial = true; - }); - } + // Show tutorial after a short delay to ensure the screen is fully built + await Future.delayed(const Duration(milliseconds: 500)); + if (mounted) { + setState(() { + _showTutorial = true; + }); + } // } } @@ -74,12 +75,17 @@ class _OrganSelectorPageState extends State { loadingText: LocaleKeys.pleaseWait.tr(context: context), ); - final String userName = 'guest_user'; - final String password = '123456'; + // Get fileNo if user is logged in + String? fileNo; + if (_appState.isAuthenticated) { + final user = _appState.getAuthenticatedUser(); + fileNo = user?.patientId.toString(); + } await viewModel.getSymptomsUserDetails( - userName: userName, - password: password, + userName: ApiConsts.symptomsCheckerUsername, + password: ApiConsts.symptomsCheckerPassword, + fileNo: fileNo, onSuccess: () { LoaderBottomSheet.hideLoader(); context.navigateWithName(AppRoutes.symptomsSelectorPage); diff --git a/lib/presentation/symptoms_checker/triage_screen.dart b/lib/presentation/symptoms_checker/triage_screen.dart index 13715c71..a94222b6 100644 --- a/lib/presentation/symptoms_checker/triage_screen.dart +++ b/lib/presentation/symptoms_checker/triage_screen.dart @@ -175,20 +175,44 @@ class _TriagePageState extends State { return; } - // Collect all evidence from all items - for (var item in currentQuestion.items!) { - final itemId = item.id ?? ""; - if (itemId.isEmpty) continue; - - final selectedChoiceIndex = viewModel.getTriageChoiceForItem(itemId); - if (selectedChoiceIndex == null) continue; - - if (item.choices != null && selectedChoiceIndex < item.choices!.length) { - final selectedChoice = item.choices![selectedChoiceIndex]; - final choiceId = selectedChoice.id ?? ""; - - if (choiceId.isNotEmpty) { - viewModel.addTriageEvidence(itemId, choiceId); + // Collect evidence based on question type + if (viewModel.isTriageQuestionSingleSelection) { + // Type 1: Single selection - only one evidence entry + final selectedItemId = viewModel.selectedSingleItemId; + final selectedChoiceIndex = viewModel.selectedSingleChoiceIndex; + + if (selectedItemId != null && selectedChoiceIndex != null) { + // Find the item and choice + for (var item in currentQuestion.items!) { + if (item.id == selectedItemId) { + if (item.choices != null && selectedChoiceIndex < item.choices!.length) { + final selectedChoice = item.choices![selectedChoiceIndex]; + final choiceId = selectedChoice.id ?? ""; + + if (choiceId.isNotEmpty) { + viewModel.addTriageEvidence(selectedItemId, choiceId); + } + } + break; + } + } + } + } else { + // Type 2: Multi-item selection - collect evidence from all items + for (var item in currentQuestion.items!) { + final itemId = item.id ?? ""; + if (itemId.isEmpty) continue; + + final selectedChoiceIndex = viewModel.getTriageChoiceForItem(itemId); + if (selectedChoiceIndex == null) continue; + + if (item.choices != null && selectedChoiceIndex < item.choices!.length) { + final selectedChoice = item.choices![selectedChoiceIndex]; + final choiceId = selectedChoice.id ?? ""; + + if (choiceId.isNotEmpty) { + viewModel.addTriageEvidence(itemId, choiceId); + } } } } @@ -390,7 +414,10 @@ class _TriagePageState extends State { SizedBox(height: 8.h), // Choices for this item ...List.generate(choices.length, (choiceIndex) { - bool selected = viewModel.getTriageChoiceForItem(itemId) == choiceIndex; + // Check selection based on question type + bool selected = viewModel.isTriageQuestionSingleSelection + ? viewModel.isTriageSingleOptionSelected(itemId, choiceIndex) + : viewModel.getTriageChoiceForItem(itemId) == choiceIndex; return _buildOptionItem(itemId, choiceIndex, selected, choices[choiceIndex].label ?? ""); }), @@ -468,18 +495,12 @@ class _TriagePageState extends State { text: TextSpan( text: "${LocaleKeys.possibleSymptom.tr(context: context)} ", style: TextStyle( - color: AppColors.greyTextColor, fontWeight: FontWeight.w600, fontSize: 14.f, fontFamily: isArabic ? 'CairoArabic' : 'Poppins'), + color: AppColors.greyTextColor, fontWeight: FontWeight.w600, fontSize: 14.f, fontFamily: isArabic ? 'CairoArabic' : 'Poppins'), children: [ TextSpan( text: suggestedCondition, - style: TextStyle( - color: AppColors.textColor, - fontWeight: FontWeight.w600, - - fontSize: 14.f, fontFamily: isArabic ? 'CairoArabic' : 'Poppins'), - - + color: AppColors.textColor, fontWeight: FontWeight.w600, fontSize: 14.f, fontFamily: isArabic ? 'CairoArabic' : 'Poppins'), ), ], ), diff --git a/lib/presentation/symptoms_checker/user_info_selection/pages/height_selection_page.dart b/lib/presentation/symptoms_checker/user_info_selection/pages/height_selection_page.dart index 28de7894..42e017ae 100644 --- a/lib/presentation/symptoms_checker/user_info_selection/pages/height_selection_page.dart +++ b/lib/presentation/symptoms_checker/user_info_selection/pages/height_selection_page.dart @@ -53,9 +53,10 @@ class HeightSelectionPage extends StatelessWidget { child: Text( 'CM', style: TextStyle( - fontWeight: FontWeight.w700, - fontSize: 14.f, - color: viewModel.isHeightCm ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.6), fontFamily: "Poppins"), + fontWeight: FontWeight.w700, + fontSize: 14.f, + color: viewModel.isHeightCm ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.6), + fontFamily: "Poppins"), ), ), ), @@ -74,9 +75,10 @@ class HeightSelectionPage extends StatelessWidget { child: Text( 'FT', style: TextStyle( - fontWeight: FontWeight.w700, - fontSize: 14.f, - color: !viewModel.isHeightCm ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.6), fontFamily: "Poppins"), + fontWeight: FontWeight.w700, + fontSize: 14.f, + color: !viewModel.isHeightCm ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.6), + fontFamily: "Poppins"), ), ), ), @@ -128,10 +130,7 @@ class HeightSelectionPage extends StatelessWidget { TextSpan( text: viewModel.isHeightCm ? viewModel.selectedHeight?.round().toString() : viewModel.selectedHeight?.toStringAsFixed(1), - style: TextStyle( - fontSize: 90.f, - color: AppColors.textColor, - height: 1, fontFamily: "Poppins"), + style: TextStyle(fontSize: 90.f, color: AppColors.textColor, height: 1, fontFamily: "Poppins"), ), TextSpan( text: viewModel.isHeightCm ? 'cm' : 'ft', @@ -142,7 +141,7 @@ class HeightSelectionPage extends StatelessWidget { ), ], ), - ).paddingOnly(bottom: 100.h, left: 20.w); + ).paddingOnly(bottom: 100.h, left: isFoldable ? 40.w : 20.w); }, ), ), diff --git a/lib/presentation/symptoms_checker/user_info_selection/widgets/height_scale.dart b/lib/presentation/symptoms_checker/user_info_selection/widgets/height_scale.dart index 6695bbd4..d95c6c82 100644 --- a/lib/presentation/symptoms_checker/user_info_selection/widgets/height_scale.dart +++ b/lib/presentation/symptoms_checker/user_info_selection/widgets/height_scale.dart @@ -131,12 +131,11 @@ class _HeightScaleState extends State { child: Text( widget.isCm ? height.round().toString() : height.toStringAsFixed(1), style: TextStyle( - fontSize: 11.f, - color: AppColors.greyTextColor, + fontSize: 11.f, + color: AppColors.greyTextColor, fontWeight: FontWeight.w600, - height: 1, - fontFamily: "Poppins" - ), + height: isFoldable ? 0.5 : 1, + fontFamily: "Poppins"), textAlign: TextAlign.right, ), ) diff --git a/lib/presentation/todo_section/ancillary_procedures_details_page.dart b/lib/presentation/todo_section/ancillary_procedures_details_page.dart index 4d2034ba..41428a6e 100644 --- a/lib/presentation/todo_section/ancillary_procedures_details_page.dart +++ b/lib/presentation/todo_section/ancillary_procedures_details_page.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:ui' as ui; import 'package:collection/collection.dart'; import 'package:easy_localization/easy_localization.dart'; @@ -24,8 +25,6 @@ import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:provider/provider.dart'; -import 'dart:ui' as ui; - class AncillaryOrderDetailsList extends StatefulWidget { final int appointmentNoVida; final int orderNo; @@ -653,13 +652,15 @@ class _AncillaryOrderDetailsListState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ SizedBox( - width: 200.h, + width: isFoldable ? 220.w : 200.w, child: Utils.getPaymentMethods(), ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Utils.getPaymentAmountWithSymbol(NumberFormat.decimalPattern().format(_getTotalAmount()).toText24(isBold: true, isEnglishOnly: true), AppColors.blackColor, 17, isSaudiCurrency: true), + Utils.getPaymentAmountWithSymbol( + NumberFormat.decimalPattern().format(_getTotalAmount()).toText24(isBold: true, isEnglishOnly: true), AppColors.blackColor, 17, + isSaudiCurrency: true), ], ), ], @@ -695,40 +696,5 @@ class _AncillaryOrderDetailsListState extends State { ], ).paddingOnly(left: 16.h, top: 24.h, right: 16.h, bottom: 0.h), ); - - // Column( - // mainAxisAlignment: MainAxisAlignment.spaceBetween, - // children: [ - // SizedBox(height: 16.h), - // _buildSummarySection(orderData), - // SizedBox(height: 16.h), - // CustomButton( - // borderWidth: 0, - // backgroundColor: AppColors.infoLightColor, - // text: "Proceed to Payment".needTranslation, - // onPressed: () { - // // Navigate to payment page with selected procedures - // Navigator.of(context).push( - // CustomPageRoute( - // page: AncillaryOrderPaymentPage( - // appointmentNoVida: widget.appointmentNoVida, - // orderNo: widget.orderNo, - // projectID: widget.projectID, - // selectedProcedures: selectedProcedures, - // totalAmount: _getTotalAmount(), - // appointmentDate: orderData.appointmentDate, - // ), - // ), - // ); - // }, - // isDisabled: !isButtonEnabled, - // textColor: AppColors.whiteColor, - // borderRadius: 12.r, - // borderColor: Colors.transparent, - // padding: EdgeInsets.symmetric(vertical: 16.h), - // ), - // SizedBox(height: 22.h), - // ], - // ).paddingSymmetrical(24.w, 0); } } diff --git a/lib/widgets/appbar/collapsing_list_view.dart b/lib/widgets/appbar/collapsing_list_view.dart index 805fa677..c3ebe4ba 100644 --- a/lib/widgets/appbar/collapsing_list_view.dart +++ b/lib/widgets/appbar/collapsing_list_view.dart @@ -115,7 +115,8 @@ class CollapsingListView extends StatelessWidget { margin: EdgeInsets.fromLTRB(24.w, 0, 24.w, 0), child: Transform.flip( flipX: appState.isArabic(), - child: Utils.buildSvgWithAssets(icon: isClose ? AppAssets.close_bottom_nav_trans : AppAssets.arrow_back_new, width: 24.h, height: 24.h), + child: Utils.buildSvgWithAssets( + icon: isClose ? AppAssets.close_bottom_nav_trans : AppAssets.arrow_back_new, width: 24.h, height: 24.h), ), ).onPress(() { if (leadingCallback != null) { @@ -288,7 +289,8 @@ class _ScrollAnimatedTitleState extends State { return Container( // height: (widget.preferredSize.height - _fontSize / 2).h, height: 56.h, - alignment: isRtl ? (widget.showBack ? Alignment.topRight : Alignment.centerRight) : (widget.showBack ? Alignment.topLeft : Alignment.centerLeft), + alignment: + isRtl ? (widget.showBack ? Alignment.topRight : Alignment.centerRight) : (widget.showBack ? Alignment.topLeft : Alignment.centerLeft), padding: EdgeInsets.fromLTRB(24.w, 0, 24.w, 0), child: Row( spacing: 4.h, @@ -304,19 +306,38 @@ class _ScrollAnimatedTitleState extends State { ), ).expanded, ...[ - if (widget.logout != null) actionButton(context, t, title: LocaleKeys.logout.tr(context: context), icon: AppAssets.logout).onPress(widget.logout!), - if (widget.report != null) actionButton(context, t, title: LocaleKeys.feedback.tr(context: context), icon: AppAssets.report_icon).onPress(widget.report!), - if (widget.history != null) actionButton(context, t, title: LocaleKeys.history.tr(context: context), icon: AppAssets.insurance_history_icon).onPress(widget.history!), - if (widget.instructions != null) actionButton(context, t, title: LocaleKeys.instructions.tr(context: context), icon: AppAssets.requests).onPress(widget.instructions!), - if (widget.requests != null) actionButton(context, t, title: LocaleKeys.requests.tr(context: context), icon: AppAssets.insurance_history_icon).onPress(widget.requests!), - if (widget.sendEmail != null) actionButton(context, t, title: LocaleKeys.sendEmail.tr(context: context), icon: AppAssets.email).onPress(widget.sendEmail!), - if (widget.doctorResponse != null) actionButton(context, t, title: LocaleKeys.doctorResponses.tr(context: context), icon: AppAssets.doctorResponseIcon).onPress(widget.doctorResponse!), + if (widget.logout != null) + actionButton(context, t, title: LocaleKeys.logout.tr(context: context), icon: AppAssets.logout).onPress(widget.logout!), + if (widget.report != null) + actionButton(context, t, title: LocaleKeys.feedback.tr(context: context), icon: AppAssets.report_icon).onPress(widget.report!), + if (widget.history != null) + actionButton(context, t, title: LocaleKeys.history.tr(context: context), icon: AppAssets.insurance_history_icon) + .onPress(widget.history!), + if (widget.instructions != null) + actionButton(context, t, title: LocaleKeys.instructions.tr(context: context), icon: AppAssets.requests).onPress(widget.instructions!), + if (widget.requests != null) + actionButton(context, t, title: LocaleKeys.requests.tr(context: context), icon: AppAssets.insurance_history_icon) + .onPress(widget.requests!), + if (widget.sendEmail != null) + actionButton(context, t, title: LocaleKeys.sendEmail.tr(context: context), icon: AppAssets.email).onPress(widget.sendEmail!), + if (widget.doctorResponse != null) + actionButton(context, t, title: LocaleKeys.doctorResponses.tr(context: context), icon: AppAssets.doctorResponseIcon) + .onPress(widget.doctorResponse!), if (widget.search != null) Utils.buildSvgWithAssets(icon: AppAssets.search_icon).onPress(widget.search!), - if (widget.aiOverview != null) actionButton(context, t, title: LocaleKeys.aiOverView.tr(context: context), icon: AppAssets.aiOverView, isAiButton: true).onPress(widget.aiOverview!), - if (widget.downloadReport != null) actionButton(context, t, title: LocaleKeys.downloadReport.tr(context: context), icon: AppAssets.download).onPress(widget.downloadReport!), - if (widget.viewImage != null) actionButton(context, t, title: LocaleKeys.viewRadiologyImage.tr(context: context), icon: AppAssets.download).onPress(widget.viewImage!), - if (widget.location != null) actionButton(context, t, title: LocaleKeys.sortByLocation.tr(context: context), icon: AppAssets.location).onPress(widget.location!), - if (widget.downloadInvoice != null) actionButton(context, t, title: LocaleKeys.downloadInvoice.tr(context: context), icon: AppAssets.download).onPress(widget.downloadInvoice!), + if (widget.aiOverview != null) + actionButton(context, t, title: LocaleKeys.aiOverView.tr(context: context), icon: AppAssets.aiOverView, isAiButton: true) + .onPress(widget.aiOverview!), + if (widget.downloadReport != null) + actionButton(context, t, title: LocaleKeys.downloadReport.tr(context: context), icon: AppAssets.download) + .onPress(widget.downloadReport!), + if (widget.viewImage != null) + actionButton(context, t, title: LocaleKeys.viewRadiologyImage.tr(context: context), icon: AppAssets.download) + .onPress(widget.viewImage!), + if (widget.location != null) + actionButton(context, t, title: LocaleKeys.sortByLocation.tr(context: context), icon: AppAssets.location).onPress(widget.location!), + if (widget.downloadInvoice != null) + actionButton(context, t, title: LocaleKeys.downloadInvoice.tr(context: context), icon: AppAssets.download) + .onPress(widget.downloadInvoice!), if (widget.trailing != null) widget.trailing!, ] ], @@ -330,9 +351,10 @@ class _ScrollAnimatedTitleState extends State { duration: Duration(milliseconds: 150), child: Center( child: Container( - height: 40.h, + height: isFoldable ? 50.h : 40.h, padding: EdgeInsets.all(8.w), - decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 8.r, side: BorderSide(width: 1, color: AppColors.borderGrayColor)), + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, borderRadius: 8.r, side: BorderSide(width: 1, color: AppColors.borderGrayColor)), child: ShaderMask( blendMode: BlendMode.srcIn, shaderCallback: (bounds) => AppColors.aiLinearGradient.createShader(bounds), @@ -365,7 +387,7 @@ class _ScrollAnimatedTitleState extends State { : AnimatedSize( duration: Duration(milliseconds: 150), child: Container( - height: 40.h, + height: isFoldable ? 50.h : 40.h, padding: EdgeInsets.all(8.w), decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.secondaryLightRedColor,