Comprehensive checkup Completed

pull/98/head
faizatflutter 4 months ago
parent 721bf95c1b
commit 3331edc10d

@ -842,6 +842,7 @@ class ApiConsts {
static final String allCMCOrdersRc = 'api/cmc/list';
static final String allCMCServicesRc = 'api/cmc/getallcmc';
static final String updateCMCOrder = 'api/cmc/update';
static final String getHospitalsList = 'Services/Lists.svc/REST/GetProject';
// CMC RC SERVICES
var GET_ALL_CMC_SERVICES_RC = 'api/cmc/getallcmc';

@ -215,7 +215,7 @@ class AppDependencies {
);
getIt.registerLazySingleton<HmgServicesViewModel>(
() => HmgServicesViewModel(hmgServicesRepo: getIt(), errorHandlerService: getIt()),
() => HmgServicesViewModel(bookAppointmentsRepo: getIt(), hmgServicesRepo: getIt(), errorHandlerService: getIt()),
);
// Screen-specific VMs Factory

@ -3,7 +3,6 @@ import 'dart:async';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/cache_consts.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/location_util.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
@ -105,8 +104,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
List<String> searchedRegionList = [];
List<String> facilityList = ["hmgHospitals", "hmcMedicalClinic"];
List<String> searchedHospitalList = [];
List<PatientDoctorAppointmentList>
searchedPatientDoctorAppointmentHospitalsList = [];
List<PatientDoctorAppointmentList> searchedPatientDoctorAppointmentHospitalsList = [];
List<String> searchedClinicList = [];
PatientDoctorAppointmentList? selectedHospitalForFilters;
@ -114,15 +112,14 @@ class BookAppointmentsViewModel extends ChangeNotifier {
String? selectedClinicForFilters;
bool applyFilters = false;
///variables for laser clinic
List<LaserCategoryType> femaleLaserCategory = [
List<LaserCategoryType> femaleLaserCategory = [
LaserCategoryType(1, 'bodyString'),
LaserCategoryType(2, 'face'),
LaserCategoryType(10,'bikini'),
LaserCategoryType(10, 'bikini'),
LaserCategoryType(11, 'retouch'),
];
List<LaserCategoryType> maleLaserCategory =[
List<LaserCategoryType> maleLaserCategory = [
LaserCategoryType(1, 'body'),
LaserCategoryType(2, 'face'),
LaserCategoryType(11, 'retouch'),
@ -136,9 +133,13 @@ class BookAppointmentsViewModel extends ChangeNotifier {
bool isBodyPartsLoading = false;
int duration = 0;
BookAppointmentsViewModel(
{required this.bookAppointmentsRepo, required this.errorHandlerService, required this.navigationService, required this.myAppointmentsViewModel, required this.locationUtils, required this.dialogService }) {
{required this.bookAppointmentsRepo,
required this.errorHandlerService,
required this.navigationService,
required this.myAppointmentsViewModel,
required this.locationUtils,
required this.dialogService}) {
initBookAppointmentViewModel();
}
@ -287,7 +288,8 @@ class BookAppointmentsViewModel extends ChangeNotifier {
Future<void> getLiveCareScheduleClinics({Function(dynamic)? onSuccess, Function(String)? onError}) async {
liveCareClinicsList.clear();
final result = await bookAppointmentsRepo.getLiveCareScheduleClinics(_appState.getAuthenticatedUser()!.age!, _appState.getAuthenticatedUser()!.gender!);
final result =
await bookAppointmentsRepo.getLiveCareScheduleClinics(_appState.getAuthenticatedUser()!.age!, _appState.getAuthenticatedUser()!.gender!);
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),
@ -309,8 +311,9 @@ class BookAppointmentsViewModel extends ChangeNotifier {
Future<void> getLiveCareDoctorsList({Function(dynamic)? onSuccess, Function(String)? onError}) async {
doctorsList.clear();
final result =
await bookAppointmentsRepo.getLiveCareDoctorsList(selectedLiveCareClinic.serviceID!, _appState.getAuthenticatedUser()!.age!, _appState.getAuthenticatedUser()!.gender!, onError: onError);
final result = await bookAppointmentsRepo.getLiveCareDoctorsList(
selectedLiveCareClinic.serviceID!, _appState.getAuthenticatedUser()!.age!, _appState.getAuthenticatedUser()!.gender!,
onError: onError);
result.fold(
(failure) async {
@ -333,10 +336,17 @@ class BookAppointmentsViewModel extends ChangeNotifier {
}
//TODO: Make the API dynamic with parameters for ProjectID, isNearest, languageID, doctorId, doctorName
Future<void> getDoctorsList({int projectID = 0, bool isNearest = false, int doctorId = 0, String doctorName = "", Function(dynamic)? onSuccess, Function(String)? onError}) async {
Future<void> getDoctorsList(
{int projectID = 0,
bool isNearest = false,
int doctorId = 0,
String doctorName = "",
Function(dynamic)? onSuccess,
Function(String)? onError}) async {
doctorsList.clear();
projectID = currentlySelectedHospitalFromRegionFlow != null ? int.parse(currentlySelectedHospitalFromRegionFlow!) : projectID;
final result = await bookAppointmentsRepo.getDoctorsList(selectedClinic.clinicID ?? 0, projectID, isNearest, doctorId, doctorName, isContinueDentalPlan: isContinueDentalPlan);
final result = await bookAppointmentsRepo.getDoctorsList(selectedClinic.clinicID ?? 0, projectID, isNearest, doctorId, doctorName,
isContinueDentalPlan: isContinueDentalPlan);
result.fold(
(failure) async {
@ -365,7 +375,13 @@ class BookAppointmentsViewModel extends ChangeNotifier {
}
Future<void> getMappedDoctors(
{int projectID = 0, bool isNearest = false, int doctorId = 0, String doctorName = "", isContinueDentalPlan = false, Function(dynamic)? onSuccess, Function(String)? onError}) async {
{int projectID = 0,
bool isNearest = false,
int doctorId = 0,
String doctorName = "",
isContinueDentalPlan = false,
Function(dynamic)? onSuccess,
Function(String)? onError}) async {
filteredHospitalList = null;
hospitalList = null;
isRegionListLoading = true;
@ -374,10 +390,10 @@ class BookAppointmentsViewModel extends ChangeNotifier {
final result = await bookAppointmentsRepo.getDoctorsList(selectedClinic.clinicID ?? 0, projectID, isNearest, doctorId, doctorName);
result.fold(
(failure) async {
(failure) async {
onError?.call("No doctors found for the search criteria".needTranslation);
},
(apiResponse) async {
(apiResponse) async {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
@ -401,7 +417,8 @@ class BookAppointmentsViewModel extends ChangeNotifier {
}
Future<void> getDoctorProfile({Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await bookAppointmentsRepo.getDoctorProfile(selectedDoctor.clinicID ?? 0, selectedDoctor.projectID ?? 0, selectedDoctor.doctorID ?? 0, onError: onError);
final result = await bookAppointmentsRepo
.getDoctorProfile(selectedDoctor.clinicID ?? 0, selectedDoctor.projectID ?? 0, selectedDoctor.doctorID ?? 0, onError: onError);
result.fold(
(failure) async {},
@ -457,7 +474,8 @@ class BookAppointmentsViewModel extends ChangeNotifier {
// :
date = DateUtil.convertStringToDateSaudiTimezone(element, int.parse(selectedDoctor.projectID.toString()));
slotsList.add(FreeSlot(date, ['slot']));
docFreeSlots.add(TimeSlot(isoTime: formatter.format(date), start: new DateTime(date.year, date.month, date.day, 0, 0, 0, 0), end: date, vidaDate: element));
docFreeSlots.add(TimeSlot(
isoTime: formatter.format(date), start: new DateTime(date.year, date.month, date.day, 0, 0, 0, 0), end: date, vidaDate: element));
});
notifyListeners();
@ -476,8 +494,8 @@ class BookAppointmentsViewModel extends ChangeNotifier {
final DateFormat dateFormatter = DateFormat('yyyy-MM-dd');
Map<DateTime, List> _eventsParsed;
final result = await bookAppointmentsRepo.getLiveCareDoctorFreeSlots(
selectedDoctor.clinicID ?? 0, selectedLiveCareClinic.serviceID ?? 0, selectedDoctor.projectID ?? 0, selectedDoctor.doctorID ?? 0, isBookingForLiveCare,
final result = await bookAppointmentsRepo.getLiveCareDoctorFreeSlots(selectedDoctor.clinicID ?? 0, selectedLiveCareClinic.serviceID ?? 0,
selectedDoctor.projectID ?? 0, selectedDoctor.doctorID ?? 0, isBookingForLiveCare,
onError: onError);
result.fold(
@ -501,7 +519,8 @@ class BookAppointmentsViewModel extends ChangeNotifier {
// :
date = DateUtil.convertStringToDateSaudiTimezone(element, int.parse(selectedDoctor.projectID.toString()));
slotsList.add(FreeSlot(date, ['slot']));
docFreeSlots.add(TimeSlot(isoTime: formatter.format(date), start: new DateTime(date.year, date.month, date.day, 0, 0, 0, 0), end: date, vidaDate: element));
docFreeSlots.add(TimeSlot(
isoTime: formatter.format(date), start: new DateTime(date.year, date.month, date.day, 0, 0, 0, 0), end: date, vidaDate: element));
});
notifyListeners();
@ -513,7 +532,10 @@ class BookAppointmentsViewModel extends ChangeNotifier {
);
}
Future<void> cancelAppointment({required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, Function(dynamic)? onSuccess, Function(String)? onError}) async {
Future<void> cancelAppointment(
{required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel,
Function(dynamic)? onSuccess,
Function(String)? onError}) async {
final result = await bookAppointmentsRepo.cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel);
result.fold(
@ -597,13 +619,15 @@ class BookAppointmentsViewModel extends ChangeNotifier {
await cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel).then((val) async {
navigationService.pop();
Future.delayed(Duration(milliseconds: 50)).then((value) async {});
LoadingUtils.showFullScreenLoader(barrierDismissible: true, isSuccessDialog: false, loadingText: "Booking your appointment...".needTranslation);
LoadingUtils.showFullScreenLoader(
barrierDismissible: true, isSuccessDialog: false, loadingText: "Booking your appointment...".needTranslation);
await insertSpecificAppointment(
onError: (err) {},
onSuccess: (apiResp) async {
LoadingUtils.hideFullScreenLoader();
await Future.delayed(Duration(milliseconds: 50)).then((value) async {
LoadingUtils.showFullScreenLoader(barrierDismissible: true, isSuccessDialog: true, loadingText: LocaleKeys.appointmentSuccess.tr());
LoadingUtils.showFullScreenLoader(
barrierDismissible: true, isSuccessDialog: true, loadingText: LocaleKeys.appointmentSuccess.tr());
await Future.delayed(Duration(milliseconds: 4000)).then((value) {
LoadingUtils.hideFullScreenLoader();
Navigator.pushAndRemoveUntil(
@ -693,13 +717,15 @@ class BookAppointmentsViewModel extends ChangeNotifier {
await cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel).then((val) async {
navigationService.pop();
Future.delayed(Duration(milliseconds: 50)).then((value) async {});
LoadingUtils.showFullScreenLoader(barrierDismissible: true, isSuccessDialog: false, loadingText: "Booking your appointment...".needTranslation);
LoadingUtils.showFullScreenLoader(
barrierDismissible: true, isSuccessDialog: false, loadingText: "Booking your appointment...".needTranslation);
await insertSpecificAppointment(
onError: (err) {},
onSuccess: (apiResp) async {
LoadingUtils.hideFullScreenLoader();
await Future.delayed(Duration(milliseconds: 50)).then((value) async {
LoadingUtils.showFullScreenLoader(barrierDismissible: true, isSuccessDialog: true, loadingText: LocaleKeys.appointmentSuccess.tr());
LoadingUtils.showFullScreenLoader(
barrierDismissible: true, isSuccessDialog: true, loadingText: LocaleKeys.appointmentSuccess.tr());
await Future.delayed(Duration(milliseconds: 4000)).then((value) {
LoadingUtils.hideFullScreenLoader();
Navigator.pushAndRemoveUntil(
@ -773,7 +799,9 @@ class BookAppointmentsViewModel extends ChangeNotifier {
} else {
filteredHospitalList = RegionList();
var list = isHMG ? hospitalList?.registeredDoctorMap![selectedRegionId]!.hmgDoctorList : hospitalList?.registeredDoctorMap![selectedRegionId]!.hmcDoctorList;
var list = isHMG
? hospitalList?.registeredDoctorMap![selectedRegionId]!.hmgDoctorList
: hospitalList?.registeredDoctorMap![selectedRegionId]!.hmcDoctorList;
if (list != null && list.isEmpty) {
notifyListeners();
@ -856,12 +884,8 @@ class BookAppointmentsViewModel extends ChangeNotifier {
notifyListeners();
}
void setSelections(
List<String>? selectedFacilityForFilters,
List<String>? selectedRegionForFilters,
String? selectedClinicForFilters,
PatientDoctorAppointmentList? selectedHospitalForFilters,
bool applyFilters) {
void setSelections(List<String>? selectedFacilityForFilters, List<String>? selectedRegionForFilters, String? selectedClinicForFilters,
PatientDoctorAppointmentList? selectedHospitalForFilters, bool applyFilters) {
this.selectedFacilityForFilters = selectedFacilityForFilters;
this.selectedClinicForFilters = selectedClinicForFilters;
this.selectedHospitalForFilters = selectedHospitalForFilters;
@ -872,17 +896,14 @@ class BookAppointmentsViewModel extends ChangeNotifier {
void getFiltersFromDoctorList() {
doctorsList.forEach((element) {
if (!searchedRegionList
.contains(element.getRegionName(_appState.isArabic()))) {
searchedRegionList
.add(element.getRegionName(_appState.isArabic()) ?? "");
if (!searchedRegionList.contains(element.getRegionName(_appState.isArabic()))) {
searchedRegionList.add(element.getRegionName(_appState.isArabic()) ?? "");
}
if (!searchedHospitalList.contains(element.projectName)) {
searchedPatientDoctorAppointmentHospitalsList
.add(PatientDoctorAppointmentList()
..filterName = element.projectName
..isHMC = element.isHMC
..distanceInKMs = "0");
searchedPatientDoctorAppointmentHospitalsList.add(PatientDoctorAppointmentList()
..filterName = element.projectName
..isHMC = element.isHMC
..distanceInKMs = "0");
searchedHospitalList.add(element.projectName ?? "");
}
if (!searchedClinicList.contains(element.clinicName)) {
@ -939,27 +960,15 @@ class BookAppointmentsViewModel extends ChangeNotifier {
return doctorsList;
}
var list = doctorsList.where((element) {
var isInSelectedRegion = (selectedRegionForFilters?.isEmpty == true)
? true
: selectedRegionForFilters
?.any((region) => region == element.getRegionName(isArabic()));
var shouldApplyFacilityFilter =
(selectedFacilityForFilters?.isEmpty == true) ? false : true;
var isHMC = (selectedFacilityForFilters?.isEmpty == true)
? true
: selectedFacilityForFilters?.any((item) => item.contains("hmc"));
var isInSelectedClinic = (selectedClinicForFilters == null)
? true
: selectedClinicForFilters == element.clinicName;
var isInSelectedHospital = (selectedHospitalForFilters == null)
? true
: element.projectName == selectedHospitalForFilters?.filterName;
var isInSelectedRegion =
(selectedRegionForFilters?.isEmpty == true) ? true : selectedRegionForFilters?.any((region) => region == element.getRegionName(isArabic()));
var shouldApplyFacilityFilter = (selectedFacilityForFilters?.isEmpty == true) ? false : true;
var isHMC = (selectedFacilityForFilters?.isEmpty == true) ? true : selectedFacilityForFilters?.any((item) => item.contains("hmc"));
var isInSelectedClinic = (selectedClinicForFilters == null) ? true : selectedClinicForFilters == element.clinicName;
var isInSelectedHospital = (selectedHospitalForFilters == null) ? true : element.projectName == selectedHospitalForFilters?.filterName;
var facilityFilter = ((shouldApplyFacilityFilter == true) ? isHMC : true);
return (isInSelectedRegion ?? true) &&
(facilityFilter ?? true) &&
isInSelectedClinic &&
isInSelectedHospital;
return (isInSelectedRegion ?? true) && (facilityFilter ?? true) && isInSelectedClinic && isInSelectedHospital;
}).toList();
return list;
}
@ -1003,7 +1012,8 @@ class BookAppointmentsViewModel extends ChangeNotifier {
dentalChiefComplaintsList.clear();
notifyListeners();
int patientID = _appState.isAuthenticated ? _appState.getAuthenticatedUser()!.patientId ?? -1 : -1;
final result = await bookAppointmentsRepo.getDentalChiefComplaintsList(patientID: patientID, projectID: int.parse(currentlySelectedHospitalFromRegionFlow ?? "0"), clinicID: 17);
final result = await bookAppointmentsRepo.getDentalChiefComplaintsList(
patientID: patientID, projectID: int.parse(currentlySelectedHospitalFromRegionFlow ?? "0"), clinicID: 17);
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),
@ -1051,7 +1061,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
);
}
setBodyType(int bodyType){
setBodyType(int bodyType) {
selectedBodyTypeIndex = bodyType;
selectedCategory = 0;
selectedBodyPartList = [];
@ -1059,33 +1069,33 @@ class BookAppointmentsViewModel extends ChangeNotifier {
notifyListeners();
}
FutureOr<void> getLaserClinic() async{
FutureOr<void> getLaserClinic() async {
isBodyPartsLoading = true;
int id = bodyTypes[selectedBodyTypeIndex][selectedCategory].laserCategoryID;
int projectID = currentlySelectedHospitalFromRegionFlow != null ? int.parse(currentlySelectedHospitalFromRegionFlow!) : 0;
int languageID = _appState.isArabic() ? 1 : 0;
final result = await bookAppointmentsRepo.getLaserClinics(id, projectID, languageID);
result.fold(
(failure) {
(failure) {
isBodyPartsLoading = false;
notifyListeners();
},
(apiResponse) {isBodyPartsLoading = false;
(apiResponse) {
isBodyPartsLoading = false;
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
List<LaserBodyPart> response =apiResponse.data!;
if(response.first.category == 2 || response.first.category == 10 ) response.remove(response.first);
List<LaserBodyPart> response = apiResponse.data!;
if (response.first.category == 2 || response.first.category == 10) response.remove(response.first);
laserBodyPartsList = response;
}
notifyListeners();
notifyListeners();
},
);
}
int getDuration() {
var duration = 0;
var duration = 0;
var lowerUpperLegsList = selectedBodyPartList.where((element) => element.mappingCode == "47" || element.mappingCode == "48")?.toList() ?? [];
var upperLowerArmsList = selectedBodyPartList.where((element) => element.mappingCode == "40" || element.mappingCode == "41")?.toList() ?? [];
@ -1110,21 +1120,25 @@ class BookAppointmentsViewModel extends ChangeNotifier {
}
void setSelectedBodyPart(LaserBodyPart part) {
if(selectedBodyPartList.contains(part)){
if (selectedBodyPartList.contains(part)) {
selectedBodyPartList.remove(part);
this.duration = getDuration();
notifyListeners();
} else {
if(this.duration == 90){
dialogService.showErrorBottomSheet(message: "Duration can not exceed 90 min".needTranslation,);
if (this.duration == 90) {
dialogService.showErrorBottomSheet(
message: "Duration can not exceed 90 min".needTranslation,
);
return;
}
selectedBodyPartList.add(part);
var duration = getDuration();
if(duration > 90){
if (duration > 90) {
selectedBodyPartList.remove(part);
dialogService.showErrorBottomSheet(message: "Duration Exceeds 90 min".needTranslation,);
dialogService.showErrorBottomSheet(
message: "Duration Exceeds 90 min".needTranslation,
);
return;
}
this.duration = duration;
@ -1137,10 +1151,10 @@ class BookAppointmentsViewModel extends ChangeNotifier {
}
String getLaserProcedureNameWRTLanguage(LaserBodyPart part) {
if(_appState.isArabic()){
return part.bodyPartN??"";
}else {
return part.bodyPart??"";
if (_appState.isArabic()) {
return part.bodyPartN ?? "";
} else {
return part.bodyPart ?? "";
}
}

@ -2,22 +2,18 @@ import 'dart:async';
import 'package:flutter/material.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/core/location_util.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/core/utils/doctor_response_mapper.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart';
import 'package:hmg_patient_app_new/features/authentication/models/resp_models/authenticated_user_resp_model.dart';
import 'package:hmg_patient_app_new/features/emergency_services/emergency_services_repo.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/EROnlineCheckInPaymentDetailsResponse.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/facility_selection.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/AmbulanceCallingPlace.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/request_model/PatientER_RC.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/AmbulanceRequestOrdersModel.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/EROnlineCheckInPaymentDetailsResponse.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/PatientERTransportationMethod.dart'
show PatientERTransportationMethod;
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/ProjectAvgERWaitingTime.dart';
@ -25,16 +21,14 @@ import 'package:hmg_patient_app_new/features/emergency_services/models/resp_mode
import 'package:hmg_patient_app_new/features/location/PlaceDetails.dart' show PlaceDetails;
import 'package:hmg_patient_app_new/features/location/PlacePrediction.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/facility_selection.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/doctor_list_api_response.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_repo.dart';
import 'package:hmg_patient_app_new/presentation/authentication/login.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/call_ambulance_page.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/er_online_checkin/er_online_checkin_home.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/er_online_checkin/er_online_checkin_payment_details_page.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/requesting_services_page.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/tracking_screen.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/er_online_checkin/er_online_checkin_home.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/er_online_checkin/er_online_checkin_payment_details_page.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/nearest_er_page.dart';
import 'package:hmg_patient_app_new/routes/app_routes.dart' show AppRoutes;
import 'package:hmg_patient_app_new/services/dialog_service.dart';
@ -104,8 +98,7 @@ class EmergencyServicesViewModel extends ChangeNotifier {
notifyListeners();
}
get isGMSAvailable
{
get isGMSAvailable {
return appState.isGMSAvailable;
}
@ -173,7 +166,8 @@ class EmergencyServicesViewModel extends ChangeNotifier {
if (query.isEmpty) {
nearestERFilteredList = nearestERList;
} else {
nearestERFilteredList = nearestERList.where((er) => er.projectName != null && er.projectName!.toLowerCase().contains(query.toLowerCase())).toList();
nearestERFilteredList =
nearestERList.where((er) => er.projectName != null && er.projectName!.toLowerCase().contains(query.toLowerCase())).toList();
}
notifyListeners();
}
@ -256,8 +250,7 @@ class EmergencyServicesViewModel extends ChangeNotifier {
onSuccess: (position) {
updateBottomSheetState(BottomSheetType.FIXED);
navServices.push(
CustomPageRoute(
page: CallAmbulancePage(), direction: AxisDirection.down),
CustomPageRoute(page: CallAmbulancePage(), direction: AxisDirection.down),
);
});
} else {
@ -265,9 +258,7 @@ class EmergencyServicesViewModel extends ChangeNotifier {
message: "You Need To Login First To Continue".needTranslation,
onOkPressed: () {
navServices.pop();
navServices.pushAndReplace(
AppRoutes.loginScreen
);
navServices.pushAndReplace(AppRoutes.loginScreen);
});
}
}
@ -299,19 +290,20 @@ class EmergencyServicesViewModel extends ChangeNotifier {
void setIsGMSAvailable(bool value) {
notifyListeners();
}
Future<void> checkPatientERAdvanceBalance({Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await emergencyServicesRepo.checkPatientERAdvanceBalance();
result.fold(
// (failure) async => await errorHandlerService.handleError(failure: failure),
(failure) {
(failure) {
patientHasAdvanceERBalance = false;
isERBookAppointment = true;
if (onSuccess != null) {
onSuccess(failure.message);
}
},
(apiResponse) {
(apiResponse) {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
patientHasAdvanceERBalance = false;
@ -332,12 +324,12 @@ class EmergencyServicesViewModel extends ChangeNotifier {
final result = await emergencyServicesRepo.checkPatientERPaymentInformation(projectID: selectedHospital!.iD);
result.fold(
(failure) {
(failure) {
if (onError != null) {
onError(failure.message);
}
},
(apiResponse) {
(apiResponse) {
if (apiResponse.messageStatus == 2) {
} else if (apiResponse.messageStatus == 1) {
erOnlineCheckInPaymentDetailsResponse = apiResponse.data!;
@ -350,7 +342,8 @@ class EmergencyServicesViewModel extends ChangeNotifier {
);
}
Future<void> ER_CreateAdvancePayment({required String paymentMethodName, required String paymentReference, Function(dynamic)? onSuccess, Function(String)? onError}) async {
Future<void> ER_CreateAdvancePayment(
{required String paymentMethodName, required String paymentReference, Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await emergencyServicesRepo.createAdvancePaymentForER(
projectID: selectedHospital!.iD,
authUser: appState.getAuthenticatedUser()!,
@ -359,12 +352,12 @@ class EmergencyServicesViewModel extends ChangeNotifier {
paymentReference: paymentReference);
result.fold(
(failure) {
(failure) {
if (onError != null) {
onError(failure.message);
}
},
(apiResponse) {
(apiResponse) {
if (apiResponse.messageStatus == 2) {
} else if (apiResponse.messageStatus == 1) {
// erOnlineCheckInPaymentDetailsResponse = apiResponse.data!;
@ -378,12 +371,17 @@ class EmergencyServicesViewModel extends ChangeNotifier {
}
Future<void> addAdvanceNumberRequest(
{required String advanceNumber, required String paymentReference, required String appointmentNo, Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await emergencyServicesRepo.addAdvanceNumberRequest(advanceNumber: advanceNumber, paymentReference: paymentReference, appointmentNo: appointmentNo);
{required String advanceNumber,
required String paymentReference,
required String appointmentNo,
Function(dynamic)? onSuccess,
Function(String)? onError}) async {
final result = await emergencyServicesRepo.addAdvanceNumberRequest(
advanceNumber: advanceNumber, paymentReference: paymentReference, appointmentNo: appointmentNo);
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),
(apiResponse) {
(failure) async => await errorHandlerService.handleError(failure: failure),
(apiResponse) {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
@ -401,12 +399,12 @@ class EmergencyServicesViewModel extends ChangeNotifier {
result.fold(
// (failure) async => await errorHandlerService.handleError(failure: failure),
(failure) {
(failure) {
if (onError != null) {
onError(failure.message);
}
},
(apiResponse) {
(apiResponse) {
if (apiResponse.messageStatus == 2) {
if (onError != null) {
onError(apiResponse.errorMessage!);
@ -426,12 +424,12 @@ class EmergencyServicesViewModel extends ChangeNotifier {
result.fold(
// (failure) async => await errorHandlerService.handleError(failure: failure),
(failure) {
(failure) {
if (onError != null) {
onError(failure.message);
}
},
(apiResponse) {
(apiResponse) {
if (apiResponse.messageStatus == 2) {
if (onError != null) {
onError(apiResponse.data["InvoiceResponse"]["Message"]);
@ -457,7 +455,7 @@ class EmergencyServicesViewModel extends ChangeNotifier {
onOkPressed: () {
navServices.pop();
print("inside the ok button");
getIt<AuthenticationViewModel>().onLoginPressed();
getIt<AuthenticationViewModel>().onLoginPressed();
});
return;
}
@ -465,8 +463,7 @@ class EmergencyServicesViewModel extends ChangeNotifier {
if (transportationOptions.isNotEmpty) return;
int? id = appState.getAuthenticatedUser()?.patientId;
LoaderBottomSheet.showLoader(
loadingText: "Getting Ambulance Transport Option".needTranslation);
LoaderBottomSheet.showLoader(loadingText: "Getting Ambulance Transport Option".needTranslation);
notifyListeners();
var response = await emergencyServicesRepo.getTransportationMethods(id: id);
@ -485,8 +482,7 @@ class EmergencyServicesViewModel extends ChangeNotifier {
Future<void> getTransportationMethods() async {
int? id = appState.getAuthenticatedUser()?.patientId;
LoaderBottomSheet.showLoader(
loadingText: "Getting Ambulance Transport Option".needTranslation);
LoaderBottomSheet.showLoader(loadingText: "Getting Ambulance Transport Option".needTranslation);
notifyListeners();
var response = await emergencyServicesRepo.getTransportationMethods(id: id);
@ -597,11 +593,7 @@ class EmergencyServicesViewModel extends ChangeNotifier {
sourceList = hmcHospitalList;
break;
}
displayList = sourceList
?.where((hospital) =>
hospital.name != null &&
hospital.name!.toLowerCase().contains(query.toLowerCase()))
.toList();
displayList = sourceList?.where((hospital) => hospital.name != null && hospital.name!.toLowerCase().contains(query.toLowerCase())).toList();
notifyListeners();
}
@ -620,7 +612,6 @@ class EmergencyServicesViewModel extends ChangeNotifier {
notifyListeners();
}
void setSelectedHospital(HospitalsModel? hospital) {
selectedHospital = hospital;
notifyListeners();
@ -668,13 +659,12 @@ class EmergencyServicesViewModel extends ChangeNotifier {
}
Future<void> updateAppointment(bool value) async {
if (value) {
await getAppointments();
} else {
clearAppointmentData();
}
if(appointments?.isNotEmpty == true) {
if (appointments?.isNotEmpty == true) {
haveAnAppointment = value;
}
notifyListeners();
@ -729,18 +719,20 @@ class EmergencyServicesViewModel extends ChangeNotifier {
}
Future<void> getTransportationOrders({bool shouldNavigateToTrackingScreen = false, bool showLoader = false}) async {
if(shouldNavigateToTrackingScreen == false && showLoader ) {
if (shouldNavigateToTrackingScreen == false && showLoader) {
LoaderBottomSheet.showLoader(loadingText: "Fetching Orders");
}
int? id = appState.getAuthenticatedUser()?.patientId;
var response = await emergencyServicesRepo.getTransportationOrders(id: id);
if(shouldNavigateToTrackingScreen == false && showLoader ) {
LoaderBottomSheet.hideLoader();}
if (shouldNavigateToTrackingScreen == false && showLoader) {
LoaderBottomSheet.hideLoader();
}
response.fold(
(failure) async {
if (shouldNavigateToTrackingScreen) {
navServices.pushAndRemoveUntil(CustomPageRoute(page: TrackingScreen(state: OrderTrackingState.waitingForCall)), ModalRoute.withName("/EmergencyServicesPage"));
navServices.pushAndRemoveUntil(
CustomPageRoute(page: TrackingScreen(state: OrderTrackingState.waitingForCall)), ModalRoute.withName("/EmergencyServicesPage"));
}
},
(apiResponse) {

@ -8,6 +8,7 @@ import 'package:hmg_patient_app_new/core/exceptions/api_failure.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/resq_models/get_cmc_all_orders_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/services/logger_service.dart';
abstract class HmgServicesRepo {
@ -16,6 +17,8 @@ abstract class HmgServicesRepo {
Future<Either<Failure, GenericApiModel<bool>>> updateCmcPresOrder(OrderUpdateRequestModel requestModel);
Future<Either<Failure, GenericApiModel<List<GetCMCServicesResponseModel>>>> getAllCmcServices({required int patientID});
Future<Either<Failure, GenericApiModel<List<HospitalsModel>>>> getHospitalsList();
}
class HmgServicesRepoImp implements HmgServicesRepo {
@ -175,4 +178,66 @@ class HmgServicesRepoImp implements HmgServicesRepo {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<List<HospitalsModel>>>> getHospitalsList() async {
Map<String, dynamic> requestBody = {};
try {
GenericApiModel<List<HospitalsModel>>? apiResponse;
Failure? failure;
await apiClient.post(
ApiConsts.getHospitalsList,
isRCService: false, // This uses the base HIS API URL, not RC
body: requestBody,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
loggerService.logError("Get Hospitals List API Failed: $error, Status: $statusCode");
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
List<HospitalsModel> hospitalsList = [];
loggerService.logInfo("Hospitals List Raw Response: $response");
if (response['ListProject'] != null && response['ListProject'] is List) {
final projectsList = response['ListProject'] as List;
for (var projectJson in projectsList) {
try {
if (projectJson is Map<String, dynamic>) {
hospitalsList.add(HospitalsModel.fromJson(projectJson));
}
} catch (e) {
loggerService.logError('Error parsing hospital item: ${e.toString()}');
}
}
} else {
loggerService.logInfo('Hospitals list response array is empty or missing');
}
apiResponse = GenericApiModel<List<HospitalsModel>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: errorMessage,
data: hospitalsList,
);
loggerService.logInfo("Hospitals fetched successfully: ${hospitalsList.length} hospitals");
} catch (e) {
loggerService.logError("Error parsing hospitals list: ${e.toString()}");
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
loggerService.logError("Unknown error in getHospitalsList: ${e.toString()}");
return Left(UnknownFailure(e.toString()));
}
}
}

@ -1,22 +1,35 @@
import 'dart:developer';
import 'package:flutter/material.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/order_update_req_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/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/services/error_handler_service.dart';
class HmgServicesViewModel extends ChangeNotifier {
final HmgServicesRepo hmgServicesRepo;
final BookAppointmentsRepo bookAppointmentsRepo;
final ErrorHandlerService errorHandlerService;
HmgServicesViewModel({required this.hmgServicesRepo, required this.errorHandlerService});
HmgServicesViewModel({required this.bookAppointmentsRepo, required this.hmgServicesRepo, required this.errorHandlerService});
bool isCmcOrdersLoading = false;
bool isCmcServicesLoading = false;
bool isUpdatingOrder = false;
bool isHospitalListLoading = false;
List<GetCMCAllOrdersResponseModel> cmcOrdersList = [];
List<GetCMCServicesResponseModel> cmcServicesList = [];
List<HospitalsModel> hospitalsList = [];
List<HospitalsModel> filteredHospitalsList = [];
HospitalsModel? selectedHospital;
// CMC order creation state
HospitalsModel? selectedHospitalForOrder;
GetCMCServicesResponseModel? selectedServiceForOrder;
Future<void> getOrdersList() async {
cmcOrdersList.clear();
@ -134,4 +147,81 @@ class HmgServicesViewModel extends ChangeNotifier {
return success;
}
Future<void> getHospitalsList({Function(dynamic)? onSuccess, Function(String)? onError}) async {
isHospitalListLoading = true;
notifyListeners();
final result = await hmgServicesRepo.getHospitalsList();
result.fold(
(failure) async {
isHospitalListLoading = false;
notifyListeners();
await errorHandlerService.handleError(failure: failure);
if (onError != null) {
onError(failure.toString());
}
},
(apiResponse) {
isHospitalListLoading = false;
if (apiResponse.messageStatus == 1) {
log("apiResponse.messageStatus: ${apiResponse.data}");
hospitalsList = apiResponse.data ?? [];
filteredHospitalsList = List.from(hospitalsList);
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
} else {
notifyListeners();
if (onError != null) {
onError(apiResponse.errorMessage ?? 'Unknown error');
}
}
},
);
}
void filterHospitalsByString(String searchText, bool isArabic) {
if (searchText.isEmpty) {
filteredHospitalsList = List.from(hospitalsList);
} else {
filteredHospitalsList = hospitalsList.where((HospitalsModel hospital) {
final name = isArabic ? (hospital.nameN ?? '') : (hospital.name ?? '');
return name.toLowerCase().contains(searchText.toLowerCase());
}).toList();
}
notifyListeners();
}
void setSelectedHospital(HospitalsModel? hospital) {
selectedHospital = hospital;
notifyListeners();
}
void clearHospitalSelection() {
selectedHospital = null;
filteredHospitalsList = List.from(hospitalsList);
notifyListeners();
}
// CMC Order management methods
void setSelectedHospitalForOrder(HospitalsModel? hospital) {
selectedHospitalForOrder = hospital;
notifyListeners();
}
void setSelectedServiceForOrder(GetCMCServicesResponseModel? service) {
selectedServiceForOrder = service;
notifyListeners();
}
void clearOrderSelection() {
selectedHospitalForOrder = null;
selectedServiceForOrder = null;
notifyListeners();
}
bool get isOrderReadyToConfirm => selectedHospitalForOrder != null && selectedServiceForOrder != null;
}

@ -1,18 +1,13 @@
import 'package:easy_localization/easy_localization.dart'
show tr, StringTranslateExtension;
import 'package:easy_localization/easy_localization.dart' show StringTranslateExtension;
import 'package:flutter/material.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/features/book_appointments/book_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/appointment_via_region_viewmodel.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/facility_selection.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/hospital_bottom_sheet/hospital_list_items.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/hospital_bottom_sheet/type_selection_widget.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/theme/colors.dart' show AppColors;
import 'package:hmg_patient_app_new/widgets/input_widget.dart';
import 'package:provider/provider.dart';
@ -53,8 +48,8 @@ class HospitalBottomSheetBody extends StatelessWidget {
hintText: LocaleKeys.searchHospital.tr(),
controller: searchText,
onChange: (value) {
appointmentsViewModel.filterHospitalListByString(value, regionalViewModel.selectedRegionId , regionalViewModel.selectedFacilityType ==
FacilitySelection.HMG.name);
appointmentsViewModel.filterHospitalListByString(
value, regionalViewModel.selectedRegionId, regionalViewModel.selectedFacilityType == FacilitySelection.HMG.name);
},
isEnable: true,
prefix: null,
@ -77,25 +72,15 @@ class HospitalBottomSheetBody extends StatelessWidget {
SizedBox(
height: MediaQuery.sizeOf(context).height * .4,
child: ListView.separated(
itemBuilder: (_, index)
{
var hospital = regionalViewModel.selectedFacilityType ==
FacilitySelection.HMG.name
? appointmentsViewModel
.filteredHospitalList!
.registeredDoctorMap![
regionalViewModel.selectedRegionId!]!
.hmgDoctorList![index]
: appointmentsViewModel
.filteredHospitalList
?.registeredDoctorMap?[
regionalViewModel.selectedRegionId!]
?.hmcDoctorList?[index];
itemBuilder: (_, index) {
var hospital = regionalViewModel.selectedFacilityType == FacilitySelection.HMG.name
? appointmentsViewModel.filteredHospitalList!.registeredDoctorMap![regionalViewModel.selectedRegionId!]!.hmgDoctorList![index]
: appointmentsViewModel.filteredHospitalList?.registeredDoctorMap?[regionalViewModel.selectedRegionId!]?.hmcDoctorList?[index];
return HospitalListItem(
hospitalData: hospital,
isLocationEnabled: appointmentsViewModel.isLocationEnabled(),
).onPress(() {
regionalViewModel.setHospitalModel(hospital);
hospitalData: hospital,
isLocationEnabled: appointmentsViewModel.isLocationEnabled(),
).onPress(() {
regionalViewModel.setHospitalModel(hospital);
if (regionalViewModel.regionBottomSheetType == RegionBottomSheetType.FOR_REGION) {
regionalViewModel.setBottomSheetState(AppointmentViaRegionState.CLINIC_SELECTION);
regionalViewModel.handleLastStepForRegion();
@ -104,21 +89,18 @@ class HospitalBottomSheetBody extends StatelessWidget {
regionalViewModel.handleLastStepForClinic();
} else if (regionalViewModel.regionBottomSheetType == RegionBottomSheetType.REGION_FOR_DENTAL_AND_LASER) {
regionalViewModel.setBottomSheetState(AppointmentViaRegionState.DOCTOR_SELECTION);
regionalViewModel.handleLastStepForClinicForDentalAndLaser(appointmentsViewModel.selectedClinic.clinicID??-1);
regionalViewModel.handleLastStepForClinicForDentalAndLaser(appointmentsViewModel.selectedClinic.clinicID ?? -1);
// regionalViewModel.handleLastStepForClinic();
}
});},
});
},
separatorBuilder: (_, __) => SizedBox(
height: 16.h,
),
itemCount: (regionalViewModel.selectedFacilityType ==
FacilitySelection.HMG.name
? (appointmentsViewModel.filteredHospitalList?.registeredDoctorMap?[
regionalViewModel.selectedRegionId]?.hmgDoctorList)
: (appointmentsViewModel
.filteredHospitalList
?.registeredDoctorMap?[
regionalViewModel.selectedRegionId]?.hmcDoctorList))?.length ??
itemCount: (regionalViewModel.selectedFacilityType == FacilitySelection.HMG.name
? (appointmentsViewModel.filteredHospitalList?.registeredDoctorMap?[regionalViewModel.selectedRegionId]?.hmgDoctorList)
: (appointmentsViewModel.filteredHospitalList?.registeredDoctorMap?[regionalViewModel.selectedRegionId]?.hmcDoctorList))
?.length ??
0),
)
],

@ -0,0 +1,380 @@
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/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/route_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/features/hmg_services/hmg_services_view_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/presentation/comprehensive_checkup/widgets/cmc_hospital_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:maps_launcher/maps_launcher.dart';
import 'package:provider/provider.dart';
class CmcSelectionReviewPage extends StatefulWidget {
final GetCMCServicesResponseModel selectedService;
final HospitalsModel? preSelectedHospital;
const CmcSelectionReviewPage({
super.key,
required this.selectedService,
this.preSelectedHospital,
});
@override
State<CmcSelectionReviewPage> createState() => _CmcSelectionReviewPageState();
}
class _CmcSelectionReviewPageState extends State<CmcSelectionReviewPage> {
@override
void initState() {
super.initState();
// Initialize ViewModel state with preselected hospital if provided
if (widget.preSelectedHospital != null) {
WidgetsBinding.instance.addPostFrameCallback((_) {
final hmgServicesViewModel = context.read<HmgServicesViewModel>();
hmgServicesViewModel.setSelectedHospitalForOrder(widget.preSelectedHospital);
hmgServicesViewModel.setSelectedServiceForOrder(widget.selectedService);
});
}
}
@override
Widget build(BuildContext context) {
final appState = getIt.get<AppState>();
final isArabic = appState.isArabic();
return CollapsingListView(
title: "Summary".needTranslation,
bottomChild: _buildBottomButton(),
child: SingleChildScrollView(
padding: EdgeInsets.all(16.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildOrderSummaryCard(isArabic),
SizedBox(height: 16.h),
_buildSelectedServiceCard(isArabic),
],
),
),
);
}
Widget _buildOrderSummaryCard(bool isArabic) {
return Consumer<HmgServicesViewModel>(
builder: (context, hmgServicesViewModel, child) {
final selectedHospital = hmgServicesViewModel.selectedHospitalForOrder;
final isLocationSelected = selectedHospital != null;
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 16.r,
),
padding: EdgeInsets.all(16.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Select Hospital".needTranslation,
style: TextStyle(
fontSize: 16.f,
fontWeight: FontWeight.w700,
color: AppColors.blackColor,
letterSpacing: -0.5,
),
),
SizedBox(height: 12.h),
_buildHospitalSelector(isArabic, selectedHospital, isLocationSelected),
if (isLocationSelected && selectedHospital != null) ...[
SizedBox(height: 16.h),
_buildHospitalMap(selectedHospital),
],
],
),
);
},
);
}
Widget _buildHospitalSelector(bool isArabic, HospitalsModel? selectedHospital, bool isLocationSelected) {
return InkWell(
onTap: _showHospitalSelectionBottomSheet,
child: 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: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
isLocationSelected && selectedHospital != null
? (isArabic ? (selectedHospital.nameN ?? selectedHospital.name ?? '') : (selectedHospital.name ?? ''))
: "Select Hospital".needTranslation,
style: TextStyle(
fontSize: 14.f,
fontWeight: isLocationSelected ? FontWeight.w600 : FontWeight.w400,
color: isLocationSelected ? AppColors.blackColor : AppColors.greyTextColor,
letterSpacing: -0.4,
),
),
],
),
),
Icon(
Icons.keyboard_arrow_down,
color: AppColors.greyTextColor,
size: 24.h,
),
],
),
),
);
}
Widget _buildHospitalMap(HospitalsModel selectedHospital) {
final String lat = selectedHospital.latitude ?? "0.0";
final String lng = selectedHospital.longitude ?? "0.0";
if (lat == "0.0" || lng == "0.0") return SizedBox.shrink();
// final String staticMapUrl =
// "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";
return Stack(
children: [
ClipRRect(
borderRadius: BorderRadius.circular(12.r),
child: Image.network(
"staticMapUrl",
height: 200.h,
width: double.infinity,
fit: BoxFit.cover,
loadingBuilder: (context, child, loadingProgress) {
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,
),
),
],
),
),
),
),
],
);
}
Widget _buildSelectedServiceCard(bool isArabic) {
final serviceName = isArabic ? (widget.selectedService.textN ?? widget.selectedService.text ?? '') : (widget.selectedService.text ?? '');
final price = widget.selectedService.priceTotal ?? 0.0;
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 16.r,
),
padding: EdgeInsets.all(16.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Selected Service".needTranslation.toText14(
weight: FontWeight.w600,
color: AppColors.greyTextColor,
letterSpacing: -0.4,
),
SizedBox(height: 12.h),
Row(
children: [
Expanded(child: serviceName.toText16(weight: FontWeight.w700, color: AppColors.blackColor, letterSpacing: -0.5)),
],
),
SizedBox(height: 8.h),
Row(
children: [
"${"Price".needTranslation}: ".toText14(weight: FontWeight.w500, color: AppColors.greyTextColor, letterSpacing: -0.4),
Utils.getPaymentAmountWithSymbol(
isExpanded: false,
price.toString().toText14(weight: FontWeight.w700),
AppColors.primaryRedColor,
16,
isSaudiCurrency: true,
),
],
),
],
),
);
}
Widget _buildBottomButton() {
return Consumer<HmgServicesViewModel>(
builder: (context, hmgServicesViewModel, child) {
final isLocationSelected = hmgServicesViewModel.selectedHospitalForOrder != null;
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: () {
isLocationSelected ? _handleConfirm : null;
},
textColor: AppColors.whiteColor,
backgroundColor: isLocationSelected ? AppColors.successColor : AppColors.greyColor,
borderRadius: 12.r,
borderColor: Colors.transparent,
borderWidth: 0,
padding: EdgeInsets.symmetric(vertical: 14.h),
),
),
);
},
);
}
void _showHospitalSelectionBottomSheet() {
CmcHospitalSelectionHelper.showHospitalSelectionBottomSheet(context: context, onHospitalSelected: (hospital) => context.pop());
}
void _launchDirections(HospitalsModel selectedHospital) {
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) {
MapsLauncher.launchCoordinates(
lat,
lng,
selectedHospital.name ?? "Hospital",
);
}
}
void _handleConfirm() {
final hmgServicesViewModel = context.read<HmgServicesViewModel>();
final selectedHospital = hmgServicesViewModel.selectedHospitalForOrder;
if (selectedHospital == null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text("Please select a hospital to continue".needTranslation),
backgroundColor: AppColors.errorColor,
),
);
return;
}
// TODO: Implement order creation API call
// Create CMC order with:
// - hmgServicesViewModel.selectedServiceForOrder (the medical checkup service)
// - hmgServicesViewModel.selectedHospitalForOrder (the chosen hospital)
// - Call hmgServicesViewModel.createCmcOrder() or similar method
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
"Order confirmed! Service: ${widget.selectedService.text}, Hospital: ${selectedHospital.name}",
),
backgroundColor: AppColors.successColor,
),
);
// Navigate back after confirmation
Future.delayed(Duration(seconds: 2), () {
Navigator.of(context).pop();
Navigator.of(context).pop();
// Clear order selection after successful confirmation
hmgServicesViewModel.clearOrderSelection();
});
}
}

@ -12,6 +12,8 @@ import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_view_mode
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/features/hmg_services/models/resq_models/get_cmc_services_resp_model.dart';
import 'package:hmg_patient_app_new/presentation/comprehensive_checkup/cmc_order_detail_page.dart';
import 'package:hmg_patient_app_new/presentation/comprehensive_checkup/cmc_selection_review_page.dart';
import 'package:hmg_patient_app_new/presentation/comprehensive_checkup/widgets/cmc_hospital_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';
@ -264,10 +266,14 @@ class _ComprehensiveCheckupPageState extends State<ComprehensiveCheckupPage> {
color: Color.fromARGB(51, 0, 0, 0),
borderRadius: BorderRadius.circular(1000.r),
),
margin: EdgeInsets.all(12.h),
margin: EdgeInsets.all(16.h),
child: IconButton(
icon: Icon(Icons.zoom_in, color: Colors.white),
padding: EdgeInsets.all(12.h),
icon: Icon(
Icons.zoom_in,
color: Colors.white,
size: 26.w,
),
padding: EdgeInsets.all(10.h),
onPressed: () => _showFullScreenImage(context, imagePath, isSvg: false),
),
),
@ -281,13 +287,26 @@ class _ComprehensiveCheckupPageState extends State<ComprehensiveCheckupPage> {
void _proceedWithSelectedService() {
if (_selectedService != null) {
// TODO: Navigate to next step or create order
// This will be implemented based on your flow
// For now, just show a message
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Selected: ${_selectedService!.text}'),
),
final hmgServicesViewModel = context.read<HmgServicesViewModel>();
// Store selected service in ViewModel
hmgServicesViewModel.setSelectedServiceForOrder(_selectedService);
hmgServicesViewModel.getHospitalsList();
// Show hospital selection bottom sheet using common helper
CmcHospitalSelectionHelper.showHospitalSelectionBottomSheet(
context: context,
onHospitalSelected: (hospital) {
// Navigate to review page
Navigator.of(context).pushReplacement(
CustomPageRoute(
page: CmcSelectionReviewPage(
selectedService: _selectedService!,
preSelectedHospital: hospital,
),
direction: AxisDirection.down,
),
);
},
);
}
}
@ -319,18 +338,11 @@ class _ComprehensiveCheckupPageState extends State<ComprehensiveCheckupPage> {
Widget build(BuildContext context) {
return CollapsingListView(
title: "Comprehensive Checkup".needTranslation,
requests: () {
Navigator.of(context).push(CustomPageRoute(page: CmcOrderDetailPage(), direction: AxisDirection.up));
},
// bottomChild sticks to the bottom of the scaffold; make it reactive using Consumer
history: () => Navigator.of(context).push(CustomPageRoute(page: CmcOrderDetailPage(), direction: AxisDirection.up)),
bottomChild: Consumer<HmgServicesViewModel>(
builder: (context, hmgServicesViewModel, child) {
// if still loading, don't show the bottom button
if (hmgServicesViewModel.isCmcOrdersLoading || hmgServicesViewModel.isCmcServicesLoading) return SizedBox.shrink();
final pendingOrder = _getPendingOrder(hmgServicesViewModel.cmcOrdersList);
// show button only when there is no pending order and a service is selected
if (pendingOrder == null && _selectedServiceId != null) {
return SafeArea(
top: false,
@ -348,7 +360,6 @@ class _ComprehensiveCheckupPageState extends State<ComprehensiveCheckupPage> {
),
);
}
return SizedBox.shrink();
},
),
@ -357,12 +368,8 @@ class _ComprehensiveCheckupPageState extends State<ComprehensiveCheckupPage> {
if (hmgServicesViewModel.isCmcOrdersLoading || hmgServicesViewModel.isCmcServicesLoading) {
return _buildLoadingShimmer();
}
final pendingOrder = _getPendingOrder(hmgServicesViewModel.cmcOrdersList);
if (pendingOrder != null) {
// Return the pending order card directly. The outer CollapsingListView's
// CustomScrollView/SliverList will provide proper scroll constraints.
return _buildPendingOrderCard(pendingOrder);
} else {
return _buildServiceSelectionList(hmgServicesViewModel.cmcServicesList);

@ -1,195 +1,427 @@
// import 'dart:async';
//
// import 'package:hmg_patient_app/core/enum/viewstate.dart';
// import 'package:hmg_patient_app/core/model/AlHabibMedicalService/ComprehensiveMedicalCheckup/cmc_insert_pres_order_request_model.dart';
// import 'package:hmg_patient_app/core/model/ImagesInfo.dart';
// import 'package:hmg_patient_app/core/model/hospitals/hospitals_model.dart';
// import 'package:hmg_patient_app/core/viewModels/AlHabibMedicalService/cmc_view_model.dart';
// import 'package:hmg_patient_app/core/viewModels/project_view_model.dart';
// import 'package:hmg_patient_app/pages/AlHabibMedicalService/ComprehensiveMedicalCheckup/NewCMC/new_cmc_step_three_page.dart';
// import 'package:hmg_patient_app/pages/AlHabibMedicalService/ComprehensiveMedicalCheckup/Dialog/confirm_dialog.dart';
// import 'package:hmg_patient_app/services/clinic_services/get_clinic_service.dart';
// import 'package:hmg_patient_app/theme/colors.dart';
// import 'package:hmg_patient_app/uitl/app_toast.dart';
// import 'package:hmg_patient_app/uitl/gif_loader_dialog_utils.dart';
// import 'package:hmg_patient_app/uitl/translations_delegate_base.dart';
// import 'package:hmg_patient_app/uitl/utils.dart';
// import 'package:hmg_patient_app/uitl/utils_new.dart';
// import 'package:hmg_patient_app/widgets/buttons/defaultButton.dart';
// import 'package:hmg_patient_app/widgets/dragable_sheet.dart';
// import 'package:hmg_patient_app/widgets/others/app_scaffold_widget.dart';
// import 'package:hmg_patient_app/widgets/photo_view_page.dart';
// import 'package:flutter/cupertino.dart';
// import 'package:flutter/material.dart';
// import 'package:flutter_svg/svg.dart';
// import 'package:flutter_svg/flutter_svg.dart';
// import 'package:google_maps_flutter/google_maps_flutter.dart';
// import 'package:maps_launcher/maps_launcher.dart';
// import 'package:provider/provider.dart';
//
// import 'new_cmc_step_tow_page.dart';
//
// class NewCMCStepOnePage extends StatefulWidget {
// final CMCInsertPresOrderRequestModel cMCInsertPresOrderRequestModel;
// final Function changePageViewIndex;
// class NewCMCStepThreePage extends StatefulWidget {
// final CMCInsertPresOrderRequestModel cmcInsertPresOrderRequestModel;
// final CMCViewModel model;
//
// final double latitude;
// final double longitude;
//
// const NewCMCStepOnePage({Key? key, required this.cMCInsertPresOrderRequestModel, required this.model, required this.changePageViewIndex, required this.latitude, required this.longitude})
// : super(key: key);
// NewCMCStepThreePage(
// {Key? key,
// required this.model,
// required this.cmcInsertPresOrderRequestModel});
//
// @override
// _NewCMCStepOnePageState createState() => _NewCMCStepOnePageState();
// _NewCMCStepThreePageState createState() => _NewCMCStepThreePageState();
// }
//
// class _NewCMCStepOnePageState extends State<NewCMCStepOnePage> {
// int selectedItem = 0;
// class _NewCMCStepThreePageState extends State<NewCMCStepThreePage> {
// Completer<GoogleMapController> _controller = Completer();
//
// String? projectDropdownValue;
// late List<HospitalsModel> projectsList = [];
// HospitalsModel? selectedHospital;
// final GlobalKey projectDropdownKey = GlobalKey();
// bool isLocationSelected = false;
// ProjectViewModel? projectViewModel;
//
// static CameraPosition _kGooglePlex = CameraPosition(
// target: LatLng(37.42796133580664, -122.085749655962),
// zoom: 14.4746,
// );
// final Set<Marker> markers = new Set();
//
// @override
// void initState() {
// if (widget.cmcInsertPresOrderRequestModel.latitude != null) {
// markers.clear();
// markers.add(
// Marker(
// markerId: MarkerId(
// widget.cmcInsertPresOrderRequestModel.latitude.hashCode
// .toString(),
// ),
// position: LatLng(widget.cmcInsertPresOrderRequestModel.latitude!,
// widget.cmcInsertPresOrderRequestModel.longitude!)),
// );
// _kGooglePlex = CameraPosition(
// target: LatLng(widget.cmcInsertPresOrderRequestModel.latitude!,
// widget.cmcInsertPresOrderRequestModel.longitude!),
// zoom: 14.4746,
// );
// }
// WidgetsBinding.instance.addPostFrameCallback((_) {
// // if (projectViewModel.isLogin) {
// getProjectsList();
// // }
// });
// super.initState();
// }
//
// @override
// Widget build(BuildContext context) {
// ProjectViewModel projectViewModel = Provider.of(context);
//
// projectViewModel = Provider.of(context);
// return AppScaffold(
// isShowAppBar: false,
// isShowAppBar: true,
// description: TranslationBase.of(context).infoCMC,
// imagesInfo: [
// ImagesInfo(
// imageAr: 'https://hmgwebservices.com/Images/MobileApp/CMC/ar/0.png',
// imageEn:
// 'https://hmgwebservices.com/Images/MobileApp/CMC/en/0.png'),
// ],
// appBarTitle: TranslationBase.of(context).comprehensiveMedicalCheckup,
// showNewAppBar: true,
// showNewAppBarTitle: true,
// backgroundColor: CustomColors.appBackgroudGreyColor,
// baseViewModel: widget.model,
// body: Column(
// children: [
// Expanded(
// child: SingleChildScrollView(
// physics: BouncingScrollPhysics(),
// padding: EdgeInsets.all(21),
// child: Column(
// children: [
// ListView.separated(
// physics: NeverScrollableScrollPhysics(),
// shrinkWrap: true,
// itemBuilder: (context, index) {
// return Row(
// body: SingleChildScrollView(
// physics: BouncingScrollPhysics(),
// child: Container(
// height: 500,
// width: double.maxFinite,
// margin: EdgeInsets.only(left: 12, right: 12),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// SizedBox(
// height: 12,
// ),
// Text(
// TranslationBase.of(context).orderSummary,
// style: TextStyle(
// fontSize: 16,
// fontWeight: FontWeight.bold,
// letterSpacing: -0.46,
// ),
// ),
// SizedBox(
// height: 12,
// ),
// Container(
// decoration: cardRadius(12),
// child: Container(
// padding: EdgeInsets.all(8),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Container(
// width: double.infinity,
// decoration: containerRadius(Colors.white, 12),
// margin: EdgeInsets.only(top: 12),
// padding: EdgeInsets.only(
// left: 0, right: 0, top: 0, bottom: 12),
// child: Row(
// children: [
// Radio(
// value: num.tryParse(widget.model.cmcAllServicesList[index].serviceID!),
// activeColor: Colors.red[800],
// onChanged: (newValue) async {
// selectedItem = index;
// PatientERCMCInsertServicesList patientERCMCInsertServicesList = PatientERCMCInsertServicesList(
// price: widget.model.cmcAllServicesList[index].price,
// serviceID: widget.model.cmcAllServicesList[index].serviceID,
// selectedServiceName: widget.model.cmcAllServicesList[index].text,
// selectedServiceNameAR: widget.model.cmcAllServicesList[index].textN,
// recordID: 1,
// totalPrice: widget.model.cmcAllServicesList[index].priceTotal,
// vAT: widget.model.cmcAllServicesList[index].priceVAT);
// setState(() {
// widget.cMCInsertPresOrderRequestModel.patientERCMCInsertServicesList = [patientERCMCInsertServicesList];
// });
// // CMCGetItemsRequestModel cMCGetItemsRequestModel = new CMCGetItemsRequestModel(checkupType: newValue);
// // await widget.model.getCheckupItems(cMCGetItemsRequestModel: cMCGetItemsRequestModel);
// },
// groupValue: widget.cMCInsertPresOrderRequestModel.patientERCMCInsertServicesList!.length > 0
// ? int.parse(widget.cMCInsertPresOrderRequestModel.patientERCMCInsertServicesList![0].serviceID!)
// : 1),
// Expanded(
// child: Padding(
// padding: const EdgeInsets.only(
// left: 10,
// right: 10,
// top: 20,
// bottom: 20,
// ),
// child: Text(
// projectViewModel.isArabic ? widget.model.cmcAllServicesList[index].textN! : widget.model.cmcAllServicesList[index].text!,
// style: TextStyle(
// fontSize: 14,
// fontWeight: FontWeight.w600,
// letterSpacing: -0.45,
// Flexible(
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(
// TranslationBase.of(context).selectLocation,
// style: TextStyle(
// fontSize: 11,
// letterSpacing: -0.44,
// fontWeight: FontWeight.w600,
// ),
// ),
// ),
// Container(
// height: 18,
// child: DropdownButtonHideUnderline(
// child: DropdownButton<HospitalsModel>(
// key: projectDropdownKey,
// hint: new Text(
// TranslationBase.of(context)
// .selectHospital),
// value: selectedHospital,
// iconSize: 0,
// isExpanded: true,
// style: TextStyle(
// fontSize: 14,
// letterSpacing: -0.56,
// color: Colors.black),
// items: projectsList.map((item) {
// return new DropdownMenuItem<
// HospitalsModel>(
// value: item,
// child: new Text(item.name!),
// );
// }).toList(),
// onChanged:
// (HospitalsModel? newValue) async {
// setState(() {
// selectedHospital = newValue!;
// projectDropdownValue = newValue
// .mainProjectID
// .toString();
// isLocationSelected = true;
// widget.cmcInsertPresOrderRequestModel
// .projectID =
// newValue.mainProjectID;
// // getDoctorsList(context);
// });
// },
// ),
// ),
// ),
// ],
// ),
// ),
// Icon(Icons.keyboard_arrow_down),
// ],
// );
// },
// separatorBuilder: (context, index) {
// return mDivider(Colors.grey);
// },
// itemCount: widget.model.cmcAllServicesList.length),
// Stack(
// children: [
// Image.asset(
// projectViewModel.isArabic ? "assets/images/cc_ar.png" : "assets/images/cc_en.png",
// width: double.infinity,
// ),
// ),
// Align(
// alignment: Alignment.topRight,
// child: Container(
// decoration: containerColorRadiusBorder(
// Colors.black.withOpacity(0.2),
// 1000,
// Colors.white,
// ),
// margin: EdgeInsets.all(12),
// child: IconButton(
// icon: SvgPicture.asset(
// "assets/images/new/ic_zoom.svg",
// color: Colors.white,
// SizedBox(
// height: 6,
// ),
// isLocationSelected
// ? Padding(
// padding: const EdgeInsets.all(8.0),
// child: Stack(
// children: [
// Container(
// height: 200,
// decoration: containerColorRadiusBorder(
// Colors.white, 12, Colors.grey),
// clipBehavior: Clip.antiAlias,
// child: Container(
// decoration: cardRadius(12),
// clipBehavior: Clip.antiAlias,
// margin: const EdgeInsets.all(0),
// child: Image.network(
// "https://maps.googleapis.com/maps/api/staticmap?center=" +
// selectedHospital!.latitude
// .toString() +
// "," +
// selectedHospital!.longitude
// .toString() +
// "&zoom=16&size=600x300&maptype=roadmap&markers=color:red%7C" +
// selectedHospital!.latitude
// .toString() +
// "," +
// selectedHospital!.longitude
// .toString() +
// "&key=AIzaSyCyDbWUM9d_sBUGIE8PcuShzPaqO08NSC8",
// width: double.infinity,
// height: double.infinity,
// fit: BoxFit.cover,
// ),
// ),
// ),
// padding: EdgeInsets.all(12),
// onPressed: () {
// showDraggableDialog(context, PhotoViewPage(projectViewModel.isArabic ? "assets/images/cc_ar.png" : "assets/images/cc_en.png"));
// },
// ),
// Row(
// mainAxisAlignment: MainAxisAlignment.end,
// crossAxisAlignment: CrossAxisAlignment.end,
// children: [
// InkWell(
// onTap: () {
// getDirections();
// },
// child: Container(
// decoration: cardRadius(1000),
// margin: EdgeInsets.all(12),
// child: Padding(
// padding: const EdgeInsets.only(
// left: 12,
// right: 12,
// top: 6,
// bottom: 6),
// child: Row(
// children: [
// Padding(
// padding:
// const EdgeInsets.all(3.0),
// child: SvgPicture.asset(
// "assets/images/new/direction.svg",
// width: 13,
// height: 13,
// ),
// ),
// mWidth(6),
// Text(
// TranslationBase.of(context)
// .getDirections,
// style: TextStyle(
// color: Colors.black,
// fontSize: 11,
// letterSpacing: -0.44,
// fontWeight: FontWeight.w600,
// ),
// )
// ],
// ),
// ),
// ),
// ),
// ],
// ),
// ],
// ),
// )
// : Container(),
// SizedBox(
// height: 12,
// ),
// Text(
// TranslationBase.of(context).selectedService,
// style: TextStyle(
// fontSize: 14,
// fontWeight: FontWeight.bold,
// letterSpacing: -0.46,
// color: CustomColors.grey,
// ),
// ),
// ...List.generate(
// widget.cmcInsertPresOrderRequestModel
// .patientERCMCInsertServicesList!.length,
// (index) => Container(
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(
// projectViewModel!.isArabic
// ? widget
// .cmcInsertPresOrderRequestModel
// .patientERCMCInsertServicesList![index]
// .selectedServiceNameAR!
// : widget
// .cmcInsertPresOrderRequestModel
// .patientERCMCInsertServicesList![index]
// .selectedServiceName!,
// style: TextStyle(
// fontSize: 12,
// fontWeight: FontWeight.bold,
// letterSpacing: -0.46,
// ),
// ),
// ],
// ),
// ),
// )
// ],
// ),
// ],
// ),
// ),
// ),
// )
// ],
// ),
// Container(
// color: Colors.white,
// padding: EdgeInsets.only(top: 16, bottom: 16, right: 21, left: 21),
// child: DefaultButton(
// TranslationBase.of(context).next,
// () async {
// if (widget.cMCInsertPresOrderRequestModel.patientERCMCInsertServicesList!.length != 0 || widget.cMCInsertPresOrderRequestModel.patientERCMCInsertServicesList == null) {
// // int index = widget.model.cmcAllServicesList.length;
// PatientERCMCInsertServicesList patientERCMCInsertServicesList = new PatientERCMCInsertServicesList(
// price: widget.model.cmcAllServicesList[selectedItem].price,
// serviceID: widget.model.cmcAllServicesList[selectedItem].serviceID.toString(),
// selectedServiceName: widget.model.cmcAllServicesList[selectedItem].text,
// selectedServiceNameAR: widget.model.cmcAllServicesList[selectedItem].textN,
// recordID: 1,
// totalPrice: widget.model.cmcAllServicesList[selectedItem].priceTotal,
// vAT: widget.model.cmcAllServicesList[selectedItem].priceVAT,
// );
//
// widget.cMCInsertPresOrderRequestModel.patientID = projectViewModel.user!.patientID;
// widget.cMCInsertPresOrderRequestModel.patientOutSA = projectViewModel.user!.outSA;
//
// widget.cMCInsertPresOrderRequestModel.patientERCMCInsertServicesList = [patientERCMCInsertServicesList];
// navigateTo(
// context,
// NewCMCStepThreePage(
// cmcInsertPresOrderRequestModel: widget.cMCInsertPresOrderRequestModel,
// model: widget.model,
// ),
// );
// // await widget.model.getCustomerInfo();
// if (widget.model.state == ViewState.ErrorLocal) {
// Utils.showErrorToast();
// ),
// ),
// bottomSheet: Container(
// height: MediaQuery.of(context).size.height * 0.10,
// width: double.infinity,
// color: Colors.white,
// child: Column(
// mainAxisAlignment: MainAxisAlignment.center,
// children: <Widget>[
// Container(
// width: MediaQuery.of(context).size.width * 0.9,
// child: DefaultButton(
// TranslationBase.of(context).confirm,
// !isLocationSelected
// ? null
// : () async {
// GifLoaderDialogUtils.showMyDialog(context);
// String requestId = await widget.model.insertCMCOrderRC(
// order: widget.cmcInsertPresOrderRequestModel);
// GifLoaderDialogUtils.hideDialog(context);
// if (widget.model.state != ViewState.ErrorLocal) {
// showCMCConfirmDialog(
// context,
// requestId,
// onClick: () {
// Navigator.pop(context);
// Navigator.pop(context);
// },
// );
// } else {
// // navigateTo(
// // context,
// // NewCMCStepTowPage(
// // longitude: widget.longitude,
// // latitude: widget.latitude,
// // cmcInsertPresOrderRequestModel: widget.cMCInsertPresOrderRequestModel,
// // model: widget.model,
// // ),
// // );
// AppToast.showErrorToast(message: widget.model.error);
// }
// }
// },
// },
// color: CustomColors.green,
// disabledColor: CustomColors.grey,
// ),
// // SecondaryButton(
// // label: TranslationBase.of(context).confirm,
// // color: CustomColors.green,
// // onTap: () async {
// // if(isLocationSelected) {
// // GifLoaderDialogUtils.showMyDialog(context);
// // String requestId = await widget.model.insertCMCOrderRC(order: widget.cmcInsertPresOrderRequestModel);
// // GifLoaderDialogUtils.hideDialog(context);
// // if (widget.model.state != ViewState.ErrorLocal) {
// // showCMCConfirmDialog(
// // context,
// // requestId,
// // onClick: () {
// // Navigator.pop(context);
// // Navigator.pop(context);
// // },
// // );
// // } else {
// // AppToast.showErrorToast(message: widget.model.error);
// // }
// // } else {
// // Utils.showErrorToast("Please select hospital from the dropdown menu to continue");
// // }
// // },
// // textColor: Theme.of(context).backgroundColor),
// ),
// ),
// ],
// ],
// ),
// ),
// );
// }
//
// getDirections() {
// if (isLocationSelected) {
// MapsLauncher.launchCoordinates(double.parse(selectedHospital!.latitude!),
// double.parse(selectedHospital!.longitude!), selectedHospital!.name);
// } else {
// Utils.showErrorToast(
// "Please select address from the dropdown menu to get directions");
// }
// }
//
// getProjectsList() {
// int languageID = projectViewModel!.isArabic ? 1 : 2;
// ClinicListService service = new ClinicListService();
// GifLoaderDialogUtils.showMyDialog(context);
// List<HospitalsModel> projectsListLocal = [];
// service.getProjectsList(languageID, context).then((res) {
// if (res['MessageStatus'] == 1) {
// setState(() {
// res['ListProject'].forEach((v) {
// projectsListLocal.add(new HospitalsModel.fromJson(v));
// });
// projectsList = projectsListLocal;
// });
// }
// GifLoaderDialogUtils.hideDialog(context);
// }).catchError((err) {
// GifLoaderDialogUtils.hideDialog(context);
// }).catchError((err) {
// GifLoaderDialogUtils.hideDialog(context);
// print(err);
// });
// }
// }

@ -0,0 +1,111 @@
import 'package:easy_localization/easy_localization.dart';
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/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/features/hmg_services/hmg_services_view_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/comprehensive_checkup/widgets/cmc_hospital_list_item.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/input_widget.dart';
import 'package:provider/provider.dart';
import 'package:shimmer/shimmer.dart';
class CmcHospitalBottomSheetBody extends StatelessWidget {
final Function(HospitalsModel) onHospitalSelected;
const CmcHospitalBottomSheetBody({super.key, required this.onHospitalSelected});
Widget _buildLoadingShimmer() {
return ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: 4,
separatorBuilder: (_, __) => SizedBox(height: 12.h),
itemBuilder: (context, index) {
return Shimmer.fromColors(
baseColor: Colors.grey[300]!,
highlightColor: Colors.grey[100]!,
child: Container(
height: 80.h,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10.r),
),
),
);
},
);
}
@override
Widget build(BuildContext context) {
final appState = getIt.get<AppState>();
final bool isArabic = appState.isArabic();
final bool isLocationEnabled = (appState.userLat != 0) && (appState.userLong != 0);
return Consumer(
builder: (BuildContext context, HmgServicesViewModel hmgServicesViewModel, Widget? child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Choose your preferred hospital for the service".needTranslation.toText14(
weight: FontWeight.w400,
color: AppColors.greyTextColor,
letterSpacing: -0.4,
),
SizedBox(height: 16.h),
TextInputWidget(
labelText: LocaleKeys.search.tr(),
hintText: LocaleKeys.searchHospital.tr(),
onChange: (value) {
hmgServicesViewModel.filterHospitalsByString(value ?? '', isArabic);
},
isEnable: true,
prefix: null,
autoFocus: false,
isBorderAllowed: false,
keyboardType: TextInputType.text,
isAllowLeadingIcon: true,
selectionType: SelectionTypeEnum.search,
padding: EdgeInsets.symmetric(vertical: ResponsiveExtension(10).h, horizontal: ResponsiveExtension(15).h),
),
],
),
SizedBox(height: 8.h),
SizedBox(
height: MediaQuery.of(context).size.height * 0.4,
child: hmgServicesViewModel.isHospitalListLoading
? _buildLoadingShimmer()
: hmgServicesViewModel.filteredHospitalsList.isEmpty
? Center(
child: "No hospitals Found".needTranslation.toText16(weight: FontWeight.w500, color: AppColors.greyTextColor),
)
: ListView.separated(
itemCount: hmgServicesViewModel.filteredHospitalsList.length,
separatorBuilder: (context, index) => SizedBox(height: 12.h),
itemBuilder: (context, index) {
final hospital = hmgServicesViewModel.filteredHospitalsList[index];
return CmcHospitalListItem(
hospital: hospital,
isLocationEnabled: isLocationEnabled,
onPress: () {
hmgServicesViewModel.setSelectedHospital(hospital);
onHospitalSelected(hospital);
},
);
},
),
),
],
);
},
);
}
}

@ -0,0 +1,123 @@
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/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/my_appointments/models/resp_models/hospital_model.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
class CmcHospitalListItem extends StatelessWidget {
final HospitalsModel hospital;
final VoidCallback onPress;
final bool isLocationEnabled;
const CmcHospitalListItem({
super.key,
required this.hospital,
required this.onPress,
this.isLocationEnabled = false,
});
@override
Widget build(BuildContext context) {
final appState = getIt.get<AppState>();
final bool isArabic = appState.isArabic();
final String hospitalName = isArabic ? (hospital.nameN ?? hospital.name ?? '') : (hospital.name ?? '');
return InkWell(
onTap: onPress,
child: DecoratedBox(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: false,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 8.h,
children: [
_buildHospitalName(hospitalName),
_buildDistanceInfo(),
],
),
),
Transform.flip(
flipX: isArabic,
child: Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon_small,
iconColor: AppColors.blackColor,
width: 18.h,
height: 13.h,
fit: BoxFit.contain,
),
),
],
).paddingSymmetrical(16.h, 16.h),
),
);
}
Widget _buildHospitalName(String hospitalName) {
return Row(
children: [
Utils.buildSvgWithAssets(
icon: (hospital.isHMC == true) ? AppAssets.hmc : AppAssets.hmg,
).paddingOnly(right: 10),
Expanded(
child: Text(
hospitalName,
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 16,
color: AppColors.blackColor,
),
),
)
],
);
}
Widget _buildDistanceInfo() {
final distanceText = hospital.distanceInKilometers != null ? hospital.distanceInKilometers!.toStringAsFixed(1) : "0";
return Row(
spacing: 4.w,
children: [
Visibility(
visible: (hospital.distanceInKilometers != null && hospital.distanceInKilometers! > 0),
child: AppCustomChipWidget(
labelText: "$distanceText km".needTranslation,
deleteIcon: AppAssets.location_red,
deleteIconSize: Size(9, 12),
backgroundColor: AppColors.secondaryLightRedColor,
textColor: AppColors.errorColor,
),
),
Visibility(
visible: (hospital.distanceInKilometers == null || hospital.distanceInKilometers == 0),
child: AppCustomChipWidget(
labelText: " Distance not available".needTranslation,
textColor: AppColors.blackColor,
),
),
// Visibility(
// visible: !isLocationEnabled,
// child: AppCustomChipWidget(
// labelText: "Location turned off".needTranslation,
// deleteIcon: AppAssets.location_unavailable,
// deleteIconSize: Size(9.w, 12.h),
// textColor: AppColors.blackColor,
// ),
// ),
],
);
}
}

@ -0,0 +1,26 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_view_model.dart';
import 'package:hmg_patient_app_new/presentation/comprehensive_checkup/widgets/cmc_hospital_bottom_sheet_body.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
import 'package:provider/provider.dart';
class CmcHospitalSelectionHelper {
static void showHospitalSelectionBottomSheet({
required BuildContext context,
required Function(dynamic) onHospitalSelected,
}) {
final hmgServicesViewModel = context.read<HmgServicesViewModel>();
showCommonBottomSheetWithoutHeight(
context,
title: "Select Hospital".needTranslation,
child: CmcHospitalBottomSheetBody(
onHospitalSelected: (hospital) {
hmgServicesViewModel.setSelectedHospitalForOrder(hospital);
onHospitalSelected(hospital);
},
),
);
}
}

@ -1,5 +1,3 @@
import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
@ -14,10 +12,7 @@ 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/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_checkin_bottom_sheet.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/requesting_services_page.dart' show RequestingServicesPage;
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/tracking_screen.dart' show TrackingScreen;
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';
@ -29,7 +24,6 @@ import 'package:hmg_patient_app_new/widgets/expandable_bottom_sheet/model/Bottom
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/map.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:provider/provider.dart';
import '../../../widgets/common_bottom_sheet.dart';
@ -40,20 +34,13 @@ class CallAmbulancePage extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: Visibility(
visible: context.watch<EmergencyServicesViewModel>().bottomSheetType ==
BottomSheetType.FIXED,
visible: context.watch<EmergencyServicesViewModel>().bottomSheetType == BottomSheetType.FIXED,
child: Padding(
padding: EdgeInsetsDirectional.only(end: 8.h, bottom: 68.h),
child: DecoratedBox(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor, borderRadius: 12.h),
child: Utils.buildSvgWithAssets(
icon: AppAssets.locate_me, width: 24.h, height: 24.h)
.paddingAll(12.h)
.onPress(() {
context
.read<EmergencyServicesViewModel>()
.moveToCurrentLocation();
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 12.h),
child: Utils.buildSvgWithAssets(icon: AppAssets.locate_me, width: 24.h, height: 24.h).paddingAll(12.h).onPress(() {
context.read<EmergencyServicesViewModel>().moveToCurrentLocation();
}),
),
),
@ -62,8 +49,7 @@ class CallAmbulancePage extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
children: [
ExpandableBottomSheet(
bottomSheetType:
context.watch<EmergencyServicesViewModel>().bottomSheetType,
bottomSheetType: context.watch<EmergencyServicesViewModel>().bottomSheetType,
children: {
BottomSheetType.EXPANDED: ExpanedBottomSheet(context),
BottomSheetType.FIXED: FixedBottomSheet(context),
@ -73,42 +59,28 @@ class CallAmbulancePage extends StatelessWidget {
),
body: Stack(
children: [
if (context.read<EmergencyServicesViewModel>().isGMSAvailable )
if (context.read<EmergencyServicesViewModel>().isGMSAvailable)
GMSMap(
currentLocation:
context.read<EmergencyServicesViewModel>().getGMSLocation(),
onCameraMoved: (value) => context
.read<LocationViewModel>()
.handleGMSMapCameraMoved(value),
onCameraIdle:
context.read<LocationViewModel>().handleOnCameraIdle,
currentLocation: context.read<EmergencyServicesViewModel>().getGMSLocation(),
onCameraMoved: (value) => context.read<LocationViewModel>().handleGMSMapCameraMoved(value),
onCameraIdle: context.read<LocationViewModel>().handleOnCameraIdle,
myLocationEnabled: true,
inputController:
context.read<EmergencyServicesViewModel>().gmsController,
inputController: context.read<EmergencyServicesViewModel>().gmsController,
showCenterMarker: true,
)
else
HMSMap(
currentLocation:
context.read<EmergencyServicesViewModel>().getHMSLocation(),
onCameraMoved: (value) => context
.read<LocationViewModel>()
.handleHMSMapCameraMoved(value),
onCameraIdle:
context.read<LocationViewModel>().handleOnCameraIdle,
currentLocation: context.read<EmergencyServicesViewModel>().getHMSLocation(),
onCameraMoved: (value) => context.read<LocationViewModel>().handleHMSMapCameraMoved(value),
onCameraIdle: context.read<LocationViewModel>().handleOnCameraIdle,
myLocationEnabled: false,
inputController:
context.read<EmergencyServicesViewModel>().hmsController,
inputController: context.read<EmergencyServicesViewModel>().hmsController,
showCenterMarker: true,
),
Align(
alignment: AlignmentDirectional.topStart,
child: Utils.buildSvgWithAssets(
icon: AppAssets.closeBottomNav, width: 32.h, height: 32.h)
.onPress(() {
context
.read<EmergencyServicesViewModel>()
.flushPickupInformation();
child: Utils.buildSvgWithAssets(icon: AppAssets.closeBottomNav, width: 32.h, height: 32.h).onPress(() {
context.read<EmergencyServicesViewModel>().flushPickupInformation();
Navigator.pop(context);
}),
).paddingOnly(top: 51.h, left: 24.h),
@ -119,8 +91,7 @@ class CallAmbulancePage extends StatelessWidget {
Widget FixedBottomSheet(BuildContext context) {
return GestureDetector(
onVerticalDragUpdate: (details){
onVerticalDragUpdate: (details) {
// if(details.delta.dy<0){
//
// context.read<EmergencyServicesViewModel>().updateBottomSheetState(BottomSheetType.EXPANDED);
@ -161,7 +132,7 @@ class CallAmbulancePage extends StatelessWidget {
// ),
// ),
// ),
// .paddingOnly(right: 24.h, bottom: 24.h),
// .paddingOnly(right: 24.h, bottom: 24.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
@ -189,9 +160,7 @@ class CallAmbulancePage extends StatelessWidget {
weight: FontWeight.w600,
color: AppColors.textColor,
),
" Please select the details of pickup"
.needTranslation
.toText12(
" Please select the details of pickup".needTranslation.toText12(
fontWeight: FontWeight.w500,
color: AppColors.greyTextColor,
)
@ -200,9 +169,7 @@ class CallAmbulancePage extends StatelessWidget {
CustomButton(
text: "Select Details".needTranslation,
onPressed: () {
context
.read<EmergencyServicesViewModel>()
.updateBottomSheetState(BottomSheetType.EXPANDED);
context.read<EmergencyServicesViewModel>().updateBottomSheetState(BottomSheetType.EXPANDED);
})
],
).paddingOnly(top: 24.h, bottom: 32.h, left: 24.h, right: 24.h),
@ -217,11 +184,11 @@ class CallAmbulancePage extends StatelessWidget {
Widget ExpanedBottomSheet(BuildContext context) {
return GestureDetector(
onVerticalDragUpdate: (details){
if(details.delta.dy>0){
context.read<EmergencyServicesViewModel>().updateBottomSheetState(BottomSheetType.FIXED);
}
},
onVerticalDragUpdate: (details) {
if (details.delta.dy > 0) {
context.read<EmergencyServicesViewModel>().updateBottomSheetState(BottomSheetType.FIXED);
}
},
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
@ -239,22 +206,19 @@ class CallAmbulancePage extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 16.h,
children: [
hospitalAndPickUpSection(context),
if(context.read<EmergencyServicesViewModel>().appointment != null)
AppointmentDoctorCard(
renderWidgetForERDisplay: true,
patientAppointmentHistoryResponseModel: context.read<EmergencyServicesViewModel>().appointment!,
onAskDoctorTap: () {},
onCancelTap: () async {},
onRescheduleTap: () async {},
).onPress((){
openAppointmentList(context);
})
if (context.read<EmergencyServicesViewModel>().appointment != null)
AppointmentDoctorCard(
renderWidgetForERDisplay: true,
patientAppointmentHistoryResponseModel: context.read<EmergencyServicesViewModel>().appointment!,
onAskDoctorTap: () {},
onCancelTap: () async {},
onRescheduleTap: () async {},
).onPress(() {
openAppointmentList(context);
})
],
).paddingOnly(top: 24.h, bottom: 32.h,left: 24.h, right: 24.h),
).paddingOnly(top: 24.h, bottom: 32.h, left: 24.h, right: 24.h),
bottomPriceContent(context)
],
),
@ -286,8 +250,7 @@ class CallAmbulancePage extends StatelessWidget {
shrinkWrap: true,
itemCount: 3,
itemBuilder: (__, index) {
if (index ==
2) // todo means the end of the list so handle as per the viewmodel
if (index == 2) // todo means the end of the list so handle as per the viewmodel
{
return CustomButton(
height: 40.h,
@ -301,11 +264,8 @@ class CallAmbulancePage extends StatelessWidget {
} else {
return AddressItem(
isSelected: index == 0,
address:
"Flat No 301, Building No 12, Palm Spring Apartment, Sector 45, Gurugram, Haryana 122003",
title: index == 0
? "Home".needTranslation
: "Work".needTranslation,
address: "Flat No 301, Building No 12, Palm Spring Apartment, Sector 45, Gurugram, Haryana 122003",
title: index == 0 ? "Home".needTranslation : "Work".needTranslation,
onTap: () {},
);
}
@ -354,13 +314,9 @@ class CallAmbulancePage extends StatelessWidget {
leadingIcon: AppAssets.pickup_bed,
),
CustomSwitch(
value: context
.watch<EmergencyServicesViewModel>()
.pickupFromInsideTheLocation,
onChanged: (value){
context
.read<EmergencyServicesViewModel>()
.updateThePickupPlaceFromLocation(value);
value: context.watch<EmergencyServicesViewModel>().pickupFromInsideTheLocation,
onChanged: (value) {
context.read<EmergencyServicesViewModel>().updateThePickupPlaceFromLocation(value);
},
)
],
@ -374,15 +330,12 @@ class CallAmbulancePage extends StatelessWidget {
leadingIcon: AppAssets.appointment_checkin_icon,
),
CustomSwitch(
value: context
.watch<EmergencyServicesViewModel>()
.haveAnAppointment,
value: context.watch<EmergencyServicesViewModel>().haveAnAppointment,
onChanged: (value) async {
// if (value) {
// openAppointmentList(context);
// }
await context.read<EmergencyServicesViewModel>()
.updateAppointment(value);
await context.read<EmergencyServicesViewModel>().updateAppointment(value);
if (context.read<EmergencyServicesViewModel>().appointments?.isNotEmpty == true) {
openAppointmentList(context);
}
@ -454,55 +407,47 @@ class CallAmbulancePage extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
DecoratedBox(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.scaffoldBgColor,
customBorder: BorderRadius.only(
topLeft: Radius.circular(24.h),
topRight: Radius.circular(24.h),
),
hasShadow: true
DecoratedBox(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.scaffoldBgColor,
customBorder: BorderRadius.only(
topLeft: Radius.circular(24.h),
topRight: Radius.circular(24.h),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 12.h,
hasShadow: true),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 12.h,
children: [
Row(
children: [
Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 4.h,
children: [
"Total amount to pay".needTranslation.toText18(
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 4.h,
children: [
"Total amount to pay".needTranslation.toText18(
weight: FontWeight.w600,
color: AppColors.textColor,
),
Row(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.warning,
height: 18.h, width: 18.h),
SizedBox(width: 4.h,),
"Amount will be paid at the hospital"
.needTranslation
.toText12(
Row(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.warning, height: 18.h, width: 18.h),
SizedBox(
width: 4.h,
),
"Amount will be paid at the hospital".needTranslation.toText12(
fontWeight: FontWeight.w500,
color: AppColors.greyTextColor,
),
],
)
],
),
),
)
],
),
),
Utils.getPaymentAmountWithSymbol(
(Utils.formatNumberToInternationalFormat(context
.read<EmergencyServicesViewModel>()
.getTotalPrice() ??
0))
.toText24(
fontWeight: FontWeight.w600,
color: AppColors.textColor,
letterSpacing: -2),
(Utils.formatNumberToInternationalFormat(context.read<EmergencyServicesViewModel>().getTotalPrice() ?? 0))
.toText24(fontWeight: FontWeight.w600, color: AppColors.textColor, letterSpacing: -2),
AppColors.blackColor,
17.h)
@ -518,20 +463,19 @@ class CallAmbulancePage extends StatelessWidget {
PlacePrediction? placePrediction = locationViewModel.selectedPrediction;
context.read<EmergencyServicesViewModel>().submitAmbulanceRequest(response?.results.first, placeDetails, placePrediction);
})
],
).paddingOnly(top: 24.h, bottom: 12.h, left: 24.h, right: 24.h),
),
],
).paddingOnly(top: 24.h, bottom: 12.h, left: 24.h, right: 24.h),
),
],
);
}
showHospitalBottomSheet(BuildContext context){
showHospitalBottomSheet(BuildContext context) {
showCommonBottomSheetWithoutHeight(
title:
LocaleKeys.selectHospital.tr(),
title: LocaleKeys.selectHospital.tr(),
context,
child: Consumer<EmergencyServicesViewModel>(
builder:(_,vm,__)=> HospitalBottomSheetBody(
builder: (_, vm, __) => HospitalBottomSheetBody(
searchText: vm.searchController,
displayList: vm.displayList,
onFacilityClicked: (value) {
@ -545,8 +489,7 @@ class CallAmbulancePage extends StatelessWidget {
onHospitalSearch: (value) {
vm.searchHospitals(value ?? "");
},
selectedFacility:
vm.selectedFacility,
selectedFacility: vm.selectedFacility,
hmcCount: vm.hmcCount,
hmgCount: vm.hmgCount,
),
@ -583,16 +526,14 @@ class CallAmbulancePage extends StatelessWidget {
textPlaceInput(context) {
return Consumer<LocationViewModel>(builder: (_, vm, __) {
print(
"the data is ${vm.geocodeResponse?.results.first.formattedAddress ?? vm.selectedPrediction?.description}");
print("the data is ${vm.geocodeResponse?.results.first.formattedAddress ?? vm.selectedPrediction?.description}");
return SizedBox(
width: MediaQuery.sizeOf(context).width,
child: TextInputWidget(
labelText: "Enter Pickup Location Manually".needTranslation,
hintText: "Enter Pickup Location".needTranslation,
controller: TextEditingController(
text: vm.geocodeResponse?.results.first.formattedAddress ??
vm.selectedPrediction?.description,
text: vm.geocodeResponse?.results.first.formattedAddress ?? vm.selectedPrediction?.description,
),
leadingIcon: AppAssets.location_pickup,
isAllowLeadingIcon: true,
@ -614,8 +555,7 @@ class CallAmbulancePage extends StatelessWidget {
///decide which field to show first based on the selected calling place
inputFields(BuildContext context) {
return context.read<EmergencyServicesViewModel>().callingPlace ==
AmbulanceCallingPlace.FROM_HOSPITAL
return context.read<EmergencyServicesViewModel>().callingPlace == AmbulanceCallingPlace.FROM_HOSPITAL
? HospitalFieldFirstThanPlaces(context)
: PlaceFirstThanHospitalField(context);
}
@ -639,21 +579,15 @@ class CallAmbulancePage extends StatelessWidget {
hospitalField(BuildContext context) {
return DecoratedBox(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor, borderRadius: 12.h),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 12.h),
child: Row(
children: [
hospitalAndPickUpItemContent(
title: "Select Hospital".needTranslation,
subTitle: context
.read<EmergencyServicesViewModel>()
.getSelectedHospitalName() ??
"Select Hospital".needTranslation,
subTitle: context.read<EmergencyServicesViewModel>().getSelectedHospitalName() ?? "Select Hospital".needTranslation,
leadingIcon: AppAssets.hospital,
),
Utils.buildSvgWithAssets(
icon: AppAssets.down_cheveron, width: 24.h, height: 24.h)
.paddingAll(16.h)
Utils.buildSvgWithAssets(icon: AppAssets.down_cheveron, width: 24.h, height: 24.h).paddingAll(16.h)
],
).onPress(() {
print("the item is clicked");

@ -109,7 +109,6 @@ class EmergencyServicesPage extends StatelessWidget {
CustomButton(
text: LocaleKeys.confirm.tr(context: context),
onPressed: () async {
//
Navigator.of(context).pop();
await emergencyServicesViewModel.getTransportationOption();
openTranportationSelectionBottomSheet(context);

@ -44,6 +44,7 @@ class AppCustomChipWidget extends StatelessWidget {
final EdgeInsetsDirectional? labelPadding;
final void Function()? onChipTap;
final void Function()? onDeleteTap;
@override
Widget build(BuildContext context) {
final iconS = iconSize ?? 12.w;
@ -65,7 +66,8 @@ class AppCustomChipWidget extends StatelessWidget {
child: icon.isNotEmpty
? Chip(
avatar: icon.isNotEmpty
? Utils.buildSvgWithAssets(icon: icon, width: iconS, height: iconS, iconColor: iconHasColor ? iconColor : null, fit: BoxFit.contain)
? Utils.buildSvgWithAssets(
icon: icon, width: iconS, height: iconS, iconColor: iconHasColor ? iconColor : null, fit: BoxFit.contain)
: SizedBox.shrink(),
label: richText ?? labelText!.toText10(weight: FontWeight.w500, letterSpacing: 0, color: textColor),
padding: padding,
@ -79,13 +81,15 @@ class AppCustomChipWidget extends StatelessWidget {
side: BorderSide(color: AppColors.transparent, width: 1.5),
),
deleteIcon: deleteIcon?.isNotEmpty == true
? InkWell(onTap: onDeleteTap,child:Utils.buildSvgWithAssets(
icon: deleteIcon!,
width: iconS,
height: iconS,
iconColor: deleteIconHasColor ? deleteIconColor : null,
),)
? InkWell(
onTap: onDeleteTap,
child: Utils.buildSvgWithAssets(
icon: deleteIcon!,
width: iconS,
height: iconS,
iconColor: deleteIconHasColor ? deleteIconColor : null,
),
)
: null,
onDeleted: deleteIcon?.isNotEmpty == true ? () {} : null,
)
@ -102,7 +106,10 @@ class AppCustomChipWidget extends StatelessWidget {
),
labelPadding: labelPadding ?? EdgeInsetsDirectional.only(start: 2.w, end: deleteIcon?.isNotEmpty == true ? 2.w : 8.w),
deleteIcon: deleteIcon?.isNotEmpty == true
? InkWell(onTap: onDeleteTap,child: Utils.buildSvgWithAssets(icon: deleteIcon!, width: iconS, height: iconS, iconColor: deleteIconHasColor ? deleteIconColor : null))
? InkWell(
onTap: onDeleteTap,
child: Utils.buildSvgWithAssets(
icon: deleteIcon!, width: iconS, height: iconS, iconColor: deleteIconHasColor ? deleteIconColor : null))
: null,
onDeleted: deleteIcon?.isNotEmpty == true ? () {} : null,
),

@ -104,20 +104,18 @@ class ButtonSheetContent extends StatelessWidget {
}
}
void showCommonBottomSheetWithoutHeight(
BuildContext context, {
required Widget child,
VoidCallback? callBackFunc,
String title = "",
bool isCloseButtonVisible = true,
bool isFullScreen = true,
bool isDismissible = true,
Widget? titleWidget,
bool useSafeArea = false,
bool hasBottomPadding = true,
Color backgroundColor = AppColors.bottomSheetBgColor,
VoidCallback? onCloseClicked
}) {
void showCommonBottomSheetWithoutHeight(BuildContext context,
{required Widget child,
VoidCallback? callBackFunc,
String title = "",
bool isCloseButtonVisible = true,
bool isFullScreen = true,
bool isDismissible = true,
Widget? titleWidget,
bool useSafeArea = false,
bool hasBottomPadding = true,
Color backgroundColor = AppColors.bottomSheetBgColor,
VoidCallback? onCloseClicked}) {
showModalBottomSheet<String>(
sheetAnimationStyle: AnimationStyle(
duration: Duration(milliseconds: 500),
@ -146,43 +144,44 @@ void showCommonBottomSheetWithoutHeight(
physics: ClampingScrollPhysics(),
child: isCloseButtonVisible
? Container(
padding: EdgeInsets.only(
left: 24,
top: 24,
right: 24,
bottom: 12,
),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.bottomSheetBgColor,
borderRadius: 24.h,
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
titleWidget ??
Expanded(
child: title.toText20(weight: FontWeight.w600),
),
if (isCloseButtonVisible) ...[
Utils.buildSvgWithAssets(
icon: AppAssets.close_bottom_sheet_icon,
iconColor: Color(0xff2B353E),
).onPress(() {
onCloseClicked?.call();
Navigator.of(context).pop();
}),],
],
),
SizedBox(height: 16.h),
child,
],
),
)
padding: EdgeInsets.only(
left: 24,
top: 24,
right: 24,
bottom: 12,
),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.bottomSheetBgColor,
borderRadius: 24.h,
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
titleWidget ??
Expanded(
child: title.toText20(weight: FontWeight.w600),
),
if (isCloseButtonVisible) ...[
Utils.buildSvgWithAssets(
icon: AppAssets.close_bottom_sheet_icon,
iconColor: Color(0xff2B353E),
).onPress(() {
onCloseClicked?.call();
Navigator.of(context).pop();
}),
],
],
),
SizedBox(height: 16.h),
child,
],
),
)
: child,
),
),

Loading…
Cancel
Save