Completed the HHC and CMC

pull/113/head
faizatflutter 5 months ago
parent 5e437e42a9
commit 8068de70cb

@ -513,12 +513,6 @@ var PATIENT_ER_INSERT_PRES_ORDER = 'Services/Patients.svc/REST/PatientER_InsertP
var BLOOD_DONATION_REGISTER_BLOOD_TYPE = 'Services/PatientVarification.svc/REST/BloodDonation_RegisterBloodType'; var BLOOD_DONATION_REGISTER_BLOOD_TYPE = 'Services/PatientVarification.svc/REST/BloodDonation_RegisterBloodType';
var ADD_USER_AGREEMENT_FOR_BLOOD_DONATION = 'Services/PatientVarification.svc/REST/AddUserAgreementForBloodDonation'; var ADD_USER_AGREEMENT_FOR_BLOOD_DONATION = 'Services/PatientVarification.svc/REST/AddUserAgreementForBloodDonation';
// HHC RC SERVICES
var HHC_GET_ALL_SERVICES_RC = "api/HHC/getallhhc";
var ADD_HHC_ORDER_RC = "api/HHC/add";
var GET_ALL_HHC_ORDERS_RC = 'api/hhc/list';
var UPDATE_HHC_ORDER_RC = 'api/hhc/update';
// RRT RC SERVICES // RRT RC SERVICES
var ADD_RRT_ORDER_RC = "api/rrt/add"; var ADD_RRT_ORDER_RC = "api/rrt/add";
var GET_ALL_RRT_ORDERS_RC = "api/rrt/list"; var GET_ALL_RRT_ORDERS_RC = "api/rrt/list";
@ -858,3 +852,7 @@ class ApiConsts {
static final String appGeneralId = "Cs2020@2016\$2958"; static final String appGeneralId = "Cs2020@2016\$2958";
static final String sessionID = 'TMRhVmkGhOsvamErw'; static final String sessionID = 'TMRhVmkGhOsvamErw';
} }
class ApiKeyConstants {
static final String googleMapsApiKey = 'AIzaSyB6TERnxIr0yJ3qG4ULBZbu0sAD4tGqtng';
}

