* 'master' of http://34.17.182.140/Haroon6138/HMG_Patient_App_New:
  updates
  family file switch back issue fixed
  Vital sign updates
  updates
  Updates
  Added location option in region selection bottom sheet
  Updates
  Profile settings update
dev_sultan
Sultan khan 9 hours ago
commit c970a3f697

Binary file not shown.

After

Width:  |  Height:  |  Size: 471 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 428 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 436 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 475 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 428 KiB

@ -187,7 +187,7 @@
"lastName": "اسم العائلة",
"female": "أنثى",
"male": "ذكر",
"preferredLanguage": "اللغة المفضلة *",
"preferredLanguage": "اللغة المفضلة",
"locationsRegister": "أين ترغب في إنشاء هذا الملف؟",
"ksa": "السعودية",
"dubai": "دبي",
@ -1613,7 +1613,10 @@
"verifyInsurance": "التحقق من التأمين",
"tests": "تحليل",
"calendarPermissionAlert": "يرجى منح إذن الوصول إلى التقويم من إعدادات التطبيق لضبط تذكير تناول الدواء.",
"sortByNearestLocation": "فرز حسب الأقرب إلى موقعك",
"giveLocationPermissionForNearestList": "يرجى منح إذن الوصول إلى الموقع من إعدادات التطبيق لعرض أقرب المواقع.",
"sortByLocation": "الترتيب حسب الموقع",
"timeForFirstReminder": "وقت التذكير الأول",
"reminderRemovalNote": "يمكنك إزالتها من التقويم الخاص بك لاحقاً عن طريق إيقاف تشغيل التذكير"
"reminderRemovalNote": "يمكنك إزالتها من التقويم الخاص بك لاحقاً عن طريق إيقاف تشغيل التذكير",
"communicationLanguage": "لغة التواصل"
}

@ -187,7 +187,7 @@
"lastName": "Last Name",
"female": "Female",
"male": "Male",
"preferredLanguage": "Preferred Language *",
"preferredLanguage": "Preferred Language",
"locationsRegister": "Where do you want to create this file?",
"ksa": "KSA",
"dubai": "Dubai",
@ -1606,7 +1606,10 @@
"verifyInsurance": "Verify Insurance",
"tests": "tests",
"calendarPermissionAlert": "Please grant calendar access permission from app settings to set medication reminder.",
"sortByLocation": "Sort by location",
"timeForFirstReminder": "Time for 1st reminder",
"reminderRemovalNote": "You can remove it from your calendar later by switching off the reminder"
"reminderRemovalNote": "You can remove it from your calendar later by switching off the reminder",
"sortByLocation": "Sort by location",
"sortByNearestLocation": "Sort by nearest to your location",
"giveLocationPermissionForNearestList": "Please grant location permission from app settings to see the nearest locations.",
"communicationLanguage": "Communication Language"
}

@ -234,7 +234,7 @@ class ApiConsts {
static String getAiOverViewLabOrder = "Services/Patients.svc/REST/HMGAI_Lab_Analyzer_API";
// ************ static values for Api ****************
static final double appVersionID = 20.5;
static final double appVersionID = 20.9;
// static final double appVersionID = 50.7;
static final int appChannelId = 3;

@ -361,6 +361,11 @@ class AppAssets {
static const String homeHealthCareService = '$pngBasePath/home_health_care.png';
static const String pharmacyService = '$pngBasePath/pharmacy_service.png';
static const String bloodDonationService = '$pngBasePath/blood_donation_image.png';
static const String waterConsumptionService = '$pngBasePath/water_consumption_image.png';
static const String emergencyService = '$pngBasePath/emergency_services_image.png';
static const String cmcService = '$pngBasePath/cmc_services_image.png';
static const String eReferralService = '$pngBasePath/ereferral_services_image.png';
static const String maleImg = '$pngBasePath/male_img.png';
static const String femaleImg = '$pngBasePath/female_img.png';

@ -169,7 +169,7 @@ class AppState {
///this will be called if there is any problem in getting the user location
void resetLocation() {
userLong = 0.0;
userLong = 0.0;
userLat = 0.0;
}
setRatedVisible(bool value) {

@ -382,7 +382,7 @@ class Utils {
children: [
Lottie.asset(AppAnimations.checkmark, repeat: true, reverse: false, frameRate: FrameRate(60), width: 100.h, height: 100.h, fit: BoxFit.fill),
SizedBox(height: 8.h),
(loadingText ?? LocaleKeys.loadingText.tr()).toText16(color: AppColors.blackColor),
(loadingText ?? LocaleKeys.loadingText.tr()).toText16(color: AppColors.blackColor).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 8.h),
],
).center;
@ -396,7 +396,7 @@ class Utils {
Lottie.asset(AppAnimations.errorAnimation,
repeat: true, reverse: false, frameRate: FrameRate(60), width: 100.h, height: 100.h, fit: BoxFit.fill),
SizedBox(height: 8.h),
(loadingText ?? LocaleKeys.loadingText.tr()).toText16(color: AppColors.blackColor),
(loadingText ?? LocaleKeys.loadingText.tr()).toText16(color: AppColors.blackColor).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 8.h),
],
).center;
@ -769,20 +769,20 @@ class Utils {
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Image.asset(AppAssets.mada, width: 25.h, height: 25.h),
Image.asset(AppAssets.mada, width: 35.h, height: 35.h),
Image.asset(
AppAssets.tamaraEng,
width: 25.h,
height: 25.h,
width: 35.h,
height: 35.h,
fit: BoxFit.contain,
errorBuilder: (context, error, stackTrace) {
debugPrint('Failed to load Tamara PNG in payment methods: $error');
return Utils.buildSvgWithAssets(icon: AppAssets.tamara, width: 25.h, height: 25.h, fit: BoxFit.contain);
return Utils.buildSvgWithAssets(icon: AppAssets.tamara, width: 35.h, height: 35.h, fit: BoxFit.contain);
},
),
Image.asset(AppAssets.visa, width: 25.h, height: 25.h),
Image.asset(AppAssets.mastercard, width: 25.h, height: 25.h),
Image.asset(AppAssets.applePay, width: 25.h, height: 25.h),
Image.asset(AppAssets.visa, width: 35.h, height: 35.h),
Image.asset(AppAssets.mastercard, width: 35.h, height: 25.h),
Image.asset(AppAssets.applePay, width: 35.h, height: 35.h),
],
);
}

