diff --git a/lib/features/hmg_services/hmg_services_view_model.dart b/lib/features/hmg_services/hmg_services_view_model.dart index 81cd060..b1a7757 100644 --- a/lib/features/hmg_services/hmg_services_view_model.dart +++ b/lib/features/hmg_services/hmg_services_view_model.dart @@ -3,8 +3,8 @@ import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart'; import 'package:hmg_patient_app_new/core/enums.dart'; import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_repo.dart'; import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_repo.dart'; -import 'package:hmg_patient_app_new/features/hmg_services/models/req_models/create_e_referral_model.dart'; import 'package:hmg_patient_app_new/features/hmg_services/models/req_models/cmc_create_new_order_req_model.dart'; +import 'package:hmg_patient_app_new/features/hmg_services/models/req_models/create_e_referral_model.dart'; import 'package:hmg_patient_app_new/features/hmg_services/models/req_models/order_update_req_model.dart'; import 'package:hmg_patient_app_new/features/hmg_services/models/req_models/search_e_referral_req_model.dart'; import 'package:hmg_patient_app_new/features/hmg_services/models/req_models/send_activation_code_ereferral_req_model.dart'; @@ -24,8 +24,9 @@ class HmgServicesViewModel extends ChangeNotifier { final BookAppointmentsRepo bookAppointmentsRepo; final ErrorHandlerService errorHandlerService; final NavigationService navigationService; - HmgServicesViewModel({required this.bookAppointmentsRepo, required this.hmgServicesRepo, required this.errorHandlerService, required this.navigationService}); + HmgServicesViewModel( + {required this.bookAppointmentsRepo, required this.hmgServicesRepo, required this.errorHandlerService, required this.navigationService}); bool isCmcOrdersLoading = false; bool isCmcServicesLoading = false; @@ -53,12 +54,12 @@ class HmgServicesViewModel extends ChangeNotifier { // HHC order creation state (no hospital selection needed for home healthcare) GetCMCServicesResponseModel? selectedServiceForHhcOrder; - - List relationTypes =[]; - List getAllCitiesList =[]; - List searchReferralList =[]; + List relationTypes = []; + List getAllCitiesList = []; + List searchReferralList = []; Future getOrdersList() async {} + // HHC multiple services selection List selectedHhcServices = []; @@ -332,10 +333,7 @@ class HmgServicesViewModel extends ChangeNotifier { await getAllHhcOrders(); } - Future getAllHhcOrders({ - Function(dynamic)? onSuccess, - Function(String)? onError, - }) async { + Future getAllHhcOrders({Function(dynamic)? onSuccess, Function(String)? onError}) async { isHhcOrdersLoading = true; notifyListeners(); @@ -541,16 +539,14 @@ class HmgServicesViewModel extends ChangeNotifier { final result = await hmgServicesRepo.getRelationshipTypes(); result.fold( - (failure) async { - + (failure) async { notifyListeners(); await errorHandlerService.handleError(failure: failure); if (onError != null) { onError(failure.toString()); } }, - (apiResponse) { - + (apiResponse) { if (apiResponse.messageStatus == 1) { relationTypes = apiResponse.data ?? []; notifyListeners(); @@ -567,7 +563,6 @@ class HmgServicesViewModel extends ChangeNotifier { ); } - Future getAllCities({ Function(dynamic)? onSuccess, Function(String)? onError, @@ -576,16 +571,14 @@ class HmgServicesViewModel extends ChangeNotifier { final result = await hmgServicesRepo.getAllCities(); result.fold( - (failure) async { - + (failure) async { notifyListeners(); await errorHandlerService.handleError(failure: failure); if (onError != null) { onError(failure.toString()); } }, - (apiResponse) { - + (apiResponse) { if (apiResponse.messageStatus == 1) { getAllCitiesList = apiResponse.data ?? []; notifyListeners(); @@ -607,22 +600,20 @@ class HmgServicesViewModel extends ChangeNotifier { Function(GenericApiModel)? onSuccess, Function(String)? onError, }) async { - notifyListeners(); final result = await hmgServicesRepo.sendEReferralActivationCode(requestModel); result.fold( - (failure) async { + (failure) async { notifyListeners(); await errorHandlerService.handleError(failure: failure); if (onError != null) { onError(failure.toString()); } }, - (apiResponse) { + (apiResponse) { if (apiResponse.messageStatus == 1) { - notifyListeners(); if (onSuccess != null) { onSuccess(apiResponse); @@ -642,22 +633,20 @@ class HmgServicesViewModel extends ChangeNotifier { Function(GenericApiModel)? onSuccess, Function(String)? onError, }) async { - notifyListeners(); final result = await hmgServicesRepo.checkEReferralActivationCode(requestModel); result.fold( - (failure) async { + (failure) async { notifyListeners(); await errorHandlerService.handleError(failure: failure); if (onError != null) { onError(failure.toString()); } }, - (apiResponse) { + (apiResponse) { if (apiResponse.messageStatus == 1) { - notifyListeners(); if (onSuccess != null) { onSuccess(apiResponse); @@ -672,28 +661,25 @@ class HmgServicesViewModel extends ChangeNotifier { ); } - Future createEReferral({ required CreateEReferralRequestModel requestModel, Function(GenericApiModel)? onSuccess, Function(String)? onError, }) async { - notifyListeners(); final result = await hmgServicesRepo.createEReferral(requestModel); result.fold( - (failure) async { + (failure) async { notifyListeners(); await errorHandlerService.handleError(failure: failure); if (onError != null) { onError(failure.toString()); } }, - (apiResponse) { + (apiResponse) { if (apiResponse.messageStatus == 1) { - notifyListeners(); if (onSuccess != null) { onSuccess(apiResponse); @@ -708,29 +694,24 @@ class HmgServicesViewModel extends ChangeNotifier { ); } - - Future searchEReferral({ required SearchEReferralRequestModel requestModel, Function(dynamic)? onSuccess, Function(String)? onError, }) async { - notifyListeners(); final result = await hmgServicesRepo.searchEReferral(requestModel); result.fold( - (failure) async { - + (failure) async { notifyListeners(); await errorHandlerService.handleError(failure: failure); if (onError != null) { onError(failure.toString()); } }, - (apiResponse) { - + (apiResponse) { if (apiResponse.messageStatus == 1) { searchReferralList = apiResponse.data ?? []; notifyListeners(); @@ -747,28 +728,26 @@ class HmgServicesViewModel extends ChangeNotifier { ); } - Future navigateToOTPScreen( - {required OTPTypeEnum otpTypeEnum, - required String phoneNumber, - required String loginToken, - required Function onSuccess, - }) async { - + Future navigateToOTPScreen({ + required OTPTypeEnum otpTypeEnum, + required String phoneNumber, + required String loginToken, + required Function onSuccess, + }) async { navigationService.pushToOtpScreen( phoneNumber: phoneNumber, isFormFamilyFile: false, checkActivationCode: (int activationCode) async { - checkEReferralActivationCode( requestModel: CheckActivationCodeForEReferralRequestModel( logInTokenID: loginToken, activationCode: activationCode.toString(), ), onSuccess: (GenericApiModel response) { - onSuccess(); + onSuccess(); }, onError: (String errorMessage) { - print(errorMessage); + print(errorMessage); }, ); }, @@ -787,5 +766,4 @@ class HmgServicesViewModel extends ChangeNotifier { }, ); } - } diff --git a/lib/features/location/location_view_model.dart b/lib/features/location/location_view_model.dart index c6ea34e..76d7c2c 100644 --- a/lib/features/location/location_view_model.dart +++ b/lib/features/location/location_view_model.dart @@ -2,7 +2,7 @@ import 'dart:async'; import 'package:flutter/foundation.dart' show ChangeNotifier; import 'package:flutter/material.dart'; -import 'package:google_maps_flutter_platform_interface/src/types/camera.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart' as GMSMapServices; import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/features/location/GeocodeResponse.dart'; @@ -10,9 +10,6 @@ import 'package:hmg_patient_app_new/features/location/PlaceDetails.dart'; import 'package:hmg_patient_app_new/features/location/location_repo.dart'; import 'package:hmg_patient_app_new/services/error_handler_service.dart'; import 'package:huawei_map/huawei_map.dart' as HMSCameraServices; -import 'package:google_maps_flutter/google_maps_flutter.dart' as GMSMapServices; - - import 'PlacePrediction.dart'; @@ -20,12 +17,12 @@ class LocationViewModel extends ChangeNotifier { final LocationRepo locationRepo; final ErrorHandlerService errorHandlerService; - LocationViewModel({required this.locationRepo, required this.errorHandlerService}){ + LocationViewModel({required this.locationRepo, required this.errorHandlerService}) { placeValueInController(); } - List predictions = []; - PlacePrediction? selectedPrediction; + List predictions = []; + PlacePrediction? selectedPrediction; bool isPredictionLoading = false; GeocodeResponse? geocodeResponse; PlaceDetails? placeDetails; @@ -39,12 +36,11 @@ class LocationViewModel extends ChangeNotifier { return HMSCameraServices.CameraPosition(target: HMSCameraServices.LatLng(getIt().userLat, getIt().userLong), zoom: 18); } - GMSMapServices.CameraPosition getGMSLocation() { return GMSMapServices.CameraPosition(target: GMSMapServices.LatLng(getIt().userLat, getIt().userLong), zoom: 18); } - void placeValueInController() async{ + void placeValueInController() async { if (await getIt().isGMSAvailable) { gmsController = Completer(); } else { @@ -54,14 +50,14 @@ class LocationViewModel extends ChangeNotifier { FutureOr getPlacesPrediction(String input) async { predictions = []; - isPredictionLoading= true; + isPredictionLoading = true; final result = await locationRepo.getPlacePredictionsAsInput(input); result.fold( (failure) { errorHandlerService.handleError(failure: failure); }, (apiModel) { - predictions = apiModel.data??[]; + predictions = apiModel.data ?? []; }, ); isPredictionLoading = false; @@ -99,21 +95,20 @@ class LocationViewModel extends ChangeNotifier { handleGMSMapCameraMoved(GMSMapServices.CameraPosition value) { mapCapturedLocation = Location(lat: value.target.latitude, lng: value.target.longitude); - } handleHMSMapCameraMoved(HMSCameraServices.CameraPosition value) { mapCapturedLocation = Location(lat: value.target.lat, lng: value.target.lng); } - handleOnCameraIdle(){ - if(mapCapturedLocation != null) { + handleOnCameraIdle() { + if (mapCapturedLocation != null) { getPlaceEncodedData(mapCapturedLocation!.lat, mapCapturedLocation!.lng); } } void updateSearchQuery(String? value) { - if(value == null || value.isEmpty){ + if (value == null || value.isEmpty) { predictions = []; return; } @@ -123,16 +118,16 @@ class LocationViewModel extends ChangeNotifier { void flushSearchPredictions() { predictions = []; - mapCapturedLocation= null; - placeDetails= null; - geocodeResponse= null; - selectedPrediction= null; + mapCapturedLocation = null; + placeDetails = null; + geocodeResponse = null; + selectedPrediction = null; notifyListeners(); } - FutureOr selectPlacePrediction(PlacePrediction placePrediction) async{ - selectedPrediction= placePrediction; + FutureOr selectPlacePrediction(PlacePrediction placePrediction) async { + selectedPrediction = placePrediction; await getPlaceDetails(placePrediction.placeID); } @@ -141,8 +136,6 @@ class LocationViewModel extends ChangeNotifier { } void moveController(Location location) { - print("moving to location"); - print("gmsController is null or not $gmsController"); if (getIt().isGMSAvailable) { gmsController?.future.then((controller) { controller.animateCamera( @@ -169,4 +162,4 @@ class LocationViewModel extends ChangeNotifier { }); } } -} \ No newline at end of file +} diff --git a/lib/presentation/comprehensive_checkup/cmc_selection_review_page.dart b/lib/presentation/comprehensive_checkup/cmc_selection_review_page.dart index 3be209b..18b656c 100644 --- a/lib/presentation/comprehensive_checkup/cmc_selection_review_page.dart +++ b/lib/presentation/comprehensive_checkup/cmc_selection_review_page.dart @@ -170,8 +170,6 @@ class _CmcSelectionReviewPageState extends State { latitude: double.parse(lat), longitude: double.parse(lng), address: hospitalName, - title: "Hospital Location".needTranslation, - showTitle: false, showAddress: false, padding: EdgeInsets.zero, onDirectionsTap: () => _launchDirections(selectedHospital), diff --git a/lib/presentation/comprehensive_checkup/comprehensive_checkup_page.dart b/lib/presentation/comprehensive_checkup/comprehensive_checkup_page.dart index 5529b93..8b9ad89 100644 --- a/lib/presentation/comprehensive_checkup/comprehensive_checkup_page.dart +++ b/lib/presentation/comprehensive_checkup/comprehensive_checkup_page.dart @@ -366,7 +366,12 @@ class _ComprehensiveCheckupPageState extends State { if (pendingOrder == null && _selectedServiceId != null) { return SafeArea( top: false, - child: Padding( + child: Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24.r, + hasShadow: true, + ), padding: EdgeInsets.only(left: 16.w, right: 16.w, top: 12.h), child: CustomButton( borderWidth: 0, diff --git a/lib/presentation/home_health_care/hhc_order_detail_page.dart b/lib/presentation/home_health_care/hhc_order_detail_page.dart index 21b0def..92c93d1 100644 --- a/lib/presentation/home_health_care/hhc_order_detail_page.dart +++ b/lib/presentation/home_health_care/hhc_order_detail_page.dart @@ -10,10 +10,8 @@ import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_view_model.dart'; import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get_cmc_all_orders_resp_model.dart'; -import 'package:hmg_patient_app_new/presentation/home_health_care/widgets/hhc_ui_selection_helper.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:provider/provider.dart'; @@ -75,7 +73,6 @@ class _HhcOrderDetailPageState extends State { Widget _buildOrderCard(GetCMCAllOrdersResponseModel order, {bool isLoading = false}) { final statusColor = _getStatusColor(order.statusId); - final canCancel = order.statusId == 1 || order.statusId == 2; return AnimatedContainer( duration: Duration(milliseconds: 300), @@ -150,27 +147,27 @@ class _HhcOrderDetailPageState extends State { ], ), - // Cancel Button - if (canCancel || isLoading) ...[ - SizedBox(height: 16.h), - Row( - children: [ - Expanded( - child: CustomButton( - text: "Cancel Order".needTranslation, - onPressed: isLoading ? () {} : () => HhcUiSelectionHelper.showCancelConfirmationDialog(context: context, order: order), - backgroundColor: AppColors.primaryRedColor, - borderColor: AppColors.primaryRedColor, - textColor: AppColors.whiteColor, - fontSize: 14.f, - fontWeight: FontWeight.w600, - borderRadius: 10.r, - height: 44.h, - ).toShimmer2(isShow: isLoading), - ), - ], - ), - ] + // // Cancel Button + // if (canCancel || isLoading) ...[ + // SizedBox(height: 16.h), + // Row( + // children: [ + // Expanded( + // child: CustomButton( + // text: "Cancel Order".needTranslation, + // onPressed: isLoading ? () {} : () => HhcUiSelectionHelper.showCancelConfirmationDialog(context: context, order: order), + // backgroundColor: AppColors.primaryRedColor, + // borderColor: AppColors.primaryRedColor, + // textColor: AppColors.whiteColor, + // fontSize: 14.f, + // fontWeight: FontWeight.w600, + // borderRadius: 10.r, + // height: 44.h, + // ).toShimmer2(isShow: isLoading), + // ), + // ], + // ), + // ] ], ), ), @@ -219,6 +216,7 @@ class _HhcOrderDetailPageState extends State { } return ListView.separated( + padding: EdgeInsets.only(top: 24.h), shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemCount: viewModel.hhcOrdersList.length, diff --git a/lib/presentation/home_health_care/hhc_procedures_page.dart b/lib/presentation/home_health_care/hhc_procedures_page.dart index bdc2e45..41d8a2f 100644 --- a/lib/presentation/home_health_care/hhc_procedures_page.dart +++ b/lib/presentation/home_health_care/hhc_procedures_page.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; +import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_view_model.dart'; @@ -17,6 +18,7 @@ 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/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; +import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; import 'package:hmg_patient_app_new/widgets/map/map_utility_screen.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:provider/provider.dart'; @@ -61,28 +63,9 @@ class _HhcProceduresPageState extends State { } Widget _buildPendingOrderCard(GetCMCAllOrdersResponseModel order) { - int status = order.statusId ?? 0; - String statusDisp = order.statusText ?? ""; - Color statusColor; - - if (status == 1) { - // pending - statusColor = AppColors.statusPendingColor; - } else if (status == 2) { - // processing - statusColor = AppColors.statusProcessingColor; - } else if (status == 3) { - // completed - statusColor = AppColors.statusCompletedColor; - } else { - // cancel / rejected - statusColor = AppColors.statusRejectedColor; - } - final canCancel = order.statusId == 1 || order.statusId == 2; final isArabic = getIt.get().isArabic(); - // Extract services from orderselectedservice List selectedServices = []; if (order.orderselectedservice != null) { if (order.orderselectedservice is List) { @@ -108,16 +91,12 @@ class _HhcProceduresPageState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 6.h), - decoration: BoxDecoration( - color: statusColor.withValues(alpha: 0.1), - borderRadius: BorderRadius.circular(8.r), - ), - child: statusDisp.toText12( - color: statusColor, - fontWeight: FontWeight.w600, - ), + Row( + children: [ + "Request ID:".needTranslation.toText14(color: AppColors.textColorLight, weight: FontWeight.w500), + SizedBox(width: 4.w), + "${order.iD ?? '-'}".toText16(isBold: true), + ], ), SizedBox(width: 8.w), if (order.created != null) @@ -127,17 +106,7 @@ class _HhcProceduresPageState extends State { ), ], ), - - SizedBox(height: 16.h), - - // Request ID - Row( - children: [ - "Request ID:".needTranslation.toText14(color: AppColors.textColorLight, weight: FontWeight.w500), - SizedBox(width: 4.w), - "${order.iD ?? '-'}".toText16(isBold: true), - ], - ), + SizedBox(height: 8.h), // Services List if (selectedServices.isNotEmpty) ...[ @@ -212,13 +181,13 @@ class _HhcProceduresPageState extends State { ], ), ); - }).toList(), + }), ], ), ), ], - SizedBox(height: 12.h), + SizedBox(height: 8.h), // Info message Container( @@ -274,99 +243,148 @@ class _HhcProceduresPageState extends State { ); } - Widget _buildServiceSelectionList(List services) { - if (services.isEmpty) { - return Center( - child: Padding( - padding: EdgeInsets.all(24.h), - child: Text( - 'No services available'.needTranslation, - style: TextStyle( - fontSize: 16.h, - color: AppColors.greyTextColor, - ), - ), - ), - ); - } - - return Consumer( - builder: (context, viewModel, child) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox(height: 8.h), - SizedBox(height: 16.h), - Text( - 'Select Services'.needTranslation, - style: TextStyle( - fontSize: 20.h, - fontWeight: FontWeight.w700, - color: AppColors.blackColor, - letterSpacing: -0.8, + _buildServicesListBottomsSheet(List services) { + showCommonBottomSheetWithoutHeight( + hasBottomPadding: false, + padding: EdgeInsets.only(top: 24.h), + context, + title: 'Select Services'.needTranslation, + isCloseButtonVisible: true, + isDismissible: true, + callBackFunc: () {}, + child: services.isEmpty + ? Center( + child: Padding( + padding: EdgeInsets.all(24.h), + child: Text( + 'No services available'.needTranslation, + style: TextStyle( + fontSize: 16.h, + color: AppColors.greyTextColor, + ), + ), ), - ).paddingOnly(left: 16.w, right: 16.w), - SizedBox(height: 12.h), - ListView.builder( - padding: EdgeInsets.symmetric(horizontal: 16.w), - itemCount: services.length, - shrinkWrap: true, - physics: NeverScrollableScrollPhysics(), - itemBuilder: (context, index) { - final service = services[index]; - final isSelected = viewModel.isHhcServiceSelected(service); - final isArabic = getIt.get().isArabic(); - final serviceName = isArabic ? (service.textN ?? service.text ?? '') : (service.text ?? ''); + ) + : Consumer( + builder: (context, hmgServicesViewModel, child) { + final pendingOrder = _getPendingOrder(hmgServicesViewModel.hhcOrdersList); + final hasSelectedServices = pendingOrder == null && hmgServicesViewModel.selectedHhcServices.isNotEmpty; - return AnimatedContainer( - duration: Duration(milliseconds: 300), - curve: Curves.easeInOut, - margin: EdgeInsets.only(bottom: 12.h), - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 16.r, - hasShadow: true, - ), - child: Material( - color: Colors.transparent, - child: InkWell( - onTap: () => viewModel.toggleHhcServiceSelection(service), - borderRadius: BorderRadius.circular(16.r), - child: Container( - padding: EdgeInsets.all(16.w), - child: Row( - children: [ - Checkbox( - value: isSelected, - onChanged: (v) => viewModel.toggleHhcServiceSelection(service), - activeColor: AppColors.primaryRedColor, - materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, - visualDensity: VisualDensity.compact, + return Stack( + children: [ + // Services List + ConstrainedBox( + constraints: BoxConstraints(maxHeight: SizeUtils.height * 0.7), + child: ListView.separated( + separatorBuilder: (context, index) => Divider(color: AppColors.dividerColor).paddingSymmetrical(16.w, 0), + padding: EdgeInsets.only(left: 16.w, right: 16.w, bottom: hasSelectedServices ? 160.h : 8.h), + shrinkWrap: true, + itemCount: services.length, + itemBuilder: (context, index) { + final service = services[index]; + final isSelected = hmgServicesViewModel.isHhcServiceSelected(service); + final isArabic = getIt.get().isArabic(); + final serviceName = isArabic ? (service.textN ?? service.text ?? '') : (service.text ?? ''); + + return AnimatedContainer( + duration: Duration(milliseconds: 300), + curve: Curves.easeInOut, + child: InkWell( + onTap: () => hmgServicesViewModel.toggleHhcServiceSelection(service), + borderRadius: BorderRadius.circular(16.r), + child: Container( + padding: EdgeInsets.all(8.w), + child: Row( + children: [ + AnimatedContainer( + duration: const Duration(milliseconds: 300), + curve: Curves.easeInOut, + width: 24.w, + height: 24.w, + decoration: BoxDecoration( + color: isSelected ? AppColors.primaryRedColor : Colors.transparent, + borderRadius: BorderRadius.circular(5.r), + border: Border.all( + color: isSelected ? AppColors.primaryRedColor : AppColors.borderGrayColor, + width: 1.w, + ), + ), + child: isSelected ? Icon(Icons.check, size: 18.f, color: AppColors.whiteColor) : null, + ), + SizedBox(width: 12.w), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + serviceName.toText16( + weight: FontWeight.w500, + color: AppColors.blackColor, + maxlines: 2, + ), + ], + ), + ), + ], + ), + ), ), - SizedBox(width: 12.w), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + ); + }, + ), + ), + + if (hasSelectedServices) + Positioned( + left: 0, + right: 0, + bottom: 0, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 24.h), + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24.r, + hasShadow: true, + ), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - serviceName.toText16( - weight: FontWeight.w400, - color: AppColors.blackColor, - maxlines: 2, + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Selected Services".needTranslation.toText12( + color: AppColors.textColorLight, + fontWeight: FontWeight.w600, + ), + "${hmgServicesViewModel.selectedHhcServices.length} service(s) selected".toText14( + isBold: true, + weight: FontWeight.bold, + ), + ], ), ], ), - ), - ], + SizedBox(height: 16.h), + CustomButton( + borderWidth: 0, + text: "Next".needTranslation, + onPressed: () { + Navigator.pop(context); + _proceedWithSelectedService(); + }, + textColor: AppColors.whiteColor, + borderRadius: 12.r, + borderColor: Colors.transparent, + ), + ], + ), ), ), - ), - ), + ], ); }, ), - ], - ); - }, ); } @@ -426,77 +444,70 @@ class _HhcProceduresPageState extends State { @override Widget build(BuildContext context) { - return CollapsingListView( - title: "Home Health Care".needTranslation, - history: () => Navigator.of(context).push(CustomPageRoute(page: HhcOrderDetailPage(), direction: AxisDirection.up)), - bottomChild: Consumer( - builder: (context, hmgServicesViewModel, child) { - if (hmgServicesViewModel.isHhcOrdersLoading || hmgServicesViewModel.isHhcServicesLoading) return SizedBox.shrink(); - final pendingOrder = _getPendingOrder(hmgServicesViewModel.hhcOrdersList); - if (pendingOrder == null && hmgServicesViewModel.selectedHhcServices.isNotEmpty) { - return SafeArea( - top: false, - child: Container( - color: AppColors.whiteColor, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - // Selected Services Summary Widget - Container( - margin: EdgeInsets.symmetric(horizontal: 16.w, vertical: 4.h), - padding: EdgeInsets.all(16.w), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - "Selected Services".needTranslation.toText12( - color: AppColors.textColorLight, - fontWeight: FontWeight.w600, - ), - "${hmgServicesViewModel.selectedHhcServices.length} service(s) selected".toText14( - isBold: true, - weight: FontWeight.bold, - ), - ], + return Scaffold( + backgroundColor: AppColors.bgScaffoldColor, + body: Column( + children: [ + Expanded( + child: CollapsingListView( + title: "Home Health Care".needTranslation, + history: () => Navigator.of(context).push(CustomPageRoute(page: HhcOrderDetailPage(), direction: AxisDirection.up)), + child: Consumer( + builder: (context, hmgServicesViewModel, child) { + if (hmgServicesViewModel.isHhcOrdersLoading || hmgServicesViewModel.isHhcServicesLoading) { + return _buildLoadingShimmer(); + } + final pendingOrder = _getPendingOrder(hmgServicesViewModel.hhcOrdersList); + if (pendingOrder != null) { + return _buildPendingOrderCard(pendingOrder); + } else { + return Column( + children: [ + Center( + child: Utils.getNoDataWidget( + context, + noDataText: "You have no pending requests.".needTranslation, ), - ], - ), - ), - // Next Button - Padding( - padding: EdgeInsets.only(left: 16.w, right: 16.w), - child: CustomButton( - borderWidth: 0, - text: "Next".needTranslation, - onPressed: _proceedWithSelectedService, - textColor: AppColors.whiteColor, - borderRadius: 12.r, - borderColor: Colors.transparent, - padding: EdgeInsets.symmetric(vertical: 14.h), - ), - ), - ], - ), + ), + ], + ); + } + }, ), - ); - } - return SizedBox.shrink(); - }, - ), - child: Consumer( - builder: (context, hmgServicesViewModel, child) { - if (hmgServicesViewModel.isHhcOrdersLoading || hmgServicesViewModel.isHhcServicesLoading) { - return _buildLoadingShimmer(); - } - final pendingOrder = _getPendingOrder(hmgServicesViewModel.hhcOrdersList); - if (pendingOrder != null) { - return _buildPendingOrderCard(pendingOrder); - } else { - return _buildServiceSelectionList(hmgServicesViewModel.hhcServicesList); - } - }, + ), + ), + Consumer( + builder: (BuildContext context, HmgServicesViewModel hmgServicesViewModel, Widget? child) { + if (hmgServicesViewModel.isHhcOrdersLoading || hmgServicesViewModel.isHhcServicesLoading) { + return SizedBox.shrink(); + } + final pendingOrder = _getPendingOrder(hmgServicesViewModel.hhcOrdersList); + if (pendingOrder == null) { + return Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24.r, + hasShadow: true, + ), + child: Padding( + padding: EdgeInsets.only(left: 16.w, right: 16.w, bottom: 24.h, top: 24.h), + child: CustomButton( + borderWidth: 0, + text: "Create new request".needTranslation, + onPressed: () => _buildServicesListBottomsSheet(hmgServicesViewModel.hhcServicesList), + textColor: AppColors.whiteColor, + borderRadius: 12.r, + borderColor: Colors.transparent, + padding: EdgeInsets.symmetric(vertical: 14.h), + ), + ), + ); + } + + return SizedBox.shrink(); + }, + ), + ], ), ); } diff --git a/lib/presentation/home_health_care/hhc_selection_review_page.dart b/lib/presentation/home_health_care/hhc_selection_review_page.dart index 8e9ba90..37410e2 100644 --- a/lib/presentation/home_health_care/hhc_selection_review_page.dart +++ b/lib/presentation/home_health_care/hhc_selection_review_page.dart @@ -15,6 +15,7 @@ import 'package:hmg_patient_app_new/generated/locale_keys.g.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'; import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; import 'package:hmg_patient_app_new/widgets/map/location_map_widget.dart'; @@ -68,40 +69,26 @@ class _HhcSelectionReviewPageState extends State { Widget _buildSelectedServicesCard(bool isArabic) { return Container( - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 16.r, - ), + width: double.infinity, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r), padding: EdgeInsets.all(16.w), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ "Selected Services".needTranslation.toText14( weight: FontWeight.w600, - color: AppColors.greyTextColor, + color: AppColors.textColor, letterSpacing: -0.4, ), SizedBox(height: 12.h), - ...widget.selectedServices.map((service) { - final serviceName = isArabic ? (service.textN ?? service.text ?? '') : (service.text ?? ''); - final price = service.priceTotal ?? 0.0; - return Padding( - padding: EdgeInsets.only(bottom: 4.h), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: serviceName.toText14( - weight: FontWeight.w600, - color: AppColors.blackColor, - letterSpacing: -0.5, - maxlines: 2, - ), - ), - ], - ), - ); - }), + Wrap( + spacing: 8.w, + runSpacing: 12.w, + children: widget.selectedServices.map((service) { + final serviceName = isArabic ? (service.textN ?? service.text ?? '') : (service.text ?? ''); + return AppCustomChipWidget(labelText: serviceName.needTranslation); + }).toList(), + ), ], ), ); @@ -117,8 +104,8 @@ class _HhcSelectionReviewPageState extends State { return SizedBox.shrink(); } - final double lat = mapCapturedLocation.lat ?? 0.0; - final double lng = mapCapturedLocation.lng ?? 0.0; + final double lat = mapCapturedLocation?.lat ?? 0.0; + final double lng = mapCapturedLocation?.lng ?? 0.0; if (lat == 0.0 || lng == 0.0) return SizedBox.shrink(); @@ -132,36 +119,25 @@ class _HhcSelectionReviewPageState extends State { latitude: lat, longitude: lng, address: address, - title: "Service Location".needTranslation, onDirectionsTap: () => _launchDirectionsToLocation(lat, lng, address), ); } Widget _buildBottomButton() { - return SafeArea( - top: false, - child: Container( - padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 12.h), - decoration: BoxDecoration( - color: AppColors.whiteColor, - boxShadow: [ - BoxShadow( - color: Color.fromARGB(13, 0, 0, 0), - blurRadius: 8, - offset: Offset(0, -2), - ), - ], - ), - child: CustomButton( - text: "Confirm".needTranslation, - onPressed: _handleConfirm, - textColor: AppColors.whiteColor, - backgroundColor: AppColors.successColor, - borderRadius: 12.r, - borderColor: Colors.transparent, - borderWidth: 0, - padding: EdgeInsets.symmetric(vertical: 14.h), - ), + return Container( + padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 24.h), + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24.r, + hasShadow: true, + ), + child: CustomButton( + borderWidth: 0, + text: "Confirm".needTranslation, + onPressed: () => _handleConfirm(), + textColor: AppColors.whiteColor, + borderRadius: 12.r, + borderColor: Colors.transparent, ), ); } diff --git a/lib/presentation/medical_report/medical_reports_page.dart b/lib/presentation/medical_report/medical_reports_page.dart index 71abcb7..4047a53 100644 --- a/lib/presentation/medical_report/medical_reports_page.dart +++ b/lib/presentation/medical_report/medical_reports_page.dart @@ -10,12 +10,11 @@ import 'package:hmg_patient_app_new/features/medical_file/medical_file_view_mode import 'package:hmg_patient_app_new/features/medical_file/models/patient_medical_response_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/medical_report/medical_report_request_page.dart'; -import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/presentation/medical_report/widgets/patient_medical_report_card.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/common_bottom_sheet.dart'; -import 'package:hmg_patient_app_new/widgets/custom_tab_bar.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:provider/provider.dart'; @@ -53,7 +52,8 @@ class _MedicalReportsPageState extends State { medicalFileViewModel.onMedicalReportTabChange(0); }, backgroundColor: medicalFileVM.selectedMedicalReportsTabIndex == 0 ? AppColors.bgRedLightColor : AppColors.whiteColor, - borderColor: medicalFileVM.selectedMedicalReportsTabIndex == 0 ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2), + borderColor: + medicalFileVM.selectedMedicalReportsTabIndex == 0 ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2), textColor: medicalFileVM.selectedMedicalReportsTabIndex == 0 ? AppColors.primaryRedColor : AppColors.blackColor, fontSize: 12, fontWeight: FontWeight.w500, @@ -68,7 +68,8 @@ class _MedicalReportsPageState extends State { medicalFileViewModel.onMedicalReportTabChange(1); }, backgroundColor: medicalFileVM.selectedMedicalReportsTabIndex == 1 ? AppColors.bgRedLightColor : AppColors.whiteColor, - borderColor: medicalFileVM.selectedMedicalReportsTabIndex == 1 ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2), + borderColor: + medicalFileVM.selectedMedicalReportsTabIndex == 1 ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2), textColor: medicalFileVM.selectedMedicalReportsTabIndex == 1 ? AppColors.primaryRedColor : AppColors.blackColor, fontSize: 12, fontWeight: FontWeight.w500, @@ -83,7 +84,8 @@ class _MedicalReportsPageState extends State { medicalFileViewModel.onMedicalReportTabChange(2); }, backgroundColor: medicalFileVM.selectedMedicalReportsTabIndex == 2 ? AppColors.bgRedLightColor : AppColors.whiteColor, - borderColor: medicalFileVM.selectedMedicalReportsTabIndex == 2 ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2), + borderColor: + medicalFileVM.selectedMedicalReportsTabIndex == 2 ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2), textColor: medicalFileVM.selectedMedicalReportsTabIndex == 2 ? AppColors.primaryRedColor : AppColors.blackColor, fontSize: 12, fontWeight: FontWeight.w500, @@ -131,7 +133,8 @@ class _MedicalReportsPageState extends State { child: AnimatedContainer( duration: Duration(milliseconds: 300), curve: Curves.easeInOut, - decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true), + decoration: RoundedRectangleBorder() + .toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true), child: PatientMedicalReportCard( patientMedicalReportResponseModel: medicalFileVM.patientMedicalReportList[index], medicalFileViewModel: medicalFileVM, @@ -141,7 +144,8 @@ class _MedicalReportsPageState extends State { ), ), ) - : Utils.getNoDataWidget(context, noDataText: "You don't have any medical reports yet.".needTranslation).paddingSymmetrical(24.h, 24.h); + : Utils.getNoDataWidget(context, noDataText: "You don't have any medical reports yet.".needTranslation) + .paddingSymmetrical(24.h, 24.h); }, separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h), ), @@ -188,11 +192,10 @@ class _MedicalReportsPageState extends State { backgroundColor: AppColors.primaryRedColor, borderColor: AppColors.primaryRedColor, textColor: AppColors.whiteColor, - fontSize: 16, + fontSize: 16.f, fontWeight: FontWeight.w500, - borderRadius: 12, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 45.h, + borderRadius: 12.r, + height: 46.h, icon: AppAssets.requests, iconColor: AppColors.whiteColor, iconSize: 20.h, @@ -218,7 +221,9 @@ class _MedicalReportsPageState extends State { LoaderBottomSheet.showLoader(); await medicalFileViewModel.insertRequestForMedicalReport(onSuccess: (val) { LoaderBottomSheet.hideLoader(); - showCommonBottomSheetWithoutHeight(context, child: Utils.getSuccessWidget(loadingText: "Your medical report request has been successfully submitted.".needTranslation), callBackFunc: () { + showCommonBottomSheetWithoutHeight(context, + child: Utils.getSuccessWidget(loadingText: "Your medical report request has been successfully submitted.".needTranslation), + callBackFunc: () { medicalFileViewModel.setIsPatientMedicalReportsLoading(true); medicalFileViewModel.onMedicalReportTabChange(0); medicalFileViewModel.getPatientMedicalReportList(); diff --git a/lib/widgets/map/location_map_widget.dart b/lib/widgets/map/location_map_widget.dart index 4cf5eae..c0eb431 100644 --- a/lib/widgets/map/location_map_widget.dart +++ b/lib/widgets/map/location_map_widget.dart @@ -21,7 +21,7 @@ class LocationMapWidget extends StatelessWidget { final String address; /// The title to show above the map (e.g., "Service Location", "Hospital Location") - final String title; + final String? title; /// The zoom level for the map (default: 14) final int zoomLevel; @@ -36,9 +36,6 @@ class LocationMapWidget extends StatelessWidget { /// Whether to show the address container (default: true) final bool showAddress; - /// Whether to show the title (default: true) - final bool showTitle; - /// Custom map type (default: roadmap) final String mapType; final EdgeInsets? padding; @@ -48,12 +45,11 @@ class LocationMapWidget extends StatelessWidget { required this.latitude, required this.longitude, required this.address, - required this.title, + this.title, this.zoomLevel = 14, this.mapSize = '350x165', this.onDirectionsTap, this.showAddress = true, - this.showTitle = true, this.mapType = 'roadmap', this.padding, }); @@ -70,18 +66,15 @@ class LocationMapWidget extends StatelessWidget { "https://maps.googleapis.com/maps/api/staticmap?center=$latitude,$longitude&zoom=$zoomLevel&size=$mapSize&maptype=$mapType&markers=color:red%7C$latitude,$longitude&key=${ApiKeyConstants.googleMapsApiKey}"; return Container( - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 16.r, - ), + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r), padding: padding ?? EdgeInsets.all(16.w), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Title - if (showTitle) ...[ + if (title != null) ...[ Text( - title, + title ?? "", style: TextStyle( fontSize: 16.f, fontWeight: FontWeight.w700, @@ -94,35 +87,22 @@ class LocationMapWidget extends StatelessWidget { // Address display if (showAddress) ...[ - Container( - padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 14.h), - decoration: BoxDecoration( - color: AppColors.bgScaffoldColor, - borderRadius: BorderRadius.circular(12.r), - border: Border.all( - color: AppColors.greyColor.withAlpha(51), - width: 1, - ), - ), - child: Row( - children: [ - Icon(Icons.location_on, color: AppColors.primaryRedColor, size: 20.h), - SizedBox(width: 8.w), - Expanded( - child: Text( - address, - style: TextStyle( - fontSize: 14.f, - fontWeight: FontWeight.w500, - color: AppColors.blackColor, - letterSpacing: -0.4, - ), - maxLines: 2, - overflow: TextOverflow.ellipsis, + Row( + children: [ + Expanded( + child: Text( + address, + style: TextStyle( + fontSize: 14.f, + fontWeight: FontWeight.w500, + color: AppColors.blackColor, + letterSpacing: -0.4, ), + maxLines: 2, + overflow: TextOverflow.ellipsis, ), - ], - ), + ), + ], ), SizedBox(height: 16.h), ],