@ -2,7 +2,7 @@ import 'dart:async';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.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_assets.dart';
import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
@ -26,11 +26,7 @@ import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointmen
import 'package:hmg_patient_app_new/presentation/appointments/widgets/ask_doctor_request_type_select.dart'; import 'package:hmg_patient_app_new/presentation/appointments/widgets/ask_doctor_request_type_select.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/appointment_calendar.dart'; import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/appointment_calendar.dart';
import 'package:hmg_patient_app_new/presentation/contact_us/feedback_page.dart'; import 'package:hmg_patient_app_new/presentation/contact_us/feedback_page.dart';
import 'package:hmg_patient_app_new/presentation/lab/lab_orders_page.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/widgets/lab_rad_card.dart';
import 'package:hmg_patient_app_new/presentation/prescriptions/prescription_detail_page.dart'; import 'package:hmg_patient_app_new/presentation/prescriptions/prescription_detail_page.dart';
import 'package:hmg_patient_app_new/presentation/prescriptions/prescriptions_list_page.dart';
import 'package:hmg_patient_app_new/presentation/radiology/radiology_orders_page.dart';
import 'package:hmg_patient_app_new/theme/colors.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/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
@ -208,7 +204,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
borderRadius: BorderRadius.circular(24.r), borderRadius: BorderRadius.circular(24.r),
// Todo: what is this???? Api Key??? 😲 // Todo: what is this???? Api Key??? 😲
child: Image.network( child: Image.network(
"https://maps.googleapis.com/maps/api/staticmap?center=${widget.patientAppointmentHistoryResponseModel.latitude},${widget.patientAppointmentHistoryResponseModel.longitude}&zoom=14&size=350x165&maptype=roadmap&markers=color:red%7C${widget.patientAppointmentHistoryResponseModel.latitude},${widget.patientAppointmentHistoryResponseModel.longitude}&key=AIzaSyB6TERnxIr0yJ3qG4ULBZbu0sAD4tGqtng", "https://maps.googleapis.com/maps/api/staticmap?center=${widget.patientAppointmentHistoryResponseModel.latitude},${widget.patientAppointmentHistoryResponseModel.longitude}&zoom=14&size=350x165&maptype=roadmap&markers=color:red%7C${widget.patientAppointmentHistoryResponseModel.latitude},${widget.patientAppointmentHistoryResponseModel.longitude}&key=${ApiKeyConstants.googleMapsApiKey}",
fit: BoxFit.contain, fit: BoxFit.contain,
), ),
), ),
@ -286,17 +282,17 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
) )
// : SizedBox.shrink() // : SizedBox.shrink()
: GridView( : GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3, crossAxisCount: 3,
crossAxisSpacing: 16.h, crossAxisSpacing: 16.h,
mainAxisSpacing: 16.w, mainAxisSpacing: 16.w,
mainAxisExtent: 115.h, mainAxisExtent: 115.h,
), ),
physics: NeverScrollableScrollPhysics(), physics: NeverScrollableScrollPhysics(),
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
shrinkWrap: true, shrinkWrap: true,
children: [ children: [
MedicalFileCard( MedicalFileCard(
label: LocaleKeys.labResults.tr(context: context), label: LocaleKeys.labResults.tr(context: context),
textColor: AppColors.blackColor, textColor: AppColors.blackColor,
backgroundColor: AppColors.whiteColor, backgroundColor: AppColors.whiteColor,
@ -385,13 +381,15 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
); );
Navigator.of(context).push( Navigator.of(context).push(
CustomPageRoute( CustomPageRoute(
page: PrescriptionDetailPage(isFromAppointments: true, prescriptionsResponseModel: patientPrescriptionsResponseModel), page: PrescriptionDetailPage(
isFromAppointments: true, prescriptionsResponseModel: patientPrescriptionsResponseModel),
), ),
); );
} else { } else {
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
context, context,
child: Utils.getErrorWidget(loadingText: "You don't have any prescriptions for this appointment.".needTranslation), child: Utils.getErrorWidget(
loadingText: "You don't have any prescriptions for this appointment.".needTranslation),
callBackFunc: () {}, callBackFunc: () {},
isFullScreen: false, isFullScreen: false,
isCloseButtonVisible: true, isCloseButtonVisible: true,
@ -412,11 +410,11 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
// Navigator.of(context).push( // Navigator.of(context).push(
// CustomPageRoute( // CustomPageRoute(
// page: VaccineListPage(), // page: VaccineListPage(),
// ), // ),
// ); // );
}), }),
], ],
), ),
// Column( // Column(
// crossAxisAlignment: CrossAxisAlignment.start, // crossAxisAlignment: CrossAxisAlignment.start,
// children: [ // children: [