@ -202,8 +202,6 @@ class AuthenticationRepoImp implements AuthenticationRepo {
}
}
@override
Future<Either<Failure, GenericApiModel<dynamic>>> checkActivationCodeRepo(
{required dynamic newRequest, // could be CheckActivationCodeReq or CheckActivationCodeRegisterReq
@ -278,11 +276,10 @@ class AuthenticationRepoImp implements AuthenticationRepo {
newRequest.forRegisteration = newRequest.isRegister ?? false;
newRequest.isRegister = false;
//silent login case removed token and login token
if(newRequest.logInTokenID.isEmpty && newRequest.isSilentLogin == true && (newRequest.loginType==1 || newRequest.loginType==4)) {
if (newRequest.logInTokenID.isEmpty && newRequest.isSilentLogin == true && (newRequest.loginType == 1 || newRequest.loginType == 4)) {
newRequest.logInTokenID = null;
newRequest.deviceToken = null;
}
}
Map<String, dynamic> familyRequest = {};
@ -317,13 +314,9 @@ class AuthenticationRepoImp implements AuthenticationRepo {
}
if (appState.getSuperUserID == responseID) {
// switchRequest['LoginType'] = 0;
switchRequest['LoginType'] = loginType;
switchRequest['PatientIdentificationID'] = "";
// switchRequest["PatientID"] = responseID;
// switchRequest["SuperUser"] = responseID;
// switchRequest["PatientID"] = appState.getAuthenticatedUser()?.patientId ?? 0;
// switchRequest["PatientMobileNumber"] = newRequest.patientMobileNumber?.toString().startsWith('0') == true ? newRequest.patientMobileNumber.toString() : '0${newRequest.patientMobileNumber}';
switchRequest['DeviceToken'] = newRequest.deviceToken;
switchRequest.removeWhere((key, value) => ['NationalID', 'isDentalAllowedBackend', 'ProjectOutSA', 'ForRegisteration'].contains(key));
}
}

@ -552,16 +552,16 @@ class AuthenticationViewModel extends ChangeNotifier {
});
} else {
final resultEither = await _authenticationRepo.checkActivationCodeRepo(
newRequest: CheckActivationCodeRegisterReq.fromJson(request),
activationCode: activationCode,
isRegister: false,
isFormFamilyFile: isFormFamilyFile,
patientShareRequestID: patientShareRequestID,
responseID: responseID,
isSwitchUser: isSwitchUser,
patientID: patientID,
loginType: _appState.getSuperUserID != null ? 0 : 2,
);
newRequest: CheckActivationCodeRegisterReq.fromJson(request),
activationCode: activationCode,
isRegister: false,
isFormFamilyFile: isFormFamilyFile,
patientShareRequestID: patientShareRequestID,
responseID: responseID,
isSwitchUser: isSwitchUser,
patientID: patientID,
// loginType: _appState.getSuperUserID != null ? 0 : 2,
loginType: loginTypeEnum.toInt);
resultEither.fold(
(failure) async => await _errorHandlerService.handleError(

@ -48,13 +48,14 @@ class VitalSignUiModel {
);
}
if (s.contains('low')) {
final Color yellowBg = AppColors.warningColor.withValues(alpha: 0.12);
// Warning for both low and overweight/underweight BMI, since they can indicate potential health issues.
if (s.contains('low') || s.contains('underweight') || s.contains('overweight')) {
final Color yellowBg = AppColors.highAndLow.withValues(alpha: 0.12);
return VitalSignUiModel(
iconBg: yellowBg,
iconFg: AppColors.warningColor,
iconFg: AppColors.highAndLow,
chipBg: yellowBg,
chipFg: AppColors.warningColor,
chipFg: AppColors.highAndLow,
);
}
@ -91,12 +92,27 @@ class VitalSignUiModel {
}
static String bmiStatus(dynamic bmi) {
if (bmi == null) return 'N/A';
final double bmiValue = double.tryParse(bmi.toString()) ?? 0;
if (bmiValue < 18.5) return 'Underweight';
if (bmiValue < 25) return 'Normal';
if (bmiValue < 30) return 'Overweight';
return 'High';
String bmiStatus = 'Normal';
final double bmiResult = double.tryParse(bmi.toString()) ?? 0;
if (bmiResult >= 30) {
bmiStatus = "High";
} else if (bmiResult < 30 && bmiResult >= 25) {
bmiStatus = "Overweight";
} else if (bmiResult < 25 && bmiResult >= 18.5) {
bmiStatus = "Normal";
} else if (bmiResult < 18.5) {
bmiStatus = "Underweight";
}
// if (bmi == null) return 'N/A';
// final double bmiValue = double.tryParse(bmi.toString()) ?? 0;
// if (bmiValue < 18.5) return 'Underweight';
// if (bmiValue < 25) return 'Normal';
// if (bmiValue < 30) return 'Overweight';
// return 'High';
return bmiStatus;
}
}

@ -43,9 +43,20 @@ class AppointmentViaRegionViewmodel extends ChangeNotifier {
int hmgCount = 0;
int hmcCount = 0;
RegionBottomSheetType regionBottomSheetType = RegionBottomSheetType.FOR_REGION;
bool sortByLocation = false;
AppointmentViaRegionViewmodel({required this.navigationService,required this.appState});
void initSortByLocation() {
sortByLocation = (appState.userLat != 0.0) && (appState.userLong != 0.0);
notifyListeners();
}
void setSortByLocation(bool value) {
sortByLocation = value;
notifyListeners();
}
void setSelectedRegionId(String? regionId) {
selectedRegionId = regionId;
notifyListeners();
@ -122,6 +133,7 @@ class AppointmentViaRegionViewmodel extends ChangeNotifier {
setFacility(null);
setBottomSheetType(RegionBottomSheetType.FOR_REGION);
setBottomSheetState(AppointmentViaRegionState.REGION_SELECTION);
sortByLocation = false;
}
void setHospitalModel(PatientDoctorAppointmentList? hospital) {

@ -0,0 +1,136 @@
class GetPatientInfoForUpdate {
int? projectID;
int? patientType;
int? patientID;
String? emailAddress;
bool? isEmailAlertRequired;
bool? isSMSAlertRequired;
String? preferredLanguage;
String? emergencyContactName;
String? emergencyContactNo;
int? editedBy;
String? editedOn;
String? patientIdentificationNo;
int? patientIdentificationType;
String? firstName;
String? middleName;
String? lastName;
int? gender;
String? dateofBirth;
String? dateofBirthN;
String? firstNameN;
String? middleNameN;
String? lastNameN;
int? projectID1;
int? patientType1;
int? patientID1;
bool? isIVRStopped;
String? aGE;
String? genderString;
bool? isNeedUpdateIdintificationNo;
String? nationality;
String? type;
GetPatientInfoForUpdate(
{this.projectID,
this.patientType,
this.patientID,
this.emailAddress,
this.isEmailAlertRequired,
this.isSMSAlertRequired,
this.preferredLanguage,
this.emergencyContactName,
this.emergencyContactNo,
this.editedBy,
this.editedOn,
this.patientIdentificationNo,
this.patientIdentificationType,
this.firstName,
this.middleName,
this.lastName,
this.gender,
this.dateofBirth,
this.dateofBirthN,
this.firstNameN,
this.middleNameN,
this.lastNameN,
this.projectID1,
this.patientType1,
this.patientID1,
this.isIVRStopped,
this.aGE,
this.genderString,
this.isNeedUpdateIdintificationNo,
this.nationality,
this.type});
GetPatientInfoForUpdate.fromJson(Map<String, dynamic> json) {
projectID = json['ProjectID'];
patientType = json['PatientType'];
patientID = json['PatientID'];
emailAddress = json['EmailAddress'];
isEmailAlertRequired = json['IsEmailAlertRequired'];
isSMSAlertRequired = json['IsSMSAlertRequired'];
preferredLanguage = json['PreferredLanguage'];
emergencyContactName = json['EmergencyContactName'];
emergencyContactNo = json['EmergencyContactNo'];
editedBy = json['EditedBy'];
editedOn = json['EditedOn'];
patientIdentificationNo = json['PatientIdentificationNo'];
patientIdentificationType = json['PatientIdentificationType'];
firstName = json['FirstName'];
middleName = json['MiddleName'];
lastName = json['LastName'];
gender = json['Gender'];
dateofBirth = json['DateofBirth'];
dateofBirthN = json['DateofBirthN'];
firstNameN = json['FirstNameN'];
middleNameN = json['MiddleNameN'];
lastNameN = json['LastNameN'];
projectID1 = json['ProjectID1'];
patientType1 = json['PatientType1'];
patientID1 = json['PatientID1'];
isIVRStopped = json['IsIVRStopped'];
aGE = json['AGE'];
genderString = json['GenderString'];
isNeedUpdateIdintificationNo = json['IsNeedUpdateIdintificationNo'];
nationality = json['Nationality'];
type = json['Type'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['ProjectID'] = this.projectID;
data['PatientType'] = this.patientType;
data['PatientID'] = this.patientID;
data['EmailAddress'] = this.emailAddress;
data['IsEmailAlertRequired'] = this.isEmailAlertRequired;
data['IsSMSAlertRequired'] = this.isSMSAlertRequired;
data['PreferredLanguage'] = this.preferredLanguage;
data['EmergencyContactName'] = this.emergencyContactName;
data['EmergencyContactNo'] = this.emergencyContactNo;
data['EditedBy'] = this.editedBy;
data['EditedOn'] = this.editedOn;
data['PatientIdentificationNo'] = this.patientIdentificationNo;
data['PatientIdentificationType'] = this.patientIdentificationType;
data['FirstName'] = this.firstName;
data['MiddleName'] = this.middleName;
data['LastName'] = this.lastName;
data['Gender'] = this.gender;
data['DateofBirth'] = this.dateofBirth;
data['DateofBirthN'] = this.dateofBirthN;
data['FirstNameN'] = this.firstNameN;
data['MiddleNameN'] = this.middleNameN;
data['LastNameN'] = this.lastNameN;
data['ProjectID1'] = this.projectID1;
data['PatientType1'] = this.patientType1;
data['PatientID1'] = this.patientID1;
data['IsIVRStopped'] = this.isIVRStopped;
data['AGE'] = this.aGE;
data['GenderString'] = this.genderString;
data['IsNeedUpdateIdintificationNo'] = this.isNeedUpdateIdintificationNo;
data['Nationality'] = this.nationality;
data['Type'] = this.type;
return data;
}
}

@ -3,6 +3,7 @@ import 'package:hmg_patient_app_new/core/api/api_client.dart';
import 'package:hmg_patient_app_new/core/api_consts.dart';
import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart';
import 'package:hmg_patient_app_new/features/profile_settings/models/get_patient_info_response_model.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
abstract class ProfileSettingsRepo {
@ -13,6 +14,8 @@ abstract class ProfileSettingsRepo {
/// Deactivates (deletes) the patient's account.
Future<Either<Failure, GenericApiModel<dynamic>>> deactivateAccount();
Future<Either<Failure, GenericApiModel<dynamic>>> getProfileSettings();
}
class ProfileSettingsRepoImp implements ProfileSettingsRepo {
@ -96,5 +99,43 @@ class ProfileSettingsRepoImp implements ProfileSettingsRepo {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel>> getProfileSettings() async {
final Map<String, dynamic> body = {};
try {
GenericApiModel<GetPatientInfoForUpdate>? apiResponse;
Failure? failure;
await apiClient.post(
PROFILE_SETTING,
body: body,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final patientProfileInfo = GetPatientInfoForUpdate.fromJson(response['PateintInfoForUpdateList'][0]);
apiResponse = GenericApiModel<GetPatientInfoForUpdate>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: errorMessage,
data: patientProfileInfo,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
}

@ -1,8 +1,16 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:get_it/get_it.dart';
import 'package:hmg_patient_app_new/features/profile_settings/models/get_patient_info_response_model.dart';
import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_repo.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/profile_settings/widgets/preferred_language_widget.dart';
import 'package:hmg_patient_app_new/services/cache_service.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
class ProfileSettingsViewModel extends ChangeNotifier {
static const String _darkModeKey = 'is_dark_mode';
@ -30,6 +38,9 @@ class ProfileSettingsViewModel extends ChangeNotifier {
bool isDeactivateAccountSuccess = false;
String? deactivateAccountError;
late GetPatientInfoForUpdate getPatientInfoForUpdate;
bool isPatientProfileLoading = false;
ProfileSettingsViewModel({
required CacheService cacheService,
required this.profileSettingsRepo,
@ -88,6 +99,34 @@ class ProfileSettingsViewModel extends ChangeNotifier {
);
}
Future<void> getProfileSettings({
Function(dynamic)? onSuccess,
Function(String)? onError,
}) async {
isPatientProfileLoading = true;
notifyListeners();
final result = await profileSettingsRepo.getProfileSettings();
result.fold(
(failure) {
isPatientProfileLoading = false;
notifyListeners();
if (onError != null) {
onError(failure.message);
} else {
errorHandlerService.handleError(failure: failure);
}
},
(response) {
getPatientInfoForUpdate = response.data;
isPatientProfileLoading = false;
notifyListeners();
onSuccess?.call(response.data);
},
);
}
// Deactivate account
Future<void> deactivateAccount({
@ -123,7 +162,14 @@ class ProfileSettingsViewModel extends ChangeNotifier {
// Helpers
void notify() {
notifyListeners();
openPreferredLanguageBottomSheet() {
showCommonBottomSheetWithoutHeight(
title: LocaleKeys.preferredLanguage.tr(),
GetIt.instance<NavigationService>().navigatorKey.currentContext!,
child: PreferredLanguageWidget(),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
}
}

@ -1605,9 +1605,12 @@ abstract class LocaleKeys {
static const verifyInsurance = 'verifyInsurance';
static const tests = 'tests';
static const calendarPermissionAlert = 'calendarPermissionAlert';
static const sortByNearestLocation = 'sortByNearestLocation';
static const giveLocationPermissionForNearestList = 'giveLocationPermissionForNearestList';
static const sortByLocation = 'sortByLocation';
static const timeForFirstReminder = 'timeForFirstReminder';
static const reminderRemovalNote = 'reminderRemovalNote';
static const communicationLanguage = 'communicationLanguage';
static const featureComingSoonDescription = 'featureComingSoonDescription';
}

@ -286,7 +286,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
Positioned(
bottom: 0,
child: SizedBox(
width: MediaQuery.of(context).size.width * 0.785,
width: MediaQuery.of(context).size.width - 85.w,
child: CustomButton(
onPressed: () async {
if (widget.patientAppointmentHistoryResponseModel.projectID == 130 || widget.patientAppointmentHistoryResponseModel.projectID == 120) {
@ -394,7 +394,6 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
},
isMultiAllowed: true,
onMultiDateSuccess: (int selectedIndex) async {
isEventAddedOrRemoved = await calender.createOrUpdateEvent(
title:
"Appointment Reminder with ${widget.patientAppointmentHistoryResponseModel.doctorNameObj} on ${DateUtil.convertStringToDate(widget.patientAppointmentHistoryResponseModel.appointmentDate)}, Appointment #${widget.patientAppointmentHistoryResponseModel.appointmentNo}",
@ -822,8 +821,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
child: LocaleKeys.upcomingPaymentNow
.tr(context: context)
.toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor)),
"VAT 15%(${widget.patientAppointmentHistoryResponseModel.patientTaxAmount})"
.toText14(isBold: true, color: AppColors.greyTextColor, letterSpacing: -2),
"VAT 15%(${widget.patientAppointmentHistoryResponseModel.patientTaxAmount})".toText14(isBold: true, color: AppColors.greyTextColor, letterSpacing: -0.64),
],
),
SizedBox(height: 18.h),
@ -831,7 +829,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
width: 150.h,
width: 200.h,
child: Utils.getPaymentMethods(),
),
Row(

@ -1,11 +1,13 @@
import 'package:easy_localization/easy_localization.dart' show StringTranslateExtension;
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/core/utils/debouncer.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/core/utils/utils.dart' show Utils;
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/models/resp_models/doctor_list_api_response.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
@ -14,7 +16,6 @@ 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';
import '../../../../features/my_appointments/models/resp_models/hospital_model.dart' show HospitalsModel;
import '../../../emergency_services/call_ambulance/widgets/type_selection_widget.dart' show TypeSelectionWidget;
// class HospitalBottomSheetBody extends StatelessWidget {
@ -125,66 +126,111 @@ class HospitalBottomSheetBody extends StatelessWidget {
final Function(FacilitySelection) onFacilityClicked;
final Function(PatientDoctorAppointmentList) onHospitalClicked;
final Function(String) onHospitalSearch;
final bool sortByLocation;
final Function(bool)? onSortByLocationToggle;
HospitalBottomSheetBody({super.key, required this.hmcCount, required this.hmgCount, this.displayList, required this.selectedFacility, required this.onFacilityClicked, required this.onHospitalClicked, required this.onHospitalSearch, required this.searchText});
HospitalBottomSheetBody({super.key, required this.hmcCount, required this.hmgCount, this.displayList, required this.selectedFacility, required this.onFacilityClicked, required this.onHospitalClicked, required this.onHospitalSearch, required this.searchText, this.sortByLocation = false, this.onSortByLocationToggle});
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextInputWidget(
labelText: LocaleKeys.search.tr(context: context),
hintText: LocaleKeys.searchHospital.tr(context: context),
controller: searchText,
onChange: (value) {
debouncer.run((){
onHospitalSearch(value??"");
});
},
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,
return Consumer<BookAppointmentsViewModel>(builder: (context, myAppointmentsVM, child) {
if (myAppointmentsVM.isRegionListLoading) {
return Container(
height: MediaQuery.of(context).size.height * 0.3,
decoration: BoxDecoration(
color: AppColors.whiteColor,
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
),
),
SizedBox(height: 24.h),
TypeSelectionWidget(
selectedFacility:selectedFacility ,
hmcCount: hmcCount.toString(),
hmgCount: hmgCount.toString(),
onitemClicked: (selectedValue){
onFacilityClicked(selectedValue);
},
),
SizedBox(height: 21.h),
SizedBox(
height: MediaQuery.sizeOf(context).height * .4,
child: ListView.separated(
itemBuilder: (_, index)
{
var hospital = displayList?[index];
return HospitalListItem(
hospitalData: hospital,
isLocationEnabled: true,
).onPress(() {
onHospitalClicked(hospital!);
});},
separatorBuilder: (_, __) => SizedBox(
height: 16.h,
child: Center(
child: Utils.getLoadingWidget(),
),
);
} else {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextInputWidget(
labelText: LocaleKeys.search.tr(context: context),
hintText: LocaleKeys.searchHospital.tr(context: context),
controller: searchText,
onChange: (value) {
debouncer.run(() {
onHospitalSearch(value ?? "");
});
},
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: 16.h),
if (onSortByLocationToggle != null)
Padding(
padding: EdgeInsets.symmetric(horizontal: 4.w),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.location, iconColor: AppColors.greyTextColor, width: 18.h, height: 18.h),
SizedBox(width: 8.w),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.sortByLocation.tr(context: context).toText14(isBold: true),
// SizedBox(height: 4.h),
LocaleKeys.sortByNearestLocation.tr(context: context).toText11(color: AppColors.textColorLight, weight: FontWeight.w500),
],
),
],
),
Switch(
value: sortByLocation,
onChanged: onSortByLocationToggle,
activeThumbColor: AppColors.successColor,
activeTrackColor: AppColors.successColor.withValues(alpha: 0.15),
),
],
),
),
itemCount: displayList?.length ?? 0,
))
],
);
if (onSortByLocationToggle != null) SizedBox(height: 8.h),
TypeSelectionWidget(
selectedFacility: selectedFacility,
hmcCount: hmcCount.toString(),
hmgCount: hmgCount.toString(),
onitemClicked: (selectedValue) {
onFacilityClicked(selectedValue);
},
),
SizedBox(height: 21.h),
SizedBox(
height: MediaQuery.sizeOf(context).height * .4,
child: ListView.separated(
itemBuilder: (_, index) {
var hospital = displayList?[index];
return HospitalListItem(
hospitalData: hospital,
isLocationEnabled: sortByLocation,
).onPress(() {
onHospitalClicked(hospital!);
});
},
separatorBuilder: (_, __) => SizedBox(
height: 16.h,
),
itemCount: displayList?.length ?? 0,
))
],
);
}
});
}
}

@ -97,14 +97,14 @@ class HospitalListItem extends StatelessWidget {
// )
],
)),
Visibility(
visible: !isLocationEnabled,
child: AppCustomChipWidget(
labelText: "Location turned off",
deleteIcon: AppAssets.location_unavailable,
deleteIconSize: Size(9.w, 12.h),
textColor: AppColors.blackColor,
)),
// Visibility(
// visible: !isLocationEnabled,
// child: AppCustomChipWidget(
// labelText: "Location turned off",
// deleteIcon: AppAssets.location_unavailable,
// deleteIconSize: Size(9.w, 12.h),
// textColor: AppColors.blackColor,
// )),
],
);
}

@ -3,6 +3,9 @@ import 'dart:async';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/location_util.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart' show Utils;
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
@ -14,6 +17,7 @@ import 'package:hmg_patient_app_new/presentation/appointments/widgets/region_bot
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:lottie/lottie.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:provider/provider.dart';
import 'package:url_launcher/url_launcher.dart';
@ -33,6 +37,7 @@ class _RegionBottomSheetBodyState extends State<RegionBottomSheetBody> {
@override
void initState() {
scheduleMicrotask(() {
regionalViewModel.initSortByLocation();
if (regionalViewModel.regionBottomSheetType == RegionBottomSheetType.FOR_REGION || regionalViewModel.regionBottomSheetType == RegionBottomSheetType.REGION_FOR_DENTAL_AND_LASER ) {
myAppointmentsViewModel.getRegionMappedProjectList();
} else if (regionalViewModel.regionBottomSheetType == RegionBottomSheetType.FOR_CLINIIC) {
@ -110,30 +115,136 @@ class _RegionBottomSheetBodyState extends State<RegionBottomSheetBody> {
} else {
return SizedBox(
height: MediaQuery.of(context).size.height * 0.5,
child: ListView.separated(
itemCount: myAppointmentsVM.hospitalList?.registeredDoctorMap?.length ?? 0,
separatorBuilder: (_, __) {
return SizedBox(
height: 16.h,
);
},
itemBuilder: (_, index) {
String key = myAppointmentsVM.hospitalList?.registeredDoctorMap?.keys.toList()[index] ?? '';
return RegionListItem(
title: key,
subTitle: "",
hmcCount: "${myAppointmentsVM.hospitalList?.registeredDoctorMap?[key]?.hmcSize ?? 0}",
hmgCount: "${myAppointmentsVM.hospitalList?.registeredDoctorMap?[key]?.hmgSize ?? 0}",
).onPress(() {
regionalViewModel.setSelectedRegionId(key);
regionalViewModel.setDisplayListAndRegionHospitalList(myAppointmentsVM.hospitalList?.registeredDoctorMap![key]);
regionalViewModel.setBottomSheetState(AppointmentViaRegionState.HOSPITAL_SELECTION);
});
},
child: Column(
children: [
Consumer<AppointmentViaRegionViewmodel>(
builder: (context, regionVM, _) {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 4.w, vertical: 8.h),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.location, iconColor: AppColors.greyTextColor, width: 24.h, height: 24.h),
SizedBox(width: 12.w),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.sortByLocation.tr(context: context).toText14(isBold: true),
// SizedBox(height: 4.h),
LocaleKeys.sortByNearestLocation.tr(context: context).toText11(color: AppColors.textColorLight, weight: FontWeight.w500),
],
),
],
),
Switch(
value: regionVM.sortByLocation,
onChanged: (value) => _handleSortByLocationToggle(value),
activeThumbColor: AppColors.successColor,
activeTrackColor: AppColors.successColor.withValues(alpha: 0.15),
),
],
),
);
},
),
Expanded(
child: ListView.separated(
itemCount: myAppointmentsVM.hospitalList?.registeredDoctorMap?.length ?? 0,
separatorBuilder: (_, __) {
return SizedBox(
height: 16.h,
);
},
itemBuilder: (_, index) {
String key = myAppointmentsVM.hospitalList?.registeredDoctorMap?.keys.toList()[index] ?? '';
return RegionListItem(
title: key,
subTitle: "",
hmcCount: "${myAppointmentsVM.hospitalList?.registeredDoctorMap?[key]?.hmcSize ?? 0}",
hmgCount: "${myAppointmentsVM.hospitalList?.registeredDoctorMap?[key]?.hmgSize ?? 0}",
).onPress(() {
regionalViewModel.setSelectedRegionId(key);
regionalViewModel.setDisplayListAndRegionHospitalList(myAppointmentsVM.hospitalList?.registeredDoctorMap![key]);
regionalViewModel.setBottomSheetState(AppointmentViaRegionState.HOSPITAL_SELECTION);
});
},
),
),
],
),
);
}
},
);
}
void _handleSortByLocationToggle(bool value) {
if (value) {
// User wants to sort by location check permission & get location
final locationUtils = getIt.get<LocationUtils>();
locationUtils.getLocation(
isShowConfirmDialog: true,
onSuccess: (latLng) {
regionalViewModel.setSortByLocation(true);
if (regionalViewModel.regionBottomSheetType == RegionBottomSheetType.FOR_REGION || regionalViewModel.regionBottomSheetType == RegionBottomSheetType.REGION_FOR_DENTAL_AND_LASER) {
myAppointmentsViewModel.getRegionMappedProjectList();
} else if (regionalViewModel.regionBottomSheetType == RegionBottomSheetType.FOR_CLINIIC) {
myAppointmentsViewModel.getMappedDoctors();
}
},
onFailure: () {
showCommonBottomSheetWithoutHeight(
title: LocaleKeys.notice.tr(context: context),
context,
child: Utils.getWarningWidget(
loadingText: LocaleKeys.giveLocationPermissionForNearestList.tr(context: context),
isShowActionButtons: true,
onCancelTap: () {
Navigator.of(context).pop();
},
onConfirmTap: () async {
Navigator.of(context).pop();
openAppSettings();
}),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
regionalViewModel.setSortByLocation(false);
},
onLocationDeniedForever: () {
showCommonBottomSheetWithoutHeight(
title: LocaleKeys.notice.tr(context: context),
context,
child: Utils.getWarningWidget(
loadingText: LocaleKeys.giveLocationPermissionForNearestList.tr(context: context),
isShowActionButtons: true,
onCancelTap: () {
Navigator.of(context).pop();
},
onConfirmTap: () async {
Navigator.of(context).pop();
openAppSettings();
}),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
regionalViewModel.setSortByLocation(false);
},
);
} else {
// User turned off sort by location reset location & re-fetch
final appState = getIt.get<AppState>();
appState.resetLocation();
regionalViewModel.setSortByLocation(false);
if (regionalViewModel.regionBottomSheetType == RegionBottomSheetType.FOR_REGION || regionalViewModel.regionBottomSheetType == RegionBottomSheetType.REGION_FOR_DENTAL_AND_LASER) {
myAppointmentsViewModel.getRegionMappedProjectList();
} else if (regionalViewModel.regionBottomSheetType == RegionBottomSheetType.FOR_CLINIIC) {
myAppointmentsViewModel.getMappedDoctors();
}
}
}
}

@ -7,6 +7,7 @@ import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_export.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
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/utils.dart';
import 'package:hmg_patient_app_new/extensions/route_extensions.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
@ -32,6 +33,7 @@ import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart' show showC
import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:provider/provider.dart';
import '../appointments/widgets/hospital_bottom_sheet/hospital_bottom_sheet_body.dart';
@ -57,7 +59,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
scheduleMicrotask(() {
// bookAppointmentsViewModel.selectedTabIndex = 0;
bookAppointmentsViewModel.initBookAppointmentViewModel();
bookAppointmentsViewModel.getLocation();
// bookAppointmentsViewModel.getLocation();
immediateLiveCareViewModel.initImmediateLiveCare();
if (appState.isAuthenticated) {
getIt.get<MyAppointmentsViewModel>().getPatientMyDoctors();
@ -642,6 +644,8 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
selectedFacility: data.selectedFacility,
hmcCount: data.hmcCount,
hmgCount: data.hmgCount,
sortByLocation: data.sortByLocation,
onSortByLocationToggle: (value) => _handleSortByLocationToggle(value, data),
);
}
if (data.bottomSheetState == AppointmentViaRegionState.CLINIC_SELECTION) {
@ -655,6 +659,78 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
return SizedBox.shrink();
}
void _handleSortByLocationToggle(bool value, AppointmentViaRegionViewmodel regionVM) {
if (value) {
final locationUtils = getIt.get<LocationUtils>();
locationUtils.getLocation(
isShowConfirmDialog: true,
onSuccess: (latLng) {
regionVM.setSortByLocation(true);
_refreshHospitalListAfterApi(regionVM);
},
onFailure: () {
showCommonBottomSheetWithoutHeight(
title: LocaleKeys.notice.tr(context: context),
context,
child: Utils.getWarningWidget(
loadingText: LocaleKeys.giveLocationPermissionForNearestList.tr(context: context),
isShowActionButtons: true,
onCancelTap: () {
Navigator.of(context).pop();
},
onConfirmTap: () async {
Navigator.of(context).pop();
openAppSettings();
}),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
regionVM.setSortByLocation(false);
},
onLocationDeniedForever: () {
showCommonBottomSheetWithoutHeight(
title: LocaleKeys.notice.tr(context: context),
context,
child: Utils.getWarningWidget(
loadingText: LocaleKeys.giveLocationPermissionForNearestList.tr(context: context),
isShowActionButtons: true,
onCancelTap: () {
Navigator.of(context).pop();
},
onConfirmTap: () async {
Navigator.of(context).pop();
openAppSettings();
}),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
regionVM.setSortByLocation(false);
},
);
} else {
final appState = getIt.get<AppState>();
appState.resetLocation();
regionVM.setSortByLocation(false);
_refreshHospitalListAfterApi(regionVM);
}
}
void _refreshHospitalListAfterApi(AppointmentViaRegionViewmodel regionVM) {
void listener() {
if (!bookAppointmentsViewModel.isRegionListLoading) {
bookAppointmentsViewModel.removeListener(listener);
final selectedRegion = regionVM.selectedRegionId;
if (selectedRegion != null && bookAppointmentsViewModel.hospitalList?.registeredDoctorMap?[selectedRegion] != null) {
regionVM.setDisplayListAndRegionHospitalList(bookAppointmentsViewModel.hospitalList!.registeredDoctorMap![selectedRegion]);
}
}
}
bookAppointmentsViewModel.addListener(listener);
bookAppointmentsViewModel.getRegionMappedProjectList();
}
getTitle(AppointmentViaRegionViewmodel data) {
if (data.selectedRegionId == null) {
return LocaleKeys.selectRegion.tr(context: context).toText20(weight: FontWeight.w600);

@ -118,10 +118,12 @@ class DoctorProfilePage extends StatelessWidget {
runSpacing: 4.h,
children: [
AppCustomChipWidget(
backgroundColor: AppColors.whiteColor,
iconColor: AppColors.ratingColorYellow,
labelText: "${bookAppointmentsViewModel.doctorsProfileResponseModel.projectName}",
),
AppCustomChipWidget(
backgroundColor: AppColors.whiteColor,
iconColor: AppColors.ratingColorYellow,
labelText: "${bookAppointmentsViewModel.doctorsProfileResponseModel.clinicDescription}",
),

@ -7,6 +7,7 @@ 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/int_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/book_appointments/book_appointments_view_model.dart';
@ -82,9 +83,7 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
runSpacing: 4.h,
children: [
AppCustomChipWidget(labelText: "${appState.getAuthenticatedUser()!.age} ${LocaleKeys.yearsOld.tr(context: context)}"),
AppCustomChipWidget(
labelText:
"${LocaleKeys.clinic.tr()}: ${(appState.isArabic() ? immediateLiveCareVM.immediateLiveCareSelectedClinic.serviceNameN : immediateLiveCareVM.immediateLiveCareSelectedClinic.serviceName) ?? ""}"),
AppCustomChipWidget(labelText: "${LocaleKeys.gender.tr(context: context)}: ${appState.getAuthenticatedUser()?.gender == 1 ? LocaleKeys.malE.tr(context: context) : LocaleKeys.femaleGender.tr(context: context)}"),
],
),
],
@ -105,17 +104,28 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
),
child: Padding(
padding: EdgeInsets.all(16.h),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AppCustomChipWidget(
labelText:
"${LocaleKeys.clinic.tr()}: ${(appState.isArabic() ? immediateLiveCareVM.immediateLiveCareSelectedClinic.serviceNameN : immediateLiveCareVM.immediateLiveCareSelectedClinic.serviceName) ?? ""}"),
SizedBox(height: 16.h),
1.divider,
SizedBox(height: 16.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Utils.buildSvgWithAssets(icon: getLiveCareTypeIcon(immediateLiveCareVM.liveCareSelectedCallType), width: 32.h, height: 32.h, fit: BoxFit.contain, applyThemeColor: false),
SizedBox(width: 8.h),
getLiveCareType(context, immediateLiveCareVM.liveCareSelectedCallType).toText16(isBold: true),
Row(
children: [
Utils.buildSvgWithAssets(icon: getLiveCareTypeIcon(immediateLiveCareVM.liveCareSelectedCallType), width: 32.h, height: 32.h, fit: BoxFit.contain, applyThemeColor: false),
SizedBox(width: 8.h),
getLiveCareType(context, immediateLiveCareVM.liveCareSelectedCallType).toText16(isBold: true),
],
),
Utils.buildSvgWithAssets(icon: AppAssets.edit_icon, width: 24.h, height: 24.h, fit: BoxFit.contain),
],
),
Utils.buildSvgWithAssets(icon: AppAssets.edit_icon, width: 24.h, height: 24.h, fit: BoxFit.contain),
],
),
),
@ -202,7 +212,7 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(width: 150.h, child: Utils.getPaymentMethods()),
SizedBox(width: 200.h, child: Utils.getPaymentMethods()),
Utils.getPaymentAmountWithSymbol(immediateLiveCareVM.liveCareImmediateAppointmentFeesList.total!.toText24(isBold: true), AppColors.blackColor, 17,
isSaudiCurrency: (immediateLiveCareVM.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "sar" ||
immediateLiveCareVM.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "ريال")),

@ -109,8 +109,8 @@ class _ReviewAppointmentPageState extends State<ReviewAppointmentPage> {
SizedBox(height: 12.h),
Wrap(
direction: Axis.horizontal,
spacing: 8.h,
runSpacing: 8.h,
spacing: 4.h,
runSpacing: 4.h,
children: [
AppCustomChipWidget(
labelText: "${LocaleKeys.clinic.tr(context: context)}: ${bookAppointmentsViewModel.selectedDoctor.clinicName}",
@ -156,7 +156,15 @@ class _ReviewAppointmentPageState extends State<ReviewAppointmentPage> {
children: [
"${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}".toText16(isBold: true),
SizedBox(height: 8.h),
AppCustomChipWidget(labelText: "${appState.getAuthenticatedUser()!.age} Years Old"),
Wrap(
direction: Axis.horizontal,
spacing: 4.h,
runSpacing: 4.h,
children: [
AppCustomChipWidget(labelText: "${appState.getAuthenticatedUser()!.age} Years Old"),
AppCustomChipWidget(labelText: "${LocaleKeys.gender.tr(context: context)}: ${appState.getAuthenticatedUser()?.gender == 1 ? LocaleKeys.malE.tr(context: context) : LocaleKeys.femaleGender.tr(context: context)}"),
],
),
],
),
],

@ -52,7 +52,7 @@ class _SearchDoctorByNameState extends State<SearchDoctorByName> {
children: [
Expanded(
child: CollapsingListView(
title: LocaleKeys.chooseDoctor.tr(),
title: LocaleKeys.chooseDoctor.tr(context: context),
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 24.h),
@ -142,49 +142,49 @@ class _SearchDoctorByNameState extends State<SearchDoctorByName> {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (bookAppointmentsVM.isDoctorSearchByNameStarted)
Row(
children: [
CustomButton(
text: LocaleKeys.byClinic.tr(context: context),
onPressed: () {
bookAppointmentsVM.sortFilteredDoctorList(true);
},
backgroundColor: bookAppointmentsVM.isSortByClinic ? AppColors.bgRedLightColor : AppColors.whiteColor,
borderColor: bookAppointmentsVM.isSortByClinic ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2),
textColor: bookAppointmentsVM.isSortByClinic ? AppColors.primaryRedColor : AppColors.blackColor,
fontSize: 12,
fontWeight: FontWeight.w500,
borderRadius: 10,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h,
),
SizedBox(width: 8.h),
CustomButton(
text: LocaleKeys.byHospital.tr(context: context),
onPressed: () {
bookAppointmentsVM.sortFilteredDoctorList(false);
},
backgroundColor: bookAppointmentsVM.isSortByClinic ? AppColors.whiteColor : AppColors.bgRedLightColor,
borderColor: bookAppointmentsVM.isSortByClinic ? AppColors.textColor.withOpacity(0.2) : AppColors.primaryRedColor,
textColor: bookAppointmentsVM.isSortByClinic ? AppColors.blackColor : AppColors.primaryRedColor,
fontSize: 12,
fontWeight: FontWeight.w500,
borderRadius: 10,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h,
),
],
).paddingSymmetrical(0.h, 0.h),
// if (bookAppointmentsVM.isDoctorSearchByNameStarted)
// Row(
// children: [
// CustomButton(
// text: LocaleKeys.byClinic.tr(context: context),
// onPressed: () {
// bookAppointmentsVM.sortFilteredDoctorList(true);
// },
// backgroundColor: bookAppointmentsVM.isSortByClinic ? AppColors.bgRedLightColor : AppColors.whiteColor,
// borderColor: bookAppointmentsVM.isSortByClinic ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2),
// textColor: bookAppointmentsVM.isSortByClinic ? AppColors.primaryRedColor : AppColors.blackColor,
// fontSize: 12,
// fontWeight: FontWeight.w500,
// borderRadius: 10,
// padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
// height: 40.h,
// ),
// SizedBox(width: 8.h),
// CustomButton(
// text: LocaleKeys.byHospital.tr(context: context),
// onPressed: () {
// bookAppointmentsVM.sortFilteredDoctorList(false);
// },
// backgroundColor: bookAppointmentsVM.isSortByClinic ? AppColors.whiteColor : AppColors.bgRedLightColor,
// borderColor: bookAppointmentsVM.isSortByClinic ? AppColors.textColor.withOpacity(0.2) : AppColors.primaryRedColor,
// textColor: bookAppointmentsVM.isSortByClinic ? AppColors.blackColor : AppColors.primaryRedColor,
// fontSize: 12,
// fontWeight: FontWeight.w500,
// borderRadius: 10,
// padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
// height: 40.h,
// ),
// ],
// ).paddingSymmetrical(0.h, 0.h),
bookAppointmentsVM.isDoctorSearchByNameStarted
? ListView.separated(
padding: EdgeInsets.only(top: 20.h),
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: bookAppointmentsVM.isDoctorsListLoading ? 5 : bookAppointmentsVM.getGroupedFilteredDoctorsList().length,
itemCount: bookAppointmentsVM.isDoctorsListLoading ? 5 : bookAppointmentsVM.filteredDoctorList.length,
itemBuilder: (context, index) {
final isExpanded = bookAppointmentsVM.expandedGroupIndex == index;
final groupedDoctors = bookAppointmentsVM.getGroupedFilteredDoctorsList();
// final isExpanded = bookAppointmentsVM.expandedGroupIndex == index;
// final groupedDoctors = bookAppointmentsVM.getGroupedFilteredDoctorsList();
return bookAppointmentsVM.isDoctorsListLoading
? DoctorCard(
@ -203,112 +203,184 @@ class _SearchDoctorByNameState extends State<SearchDoctorByName> {
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true),
child: InkWell(
onTap: () {
bookAppointmentsVM.toggleGroupExpansion(index);
// After rebuild, ensure the expanded item is visible
WidgetsBinding.instance.addPostFrameCallback((_) {
final key = _itemKeys[index];
if (key != null && key.currentContext != null && bookAppointmentsVM.expandedGroupIndex == index) {
Scrollable.ensureVisible(
key.currentContext!,
duration: Duration(milliseconds: 350),
curve: Curves.easeInOut,
alignment: 0.1,
child: Container(
key: ValueKey<int>(index),
padding: EdgeInsets.only(top: 12.h),
child: DoctorCard(
doctorsListResponseModel: bookAppointmentsVM.filteredDoctorList[index],
isLoading: false,
bookAppointmentsViewModel: bookAppointmentsViewModel,
).paddingSymmetrical(16.h, 0.h).onPress(() async {
bookAppointmentsVM.setSelectedDoctor(bookAppointmentsVM.filteredDoctorList[index]);
LoaderBottomSheet.showLoader();
await bookAppointmentsVM.getDoctorProfile(
onSuccess: (dynamic respData) {
LoaderBottomSheet.hideLoader();
Navigator.of(context).push(
CustomPageRoute(
page: DoctorProfilePage(),
),
);
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
}
});
},
child: Padding(
padding: EdgeInsets.all(16.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
CustomButton(
text: "${groupedDoctors[index].length} ${'doctors'}",
onPressed: () {},
backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor,
textColor: AppColors.blackColor,
fontSize: 10,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 30.h),
Icon(isExpanded ? Icons.expand_less : Icons.expand_more),
],
),
SizedBox(height: 8.h),
// Clinic/Hospital name as group title
Text(
bookAppointmentsVM.isSortByClinic
? (groupedDoctors[index].first.clinicName ?? 'Unknown')
: (groupedDoctors[index].first.projectName ?? 'Unknown'),
style: TextStyle(fontSize: 16.h, fontWeight: FontWeight.w600),
overflow: TextOverflow.ellipsis,
),
// Expanded content - list of doctors in this group
AnimatedSwitcher(
duration: Duration(milliseconds: 400),
child: isExpanded
? Container(
key: ValueKey<int>(index),
padding: EdgeInsets.only(top: 12.h),
child: Column(
children: groupedDoctors[index].asMap().entries.map<Widget>((entry) {
final doctorIndex = entry.key;
final doctor = entry.value;
final isLastDoctor = doctorIndex == groupedDoctors[index].length - 1;
return Column(
children: [
DoctorCard(
doctorsListResponseModel: doctor,
isLoading: false,
bookAppointmentsViewModel: bookAppointmentsViewModel,
).onPress(() async {
bookAppointmentsVM.setSelectedDoctor(doctor);
LoaderBottomSheet.showLoader();
await bookAppointmentsVM.getDoctorProfile(
onSuccess: (dynamic respData) {
LoaderBottomSheet.hideLoader();
Navigator.of(context).push(
CustomPageRoute(
page: DoctorProfilePage(),
),
);
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
},
);
}),
if (!isLastDoctor)
Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h),
],
);
}).toList(),
),
)
: SizedBox.shrink(),
),
],
),
),
},
);
// Column(
// children: bookAppointmentsVM.doctorsList[index].map<Widget>((entry) {
// final doctorIndex = entry.key;
// final doctor = entry.value;
// final isLastDoctor = doctorIndex == groupedDoctors[index].length - 1;
// return Column(
// children: [
// DoctorCard(
// doctorsListResponseModel: doctor,
// isLoading: false,
// bookAppointmentsViewModel: bookAppointmentsViewModel,
// ).onPress(() async {
// bookAppointmentsVM.setSelectedDoctor(doctor);
// LoaderBottomSheet.showLoader();
// await bookAppointmentsVM.getDoctorProfile(
// onSuccess: (dynamic respData) {
// LoaderBottomSheet.hideLoader();
// Navigator.of(context).push(
// CustomPageRoute(
// page: DoctorProfilePage(),
// ),
// );
// },
// onError: (err) {
// LoaderBottomSheet.hideLoader();
// showCommonBottomSheetWithoutHeight(
// context,
// child: Utils.getErrorWidget(loadingText: err),
// callBackFunc: () {},
// isFullScreen: false,
// isCloseButtonVisible: true,
// );
// },
// );
// }),
// if (!isLastDoctor)
// Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h),
// ],
// );
// }).toList(),
// ),
}),
// InkWell(
// onTap: () {
// bookAppointmentsVM.toggleGroupExpansion(index);
// // After rebuild, ensure the expanded item is visible
// WidgetsBinding.instance.addPostFrameCallback((_) {
// final key = _itemKeys[index];
// if (key != null && key.currentContext != null && bookAppointmentsVM.expandedGroupIndex == index) {
// Scrollable.ensureVisible(
// key.currentContext!,
// duration: Duration(milliseconds: 350),
// curve: Curves.easeInOut,
// alignment: 0.1,
// );
// }
// });
// },
// child: Padding(
// padding: EdgeInsets.all(16.h),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// CustomButton(
// text: "${groupedDoctors[index].length} ${'doctors'}",
// onPressed: () {},
// backgroundColor: AppColors.greyColor,
// borderColor: AppColors.greyColor,
// textColor: AppColors.blackColor,
// fontSize: 10,
// fontWeight: FontWeight.w500,
// borderRadius: 8,
// padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
// height: 30.h),
// Icon(isExpanded ? Icons.expand_less : Icons.expand_more),
// ],
// ),
// SizedBox(height: 8.h),
// // Clinic/Hospital name as group title
// Text(
// bookAppointmentsVM.isSortByClinic
// ? (groupedDoctors[index].first.clinicName ?? 'Unknown')
// : (groupedDoctors[index].first.projectName ?? 'Unknown'),
// style: TextStyle(fontSize: 16.h, fontWeight: FontWeight.w600),
// overflow: TextOverflow.ellipsis,
// ),
// // Expanded content - list of doctors in this group
// // AnimatedSwitcher(
// // duration: Duration(milliseconds: 400),
// // child: isExpanded
// // ? Container(
// // key: ValueKey<int>(index),
// // padding: EdgeInsets.only(top: 12.h),
// // child: Column(
// // children: groupedDoctors[index].asMap().entries.map<Widget>((entry) {
// // final doctorIndex = entry.key;
// // final doctor = entry.value;
// // final isLastDoctor = doctorIndex == groupedDoctors[index].length - 1;
// // return Column(
// // children: [
// // DoctorCard(
// // doctorsListResponseModel: doctor,
// // isLoading: false,
// // bookAppointmentsViewModel: bookAppointmentsViewModel,
// // ).onPress(() async {
// // bookAppointmentsVM.setSelectedDoctor(doctor);
// // LoaderBottomSheet.showLoader();
// // await bookAppointmentsVM.getDoctorProfile(
// // onSuccess: (dynamic respData) {
// // LoaderBottomSheet.hideLoader();
// // Navigator.of(context).push(
// // CustomPageRoute(
// // page: DoctorProfilePage(),
// // ),
// // );
// // },
// // onError: (err) {
// // LoaderBottomSheet.hideLoader();
// // showCommonBottomSheetWithoutHeight(
// // context,
// // child: Utils.getErrorWidget(loadingText: err),
// // callBackFunc: () {},
// // isFullScreen: false,
// // isCloseButtonVisible: true,
// // );
// // },
// // );
// // }),
// // if (!isLastDoctor)
// // Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h),
// // ],
// // );
// // }).toList(),
// // ),
// // )
// // : SizedBox.shrink(),
// // ),
// ],
// ),
// ),
// ),
),
),
),
),
);
));
},
separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h),
)