@ -2,7 +2,6 @@ import 'dart:developer';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
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/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.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/size_utils.dart';
@ -22,6 +21,7 @@ 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/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.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/loader/bottomsheet_loader.dart';
import 'package:hmg_patient_app_new/widgets/map/location_map_widget.dart';
import 'package:maps_launcher/maps_launcher.dart'; import 'package:maps_launcher/maps_launcher.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -155,100 +155,26 @@ class _CmcSelectionReviewPageState extends State<CmcSelectionReviewPage> {
} }
Widget _buildHospitalMap(HospitalsModel selectedHospital) { Widget _buildHospitalMap(HospitalsModel selectedHospital) {
final String lat = selectedHospital.latitude ?? "0.0"; final String lat = ((selectedHospital.latitude == null || selectedHospital.latitude!.isEmpty) ? "0.0" : selectedHospital.latitude) ?? "0.0";
final String lng = selectedHospital.longitude ?? "0.0"; final String lng = ((selectedHospital.longitude == null || selectedHospital.longitude!.isEmpty) ? "0.0" : selectedHospital.longitude) ?? "0.0";
log("selectedHospital: $lng and $lat"); log("selectedHospital: $lng and $lat");
if (lat == "0.0" || lng == "0.0") return SizedBox.shrink(); if (lat == "0.0" || lng == "0.0") return SizedBox.shrink();
final String staticMapUrl = final appState = getIt.get<AppState>();
"https://maps.googleapis.com/maps/api/staticmap?center=$lat,$lng&zoom=16&size=600x300&maptype=roadmap&markers=color:red%7C$lat,$lng&key=AIzaSyCyDbWUM9d_sBUGIE8PcuShzPaqO08NSC8"; final isArabic = appState.isArabic();
final hospitalName = isArabic ? (selectedHospital.nameN ?? selectedHospital.name ?? '') : (selectedHospital.name ?? '');
return Stack(
children: [ return LocationMapWidget(
ClipRRect( latitude: double.parse(lat),
borderRadius: BorderRadius.circular(12.r), longitude: double.parse(lng),
child: Image.network( address: hospitalName,
staticMapUrl, title: "Hospital Location".needTranslation,
height: 200.h, showTitle: false,
width: double.infinity, showAddress: false,
fit: BoxFit.cover, padding: EdgeInsets.zero,
loadingBuilder: (context, child, loadingProgress) { onDirectionsTap: () => _launchDirections(selectedHospital),
if (loadingProgress == null) return child;
return Container(
height: 200.h,
decoration: BoxDecoration(
color: AppColors.bgScaffoldColor,
borderRadius: BorderRadius.circular(12.r),
),
child: Center(
child: CircularProgressIndicator(
color: AppColors.primaryRedColor,
),
),
);
},
errorBuilder: (context, error, stackTrace) {
return Container(
height: 200.h,
decoration: BoxDecoration(
color: AppColors.bgScaffoldColor,
borderRadius: BorderRadius.circular(12.r),
),
child: Center(
child: Icon(
Icons.error_outline,
size: 48.h,
color: AppColors.greyTextColor,
),
),
);
},
),
),
Positioned(
bottom: 12.h,
right: 12.w,
child: InkWell(
onTap: () => _launchDirections(selectedHospital),
child: Container(
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 8.h),
decoration: BoxDecoration(
color: AppColors.whiteColor,
borderRadius: BorderRadius.circular(1000.r),
boxShadow: [
BoxShadow(
color: Color.fromARGB(26, 0, 0, 0),
blurRadius: 8,
offset: Offset(0, 2),
),
],
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Utils.buildSvgWithAssets(
icon: AppAssets.directions_icon,
width: 16.w,
height: 16.h,
),
SizedBox(width: 6.w),
Text(
"Get Directions".needTranslation,
style: TextStyle(
fontSize: 12.f,
fontWeight: FontWeight.w600,
color: AppColors.blackColor,
letterSpacing: -0.4,
),
),
],
),
),
),
),
],
); );
} }

@ -13,9 +13,11 @@ import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get
import 'package:hmg_patient_app_new/presentation/home_health_care/hhc_order_detail_page.dart'; import 'package:hmg_patient_app_new/presentation/home_health_care/hhc_order_detail_page.dart';
import 'package:hmg_patient_app_new/presentation/home_health_care/hhc_selection_review_page.dart'; import 'package:hmg_patient_app_new/presentation/home_health_care/hhc_selection_review_page.dart';
import 'package:hmg_patient_app_new/presentation/home_health_care/widgets/hhc_ui_selection_helper.dart'; import 'package:hmg_patient_app_new/presentation/home_health_care/widgets/hhc_ui_selection_helper.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.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/buttons/custom_button.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:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:shimmer/shimmer.dart'; import 'package:shimmer/shimmer.dart';
@ -78,6 +80,15 @@ class _HhcProceduresPageState extends State<HhcProceduresPage> {
} }
final canCancel = order.statusId == 1 || order.statusId == 2; final canCancel = order.statusId == 1 || order.statusId == 2;
final isArabic = getIt.get<AppState>().isArabic();
// Extract services from orderselectedservice
List<dynamic> selectedServices = [];
if (order.orderselectedservice != null) {
if (order.orderselectedservice is List) {
selectedServices = order.orderselectedservice as List;
}
}
return Container( return Container(
width: double.infinity, width: double.infinity,
@ -128,6 +139,85 @@ class _HhcProceduresPageState extends State<HhcProceduresPage> {
], ],
), ),
// Services List
if (selectedServices.isNotEmpty) ...[
SizedBox(height: 16.h),
Container(
padding: EdgeInsets.all(12.w),
decoration: BoxDecoration(
color: AppColors.bgScaffoldColor,
borderRadius: BorderRadius.circular(12.r),
border: Border.all(
color: AppColors.greyColor.withAlpha(51),
width: 1,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(
Icons.medical_services_outlined,
size: 18.h,
color: AppColors.primaryRedColor,
),
SizedBox(width: 6.w),
"Requested Services".needTranslation.toText14(
weight: FontWeight.w600,
color: AppColors.blackColor,
),
],
),
SizedBox(height: 8.h),
...selectedServices.asMap().entries.map((entry) {
int index = entry.key;
var service = entry.value;
String serviceName = '';
if (service is Map) {
if (isArabic) {
serviceName = service['SelectedServiceNameAR']?.toString() ??
service['selectedServiceNameAR']?.toString() ??
service['SelectedServiceName']?.toString() ??
service['selectedServiceName']?.toString() ??
'';
} else {
serviceName = service['SelectedServiceName']?.toString() ?? service['selectedServiceName']?.toString() ?? '';
}
}
return Padding(
padding: EdgeInsets.only(top: index > 0 ? 6.h : 0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: EdgeInsets.only(top: 6.h),
width: 6.w,
height: 6.w,
decoration: BoxDecoration(
color: AppColors.primaryRedColor,
shape: BoxShape.circle,
),
),
SizedBox(width: 8.w),
Expanded(
child: serviceName.toText14(
color: AppColors.blackColor,
weight: FontWeight.w500,
maxlines: 3,
),
),
],
),
);
}).toList(),
],
),
),
],
SizedBox(height: 12.h), SizedBox(height: 12.h),
// Info message // Info message
@ -206,36 +296,6 @@ class _HhcProceduresPageState extends State<HhcProceduresPage> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
SizedBox(height: 8.h), SizedBox(height: 8.h),
if (viewModel.selectedHhcServices.isNotEmpty) ...[
SizedBox(height: 16.h),
Container(
margin: EdgeInsets.symmetric(horizontal: 16.w),
padding: EdgeInsets.all(16.w),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.greyLightColor,
borderRadius: 16.r,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Selected Services".needTranslation.toText12(
color: AppColors.textColorLight,
fontWeight: FontWeight.w600,
),
"${viewModel.selectedHhcServices.length} service(s) selected".toText14(
isBold: true,
weight: FontWeight.bold,
),
],
),
],
),
),
],
SizedBox(height: 16.h), SizedBox(height: 16.h),
Text( Text(
'Select Services'.needTranslation, 'Select Services'.needTranslation,
@ -304,18 +364,35 @@ class _HhcProceduresPageState extends State<HhcProceduresPage> {
); );
}, },
), ),
// Summary Section
], ],
); );
}, },
); );
} }
void _proceedWithSelectedService() { void _proceedWithSelectedService() async {
final navigationServices = getIt.get<NavigationService>();
final appState = getIt.get<AppState>();
final hmgServicesViewModel = context.read<HmgServicesViewModel>(); final hmgServicesViewModel = context.read<HmgServicesViewModel>();
if (hmgServicesViewModel.selectedHhcServices.isNotEmpty) { if (hmgServicesViewModel.selectedHhcServices.isNotEmpty) {
hmgServicesViewModel.setSelectedServiceForHhcOrder(hmgServicesViewModel.selectedHhcServices.first); hmgServicesViewModel.setSelectedServiceForHhcOrder(hmgServicesViewModel.selectedHhcServices.first);
Navigator.of(context).pushReplacement(
bool result = await navigationServices.push(
CustomPageRoute(
page: MapUtilityScreen(
confirmButtonString: "Submit Request ".needTranslation,
titleString: "Select Location",
subTitleString: "Please select the location".needTranslation,
isGmsAvailable: appState.isGMSAvailable,
),
direction: AxisDirection.down),
);
if (!result) {
return;
}
Navigator.of(context).push(
CustomPageRoute( CustomPageRoute(
page: HhcSelectionReviewPage(selectedServices: hmgServicesViewModel.selectedHhcServices), page: HhcSelectionReviewPage(selectedServices: hmgServicesViewModel.selectedHhcServices),
direction: AxisDirection.left, direction: AxisDirection.left,
@ -359,16 +436,48 @@ class _HhcProceduresPageState extends State<HhcProceduresPage> {
if (pendingOrder == null && hmgServicesViewModel.selectedHhcServices.isNotEmpty) { if (pendingOrder == null && hmgServicesViewModel.selectedHhcServices.isNotEmpty) {
return SafeArea( return SafeArea(
top: false, top: false,
child: Padding( child: Container(
padding: EdgeInsets.only(left: 16.w, right: 16.w, top: 12.h), color: AppColors.whiteColor,
child: CustomButton( child: Column(
borderWidth: 0, mainAxisSize: MainAxisSize.min,
text: "Next".needTranslation, children: [
onPressed: _proceedWithSelectedService, // Selected Services Summary Widget
textColor: AppColors.whiteColor, Container(
borderRadius: 12.r, margin: EdgeInsets.symmetric(horizontal: 16.w, vertical: 4.h),
borderColor: Colors.transparent, padding: EdgeInsets.all(16.w),
padding: EdgeInsets.symmetric(vertical: 14.h), 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,
),
],
),
],
),
),
// 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),
),
),
],
), ),
), ),
); );

@ -10,13 +10,14 @@ 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/hmg_services_view_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/cmc_create_new_order_req_model.dart';
import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get_cmc_services_resp_model.dart'; import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get_cmc_services_resp_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart'; import 'package:hmg_patient_app_new/features/location/location_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; 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/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.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/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.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/loader/bottomsheet_loader.dart';
import 'package:hmg_patient_app_new/widgets/map/location_map_widget.dart';
import 'package:maps_launcher/maps_launcher.dart'; import 'package:maps_launcher/maps_launcher.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -57,6 +58,8 @@ class _HhcSelectionReviewPageState extends State<HhcSelectionReviewPage> {
children: [ children: [
_buildSelectedServicesCard(isArabic), _buildSelectedServicesCard(isArabic),
SizedBox(height: 16.h), SizedBox(height: 16.h),
_buildLocationMap(),
SizedBox(height: 16.h),
], ],
), ),
), ),
@ -104,6 +107,36 @@ class _HhcSelectionReviewPageState extends State<HhcSelectionReviewPage> {
); );
} }
Widget _buildLocationMap() {
final locationViewModel = getIt.get<LocationViewModel>();
final geocodeResponse = locationViewModel.geocodeResponse;
final mapCapturedLocation = locationViewModel.mapCapturedLocation;
// Check if we have location data
if (mapCapturedLocation == null || (mapCapturedLocation.lat == 0.0 && mapCapturedLocation.lng == 0.0)) {
return SizedBox.shrink();
}
final double lat = mapCapturedLocation.lat ?? 0.0;
final double lng = mapCapturedLocation.lng ?? 0.0;
if (lat == 0.0 || lng == 0.0) return SizedBox.shrink();
// Get address from geocode response
String address = "Selected Location".needTranslation;
if (geocodeResponse != null && geocodeResponse.results.isNotEmpty) {
address = geocodeResponse.results.first.formattedAddress;
}
return LocationMapWidget(
latitude: lat,
longitude: lng,
address: address,
title: "Service Location".needTranslation,
onDirectionsTap: () => _launchDirectionsToLocation(lat, lng, address),
);
}
Widget _buildBottomButton() { Widget _buildBottomButton() {
return SafeArea( return SafeArea(
top: false, top: false,
@ -133,16 +166,9 @@ class _HhcSelectionReviewPageState extends State<HhcSelectionReviewPage> {
); );
} }
void _launchDirections(HospitalsModel selectedHospital) { void _launchDirectionsToLocation(double lat, double lng, String locationName) {
final double lat = double.parse(selectedHospital.latitude ?? "0.0");
final double lng = double.parse(selectedHospital.longitude ?? "0.0");
if (lat != 0.0 && lng != 0.0) { if (lat != 0.0 && lng != 0.0) {
MapsLauncher.launchCoordinates( MapsLauncher.launchCoordinates(lat, lng, locationName);
lat,
lng,
selectedHospital.name ?? "Hospital",
);
} }
} }

@ -0,0 +1,199 @@
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/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/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:maps_launcher/maps_launcher.dart';
/// A reusable location map widget that displays a static map with address and directions button
/// Can be used in any review screen (HHC, CMC, etc.)
class LocationMapWidget extends StatelessWidget {
/// The latitude coordinate of the location
final double latitude;
/// The longitude coordinate of the location
final double longitude;
/// The formatted address or location name to display
final String address;
/// The title to show above the map (e.g., "Service Location", "Hospital Location")
final String title;
/// The zoom level for the map (default: 14)
final int zoomLevel;
/// The size of the map image (default: 350x165)
final String mapSize;
/// Optional callback when directions button is pressed
/// If not provided, will use default MapsLauncher
final VoidCallback? onDirectionsTap;
/// 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;
const LocationMapWidget({
super.key,
required this.latitude,
required this.longitude,
required this.address,
required this.title,
this.zoomLevel = 14,
this.mapSize = '350x165',
this.onDirectionsTap,
this.showAddress = true,
this.showTitle = true,
this.mapType = 'roadmap',
this.padding,
});
void _defaultLaunchDirections() {
if (latitude != 0.0 && longitude != 0.0) {
MapsLauncher.launchCoordinates(latitude, longitude, address);
}
}
@override
Widget build(BuildContext context) {
final String staticMapUrl =
"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,
),
padding: padding ?? EdgeInsets.all(16.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Title
if (showTitle) ...[
Text(
title,
style: TextStyle(
fontSize: 16.f,
fontWeight: FontWeight.w700,
color: AppColors.blackColor,
letterSpacing: -0.5,
),
),
SizedBox(height: 12.h),
],
// 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,
),
),
],
),
),
SizedBox(height: 16.h),
],
// Map display with bottom button overlay
Stack(
children: [
ClipRRect(
clipBehavior: Clip.hardEdge,
borderRadius: BorderRadius.circular(24.r),
child: Image.network(
staticMapUrl,
fit: BoxFit.contain,
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return Container(
height: 165.h,
decoration: BoxDecoration(
color: AppColors.bgScaffoldColor,
borderRadius: BorderRadius.circular(24.r),
),
child: Center(
child: CircularProgressIndicator(
color: AppColors.primaryRedColor,
),
),
);
},
errorBuilder: (context, error, stackTrace) {
return Container(
height: 165.h,
decoration: BoxDecoration(
color: AppColors.bgScaffoldColor,
borderRadius: BorderRadius.circular(24.r),
),
child: Center(
child: Icon(
Icons.error_outline,
size: 48.h,
color: AppColors.greyTextColor,
),
),
);
},
),
),
Positioned(
bottom: 0,
child: SizedBox(
width: MediaQuery.of(context).size.width * 0.785,
child: CustomButton(
text: "Get Directions".needTranslation,
onPressed: onDirectionsTap ?? _defaultLaunchDirections,
backgroundColor: AppColors.textColor.withValues(alpha: 0.8),
borderColor: AppColors.textColor.withValues(alpha: 0.01),
textColor: AppColors.whiteColor,
fontSize: 14.f,
fontWeight: FontWeight.w500,
borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w),
height: 40.h,
icon: AppAssets.directions_icon,
iconColor: AppColors.whiteColor,
iconSize: 14.h,
).paddingAll(12.h),
),
),
],
),
],
),
);
}
}