@ -7,6 +7,7 @@ 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/enums.dart';
import 'package:hmg_patient_app_new/core/location_util.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';
@ -1118,6 +1119,8 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
selectedFacility: data.selectedFacility,
hmcCount: data.hmcCount,
hmgCount: data.hmgCount,
sortByLocation: data.sortByLocation,
onSortByLocationToggle: (value) => _handleSortByLocationToggle(value, data),
);
}
if (data.bottomSheetState == AppointmentViaRegionState.DOCTOR_SELECTION) {
@ -1301,4 +1304,49 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
initDentalAppointmentBookingFlow(int.parse(bookAppointmentsViewModel.currentlySelectedHospitalFromRegionFlow ?? "0"));
return;
}
void _handleSortByLocationToggle(bool value, AppointmentViaRegionViewmodel regionVM) {
if (value) {
final locationUtils = getIt.get<LocationUtils>();
locationUtils.getLocation(
isShowConfirmDialog: true,
onSuccess: (latLng) {
regionVM.setSortByLocation(true);
_refreshHospitalListAfterApi(regionVM);
},
onFailure: () {
regionVM.setSortByLocation(false);
},
onLocationDeniedForever: () {
regionVM.setSortByLocation(false);
},
);
} else {
final appState = getIt.get<AppState>();
appState.resetLocation();
regionVM.setSortByLocation(false);
_refreshHospitalListAfterApi(regionVM);
}
}
void _refreshHospitalListAfterApi(AppointmentViaRegionViewmodel regionVM) {
void listener() {
if (!bookAppointmentsViewModel.isRegionListLoading) {
bookAppointmentsViewModel.removeListener(listener);
final selectedRegion = regionVM.selectedRegionId;
if (selectedRegion != null && bookAppointmentsViewModel.hospitalList?.registeredDoctorMap?[selectedRegion] != null) {
regionVM.setDisplayListAndRegionHospitalList(bookAppointmentsViewModel.hospitalList!.registeredDoctorMap![selectedRegion]);
}
}
}
bookAppointmentsViewModel.addListener(listener);
if (regionalViewModel.regionBottomSheetType == RegionBottomSheetType.FOR_REGION || regionalViewModel.regionBottomSheetType == RegionBottomSheetType.REGION_FOR_DENTAL_AND_LASER) {
bookAppointmentsViewModel.getRegionMappedProjectList();
} else if (regionalViewModel.regionBottomSheetType == RegionBottomSheetType.FOR_CLINIIC) {
bookAppointmentsViewModel.getMappedDoctors();
}
// bookAppointmentsViewModel.getRegionMappedProjectList();
}
}