@ -1,29 +1,13 @@
import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.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_export.dart';
import 'package:hmg_patient_app_new/core/utils/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/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/emergency_services/emergency_services_view_model.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/AmbulanceCallingPlace.dart';
import 'package:hmg_patient_app_new/features/location/GeocodeResponse.dart';
import 'package:hmg_patient_app_new/features/location/PlaceDetails.dart';
import 'package:hmg_patient_app_new/features/location/PlacePrediction.dart';
import 'package:hmg_patient_app_new/features/location/location_view_model.dart'; import 'package:hmg_patient_app_new/features/location/location_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_doctor_card.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/widgets/AddressItem.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/widgets/HospitalBottomSheetBody.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/widgets/appointment_bottom_sheet.dart' show AppointmentBottomSheet;
import 'package:hmg_patient_app_new/presentation/emergency_services/widgets/location_input_bottom_sheet.dart'; import 'package:hmg_patient_app_new/presentation/emergency_services/widgets/location_input_bottom_sheet.dart';
import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/CustomSwitch.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/expandable_bottom_sheet/ExpandableBottomSheet.dart';
import 'package:hmg_patient_app_new/widgets/expandable_bottom_sheet/model/BottomSheetType.dart';
import 'package:hmg_patient_app_new/widgets/input_widget.dart'; import 'package:hmg_patient_app_new/widgets/input_widget.dart';
import 'package:hmg_patient_app_new/widgets/map/HMSMap.dart'; import 'package:hmg_patient_app_new/widgets/map/HMSMap.dart';
import 'package:hmg_patient_app_new/widgets/map/gms_map.dart'; import 'package:hmg_patient_app_new/widgets/map/gms_map.dart';
@ -42,14 +26,22 @@ import '../../../widgets/common_bottom_sheet.dart';
/// it results [true] if the user clicks on the submit button /// it results [true] if the user clicks on the submit button
/// and [false] if the user closes the screen without giving the consent to proceed for the request /// and [false] if the user closes the screen without giving the consent to proceed for the request
class MapUtilityScreen extends StatelessWidget { class MapUtilityScreen extends StatelessWidget {
final String confirmButtonString; final String confirmButtonString;
final String titleString; final String titleString;
final String subTitleString; final String subTitleString;
final bool isGmsAvailable; final bool isGmsAvailable;
final VoidCallback? onCrossClicked; final VoidCallback? onCrossClicked;
final VoidCallback? onSubmitted;
const MapUtilityScreen({super.key, required this.confirmButtonString, required this.titleString, required this.subTitleString, required this.isGmsAvailable, this.onCrossClicked}); const MapUtilityScreen({
super.key,
required this.confirmButtonString,
required this.titleString,
required this.subTitleString,
required this.isGmsAvailable,
this.onCrossClicked,
this.onSubmitted,
});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -57,15 +49,9 @@ class MapUtilityScreen extends StatelessWidget {
floatingActionButton: Padding( floatingActionButton: Padding(
padding: EdgeInsetsDirectional.only(end: 8.h, bottom: 68.h), padding: EdgeInsetsDirectional.only(end: 8.h, bottom: 68.h),
child: DecoratedBox( child: DecoratedBox(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration( decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 12.h),
color: AppColors.whiteColor, borderRadius: 12.h), child: Utils.buildSvgWithAssets(icon: AppAssets.locate_me, width: 24.h, height: 24.h).paddingAll(12.h).onPress(() {
child: Utils.buildSvgWithAssets( context.read<LocationViewModel>().moveToCurrentLocation();
icon: AppAssets.locate_me, width: 24.h, height: 24.h)
.paddingAll(12.h)
.onPress(() {
context
.read<LocationViewModel>()
.moveToCurrentLocation();
}), }),
), ),
), ),
@ -74,38 +60,26 @@ class MapUtilityScreen extends StatelessWidget {
children: [ children: [
if (isGmsAvailable) if (isGmsAvailable)
GMSMap( GMSMap(
currentLocation: currentLocation: context.read<LocationViewModel>().getGMSLocation(),
context.read<LocationViewModel>().getGMSLocation(), onCameraMoved: (value) => context.read<LocationViewModel>().handleGMSMapCameraMoved(value),
onCameraMoved: (value) => context onCameraIdle: context.read<LocationViewModel>().handleOnCameraIdle,
.read<LocationViewModel>()
.handleGMSMapCameraMoved(value),
onCameraIdle:
context.read<LocationViewModel>().handleOnCameraIdle,
myLocationEnabled: true, myLocationEnabled: true,
inputController: inputController: context.read<LocationViewModel>().gmsController,
context.read<LocationViewModel>().gmsController,
showCenterMarker: true, showCenterMarker: true,
) )
else else
HMSMap( HMSMap(
currentLocation: currentLocation: context.read<LocationViewModel>().getHMSLocation(),
context.read<LocationViewModel>().getHMSLocation(), onCameraMoved: (value) => context.read<LocationViewModel>().handleHMSMapCameraMoved(value),
onCameraMoved: (value) => context onCameraIdle: context.read<LocationViewModel>().handleOnCameraIdle,
.read<LocationViewModel>()
.handleHMSMapCameraMoved(value),
onCameraIdle:
context.read<LocationViewModel>().handleOnCameraIdle,
myLocationEnabled: false, myLocationEnabled: false,
inputController: inputController: context.read<LocationViewModel>().hmsController,
context.read<LocationViewModel>().hmsController,
showCenterMarker: true, showCenterMarker: true,
), ),
Align( Align(
alignment: AlignmentDirectional.topStart, alignment: AlignmentDirectional.topStart,
child: Utils.buildSvgWithAssets( child: Utils.buildSvgWithAssets(icon: AppAssets.closeBottomNav, width: 32.h, height: 32.h).onPress(() {
icon: AppAssets.closeBottomNav, width: 32.h, height: 32.h) onCrossClicked?.call();
.onPress(() {
onCrossClicked?.call();
// context // context
// .read<EmergencyServicesViewModel>() // .read<EmergencyServicesViewModel>()
// .flushPickupInformation(); // .flushPickupInformation();
@ -120,8 +94,7 @@ class MapUtilityScreen extends StatelessWidget {
Widget FixedBottomSheet(BuildContext context) { Widget FixedBottomSheet(BuildContext context) {
return GestureDetector( return GestureDetector(
onVerticalDragUpdate: (details){ onVerticalDragUpdate: (details) {},
},
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
@ -149,20 +122,23 @@ class MapUtilityScreen extends StatelessWidget {
spacing: 4.h, spacing: 4.h,
children: [ children: [
titleString.toText21( titleString.toText21(
weight: FontWeight.w600, weight: FontWeight.w600,
color: AppColors.textColor, color: AppColors.textColor,
), ),
subTitleString.needTranslation.toText12( subTitleString.needTranslation.toText12(
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: AppColors.greyTextColor, color: AppColors.greyTextColor,
) )
], ],
), ),
CustomButton( CustomButton(
text: confirmButtonString.needTranslation, text: confirmButtonString.needTranslation,
onPressed: () { onPressed: () {
///indicates that the screen has resulted success and should be closed if (onSubmitted != null) {
Navigator.pop(context,true); onSubmitted!();
} else {
Navigator.pop(context, true);
}
}, },
) )
], ],
@ -190,8 +166,6 @@ class MapUtilityScreen extends StatelessWidget {
); );
} }
textPlaceInput(context) { textPlaceInput(context) {
return Consumer<LocationViewModel>(builder: (_, vm, __) { return Consumer<LocationViewModel>(builder: (_, vm, __) {
return SizedBox( return SizedBox(
@ -200,8 +174,7 @@ class MapUtilityScreen extends StatelessWidget {
labelText: "Enter Pickup Location Manually".needTranslation, labelText: "Enter Pickup Location Manually".needTranslation,
hintText: "Enter Pickup Location".needTranslation, hintText: "Enter Pickup Location".needTranslation,
controller: TextEditingController( controller: TextEditingController(
text: vm.geocodeResponse?.results.first.formattedAddress ?? text: vm.geocodeResponse?.results.first.formattedAddress ?? vm.selectedPrediction?.description,
vm.selectedPrediction?.description,
), ),
leadingIcon: AppAssets.location_pickup, leadingIcon: AppAssets.location_pickup,
isAllowLeadingIcon: true, isAllowLeadingIcon: true,

Loading…
Cancel
Save