@ -99,12 +99,12 @@ class _AppointmentCalendarState extends State<AppointmentCalendar> {
showNavigationArrow: true,
headerHeight: 60.h,
headerStyle: CalendarHeaderStyle(
backgroundColor: AppColors.scaffoldBgColor,
backgroundColor: AppColors.transparent,
textAlign: TextAlign.start,
textStyle: TextStyle(fontSize: 18.f, fontWeight: FontWeight.w600, letterSpacing: -0.46, color: AppColors.primaryRedColor, fontFamily: "Poppins"),
),
viewHeaderStyle: ViewHeaderStyle(
backgroundColor: AppColors.scaffoldBgColor,
// backgroundColor: AppColors.scaffoldBgColor,
dayTextStyle: TextStyle(fontSize: 14.f, fontWeight: FontWeight.w600, letterSpacing: -0.46, color: AppColors.textColor, fontFamily: "Poppins"),
),
view: CalendarView.month,

@ -127,23 +127,23 @@ class DoctorCard extends StatelessWidget {
spacing: 3.h,
runSpacing: 4.h,
children: [
AppCustomChipWidget(
labelText: "${isLoading ? "Cardiologist" : doctorsListResponseModel.clinicName}",
).toShimmer2(isShow: isLoading),
AppCustomChipWidget(
labelText: "${isLoading ? "Olaya Hospital" : doctorsListResponseModel.projectName}",
).toShimmer2(isShow: isLoading),
bookAppointmentsViewModel.isNearestAppointmentSelected
? doctorsListResponseModel.nearestFreeSlot != null
? AppCustomChipWidget(
// labelText: (isLoading ? "Cardiologist" : DateUtil.getDateStringForNearestSlot(doctorsListResponseModel.nearestFreeSlot)),
richText: (isLoading ? "Cardiologist" : DateUtil.getDateStringForNearestSlot(doctorsListResponseModel.nearestFreeSlot))
.toText10(isEnglishOnly: true, color: AppColors.whiteColor),
backgroundColor: AppColors.successColor,
textColor: AppColors.whiteColor,
labelText: (isLoading ? "Cardiologist" : DateUtil.getDateStringForNearestSlot(doctorsListResponseModel.nearestFreeSlot)),
// richText: (isLoading ? "Cardiologist" : DateUtil.getDateStringForNearestSlot(doctorsListResponseModel.nearestFreeSlot))
// .toText10(isEnglishOnly: true, color: AppColors.textColor),
// backgroundColor: AppColors.successColor,
textColor: AppColors.textColor,
).toShimmer2(isShow: isLoading)
: SizedBox.shrink()
: SizedBox.shrink(),
AppCustomChipWidget(
labelText: "${isLoading ? "Cardiologist" : doctorsListResponseModel.clinicName}",
).toShimmer2(isShow: isLoading),
AppCustomChipWidget(
labelText: "${isLoading ? "Olaya Hospital" : doctorsListResponseModel.projectName}",
).toShimmer2(isShow: isLoading),
],
),
],
@ -155,7 +155,7 @@ class DoctorCard extends StatelessWidget {
),
],
),
SizedBox(height: 12.h),
SizedBox(height: 16.h),
CustomButton(
text: LocaleKeys.bookAppo.tr(context: context),
onPressed: () async {

@ -14,6 +14,8 @@ import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/contact_us/feedback_page.dart';
import 'package:hmg_patient_app_new/presentation/contact_us/find_us_page.dart';
import 'package:hmg_patient_app_new/presentation/contact_us/live_chat_page.dart';
import 'package:hmg_patient_app_new/presentation/home/service_info_page.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:provider/provider.dart';
@ -80,15 +82,23 @@ class ContactUs extends StatelessWidget {
LocaleKeys.liveChat.tr(),
LocaleKeys.liveChatWithHMG.tr(),
).onPress(() {
locationUtils.getCurrentLocation(onSuccess: (value) {
contactUsViewModel.getLiveChatProjectsList();
Navigator.pop(context);
if (getIt.get<AppState>().isAuthenticated) {
Navigator.of(context).push(
CustomPageRoute(
page: LiveChatPage(),
),
);
});
} else {
Navigator.of(getIt<NavigationService>().navigatorKey.currentContext!).push(
CustomPageRoute(
page: ServiceInfoPage(
serviceName: LocaleKeys.liveChat.tr(),
serviceHeader: "HMG Hospital E-Referral: Streamlined patient referrals".needTranslation,
serviceDescription: "Facilitate seamless patient transfers to HMG with our secure e-referral system. Ensure continuity of care for every patient.".needTranslation,
serviceImage: AppAssets.eReferralService),
),
);
}
}),
],
);

@ -59,7 +59,7 @@ class FindUsPage extends StatelessWidget {
children: [
LocaleKeys.sortByLocation.tr(context: context).toText14(isBold: true),
SizedBox(height: 4.h),
"Sort the locations by nearest to your location".toText11(color: AppColors.textColorLight, weight: FontWeight.w500),
LocaleKeys.sortByNearestLocation.tr(context: context).toText11(color: AppColors.textColorLight, weight: FontWeight.w500),
],
),
const Spacer(),

@ -1,6 +1,8 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/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';
@ -12,7 +14,9 @@ import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/RRT/rrt_request_type_select.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/widgets/ambulance_option_selection_bottomsheet.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/widgets/pickup_location.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/history/er_history_listing.dart';
import 'package:hmg_patient_app_new/presentation/home/service_info_page.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';
@ -22,23 +26,46 @@ import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:lottie/lottie.dart';
import 'package:provider/provider.dart';
class EmergencyServicesPage extends StatelessWidget {
class EmergencyServicesPage extends StatefulWidget {
EmergencyServicesPage({super.key});
@override
State<EmergencyServicesPage> createState() => _EmergencyServicesPageState();
}
class _EmergencyServicesPageState extends State<EmergencyServicesPage> {
late EmergencyServicesViewModel emergencyServicesViewModel;
_handleConfirmationBottomSheet() {}
late AppState appState;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
if (appState.isAuthenticated) {
emergencyServicesViewModel.flushData();
emergencyServicesViewModel.getTransportationOrders(
showLoader: false,
);
emergencyServicesViewModel.getRRTOrders(
showLoader: false,
);
}
});
}
@override
Widget build(BuildContext context) {
emergencyServicesViewModel = Provider.of<EmergencyServicesViewModel>(context, listen: false);
appState = getIt.get<AppState>();
return CollapsingListView(
title: LocaleKeys.emergencyServices.tr(),
history: () {
emergencyServicesViewModel.changeOrderDisplayItems(OrderDislpay.ALL);
Navigator.of(context).push(CustomPageRoute(page: ErHistoryListing(), direction: AxisDirection.up));
},
history: appState.isAuthenticated
? () {
emergencyServicesViewModel.changeOrderDisplayItems(OrderDislpay.ALL);
Navigator.of(context).push(CustomPageRoute(page: ErHistoryListing(), direction: AxisDirection.up));
}
: null,
child: Padding(
padding: EdgeInsets.all(24.h),
child: Column(
@ -60,8 +87,7 @@ class EmergencyServicesPage extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.callAmbulance.tr().toText16(isBold: true, color: AppColors.blackColor),
LocaleKeys.requestAmbulanceInEmergency.tr()
.toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500),
LocaleKeys.requestAmbulanceInEmergency.tr().toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500),
],
),
),
@ -69,65 +95,75 @@ class EmergencyServicesPage extends StatelessWidget {
Utils.buildSvgWithAssets(icon: AppAssets.forward_chevron_icon, width: 13.h, height: 13.h),
],
).onPress(() {
showCommonBottomSheetWithoutHeight(
context,
child: Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.primaryRedColor,
borderRadius: 24.h,
),
child: Padding(
padding: EdgeInsets.all(24.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"".toText14(),
Utils.buildSvgWithAssets(
icon: AppAssets.cancel_circle_icon,
iconColor: Colors.white,
width: 24.h,
height: 24.h,
fit: BoxFit.contain,
).onPress(() {
if(appState.isAuthenticated) {
showCommonBottomSheetWithoutHeight(
context,
child: Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.primaryRedColor,
borderRadius: 24.h,
),
child: Padding(
padding: EdgeInsets.all(24.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"".toText14(),
Utils.buildSvgWithAssets(
icon: AppAssets.cancel_circle_icon,
iconColor: Colors.white,
width: 24.h,
height: 24.h,
fit: BoxFit.contain,
).onPress(() {
Navigator.of(context).pop();
}),
],
),
Lottie.asset(AppAnimations.ambulanceAlert, repeat: false, reverse: false, frameRate: FrameRate(60), width: 120.h, height: 120.h, fit: BoxFit.contain),
SizedBox(height: 8.h),
LocaleKeys.confirmation.tr().toText28(color: Colors.white, isBold: true),
SizedBox(height: 8.h),
LocaleKeys.areYouSureYouWantToCallAmbulance.tr().toText14(color: Colors.white, weight: FontWeight.w500),
SizedBox(height: 24.h),
CustomButton(
text: LocaleKeys.confirm.tr(context: context),
onPressed: () async {
Navigator.of(context).pop();
}),
],
),
Lottie.asset(AppAnimations.ambulanceAlert,
repeat: false, reverse: false, frameRate: FrameRate(60), width: 120.h, height: 120.h, fit: BoxFit.contain),
SizedBox(height: 8.h),
LocaleKeys.confirmation.tr().toText28(color: Colors.white, isBold: true),
SizedBox(height: 8.h),
LocaleKeys.areYouSureYouWantToCallAmbulance.tr()
.toText14(color: Colors.white, weight: FontWeight.w500),
SizedBox(height: 24.h),
CustomButton(
text: LocaleKeys.confirm.tr(context: context),
onPressed: () async {
Navigator.of(context).pop();
await emergencyServicesViewModel.getTransportationOption();
openTranportationSelectionBottomSheet(context);
},
backgroundColor: Colors.white,
borderColor: Colors.white,
textColor: AppColors.primaryRedColor,
icon: AppAssets.checkmark_icon,
iconColor: AppColors.primaryRedColor,
),
SizedBox(height: 8.h),
],
await emergencyServicesViewModel.getTransportationOption();
openTranportationSelectionBottomSheet(context);
},
backgroundColor: Colors.white,
borderColor: Colors.white,
textColor: AppColors.primaryRedColor,
icon: AppAssets.checkmark_icon,
iconColor: AppColors.primaryRedColor,
),
SizedBox(height: 8.h),
],
),
),
),
),
isFullScreen: false,
isCloseButtonVisible: false,
hasBottomPadding: false,
backgroundColor: AppColors.primaryRedColor,
callBackFunc: () {},
);
isFullScreen: false,
isCloseButtonVisible: false,
hasBottomPadding: false,
backgroundColor: AppColors.primaryRedColor,
callBackFunc: () {},
);
} else {
Navigator.of(context).push(
CustomPageRoute(
page: ServiceInfoPage(
serviceName: LocaleKeys.emergencyServices.tr(),
serviceHeader: "ER Check-in, Faster Than Ever. Call ambulance / Rapid Response Team instantly".needTranslation,
serviceDescription: "In a medical emergency? Our ambulances and rapid response teams are on standby 24/7. Plus, quick ER check-in for faster care.".needTranslation,
serviceImage: AppAssets.emergencyService),
),
);
}
}),
),
SizedBox(height: 16.h),
@ -147,8 +183,7 @@ class EmergencyServicesPage extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.nearester.tr(context: context).toText16(isBold: true, color: AppColors.blackColor),
LocaleKeys.getDetailsOfNearestBranch.tr()
.toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500),
LocaleKeys.getDetailsOfNearestBranch.tr().toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500),
],
),
),
@ -176,8 +211,7 @@ class EmergencyServicesPage extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.rapidResponseTeam.tr(context: context).toText16(isBold: true, color: AppColors.blackColor),
"Comprehensive medical service for all sorts of urgent and stable cases"
.toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500),
"Comprehensive medical service for all sorts of urgent and stable cases".toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500),
],
),
),
@ -185,77 +219,101 @@ class EmergencyServicesPage extends StatelessWidget {
Utils.buildSvgWithAssets(icon: AppAssets.forward_chevron_icon, width: 13.h, height: 13.h),
],
).onPress(() {
showCommonBottomSheetWithoutHeight(
context,
child: Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.primaryRedColor,
borderRadius: 24.h,
),
child: Padding(
padding: EdgeInsets.all(24.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Lottie.asset(AppAnimations.ambulanceAlert, repeat: false, reverse: false, frameRate: FrameRate(60), width: 120.h, height: 120.h, fit: BoxFit.contain),
SizedBox(height: 8.h),
LocaleKeys.confirm.tr().toText28(color: Colors.white, isBold: true),
SizedBox(height: 8.h),
LocaleKeys.areYouSureYouWantToCallRRT.tr()
.toText14(color: Colors.white, weight: FontWeight.w500),
SizedBox(height: 24.h),
CustomButton(
text: LocaleKeys.confirm.tr(context: context),
onPressed: () async {
Navigator.of(context).pop();
LoaderBottomSheet.showLoader();
emergencyServicesViewModel.clearRRTData();
await emergencyServicesViewModel.getRRTProcedures(onSuccess: (val) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
padding: EdgeInsets.only(top: 24.h),
titleWidget: Transform.flip(
flipX: emergencyServicesViewModel.isArabic,
child: Utils.buildSvgWithAssets(
icon: AppAssets.arrow_back,
iconColor: Color(0xff2B353E),
fit: BoxFit.contain,
),
).onPress(() {
Navigator.pop(context);
}),
// title: "Rapid Response Team (RRT)".needTranslation,
context,
child: RrtRequestTypeSelect(),
isFullScreen: false,
isCloseButtonVisible: true,
hasBottomPadding: false,
backgroundColor: AppColors.bottomSheetBgColor,
callBackFunc: () {},
);
});
},
backgroundColor: Colors.white,
borderColor: Colors.white,
textColor: AppColors.primaryRedColor,
icon: AppAssets.checkmark_icon,
iconColor: AppColors.primaryRedColor,
),
SizedBox(height: 8.h),
],
if(appState.isAuthenticated) {
showCommonBottomSheetWithoutHeight(
context,
child: Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.primaryRedColor,
borderRadius: 24.h,
),
child: Padding(
padding: EdgeInsets.all(24.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"".toText14(),
Utils.buildSvgWithAssets(
icon: AppAssets.cancel_circle_icon,
iconColor: Colors.white,
width: 24.h,
height: 24.h,
fit: BoxFit.contain,
).onPress(() {
Navigator.of(context).pop();
}),
],
),
Lottie.asset(AppAnimations.ambulanceAlert, repeat: false, reverse: false, frameRate: FrameRate(60), width: 120.h, height: 120.h, fit: BoxFit.contain),
SizedBox(height: 8.h),
LocaleKeys.confirm.tr().toText28(color: Colors.white, isBold: true),
SizedBox(height: 8.h),
LocaleKeys.areYouSureYouWantToCallRRT.tr().toText14(color: Colors.white, weight: FontWeight.w500),
SizedBox(height: 24.h),
CustomButton(
text: LocaleKeys.confirm.tr(context: context),
onPressed: () async {
Navigator.of(context).pop();
LoaderBottomSheet.showLoader();
emergencyServicesViewModel.clearRRTData();
await emergencyServicesViewModel.getRRTProcedures(onSuccess: (val) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
padding: EdgeInsets.only(top: 24.h),
titleWidget: Transform.flip(
flipX: emergencyServicesViewModel.isArabic,
child: Utils.buildSvgWithAssets(
icon: AppAssets.arrow_back,
iconColor: Color(0xff2B353E),
fit: BoxFit.contain,
),
).onPress(() {
Navigator.pop(context);
}),
// title: "Rapid Response Team (RRT)".needTranslation,
context,
child: RrtRequestTypeSelect(),
isFullScreen: false,
isCloseButtonVisible: true,
hasBottomPadding: false,
backgroundColor: AppColors.bottomSheetBgColor,
callBackFunc: () {},
);
});
},
backgroundColor: Colors.white,
borderColor: Colors.white,
textColor: AppColors.primaryRedColor,
icon: AppAssets.checkmark_icon,
iconColor: AppColors.primaryRedColor,
),
SizedBox(height: 8.h),
],
),
),
),
),
isFullScreen: false,
isCloseButtonVisible: false,
hasBottomPadding: false,
backgroundColor: AppColors.primaryRedColor,
callBackFunc: () {
context.read<EmergencyServicesViewModel>().setTermsAndConditions(false);
},
);
isFullScreen: false,
isCloseButtonVisible: false,
hasBottomPadding: false,
backgroundColor: AppColors.primaryRedColor,
callBackFunc: () {
context.read<EmergencyServicesViewModel>().setTermsAndConditions(false);
},
);
} else {
Navigator.of(context).push(
CustomPageRoute(
page: ServiceInfoPage(
serviceName: LocaleKeys.emergencyServices.tr(),
serviceHeader: "ER Check-in, Faster Than Ever. Call ambulance / Rapid Response Team instantly".needTranslation,
serviceDescription: "In a medical emergency? Our ambulances and rapid response teams are on standby 24/7. Plus, quick ER check-in for faster care.".needTranslation,
serviceImage: AppAssets.emergencyService),
),
);
}
}),
),
SizedBox(height: 16.h),
@ -275,8 +333,7 @@ class EmergencyServicesPage extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.emergencyCheckIn.tr(context: context).toText16(isBold: true, color: AppColors.blackColor),
LocaleKeys.priorERCheckInToSkipLine.tr()
.toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500),
LocaleKeys.priorERCheckInToSkipLine.tr().toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500),
],
),
),
@ -284,64 +341,79 @@ class EmergencyServicesPage extends StatelessWidget {
Utils.buildSvgWithAssets(icon: AppAssets.forward_chevron_icon, width: 13.h, height: 13.h),
],
).onPress(() {
showCommonBottomSheetWithoutHeight(
context,
child: Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.primaryRedColor, borderRadius: 24.h),
child: Padding(
padding: EdgeInsets.all(24.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
if(appState.isAuthenticated) {
if (emergencyServicesViewModel.patientHasAdvanceERBalance) {
Navigator.of(context).push(CustomPageRoute(page: ErOnlineCheckinHome()));
} else {
showCommonBottomSheetWithoutHeight(
context,
child: Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.primaryRedColor, borderRadius: 24.h),
child: Padding(
padding: EdgeInsets.all(24.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"".toText14(),
Utils.buildSvgWithAssets(
icon: AppAssets.cancel_circle_icon,
iconColor: AppColors.whiteColor,
width: 24.h,
height: 24.h,
fit: BoxFit.contain,
).onPress(() {
Navigator.of(context).pop();
}),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"".toText14(),
Utils.buildSvgWithAssets(
icon: AppAssets.cancel_circle_icon,
iconColor: AppColors.whiteColor,
width: 24.h,
height: 24.h,
fit: BoxFit.contain,
).onPress(() {
Navigator.of(context).pop();
}),
],
),
Lottie.asset(AppAnimations.ambulanceAlert, repeat: false, reverse: false, frameRate: FrameRate(60), width: 120.h, height: 120.h, fit: BoxFit.contain),
SizedBox(height: 8.h),
LocaleKeys.confirm.tr().toText28(color: Colors.white, isBold: true),
SizedBox(height: 8.h),
LocaleKeys.areYouSureYouWantToMakeERCheckIn.tr().toText14(color: Colors.white, weight: FontWeight.w500),
SizedBox(height: 24.h),
CustomButton(
text: LocaleKeys.confirm.tr(context: context),
onPressed: () async {
Navigator.of(context).pop();
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingYourERAppointmentStatus.tr());
await context.read<EmergencyServicesViewModel>().checkPatientERAdvanceBalance(onSuccess: (dynamic response) {
LoaderBottomSheet.hideLoader();
context.read<EmergencyServicesViewModel>().navigateToEROnlineCheckIn();
});
},
backgroundColor: Colors.white,
borderColor: Colors.white,
textColor: AppColors.primaryRedColor,
icon: AppAssets.checkmark_icon,
iconColor: AppColors.primaryRedColor,
),
SizedBox(height: 8.h),
],
),
Lottie.asset(AppAnimations.ambulanceAlert,
repeat: false, reverse: false, frameRate: FrameRate(60), width: 120.h, height: 120.h, fit: BoxFit.contain),
SizedBox(height: 8.h),
LocaleKeys.confirm.tr().toText28(color: Colors.white, isBold: true),
SizedBox(height: 8.h),
LocaleKeys.areYouSureYouWantToMakeERCheckIn.tr().toText14(color: Colors.white, weight: FontWeight.w500),
SizedBox(height: 24.h),
CustomButton(
text: LocaleKeys.confirm.tr(context: context),
onPressed: () async {
Navigator.of(context).pop();
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingYourERAppointmentStatus.tr());
await context.read<EmergencyServicesViewModel>().checkPatientERAdvanceBalance(onSuccess: (dynamic response) {
LoaderBottomSheet.hideLoader();
context.read<EmergencyServicesViewModel>().navigateToEROnlineCheckIn();
});
},
backgroundColor: Colors.white,
borderColor: Colors.white,
textColor: AppColors.primaryRedColor,
icon: AppAssets.checkmark_icon,
iconColor: AppColors.primaryRedColor,
),
SizedBox(height: 8.h),
],
),
),
isFullScreen: false,
isCloseButtonVisible: false,
hasBottomPadding: false,
backgroundColor: AppColors.primaryRedColor,
callBackFunc: () {},
);
}
} else {
Navigator.of(context).push(
CustomPageRoute(
page: ServiceInfoPage(
serviceName: LocaleKeys.emergencyServices.tr(),
serviceHeader: "ER Check-in, Faster Than Ever. Call ambulance / Rapid Response Team instantly".needTranslation,
serviceDescription: "In a medical emergency? Our ambulances and rapid response teams are on standby 24/7. Plus, quick ER check-in for faster care.".needTranslation,
serviceImage: AppAssets.emergencyService),
),
),
isFullScreen: false,
isCloseButtonVisible: false,
hasBottomPadding: false,
backgroundColor: AppColors.primaryRedColor,
callBackFunc: () {},
);
);
}
}),
),
],
@ -355,7 +427,7 @@ class EmergencyServicesPage extends StatelessWidget {
onCloseClicked: () {
context.read<EmergencyServicesViewModel>().flushPickupInformation();
},
titleWidget: Transform.flip(
titleWidget: Transform.flip(
flipX: emergencyServicesViewModel.isArabic,
child: Utils.buildSvgWithAssets(
icon: AppAssets.arrow_back,

@ -128,7 +128,7 @@ class ErOnlineCheckinPaymentDetailsPage extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
width: 150.h,
width: 200.h,
child: Utils.getPaymentMethods(),
),
Row(

@ -468,12 +468,12 @@ class _ErOnlineCheckinPaymentPageState extends State<ErOnlineCheckinPaymentPage>
context,
child: Utils.getErrorWidget(loadingText: LocaleKeys.paymentFailedPleaseTryAgain.tr(context: context)),
callBackFunc: () {
Navigator.pushAndRemoveUntil(
context,
CustomPageRoute(
page: LandingNavigation(),
),
(r) => false);
// Navigator.pushAndRemoveUntil(
// context,
// CustomPageRoute(
// page: LandingNavigation(),
// ),
// (r) => false);
},
isFullScreen: false,
isCloseButtonVisible: true,

@ -26,6 +26,7 @@ import 'package:hmg_patient_app_new/presentation/habib_wallet/habib_wallet_page.
import 'package:hmg_patient_app_new/presentation/habib_wallet/recharge_wallet_page.dart';
import 'package:hmg_patient_app_new/presentation/hmg_services/services_view.dart';
import 'package:hmg_patient_app_new/presentation/home/data/landing_page_data.dart';
import 'package:hmg_patient_app_new/presentation/home/service_info_page.dart';
import 'package:hmg_patient_app_new/presentation/home/widgets/large_service_card.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/medical_file_page.dart';
import 'package:hmg_patient_app_new/presentation/parking/paking_page.dart';
@ -54,23 +55,23 @@ class ServicesPage extends StatelessWidget {
late final List<HmgServicesComponentModel> hmgServices = [
HmgServicesComponentModel(11, LocaleKeys.emergencyServices.tr(), "", AppAssets.emergency_services_icon, bgColor: AppColors.primaryRedColor, true, route: null, onTap: () async {
if (getIt.get<AppState>().isAuthenticated) {
getIt.get<EmergencyServicesViewModel>().flushData();
getIt.get<EmergencyServicesViewModel>().getTransportationOrders(
showLoader: false,
);
getIt.get<EmergencyServicesViewModel>().getRRTOrders(
showLoader: false,
);
// if (getIt.get<AppState>().isAuthenticated) {
// getIt.get<EmergencyServicesViewModel>().flushData();
// getIt.get<EmergencyServicesViewModel>().getTransportationOrders(
// showLoader: false,
// );
// getIt.get<EmergencyServicesViewModel>().getRRTOrders(
// showLoader: false,
// );
Navigator.of(getIt.get<NavigationService>().navigatorKey.currentContext!).push(
CustomPageRoute(
page: EmergencyServicesPage(),
settings: const RouteSettings(name: '/EmergencyServicesPage'),
),
);
} else {
await getIt.get<AuthenticationViewModel>().onLoginPressed();
}
// } else {
// await getIt.get<AuthenticationViewModel>().onLoginPressed();
// }
}),
HmgServicesComponentModel(
11,
@ -85,7 +86,15 @@ class ServicesPage extends StatelessWidget {
if (getIt.get<AppState>().isAuthenticated) {
getIt.get<NavigationService>().pushPageRoute(AppRoutes.comprehensiveCheckupPage);
} else {
await getIt.get<AuthenticationViewModel>().onLoginPressed();
Navigator.of(getIt<NavigationService>().navigatorKey.currentContext!).push(
CustomPageRoute(
page: ServiceInfoPage(
serviceName: LocaleKeys.comprehensiveMedicalCheckup.tr(),
serviceHeader: "Complete Health Checkup: Advanced diagnostics, Detailed Health insights".needTranslation,
serviceDescription: "Get detailed insights into your health with our advanced diagnostics. Understand your body better for a healthier future.".needTranslation,
serviceImage: AppAssets.cmcService),
),
);
}
}),
HmgServicesComponentModel(
@ -137,7 +146,15 @@ class ServicesPage extends StatelessWidget {
if (getIt.get<AppState>().isAuthenticated) {
getIt.get<NavigationService>().pushPageRoute(AppRoutes.eReferralPage);
} else {
await getIt.get<AuthenticationViewModel>().onLoginPressed();
Navigator.of(getIt<NavigationService>().navigatorKey.currentContext!).push(
CustomPageRoute(
page: ServiceInfoPage(
serviceName: LocaleKeys.eReferralServices.tr(),
serviceHeader: "HMG Hospital E-Referral: Streamlined patient referrals".needTranslation,
serviceDescription: "Facilitate seamless patient transfers to HMG with our secure e-referral system. Ensure continuity of care for every patient.".needTranslation,
serviceImage: AppAssets.eReferralService),
),
);
}
}),
HmgServicesComponentModel(
@ -147,7 +164,26 @@ class ServicesPage extends StatelessWidget {
AppAssets.blood_donation_icon,
bgColor: AppColors.bloodDonationCardColor,
true,
route: AppRoutes.bloodDonationPage,
route: null,
onTap: () {
if (getIt.get<AppState>().isAuthenticated) {
Navigator.of(getIt<NavigationService>().navigatorKey.currentContext!).push(
CustomPageRoute(
page: BloodDonationPage(),
),
);
} else {
Navigator.of(getIt<NavigationService>().navigatorKey.currentContext!).push(
CustomPageRoute(
page: ServiceInfoPage(
serviceName: LocaleKeys.bloodDonation.tr(),
serviceHeader: "Give Blood, Save Lives. Your donation makes a difference.".needTranslation,
serviceDescription: "Donate blood, empower lives. Your contribution creates hope. Join our blood drive and be a lifeline for those in need. Every drop counts!".needTranslation,
serviceImage: AppAssets.bloodDonationService),
),
);
}
}
),
HmgServicesComponentModel(
113,
@ -230,7 +266,15 @@ class ServicesPage extends StatelessWidget {
if (getIt.get<AppState>().isAuthenticated) {
getIt.get<NavigationService>().pushPageRoute(AppRoutes.healthTrackersPage);
} else {
await getIt.get<AuthenticationViewModel>().onLoginPressed();
Navigator.of(getIt<NavigationService>().navigatorKey.currentContext!).push(
CustomPageRoute(
page: ServiceInfoPage(
serviceName: LocaleKeys.healthTrackers.tr(),
serviceHeader: "HMG Hospital E-Referral: Streamlined patient referrals".needTranslation,
serviceDescription: "Facilitate seamless patient transfers to HMG with our secure e-referral system. Ensure continuity of care for every patient.".needTranslation,
serviceImage: AppAssets.eReferralService),
),
);
}
},
),
@ -263,7 +307,15 @@ class ServicesPage extends StatelessWidget {
},
);
} else {
await getIt.get<AuthenticationViewModel>().onLoginPressed();
Navigator.of(getIt<NavigationService>().navigatorKey.currentContext!).push(
CustomPageRoute(
page: ServiceInfoPage(
serviceName: LocaleKeys.waterConsumption.tr(),
serviceHeader: "Stay Hydrated, Stay Healthy. Track your daily water intake with ease.".needTranslation,
serviceDescription: "Quench your thirst, track your health. Effortlessly monitor your daily water intake with our user-friendly app, ensuring optimal hydration and well-being.".needTranslation,
serviceImage: AppAssets.waterConsumptionService),
),
);
}
},
),
@ -294,8 +346,21 @@ class ServicesPage extends StatelessWidget {
true,
route: null,
onTap: () async {
// if (getIt.get<AppState>().isAuthenticated) {
if (getIt.get<AppState>().isAuthenticated) {
getIt.get<NavigationService>().pushPageRoute(AppRoutes.smartWatches);
} else {
Navigator.of(getIt<NavigationService>().navigatorKey.currentContext!).push(
CustomPageRoute(
page: ServiceInfoPage(
serviceName: LocaleKeys.smartWatches.tr(),
serviceHeader: "HMG Hospital E-Referral: Streamlined patient referrals".needTranslation,
serviceDescription: "Facilitate seamless patient transfers to HMG with our secure e-referral system. Ensure continuity of care for every patient.".needTranslation,
serviceImage: AppAssets.eReferralService),
),
);
}
// if (getIt.get<AppState>().isAuthenticated) {
// getIt.get<NavigationService>().pushPageRoute(AppRoutes.smartWatches);
// } else {
// await getIt.get<AuthenticationViewModel>().onLoginPressed();
// }
@ -368,168 +433,172 @@ class ServicesPage extends StatelessWidget {
),
),
SizedBox(height: 24.h),
LocaleKeys.personalServices.tr().toText18(weight: FontWeight.w600).paddingSymmetrical(24.w, 0),
SizedBox(height: 16.h),
Row(
getIt.get<AppState>().isAuthenticated ? Column(
children: [
Expanded(
child: Container(
height: 183.h,
width: 183.h,
padding: EdgeInsets.all(16.w),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.r,
hasShadow: false,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
spacing: 8.w,
crossAxisAlignment: CrossAxisAlignment.center,
LocaleKeys.personalServices.tr().toText18(weight: FontWeight.w600).paddingSymmetrical(24.w, 0),
SizedBox(height: 16.h),
Row(
children: [
Expanded(
child: Container(
height: 183.h,
width: 183.h,
padding: EdgeInsets.all(16.w),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.r,
hasShadow: false,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Utils.buildSvgWithAssets(icon: AppAssets.wallet, width: 40.w, height: 40.h, applyThemeColor: false),
LocaleKeys.habibWallet.tr().toText14(weight: FontWeight.w600, maxlines: 2).expanded,
Utils.buildSvgWithAssets(icon: getIt.get<AppState>().isArabic() ? AppAssets.arrow_back : AppAssets.arrow_forward),
Row(
spacing: 8.w,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Utils.buildSvgWithAssets(icon: AppAssets.wallet, width: 40.w, height: 40.h, applyThemeColor: false),
LocaleKeys.habibWallet.tr().toText14(weight: FontWeight.w600, maxlines: 2).expanded,
Utils.buildSvgWithAssets(icon: getIt.get<AppState>().isArabic() ? AppAssets.arrow_back : AppAssets.arrow_forward),
],
),
Spacer(),
getIt.get<AppState>().isAuthenticated
? Consumer<HabibWalletViewModel>(builder: (context, habibWalletVM, child) {
return Utils.getPaymentAmountWithSymbol2(habibWalletVM.habibWalletAmount, isExpanded: false)
.toShimmer2(isShow: habibWalletVM.isWalletAmountLoading, radius: 12.r, width: 80.w, height: 24.h);
})
: LocaleKeys.loginToViewWalletBalance.tr().toText12(fontWeight: FontWeight.w500, maxLine: 2),
Spacer(),
getIt.get<AppState>().isAuthenticated
? CustomButton(
height: 40.h,
icon: AppAssets.recharge_icon,
iconSize: 24.w,
iconColor: AppColors.infoColor,
textColor: AppColors.infoColor,
text: LocaleKeys.recharge.tr(),
borderWidth: 0.w,
fontWeight: FontWeight.w500,
borderColor: Colors.transparent,
backgroundColor: Color(0xff45A2F8).withValues(alpha: 0.08),
padding: EdgeInsets.all(8.w),
fontSize: 14.f,
onPressed: () {
Navigator.of(context).push(CustomPageRoute(page: RechargeWalletPage()));
},
)
: SizedBox.shrink(),
],
),
Spacer(),
getIt.get<AppState>().isAuthenticated
? Consumer<HabibWalletViewModel>(builder: (context, habibWalletVM, child) {
return Utils.getPaymentAmountWithSymbol2(habibWalletVM.habibWalletAmount, isExpanded: false)
.toShimmer2(isShow: habibWalletVM.isWalletAmountLoading, radius: 12.r, width: 80.w, height: 24.h);
})
: LocaleKeys.loginToViewWalletBalance.tr().toText12(fontWeight: FontWeight.w500, maxLine: 2),
Spacer(),
getIt.get<AppState>().isAuthenticated
? CustomButton(
height: 40.h,
icon: AppAssets.recharge_icon,
iconSize: 24.w,
iconColor: AppColors.infoColor,
textColor: AppColors.infoColor,
text: LocaleKeys.recharge.tr(),
borderWidth: 0.w,
fontWeight: FontWeight.w500,
borderColor: Colors.transparent,
backgroundColor: Color(0xff45A2F8).withValues(alpha: 0.08),
padding: EdgeInsets.all(8.w),
fontSize: 14.f,
onPressed: () {
Navigator.of(context).push(CustomPageRoute(page: RechargeWalletPage()));
},
)
: SizedBox.shrink(),
],
).onPress(() async {
if (getIt.get<AppState>().isAuthenticated) {
Navigator.of(context).push(CustomPageRoute(page: HabibWalletPage()));
} else {
await getIt.get<AuthenticationViewModel>().onLoginPressed();
}
}),
),
),
SizedBox(width: 16.w),
Expanded(
child: Container(
height: 183.h,
width: 183.h,
padding: EdgeInsets.all(16.w),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.r,
hasShadow: false,
).onPress(() async {
if (getIt.get<AppState>().isAuthenticated) {
Navigator.of(context).push(CustomPageRoute(page: HabibWalletPage()));
} else {
await getIt.get<AuthenticationViewModel>().onLoginPressed();
}
}),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
spacing: 8.w,
crossAxisAlignment: CrossAxisAlignment.center,
SizedBox(width: 16.w),
Expanded(
child: Container(
height: 183.h,
width: 183.h,
padding: EdgeInsets.all(16.w),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.r,
hasShadow: false,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Utils.buildSvgWithAssets(icon: AppAssets.services_medical_file_icon, width: 40.w, height: 40.h, applyThemeColor: false),
LocaleKeys.medicalFile.tr().toText16(weight: FontWeight.w600, maxlines: 2).expanded,
Utils.buildSvgWithAssets(icon: getIt.get<AppState>().isArabic() ? AppAssets.arrow_back : AppAssets.arrow_forward),
Row(
spacing: 8.w,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Utils.buildSvgWithAssets(icon: AppAssets.services_medical_file_icon, width: 40.w, height: 40.h, applyThemeColor: false),
LocaleKeys.medicalFile.tr().toText16(weight: FontWeight.w600, maxlines: 2).expanded,
Utils.buildSvgWithAssets(icon: getIt.get<AppState>().isArabic() ? AppAssets.arrow_back : AppAssets.arrow_forward),
],
),
Spacer(),
getIt.get<AppState>().isAuthenticated
? Wrap(
spacing: -12.h,
// runSpacing: 0.h,
children: [
Utils.buildImgWithAssets(
icon: AppAssets.babyGirlImg,
height: 32.h,
width: 32.w,
border: 1,
fit: BoxFit.contain,
borderRadius: 50.r,
),
Utils.buildImgWithAssets(
icon: AppAssets.femaleImg,
height: 32.h,
width: 32.w,
border: 1,
borderRadius: 50.r,
fit: BoxFit.contain,
),
Utils.buildImgWithAssets(
icon: AppAssets.maleImg,
height: 32.h,
width: 32.w,
border: 1,
borderRadius: 50.r,
fit: BoxFit.contain,
),
],
)
: LocaleKeys.loginToViewMedicalFile.tr().toText12(fontWeight: FontWeight.w500, maxLine: 2),
Spacer(),
getIt.get<AppState>().isAuthenticated
? CustomButton(
height: 40.h,
icon: AppAssets.add_icon,
iconSize: 24.h,
iconColor: AppColors.primaryRedColor,
textColor: AppColors.primaryRedColor,
text: LocaleKeys.addMember.tr(),
borderWidth: 0.w,
fontWeight: FontWeight.w500,
borderColor: Colors.transparent,
backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.08),
padding: EdgeInsets.all(8.w),
fontSize: 14.f,
onPressed: () {
DialogService dialogService = getIt.get<DialogService>();
medicalFileViewModel.clearAuthValues();
dialogService.showAddFamilyFileSheet(
label: LocaleKeys.addFamilyMember.tr(),
message: LocaleKeys.pleaseFillBelowFieldToAddNewFamilyMember.tr(),
onVerificationPress: () {
medicalFileViewModel.addFamilyFile(otpTypeEnum: OTPTypeEnum.sms);
});
},
)
: SizedBox.shrink(),
],
),
Spacer(),
getIt.get<AppState>().isAuthenticated
? Wrap(
spacing: -12.h,
// runSpacing: 0.h,
children: [
Utils.buildImgWithAssets(
icon: AppAssets.babyGirlImg,
height: 32.h,
width: 32.w,
border: 1,
fit: BoxFit.contain,
borderRadius: 50.r,
),
Utils.buildImgWithAssets(
icon: AppAssets.femaleImg,
height: 32.h,
width: 32.w,
border: 1,
borderRadius: 50.r,
fit: BoxFit.contain,
),
Utils.buildImgWithAssets(
icon: AppAssets.maleImg,
height: 32.h,
width: 32.w,
border: 1,
borderRadius: 50.r,
fit: BoxFit.contain,
),
],
)
: LocaleKeys.loginToViewMedicalFile.tr().toText12(fontWeight: FontWeight.w500, maxLine: 2),
Spacer(),
getIt.get<AppState>().isAuthenticated
? CustomButton(
height: 40.h,
icon: AppAssets.add_icon,
iconSize: 24.h,
iconColor: AppColors.primaryRedColor,
textColor: AppColors.primaryRedColor,
text: LocaleKeys.addMember.tr(),
borderWidth: 0.w,
fontWeight: FontWeight.w500,
borderColor: Colors.transparent,
backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.08),
padding: EdgeInsets.all(8.w),
fontSize: 14.f,
onPressed: () {
DialogService dialogService = getIt.get<DialogService>();
medicalFileViewModel.clearAuthValues();
dialogService.showAddFamilyFileSheet(
label: LocaleKeys.addFamilyMember.tr(),
message: LocaleKeys.pleaseFillBelowFieldToAddNewFamilyMember.tr(),
onVerificationPress: () {
medicalFileViewModel.addFamilyFile(otpTypeEnum: OTPTypeEnum.sms);
});
},
)
: SizedBox.shrink(),
],
).onPress(() async {
if (getIt.get<AppState>().isAuthenticated) {
Navigator.of(context).push(
CustomPageRoute(
page: MedicalFilePage(),
),
);
} else {
await getIt.get<AuthenticationViewModel>().onLoginPressed();
}
}),
),
),
).onPress(() async {
if (getIt.get<AppState>().isAuthenticated) {
Navigator.of(context).push(
CustomPageRoute(
page: MedicalFilePage(),
),
);
} else {
await getIt.get<AuthenticationViewModel>().onLoginPressed();
}
}),
),
),
],
).paddingSymmetrical(24.w, 0),
],
).paddingSymmetrical(24.w, 0),
) : SizedBox(),
SizedBox(height: 24.h),
LocaleKeys.healthTools.tr().toText18(weight: FontWeight.w600).paddingSymmetrical(24.w, 0),
SizedBox(height: 16.h),

@ -349,7 +349,7 @@ class _LandingPageState extends State<LandingPage> {
).paddingSymmetrical(24.w, 0.h)
: SizedBox.shrink(),
appState.isAuthenticated
? Column(
? Column(
children: [
SizedBox(height: 12.h),
Row(
@ -498,67 +498,67 @@ class _LandingPageState extends State<LandingPage> {
),
// Consumer for ER Online Check-In pending request
Consumer<EmergencyServicesViewModel>(
builder: (context, emergencyServicesVM, child) {
return emergencyServicesVM.patientHasAdvanceERBalance
? Column(
children: [
SizedBox(height: 16.h),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.r,
hasShadow: false,
side: BorderSide(color: AppColors.primaryRedColor, width: 3.h),
),
width: double.infinity,
child: Padding(
padding: EdgeInsets.all(16.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// AppCustomChipWidget(
// labelText: LocaleKeys.erOnlineCheckInRequest.tr(context: context),
// backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.10),
// textColor: AppColors.primaryRedColor,
// ),
// Utils.buildSvgWithAssets(icon: AppAssets.appointment_checkin_icon, width: 24.h, height: 24.h, iconColor: AppColors.primaryRedColor),
// ],
// ),
SizedBox(height: 8.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.youHaveEROnlineCheckInRequest.tr(context: context).toText12(isBold: true),
Transform.flip(
flipX: getIt.get<AppState>().isArabic(),
child: Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon_small,
iconColor: AppColors.blackColor,
width: 20.h,
height: 15.h,
fit: BoxFit.contain,
),
),
],
),
],
),
),
).paddingSymmetrical(24.h, 0.h).onPress(() {
Navigator.of(context).push(CustomPageRoute(page: ErOnlineCheckinHome()));
// context.read<EmergencyServicesViewModel>().navigateToEROnlineCheckIn();
}),
SizedBox(height: 12.h),
],
)
: SizedBox(height: 0.h);
},
),
SizedBox(height: 16.h),
// Consumer<EmergencyServicesViewModel>(
// builder: (context, emergencyServicesVM, child) {
// return emergencyServicesVM.patientHasAdvanceERBalance
// ? Column(
// children: [
// SizedBox(height: 16.h),
// Container(
// decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
// color: AppColors.whiteColor,
// borderRadius: 20.r,
// hasShadow: false,
// side: BorderSide(color: AppColors.primaryRedColor, width: 3.h),
// ),
// width: double.infinity,
// child: Padding(
// padding: EdgeInsets.all(16.h),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// // Row(
// // mainAxisAlignment: MainAxisAlignment.spaceBetween,
// // children: [
// // AppCustomChipWidget(
// // labelText: LocaleKeys.erOnlineCheckInRequest.tr(context: context),
// // backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.10),
// // textColor: AppColors.primaryRedColor,
// // ),
// // Utils.buildSvgWithAssets(icon: AppAssets.appointment_checkin_icon, width: 24.h, height: 24.h, iconColor: AppColors.primaryRedColor),
// // ],
// // ),
// SizedBox(height: 8.h),
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// LocaleKeys.youHaveEROnlineCheckInRequest.tr(context: context).toText12(isBold: true),
// Transform.flip(
// flipX: getIt.get<AppState>().isArabic(),
// child: Utils.buildSvgWithAssets(
// icon: AppAssets.forward_arrow_icon_small,
// iconColor: AppColors.blackColor,
// width: 20.h,
// height: 15.h,
// fit: BoxFit.contain,
// ),
// ),
// ],
// ),
// ],
// ),
// ),
// ).paddingSymmetrical(24.h, 0.h).onPress(() {
// Navigator.of(context).push(CustomPageRoute(page: ErOnlineCheckinHome()));
// // context.read<EmergencyServicesViewModel>().navigateToEROnlineCheckIn();
// }),
// SizedBox(height: 12.h),
// ],
// )
// : SizedBox(height: 0.h);
// },
// ),
SizedBox(height: 16.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
@ -575,66 +575,61 @@ class _LandingPageState extends State<LandingPage> {
Navigator.of(context).push(CustomPageRoute(page: MedicalFilePage()));
}),
SizedBox(height: 16.h),
Container(
// height: 121.h,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r),
child: Column(
children: [
SizedBox(
height: 92.h + 32.h - 4.h,
child: RawScrollbar(
controller: _horizontalScrollController,
thumbVisibility: true,
radius: Radius.circular(10.0),
thumbColor: AppColors.primaryRedColor,
trackVisibility: true,
trackColor: Color(0xffD9D9D9),
trackBorderColor: Colors.transparent,
trackRadius: Radius.circular(10.0),
padding: EdgeInsets.only(top: 92.h + 32.h, left: MediaQuery
.sizeOf(context)
.width / 2 - 35, right: MediaQuery
.sizeOf(context)
.width / 2 - 35),
child: ListView.separated(
scrollDirection: Axis.horizontal,
itemCount: LandingPageData.getLoggedInServiceCardsList.length,
shrinkWrap: true,
controller: _horizontalScrollController,
padding: EdgeInsets.only(left: 16.h, right: 16.h, top: 16.h, bottom: 12.h),
itemBuilder: (context, index) {
return AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 1000),
child: SlideAnimation(
horizontalOffset: 100.0,
child: FadeInAnimation(
child: SmallServiceCard(
icon: LandingPageData.getLoggedInServiceCardsList[index].icon,
title: LandingPageData.getLoggedInServiceCardsList[index].title,
subtitle: LandingPageData.getLoggedInServiceCardsList[index].subtitle,
iconColor: LandingPageData.getLoggedInServiceCardsList[index].iconColor!,
textColor: LandingPageData.getLoggedInServiceCardsList[index].textColor,
backgroundColor: LandingPageData.getLoggedInServiceCardsList[index].backgroundColor,
isBold: LandingPageData.getLoggedInServiceCardsList[index].isBold,
serviceName: LandingPageData.getLoggedInServiceCardsList[index].serviceName,
Container(
// height: 121.h,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r),
child: Column(
children: [
SizedBox(
height: 92.h + 32.h - 4.h,
child: RawScrollbar(
controller: _horizontalScrollController,
thumbVisibility: true,
radius: Radius.circular(10.0),
thumbColor: AppColors.primaryRedColor,
trackVisibility: true,
trackColor: Color(0xffD9D9D9),
trackBorderColor: Colors.transparent,
trackRadius: Radius.circular(10.0),
padding: EdgeInsets.only(top: 92.h + 32.h, left: MediaQuery.sizeOf(context).width / 2.5 - 10, right: MediaQuery.sizeOf(context).width / 2.5 - 10),
child: ListView.separated(
scrollDirection: Axis.horizontal,
itemCount: LandingPageData.getLoggedInServiceCardsList.length,
shrinkWrap: true,
controller: _horizontalScrollController,
padding: EdgeInsets.only(left: 0.h, right: 0.h, top: 16.h, bottom: 12.h),
itemBuilder: (context, index) {
return AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 1000),
child: SlideAnimation(
horizontalOffset: 100.0,
child: FadeInAnimation(
child: SmallServiceCard(
icon: LandingPageData.getLoggedInServiceCardsList[index].icon,
title: LandingPageData.getLoggedInServiceCardsList[index].title,
subtitle: LandingPageData.getLoggedInServiceCardsList[index].subtitle,
iconColor: LandingPageData.getLoggedInServiceCardsList[index].iconColor!,
textColor: LandingPageData.getLoggedInServiceCardsList[index].textColor,
backgroundColor: LandingPageData.getLoggedInServiceCardsList[index].backgroundColor,
isBold: LandingPageData.getLoggedInServiceCardsList[index].isBold,
serviceName: LandingPageData.getLoggedInServiceCardsList[index].serviceName,
),
),
),
);
},
separatorBuilder: (BuildContext cxt, int index) => 10.width,
).paddingSymmetrical(16.h, 0.h),
),
),
),
);
},
separatorBuilder: (BuildContext cxt, int index) => 10.width,
),
),
),
SizedBox(height: 16.h),
],
),
).paddingSymmetrical(24.h, 0.h),
],
)
: Container(
// height: 141.h,
SizedBox(height: 16.h),
],
),
).paddingSymmetrical(24.h, 0.h),
],
)
: Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r),
child: Column(
children: [
@ -649,14 +644,13 @@ class _LandingPageState extends State<LandingPage> {
trackColor: Color(0xffD9D9D9),
trackBorderColor: Colors.transparent,
trackRadius: Radius.circular(10.0),
padding: EdgeInsets.only(top: 92.h + 32.h, left: MediaQuery.sizeOf(context).width / 2 - 35, right: MediaQuery.sizeOf(context).width / 2 - 35),
padding: EdgeInsets.only(top: 92.h + 32.h, left: MediaQuery.sizeOf(context).width / 2.5 - 10, right: MediaQuery.sizeOf(context).width / 2.5 - 10),
child: ListView.separated(
scrollDirection: Axis.horizontal,
itemCount: LandingPageData.getNotLoggedInServiceCardsList.length,
shrinkWrap: true,
controller: _horizontalScrollController,
padding: EdgeInsets.only(left: 16.h, right: 16.h, top: 16.h, bottom: 12.h),
// padding: EdgeInsets.zero,
padding: EdgeInsets.only(left: 0.h, right: 0.h, top: 16.h, bottom: 12.h),
itemBuilder: (context, index) {
return AnimationConfiguration.staggeredList(
position: index,
@ -679,7 +673,7 @@ class _LandingPageState extends State<LandingPage> {
);
},
separatorBuilder: (BuildContext cxt, int index) => 0.width,
),
).paddingSymmetrical(16.h, 0.h),
),
),
SizedBox(height: 16.h),

@ -0,0 +1,74 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.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/authentication/authentication_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
class ServiceInfoPage extends StatelessWidget {
final String serviceName;
final String serviceHeader;
final String serviceDescription;
final String serviceImage;
const ServiceInfoPage({required this.serviceName, required this.serviceHeader, required this.serviceDescription, required this.serviceImage, super.key});
@override
Widget build(BuildContext context) {
return CollapsingListView(
title: "",
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AppCustomChipWidget(
richText: serviceName.toText14(color: AppColors.infoColor, weight: FontWeight.w500),
backgroundColor: AppColors.infoColor.withAlpha(50),
textColor: AppColors.infoColor,
).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 24.h),
serviceHeader.toText28(isBold: true, height: 1.4).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 24.h),
serviceDescription.toText14(weight: FontWeight.w500, color: AppColors.greyTextColor).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 24.h),
CustomButton(
text: LocaleKeys.login.tr(context: context),
onPressed: () {
getIt<AuthenticationViewModel>().onLoginPressed();
},
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
fontSize: 16.f,
fontWeight: FontWeight.w500,
borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w),
height: 40.h,
icon: AppAssets.login1,
iconColor: AppColors.primaryRedColor,
iconSize: 18.h,
).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 36.h),
ClipRRect(
borderRadius: BorderRadius.circular(24.r),
child: Transform.flip(
flipX: getIt.get<AppState>().isArabic(),
child: Image.asset(
serviceImage,
fit: BoxFit.fitHeight,
width: 520.w,
),
),
),
],
),
);
}
}

@ -115,7 +115,7 @@ class HabibWalletCard extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
width: 150.h,
width: 200.h,
child: Utils.getPaymentMethods(),
),
CustomButton(

@ -1,6 +1,7 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/api_consts.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
@ -10,6 +11,7 @@ import 'package:hmg_patient_app_new/features/book_appointments/book_appointments
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/book_appointment_page.dart';
import 'package:hmg_patient_app_new/presentation/home/data/service_card_data.dart';
import 'package:hmg_patient_app_new/presentation/home/service_info_page.dart';
import 'package:hmg_patient_app_new/presentation/home_health_care/hhc_procedures_page.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
@ -135,11 +137,23 @@ class LargeServiceCard extends StatelessWidget {
}
case "home_health_care":
{
Navigator.of(getIt<NavigationService>().navigatorKey.currentContext!).push(
CustomPageRoute(
page: HhcProceduresPage(),
),
);
if (getIt.get<AppState>().isAuthenticated) {
Navigator.of(getIt<NavigationService>().navigatorKey.currentContext!).push(
CustomPageRoute(
page: HhcProceduresPage(),
),
);
} else {
Navigator.of(getIt<NavigationService>().navigatorKey.currentContext!).push(
CustomPageRoute(
page: ServiceInfoPage(
serviceName: LocaleKeys.homeHealthCare.tr(),
serviceHeader: "Your Health, Elevated. Premium care, delivered to your doorstep.",
serviceDescription: "We bring quality healthcare to your doorstep. Experienced nurses providing compassionate care in the comfort of your home.",
serviceImage: AppAssets.homeHealthCareService),
),
);
}
}
case "pharmacy":
{
@ -270,11 +284,23 @@ class FadedLargeServiceCard extends StatelessWidget {
}
case "home_health_care":
{
Navigator.of(getIt<NavigationService>().navigatorKey.currentContext!).push(
CustomPageRoute(
page: HhcProceduresPage(),
),
);
if (getIt.get<AppState>().isAuthenticated) {
Navigator.of(getIt<NavigationService>().navigatorKey.currentContext!).push(
CustomPageRoute(
page: HhcProceduresPage(),
),
);
} else {
Navigator.of(getIt<NavigationService>().navigatorKey.currentContext!).push(
CustomPageRoute(
page: ServiceInfoPage(
serviceName: LocaleKeys.homeHealthCare.tr(),
serviceHeader: "Your Health, Elevated. Premium care, delivered to your doorstep.".needTranslation,
serviceDescription: "We bring quality healthcare to your doorstep. Experienced nurses providing compassionate care in the comfort of your home.".needTranslation,
serviceImage: AppAssets.homeHealthCareService),
),
);
}
}
case "pharmacy":
{

@ -7,6 +7,7 @@ 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/insurance/insurance_view_model.dart';
import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/insurance/insurance_home_page.dart';
import 'package:hmg_patient_app_new/presentation/profile_settings/profile_settings.dart';
@ -40,6 +41,7 @@ class WelcomeWidget extends StatelessWidget {
spacing: 8.h,
children: [
Icon(Icons.menu, color: AppColors.textColor).onPress(() {
getIt.get<ProfileSettingsViewModel>().getProfileSettings();
Navigator.of(context).push(springPageRoute(ProfileSettings()));
}),
Image.asset(imageUrl, width: 40, height: 40),

@ -136,7 +136,7 @@ class PatientInsuranceCard extends StatelessWidget {
insuranceCardDetailsModel.groupName!.toText12(isBold: true),
Row(
children: [
insuranceCardDetailsModel.companyName!.toText12(isBold: true),
(insuranceCardDetailsModel.companyName!.length > 40 ? "${insuranceCardDetailsModel.companyName!.substring(0, 40)}..." : insuranceCardDetailsModel.companyName!).toText12(isBold: true),
SizedBox(
width: 6.h,
),
@ -146,7 +146,7 @@ class PatientInsuranceCard extends StatelessWidget {
color: AppColors.infoColor,
borderRadius: 50.r,
),
child: (insuranceCardDetailsModel.subCategoryDesc!.length > 5 ? insuranceCardDetailsModel.subCategoryDesc!.substring(0, 12) : insuranceCardDetailsModel.subCategoryDesc!)
child: ((insuranceCardDetailsModel.subCategoryDesc ?? "").length > 10 ? (insuranceCardDetailsModel.subCategoryDesc ?? "").substring(0, 10) : (insuranceCardDetailsModel.subCategoryDesc ?? ""))
.toText8(isBold: true, color: AppColors.whiteColor),
),
],

@ -473,8 +473,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
],
);
}),
SizedBox(height: 16.h),
SizedBox(height: 24.h),
// TextInputWidget(
// labelText: LocaleKeys.search.tr(context: context),
// hintText: "Type any record".needTranslation,
@ -489,7 +488,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
// leadingIcon: AppAssets.search_icon,
// hintColor: AppColors.textColor,
// ).paddingSymmetrical(24.w, 0.0),
SizedBox(height: 16.h),
// SizedBox(height: 16.h),
// Using CustomExpandableList
CustomExpandableList(
expansionMode: ExpansionMode.exactlyOne,
@ -1538,6 +1537,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
value: vitalSign.bodyMassIndex?.toString() ?? '--',
unit: '',
status: vitalSign.bodyMassIndex != null ? _getBMIStatus(vitalSign.bodyMassIndex) : null,
// status: "Overweight",
onTap: onTap,
),
),

@ -6,6 +6,7 @@ import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.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/int_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/my_invoices/models/get_invoice_details_response_model.dart';
@ -183,48 +184,6 @@ class _MyInvoicesDetailsPageState extends State<MyInvoicesDetailsPage> {
),
),
SizedBox(height: 16.h),
Row(
mainAxisSize: MainAxisSize.max,
children: [
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: true,
),
child: Padding(
padding: EdgeInsets.all(14.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
widget.getInvoiceDetailsResponseModel.listConsultation!.first.procedureName!.toText16(isBold: true),
SizedBox(height: 16.h),
Wrap(
direction: Axis.horizontal,
spacing: 6.w,
runSpacing: 6.h,
children: [
AppCustomChipWidget(
labelText: "${LocaleKeys.quantity.tr()}: ${widget.getInvoiceDetailsResponseModel.listConsultation!.first.quantity!}",
labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w),
),
AppCustomChipWidget(
labelText: "${LocaleKeys.price.tr()}: ${widget.getInvoiceDetailsResponseModel.listConsultation!.first.price!} ${LocaleKeys.sar.tr()}",
labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w),
),
AppCustomChipWidget(
labelText: "${LocaleKeys.total.tr()}: ${widget.getInvoiceDetailsResponseModel.listConsultation!.first.total!} ${LocaleKeys.sar.tr()}",
labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w),
),
],
),
],
),
),
),
],
),
SizedBox(height: 16.h),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
@ -257,6 +216,57 @@ class _MyInvoicesDetailsPageState extends State<MyInvoicesDetailsPage> {
),
),
),
SizedBox(height: 16.h),
Row(
mainAxisSize: MainAxisSize.max,
children: [
Expanded(
child: Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: true,
),
child: Padding(
padding: EdgeInsets.all(14.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header row
Row(
children: [
Expanded(flex: 3, child: LocaleKeys.name.tr().toText12(color: AppColors.textColor, fontWeight: FontWeight.w600)),
Expanded(flex: 1, child: LocaleKeys.quantity.tr().toText12(color: AppColors.textColor, fontWeight: FontWeight.w600, isCenter: true)),
Expanded(
flex: 2, child: LocaleKeys.price.tr().toText12(color: AppColors.textColor, fontWeight: FontWeight.w600, isCenter: true)),
Expanded(
flex: 2, child: LocaleKeys.total.tr().toText12(color: AppColors.textColor, fontWeight: FontWeight.w600, isCenter: true)),
],
),
SizedBox(height: 16.h),
2.divider,
SizedBox(height: 12.h),
// Data rows
...widget.getInvoiceDetailsResponseModel.listConsultation!.map(
(consultation) => Padding(
padding: EdgeInsets.symmetric(vertical: 6.h),
child: Row(
children: [
Expanded(flex: 3, child: (consultation.procedureName ?? '-').toText12(fontWeight: FontWeight.w500)),
Expanded(flex: 1, child: '${consultation.quantity ?? '-'}'.toText12(fontWeight: FontWeight.w500, isCenter: true)),
Expanded(flex: 2, child: '${consultation.price ?? '-'}'.toText12(fontWeight: FontWeight.w500, isCenter: true)),
Expanded(flex: 2, child: '${consultation.total ?? '-'}'.toText12(fontWeight: FontWeight.w500, isCenter: true)),
],
),
),
),
],
),
),
),
),
],
),
],
),
),

@ -207,7 +207,7 @@ class PrescriptionItemView extends StatelessWidget {
initialHour: DateTime.now().hour,
initialMinute: DateTime.now().minute,
use24HourFormat: true,
pickerHeight: 120.h,
pickerHeight: 200.h,
itemExtent: 100.h,
onTimeChanged: (time) {
// Handle selected time

@ -20,7 +20,7 @@ class PrescriptionReminderView extends StatefulWidget {
}
class _PrescriptionReminderViewState extends State<PrescriptionReminderView> {
final List<int> _options = [15, 30, 60, 90];
final List<int> _options = [60, 360, 720, 1440];
int _selectedOption = 0; // Nullable to represent no selection initially
@override
@ -54,7 +54,7 @@ class _PrescriptionReminderViewState extends State<PrescriptionReminderView> {
),
child: RadioListTile<int>(
title: Text(
"${_options[index]} ${LocaleKeys.minute.tr(context: context)}",
"${(_options[index] / 60).toInt()} ${LocaleKeys.hours.tr(context: context)}",
style: TextStyle(
fontSize: 16.h,
fontWeight: FontWeight.w500,

@ -28,6 +28,7 @@ import 'package:hmg_patient_app_new/presentation/habib_wallet/habib_wallet_page.
import 'package:hmg_patient_app_new/presentation/habib_wallet/recharge_wallet_page.dart';
import 'package:hmg_patient_app_new/presentation/insurance/widgets/insurance_update_details_card.dart';
import 'package:hmg_patient_app_new/presentation/profile_settings/widgets/update_email_widget.dart';
import 'package:hmg_patient_app_new/presentation/profile_settings/widgets/update_emergency_contact_widget.dart';
import 'package:hmg_patient_app_new/services/dialog_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/app_language_change.dart';
@ -39,6 +40,7 @@ import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:provider/provider.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:in_app_review/in_app_review.dart';
class ProfileSettings extends StatefulWidget {
const ProfileSettings({super.key});
@ -48,6 +50,9 @@ class ProfileSettings extends StatefulWidget {
}
class ProfileSettingsState extends State<ProfileSettings> {
final InAppReview inAppReview = InAppReview.instance;
@override
void initState() {
scheduleMicrotask(() {
@ -242,49 +247,47 @@ class ProfileSettingsState extends State<ProfileSettings> {
],
),
),
// Container(
// margin: EdgeInsets.only(left: 24.w, right: 24.w, top: 16.h, bottom: 24.h),
// padding: EdgeInsets.only(top: 4.h, bottom: 4.h),
// decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true),
// child: Column(
// children: [
// actionItem(AppAssets.language_change, LocaleKeys.language.tr(context: context), () {
// showCommonBottomSheetWithoutHeight(context, title: LocaleKeys.language.tr(context: context), child: AppLanguageChange(), callBackFunc: () {}, isFullScreen: false);
// }, trailingLabel: Utils.appState.isArabic() ? "العربية" : "English"),
// 1.divider,
// actionItem(AppAssets.bell, LocaleKeys.notificationsSettings.tr(context: context), () {
// openAppSettings();
// }),
// // 1.divider,
// // actionItem(AppAssets.touch_face_id, LocaleKeys.touchIDFaceIDServices.tr(context: context), () {}, switchValue: true),
// ],
// ),
// ),
// LocaleKeys.personalInformation.tr(context: context).toText18(weight: FontWeight.w600, textOverflow: TextOverflow.ellipsis, maxlines: 1).paddingOnly(left: 24.w, right: 24.w),
// Container(
// margin: EdgeInsets.only(left: 24.w, right: 24.w, top: 16.h, bottom: 24.h),
// padding: EdgeInsets.only(top: 4.h, bottom: 4.h),
// decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true),
// child: Column(
// children: [
// actionItem(AppAssets.email_transparent, LocaleKeys.updateEmailAddress.tr(context: context), () {
// showCommonBottomSheetWithoutHeight(
// context,
// title: LocaleKeys.updateEmailAddress.tr(context: context),
// child: UpdateEmailDialog(),
// callBackFunc: () {},
// isFullScreen: false,
// );
// }),
// // 1.divider,
// // actionItem(AppAssets.smart_phone_fill, "Phone Number".needTranslation, () {}),
// // 1.divider,
// // actionItem(AppAssets.my_address, "My Addresses".needTranslation, () {}),
// // 1.divider,
// // actionItem(AppAssets.emergency, "Emergency Contact".needTranslation, () {}),
// ],
// ),
// ),
LocaleKeys.personalInformation.tr(context: context).toText18(weight: FontWeight.w600, textOverflow: TextOverflow.ellipsis, maxlines: 1).paddingOnly(left: 24.w, right: 24.w),
Container(
margin: EdgeInsets.only(left: 24.w, right: 24.w, top: 16.h, bottom: 24.h),
padding: EdgeInsets.only(top: 4.h, bottom: 4.h),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true),
child: Column(
children: [
actionItem(AppAssets.email_transparent, LocaleKeys.updateEmailAddress.tr(context: context), () {
showCommonBottomSheetWithoutHeight(
context,
title: LocaleKeys.updateEmailAddress.tr(context: context),
child: UpdateEmailDialog(),
callBackFunc: () {},
isFullScreen: false,
);
}),
1.divider,
actionItem(AppAssets.language, LocaleKeys.communicationLanguage.tr(context: context), () {
profileVm.openPreferredLanguageBottomSheet();
},
trailingLabel: profileVm.isPatientProfileLoading
? "English"
: (profileVm.getPatientInfoForUpdate.preferredLanguage! == "1" ? LocaleKeys.arabic.tr(context: context) : LocaleKeys.english.tr(context: context)),
isShowLoading: profileVm.isPatientProfileLoading),
1.divider,
actionItem(AppAssets.smart_phone_fill, LocaleKeys.emrgNo.tr(context: context), () {
showCommonBottomSheetWithoutHeight(
context,
title: LocaleKeys.emrgNo.tr(context: context),
child: UpdateEmergencyContactDialog(),
callBackFunc: () {},
isFullScreen: false,
);
}),
// 1.divider,
// actionItem(AppAssets.my_address, "My Addresses".needTranslation, () {}),
// 1.divider,
// actionItem(AppAssets.emergency, "Emergency Contact".needTranslation, () {}),
],
),
),
LocaleKeys.helpAndSupport.tr(context: context).toText18(weight: FontWeight.w600, textOverflow: TextOverflow.ellipsis, maxlines: 1).paddingOnly(left: 24.w, right: 24.w),
Container(
margin: EdgeInsets.only(left: 24.w, right: 24.w, top: 16.h),
@ -314,17 +317,23 @@ class ProfileSettingsState extends State<ProfileSettings> {
1.divider,
// actionItem(AppAssets.permission, LocaleKeys.permissions.tr(context: context), () {}, trailingLabel: "Location, Camera"),
// 1.divider,
actionItem(AppAssets.rate, LocaleKeys.rateApp.tr(context: context), () {
if (Platform.isAndroid) {
Utils.openWebView(
url: 'https://play.google.com/store/apps/details?id=com.ejada.hmg',
);
actionItem(AppAssets.rate, LocaleKeys.rateApp.tr(context: context), () async {
if (await inAppReview.isAvailable()) {
inAppReview.requestReview();
} else {
Utils.openWebView(
url: 'https://itunes.apple.com/app/id733503978',
);
inAppReview.openStoreListing(appStoreId: '6758851027');
}
}, isExternalLink: true),
// if (Platform.isAndroid) {
// Utils.openWebView(
// url: 'https://play.google.com/store/apps/details?id=com.ejada.hmg',
// );
// } else {
// Utils.openWebView(
// url: 'https://itunes.apple.com/app/id733503978',
// );
// }
// }, isExternalLink: true),
}),
1.divider,
actionItem(AppAssets.privacy_terms, LocaleKeys.privacyPolicy.tr(context: context), () {
Utils.openWebView(
@ -340,12 +349,12 @@ class ProfileSettingsState extends State<ProfileSettings> {
],
),
),
CustomButton(
height: 56.h,
icon: AppAssets.minus,
text: LocaleKeys.deactivateAccount.tr(context: context),
onPressed: () {},
).paddingAll(24.w),
// CustomButton(
// height: 56.h,
// icon: AppAssets.minus,
// text: LocaleKeys.deactivateAccount.tr(context: context),
// onPressed: () {},
// ).paddingAll(24.w),
],
);
},
@ -382,7 +391,8 @@ class ProfileSettingsState extends State<ProfileSettings> {
return _permissionsLabel;
}
Widget actionItem(String icon, String label, VoidCallback onPress, {String trailingLabel = "", bool? switchValue, ValueChanged<bool>? onSwitchChanged, bool isExternalLink = false}) {
Widget actionItem(String icon, String label, VoidCallback onPress,
{String trailingLabel = "", bool? switchValue, ValueChanged<bool>? onSwitchChanged, bool isExternalLink = false, bool isShowLoading = false}) {
return SizedBox(
height: 56.h,
child: Row(
@ -390,7 +400,11 @@ class ProfileSettingsState extends State<ProfileSettings> {
children: [
Utils.buildSvgWithAssets(icon: icon, iconColor: AppColors.greyTextColor),
label.toText14(weight: FontWeight.w500, textOverflow: TextOverflow.ellipsis, maxlines: 1).expanded,
if (trailingLabel.isNotEmpty) trailingLabel.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500, textOverflow: TextOverflow.ellipsis, maxlines: 1),
if (trailingLabel.isNotEmpty)
ConstrainedBox(
constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width * 0.35),
child: trailingLabel.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500, textOverflow: TextOverflow.ellipsis, maxlines: 1).toShimmer2(isShow: isShowLoading),
),
switchValue != null
? Switch(
value: switchValue,

@ -0,0 +1,116 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.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/int_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/profile_settings/profile_settings_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:provider/provider.dart';
class PreferredLanguageWidget extends StatefulWidget {
PreferredLanguageWidget({super.key});
@override
State<PreferredLanguageWidget> createState() => _PreferredLanguageWidgetState();
}
class _PreferredLanguageWidgetState extends State<PreferredLanguageWidget> {
String? selectedValue;
late ProfileSettingsViewModel profileSettingsViewModel;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
setState(() {
selectedValue = profileSettingsViewModel.getPatientInfoForUpdate.preferredLanguage!;
});
});
}
@override
Widget build(BuildContext context) {
profileSettingsViewModel = Provider.of<ProfileSettingsViewModel>(context, listen: false);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 24.h,
children: [
LocaleKeys.communicationLanguage.tr(context: context).toText14(),
Container(
padding: EdgeInsets.only(top: 4, bottom: 4),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true),
child: Column(
children: [
languageItem("English", "2"),
1.divider,
languageItem("العربية", "1"),
],
),
),
CustomButton(
text: LocaleKeys.save.tr(context: context),
onPressed: () {
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.loadingText.tr(context: context));
profileSettingsViewModel!.updatePatientInfo(
patientInfo: {
"PreferredLanguage": selectedValue,
"EmailAddress": profileSettingsViewModel.getPatientInfoForUpdate.emailAddress,
"EmergencyContactName": profileSettingsViewModel.getPatientInfoForUpdate.emergencyContactName,
"EmergencyContactNo": profileSettingsViewModel.getPatientInfoForUpdate.emergencyContactNo,
"IsEmailAlertRequired": true,
"IsSMSAlertRequired": true,
},
onSuccess: (response) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(context, title: LocaleKeys.success.tr(context: context), child: Utils.getSuccessWidget(loadingText: LocaleKeys.success.tr()),
callBackFunc: () async {
Navigator.of(context).pop();
profileSettingsViewModel.getProfileSettings();
}, isFullScreen: false);
},
onError: (error) {
LoaderBottomSheet.hideLoader();
// Show error message
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(error)),
);
},
);
}),
],
);
}
Widget languageItem(String title, String _value) {
return SizedBox(
height: 72,
child: Row(
spacing: 8.h,
children: [
Radio(
value: _value,
groupValue: selectedValue,
activeColor: AppColors.errorColor,
onChanged: (value) {
setState(() {
selectedValue = _value;
});
},
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
title.toText16(weight: FontWeight.w500, textOverflow: TextOverflow.ellipsis, maxlines: 1, fontFamily: _value == "1" ? 'GESSTwo' : 'Poppins').expanded,
],
).paddingOnly(left: 16, right: 16).onPress(() {
setState(() {
selectedValue = _value;
});
}),
);
}
}

@ -31,7 +31,11 @@ class _UpdateEmailDialogState extends State<UpdateEmailDialog> {
void initState() {
_textFieldFocusNode = FocusNode();
textController = TextEditingController();
textController!.text = getIt.get<AppState>().getAuthenticatedUser()!.emailAddress ?? "";
WidgetsBinding.instance.addPostFrameCallback((_) {
setState(() {
textController!.text = profileSettingsViewModel!.getPatientInfoForUpdate.emailAddress ?? "";
});
});
super.initState();
}
@ -52,7 +56,7 @@ class _UpdateEmailDialogState extends State<UpdateEmailDialog> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Enter the new email address to be updated in your HMG File: ".toText16(textAlign: TextAlign.start, weight: FontWeight.w500),
"Enter the new email address to be updated: ".toText16(textAlign: TextAlign.start, weight: FontWeight.w500),
SizedBox(height: 12.h),
TextInputWidget(
labelText: LocaleKeys.email.tr(),
@ -78,12 +82,20 @@ class _UpdateEmailDialogState extends State<UpdateEmailDialog> {
onPressed: () {
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.updatingEmailAddress.tr(context: context));
profileSettingsViewModel!.updatePatientInfo(
patientInfo: {"EmailAddress": textController!.text},
patientInfo: {
"PreferredLanguage": profileSettingsViewModel!.getPatientInfoForUpdate.preferredLanguage,
"EmailAddress": textController!.text,
"EmergencyContactName": profileSettingsViewModel!.getPatientInfoForUpdate.emergencyContactName,
"EmergencyContactNo": profileSettingsViewModel!.getPatientInfoForUpdate.emergencyContactNo,
"IsEmailAlertRequired": true,
"IsSMSAlertRequired": true,
},
onSuccess: (response) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(context, title: LocaleKeys.success.tr(context: context), child: Utils.getSuccessWidget(loadingText: LocaleKeys.success.tr()),
callBackFunc: () async {
Navigator.of(context).pop();
profileSettingsViewModel!.getProfileSettings();
}, isFullScreen: false);
},
onError: (error) {

@ -0,0 +1,118 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/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/features/profile_settings/profile_settings_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
import 'package:hmg_patient_app_new/widgets/input_widget.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:provider/provider.dart';
class UpdateEmergencyContactDialog extends StatefulWidget {
UpdateEmergencyContactDialog({super.key});
@override
State<UpdateEmergencyContactDialog> createState() => _UpdateEmergencyContactDialogState();
}
class _UpdateEmergencyContactDialogState extends State<UpdateEmergencyContactDialog> {
late FocusNode _textFieldFocusNode;
late TextEditingController? textController;
ProfileSettingsViewModel? profileSettingsViewModel;
@override
void initState() {
_textFieldFocusNode = FocusNode();
textController = TextEditingController();
WidgetsBinding.instance.addPostFrameCallback((_) {
setState(() {
textController!.text = profileSettingsViewModel!.getPatientInfoForUpdate.emergencyContactNo!;
});
});
super.initState();
}
@override
void dispose() {
_textFieldFocusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
profileSettingsViewModel = Provider.of<ProfileSettingsViewModel>(context);
return GestureDetector(
onTap: () {
_textFieldFocusNode.unfocus();
FocusScope.of(context).unfocus();
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Enter the new emergency contact number to be updated: ".toText16(textAlign: TextAlign.start, weight: FontWeight.w500),
SizedBox(height: 12.h),
TextInputWidget(
labelText: LocaleKeys.emrgNo.tr(),
hintText: "05xxxxxxxx",
controller: textController,
focusNode: _textFieldFocusNode,
autoFocus: true,
padding: EdgeInsets.all(8.h),
keyboardType: TextInputType.number,
isEnable: true,
isReadOnly: false,
prefix: null,
isBorderAllowed: false,
isAllowLeadingIcon: true,
fontSize: 14.f,
isCountryDropDown: false,
leadingIcon: AppAssets.call_fill,
fontFamily: "Poppins",
),
SizedBox(height: 12.h),
CustomButton(
text: LocaleKeys.submit.tr(context: context),
onPressed: () {
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.loadingText.tr(context: context));
profileSettingsViewModel!.updatePatientInfo(
patientInfo: {
"PreferredLanguage": profileSettingsViewModel!.getPatientInfoForUpdate.preferredLanguage,
"EmailAddress": profileSettingsViewModel!.getPatientInfoForUpdate.emailAddress,
"EmergencyContactName": profileSettingsViewModel!.getPatientInfoForUpdate.emergencyContactName,
"EmergencyContactNo": textController!.text,
"IsEmailAlertRequired": true,
"IsSMSAlertRequired": true,
},
onSuccess: (response) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(context, title: LocaleKeys.success.tr(context: context), child: Utils.getSuccessWidget(loadingText: LocaleKeys.success.tr()),
callBackFunc: () async {
Navigator.of(context).pop();
profileSettingsViewModel!.getProfileSettings();
}, isFullScreen: false);
},
onError: (error) {
LoaderBottomSheet.hideLoader();
// Show error message
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(error)),
);
},
);
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
textColor: const Color(0xFFffffff),
),
],
),
);
}
}

@ -2,8 +2,10 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_export.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
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/location_util.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';
@ -337,6 +339,8 @@ class PossibleConditionsPage extends StatelessWidget {
selectedFacility: data.selectedFacility,
hmcCount: data.hmcCount,
hmgCount: data.hmgCount,
sortByLocation: data.sortByLocation,
onSortByLocationToggle: (value) => _handleSortByLocationToggle(value, data),
);
}
if (data.bottomSheetState == AppointmentViaRegionState.DOCTOR_SELECTION) {
@ -354,4 +358,42 @@ class PossibleConditionsPage extends StatelessWidget {
}
return SizedBox.shrink();
}
void _handleSortByLocationToggle(bool value, AppointmentViaRegionViewmodel regionVM) {
if (value) {
final locationUtils = getIt.get<LocationUtils>();
locationUtils.getLocation(
isShowConfirmDialog: true,
onSuccess: (latLng) {
regionVM.setSortByLocation(true);
_refreshHospitalListAfterApi(regionVM);
},
onFailure: () {
regionVM.setSortByLocation(false);
},
onLocationDeniedForever: () {
regionVM.setSortByLocation(false);
},
);
} else {
final appState = getIt.get<AppState>();
appState.resetLocation();
regionVM.setSortByLocation(false);
_refreshHospitalListAfterApi(regionVM);
}
}
void _refreshHospitalListAfterApi(AppointmentViaRegionViewmodel regionVM) {
void listener() {
if (!bookAppointmentsViewModel.isRegionListLoading) {
bookAppointmentsViewModel.removeListener(listener);
final selectedRegion = regionVM.selectedRegionId;
if (selectedRegion != null && bookAppointmentsViewModel.hospitalList?.registeredDoctorMap?[selectedRegion] != null) {
regionVM.setDisplayListAndRegionHospitalList(bookAppointmentsViewModel.hospitalList!.registeredDoctorMap![selectedRegion]);
}
}
}
bookAppointmentsViewModel.addListener(listener);
bookAppointmentsViewModel.getRegionMappedProjectList();
}
}

@ -640,7 +640,7 @@ class _AncillaryOrderDetailsListState extends State<AncillaryOrderDetailsList> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
width: 150.h,
width: 200.h,
child: Utils.getPaymentMethods(),
),
Row(

@ -69,16 +69,16 @@ class _VitalSignPageState extends State<VitalSignPage> {
: null;
// Debug logging for blood pressure
if (latestVitalSign != null) {
print('=== Blood Pressure Debug ===');
print('bloodPressureHigher: ${latestVitalSign.bloodPressureHigher}');
print('bloodPressureLower: ${latestVitalSign.bloodPressureLower}');
print('bloodPressureHigher type: ${latestVitalSign.bloodPressureHigher.runtimeType}');
print('bloodPressureLower type: ${latestVitalSign.bloodPressureLower.runtimeType}');
print('bloodPressureHigher == 0: ${latestVitalSign.bloodPressureHigher == 0}');
print('bloodPressureLower == 0: ${latestVitalSign.bloodPressureLower == 0}');
print('========================');
}
// if (latestVitalSign != null) {
// print('=== Blood Pressure Debug ===');
// print('bloodPressureHigher: ${latestVitalSign.bloodPressureHigher}');
// print('bloodPressureLower: ${latestVitalSign.bloodPressureLower}');
// print('bloodPressureHigher type: ${latestVitalSign.bloodPressureHigher.runtimeType}');
// print('bloodPressureLower type: ${latestVitalSign.bloodPressureLower.runtimeType}');
// print('bloodPressureHigher == 0: ${latestVitalSign.bloodPressureHigher == 0}');
// print('bloodPressureLower == 0: ${latestVitalSign.bloodPressureLower == 0}');
// print('========================');
// }
return SingleChildScrollView(
child: Column(

@ -115,18 +115,21 @@ class _ScrollWheelTimePickerState extends State<ScrollWheelTimePicker> {
widget.use24HourFormat ? index : index + 1;
final isSelected = hour == _selectedHour;
return Visibility(
visible: isSelected,
child: Center(
child: AnimatedDefaultTextStyle(
visible: true,
child: Center(
child: AnimatedDefaultTextStyle(
duration: const Duration(milliseconds: 200),
style: digitStyle.copyWith(
color: isSelected
? AppColors.textColor
: AppColors.textColor.withValues(alpha: 0.3),
),
child: Text(hour.toString().padLeft(2, '0')),
child: Text(
hour.toString().padLeft(2, '0'),
),
),
),
));
);
},
),
),
@ -157,8 +160,8 @@ class _ScrollWheelTimePickerState extends State<ScrollWheelTimePicker> {
builder: (context, index) {
final isSelected = index == _selectedMinute;
return Visibility(
visible: isSelected,
child:
visible: true,
child:
Center(
child: AnimatedDefaultTextStyle(
duration: const Duration(milliseconds: 200),

@ -2,8 +2,8 @@ name: hmg_patient_app_new
description: "New HMG Patient App"
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 0.0.15+12
#version: 0.0.1+14
#version: 0.0.15+12
version: 0.0.1+16
environment:
sdk: ">=3.6.0 <4.0.0"
@ -99,6 +99,8 @@ dependencies:
scrollable_positioned_list: ^0.3.8
in_app_review: ^2.0.11
dev_dependencies:
flutter_test:
sdk: flutter

Loading…
Cancel
Save