* 'master' of http://34.17.182.140/Haroon6138/HMG_Patient_App_New:
  search filter on select doctor page.
  family file fix
  blood group
pull/151/head
Sultan khan 1 month ago
commit e903f9c418

@ -0,0 +1,4 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="40" height="40" rx="10" fill="#EFEFF0"/>
<path d="M11.9998 21.25C11.5858 21.2503 11.2498 21.5859 11.2498 22C11.2498 22.4141 11.5858 22.7497 11.9998 22.75H14.3953C14.577 22.75 14.7553 22.7915 14.9158 22.8691L16.9578 23.8564C17.3233 24.0333 17.7251 24.125 18.1316 24.125H19.1746C19.601 24.1251 19.9516 24.3534 20.1277 24.6719L18.1931 25.207C17.9121 25.2847 17.6116 25.2563 17.3523 25.1309L15.1687 24.0752C14.7959 23.895 14.3471 24.051 14.1667 24.4238C13.9866 24.7966 14.1427 25.2454 14.5154 25.4258L16.699 26.4814C17.2874 26.7661 17.9622 26.8265 18.5925 26.6523L21.1335 25.9502C21.4836 25.8534 21.7498 25.5327 21.7498 25.1416C21.7498 25.1125 21.7468 25.0836 21.7458 25.0547L25.8132 23.8057L25.8162 23.8047C26.3135 23.6499 26.8624 23.8288 27.1892 24.2812C27.3052 24.4419 27.2446 24.6626 27.1033 24.7441L19.5876 29.0811C19.2867 29.2546 18.9351 29.2953 18.6082 29.1982L12.2136 27.3008C11.8165 27.1829 11.3988 27.4095 11.281 27.8066C11.1632 28.2037 11.3898 28.6214 11.7869 28.7393L18.1814 30.6367C18.9059 30.8517 19.6827 30.7578 20.3376 30.3799L27.8533 26.0439C28.7864 25.5055 29.0265 24.2639 28.405 23.4033C27.7121 22.4438 26.5013 22.0206 25.3708 22.3721L25.3699 22.373L21.241 23.6416C20.7675 23.0215 20.0117 22.6251 19.1746 22.625H18.1316C17.95 22.625 17.7716 22.5844 17.6111 22.5068L15.5691 21.5186C15.2035 21.3417 14.8017 21.25 14.3953 21.25H11.9998ZM22.6511 9.91992C21.7188 9.02657 20.2817 9.02657 19.3494 9.91992C18.7347 10.5091 17.9734 11.3294 17.3611 12.2773C16.7542 13.2169 16.2498 14.3489 16.2498 15.5469C16.2498 17.8542 18.0478 20.25 21.0007 20.25C23.9534 20.2497 25.7507 17.854 25.7507 15.5469C25.7507 14.3489 25.2463 13.2169 24.6394 12.2773C24.0271 11.3294 23.2657 10.5091 22.6511 9.91992ZM20.3875 11.0029C20.7396 10.6657 21.2609 10.6657 21.613 11.0029C22.181 11.5474 22.8538 12.2767 23.3796 13.0908C23.9109 13.9134 24.2507 14.7575 24.2507 15.5469C24.2507 17.1367 23.0181 18.7497 21.0007 18.75C18.9831 18.75 17.7498 17.1369 17.7498 15.5469C17.7498 14.7575 18.0895 13.9134 18.6208 13.0908C19.1467 12.2767 19.8195 11.5474 20.3875 11.0029Z" fill="#8F9AA3"/>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

@ -0,0 +1,5 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="40" height="40" rx="10" fill="#EFEFF0"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M19.9999 9.25C17.9288 9.25 16.2499 10.9289 16.2499 13C16.2499 14.0736 16.805 15.1188 17.4741 15.8701C17.8161 16.2541 18.2118 16.5896 18.6284 16.8334C19.038 17.0732 19.5126 17.25 19.9999 17.25C20.4872 17.25 20.9617 17.0732 21.3714 16.8334C21.7879 16.5896 22.1837 16.2541 22.5257 15.8701C23.1947 15.1188 23.7499 14.0736 23.7499 13C23.7499 10.9289 22.0709 9.25 19.9999 9.25ZM17.7499 13C17.7499 11.7574 18.7572 10.75 19.9999 10.75C21.2425 10.75 22.2499 11.7574 22.2499 13C22.2499 13.5832 21.9259 14.2881 21.4054 14.8725C21.1526 15.1564 20.876 15.3853 20.6137 15.5388C20.3444 15.6964 20.1334 15.75 19.9999 15.75C19.8663 15.75 19.6554 15.6964 19.3861 15.5388C19.1238 15.3853 18.8471 15.1564 18.5943 14.8725C18.0738 14.2881 17.7499 13.5832 17.7499 13Z" fill="#8F9AA3"/>
<path d="M24.536 16.4361C24.2245 16.163 23.7507 16.1941 23.4776 16.5056C23.2045 16.817 23.2356 17.2909 23.5471 17.5639C24.916 18.7642 25.6946 20.6997 24.9738 22.4145C24.8973 22.5965 24.7277 22.7039 24.5514 22.7039C24.4876 22.7039 24.4316 22.7013 24.3593 22.6978C24.3058 22.6953 24.2432 22.6923 24.1618 22.6897C24.0028 22.6845 23.7976 22.6828 23.5892 22.7127C23.3824 22.7424 23.1208 22.8099 22.8813 22.9807C22.6237 23.1644 22.4437 23.4309 22.3633 23.7588L21.266 28.2337C21.1173 28.8402 20.5889 29.25 20.0001 29.25C19.4112 29.25 18.8828 28.8402 18.7341 28.2337L17.6368 23.7588C17.5564 23.4309 17.3764 23.1644 17.1188 22.9807C16.8793 22.8099 16.6177 22.7424 16.4109 22.7127C16.2025 22.6828 15.9973 22.6845 15.8383 22.6897C15.7569 22.6923 15.6944 22.6953 15.6408 22.6978C15.5685 22.7013 15.5125 22.7039 15.4487 22.7039C15.2724 22.7039 15.1028 22.5965 15.0263 22.4145C14.3055 20.6997 15.0841 18.7642 16.4531 17.5639C16.7645 17.2909 16.7956 16.817 16.5226 16.5056C16.2495 16.1941 15.7756 16.163 15.4642 16.4361C13.7871 17.9065 12.5919 20.4941 13.6435 22.9958C13.9489 23.7223 14.6555 24.2039 15.4487 24.2039C15.5413 24.2039 15.6638 24.1985 15.7652 24.1939C15.8118 24.1918 15.8541 24.1899 15.8869 24.1889C16.0232 24.1845 16.1226 24.1867 16.1979 24.1975L16.2 24.1978L17.2772 28.591C17.5861 29.8506 18.7022 30.75 20.0001 30.75C21.2979 30.75 22.414 29.8506 22.7229 28.591L23.8001 24.1978L23.8022 24.1975C23.8775 24.1867 23.9769 24.1845 24.1132 24.1889C24.146 24.1899 24.1881 24.1918 24.2346 24.1939C24.336 24.1984 24.4588 24.2039 24.5514 24.2039C25.3446 24.2039 26.0512 23.7223 26.3566 22.9958C27.4082 20.4941 26.213 17.9065 24.536 16.4361Z" fill="#8F9AA3"/>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

@ -848,6 +848,12 @@ class ApiConsts {
static String h2oUpdateUserDetail = "Services/H2ORemainder.svc/REST/H2O_UpdateUserDetails_New";
static String h2oUndoUserActivity = "Services/H2ORemainder.svc/REST/H2o_UndoUserActivity";
//Blood Donation
static String bloodGroupUpdate = "Services/PatientVarification.svc/REST/BloodDonation_RegisterBloodType";
static String userAgreementForBloodGroupUpdate = "Services/PatientVarification.svc/REST/AddUserAgreementForBloodDonation";
static String getProjectsHaveBDClinics = "Services/OUTPs.svc/REST/BD_getProjectsHaveBDClinics";
static String getClinicsBDFreeSlots = "Services/OUTPs.svc/REST/BD_GetFreeSlots";
// ************ static values for Api ****************
static final double appVersionID = 50.3;
static final int appChannelId = 3;

@ -218,6 +218,8 @@ class AppAssets {
static const String activity = '$svgBasePath/activity.svg';
static const String age = '$svgBasePath/age_icon.svg';
static const String gender = '$svgBasePath/gender_icon.svg';
static const String genderInputIcon = '$svgBasePath/genderInputIcon.svg';
static const String bloodType = '$svgBasePath/blood_type.svg';
static const String trade_down_yellow = '$svgBasePath/trade_down_yellow.svg';
static const String trade_down_red = '$svgBasePath/trade_down_red.svg';

@ -154,26 +154,20 @@ class AppDependencies {
() => RadiologyViewModel(radiologyRepo: getIt(), errorHandlerService: getIt(), navigationService: getIt()),
);
getIt.registerLazySingleton<PrescriptionsViewModel>(
() => PrescriptionsViewModel(prescriptionsRepo: getIt(), errorHandlerService: getIt(), navServices: getIt()));
getIt.registerLazySingleton<PrescriptionsViewModel>(() => PrescriptionsViewModel(prescriptionsRepo: getIt(), errorHandlerService: getIt(), navServices: getIt()));
getIt.registerLazySingleton<InsuranceViewModel>(() => InsuranceViewModel(insuranceRepo: getIt(), errorHandlerService: getIt()));
getIt.registerLazySingleton<MyAppointmentsViewModel>(
() => MyAppointmentsViewModel(myAppointmentsRepo: getIt(), errorHandlerService: getIt(), appState: getIt()));
getIt.registerLazySingleton<MyAppointmentsViewModel>(() => MyAppointmentsViewModel(myAppointmentsRepo: getIt(), errorHandlerService: getIt(), appState: getIt()));
getIt.registerLazySingleton<AppointmentRatingViewModel>(
() => AppointmentRatingViewModel(myAppointmentsRepo: getIt(), errorHandlerService: getIt(), appState: getIt()));
getIt.registerLazySingleton<AppointmentRatingViewModel>(() => AppointmentRatingViewModel(myAppointmentsRepo: getIt(), errorHandlerService: getIt(), appState: getIt()));
getIt.registerLazySingleton<PayfortViewModel>(
() => PayfortViewModel(payfortRepo: getIt(), errorHandlerService: getIt()),
);
getIt.registerLazySingleton<HabibWalletViewModel>(
() => HabibWalletViewModel(
habibWalletRepo: getIt(),
errorHandlerService: getIt()
),
() => HabibWalletViewModel(habibWalletRepo: getIt(), errorHandlerService: getIt()),
);
getIt.registerLazySingleton<MedicalFileViewModel>(
@ -185,12 +179,7 @@ class AppDependencies {
getIt.registerLazySingleton<BookAppointmentsViewModel>(
() => BookAppointmentsViewModel(
bookAppointmentsRepo: getIt(),
errorHandlerService: getIt(),
navigationService: getIt(),
myAppointmentsViewModel: getIt(),
locationUtils: getIt(),
dialogService: getIt()),
bookAppointmentsRepo: getIt(), errorHandlerService: getIt(), navigationService: getIt(), myAppointmentsViewModel: getIt(), locationUtils: getIt(), dialogService: getIt()),
);
getIt.registerLazySingleton<ImmediateLiveCareViewModel>(
@ -204,13 +193,7 @@ class AppDependencies {
getIt.registerLazySingleton<AuthenticationViewModel>(
() => AuthenticationViewModel(
authenticationRepo: getIt(),
cacheService: getIt(),
navigationService: getIt(),
dialogService: getIt(),
appState: getIt(),
errorHandlerService: getIt(),
localAuthService: getIt()),
authenticationRepo: getIt(), cacheService: getIt(), navigationService: getIt(), dialogService: getIt(), appState: getIt(), errorHandlerService: getIt(), localAuthService: getIt()),
);
getIt.registerLazySingleton<ProfileSettingsViewModel>(() => ProfileSettingsViewModel());
@ -271,6 +254,7 @@ class AppDependencies {
navigationService: getIt(),
dialogService: getIt(),
appState: getIt(),
navServices: getIt(),
),
);

@ -3,14 +3,26 @@ 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/blood_donation/models/blood_group_hospitals_model.dart';
import 'package:hmg_patient_app_new/features/blood_donation/models/blood_group_response_model.dart';
import 'package:hmg_patient_app_new/features/blood_donation/models/cities_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
abstract class BloodDonationRepo {
Future<Either<Failure, GenericApiModel<List<CitiesModel>>>> getAllCities();
Future<Either<Failure, GenericApiModel<List<HospitalsModel>>>> getProjectList();
Future<Either<Failure, GenericApiModel<List<BdGetProjectsHaveBdClinic>>>> getBloodDonationProjectsList();
Future<Either<Failure, GenericApiModel<List_BloodGroupDetailsModel>>> getPatientBloodGroupDetails();
Future<Either<Failure, GenericApiModel<dynamic>>> updateBloodGroup({required Map<String, dynamic> request});
Future<Either<Failure, GenericApiModel<dynamic>>> getFreeBloodDonationSlots({required Map<String, dynamic> request});
Future<Either<Failure, GenericApiModel<dynamic>>> addUserAgreementForBloodDonation({required Map<String, dynamic> request});
}
class BloodDonationRepoImp implements BloodDonationRepo {
@ -93,4 +105,186 @@ class BloodDonationRepoImp implements BloodDonationRepo {
return Left(UnknownFailure(e.toString()));
}
}
}
@override
Future<Either<Failure, GenericApiModel<List<HospitalsModel>>>> getProjectList() async {
Map<String, dynamic> request = {};
try {
GenericApiModel<List<HospitalsModel>>? apiResponse;
Failure? failure;
await apiClient.post(
GET_PROJECT_LIST,
body: request,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['ListProject'];
final appointmentsList = list.map((item) => HospitalsModel.fromJson(item as Map<String, dynamic>)).toList().cast<HospitalsModel>();
apiResponse = GenericApiModel<List<HospitalsModel>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: appointmentsList,
);
} 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()));
}
}
@override
Future<Either<Failure, GenericApiModel<List<BdGetProjectsHaveBdClinic>>>> getBloodDonationProjectsList() async {
Map<String, dynamic> request = {};
try {
GenericApiModel<List<BdGetProjectsHaveBdClinic>>? apiResponse;
Failure? failure;
await apiClient.post(
ApiConsts.getProjectsHaveBDClinics,
body: request,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final listData = (response['BD_getProjectsHaveBDClinics'] as List<dynamic>);
final list = listData.map((item) => BdGetProjectsHaveBdClinic.fromJson(item as Map<String, dynamic>)).toList();
apiResponse = GenericApiModel<List<BdGetProjectsHaveBdClinic>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: list,
);
} 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()));
}
}
@override
Future<Either<Failure, GenericApiModel<List<dynamic>>>> updateBloodGroup({required Map<String, dynamic> request}) async {
try {
GenericApiModel<List<dynamic>>? apiResponse;
Failure? failure;
await apiClient.post(
ApiConsts.bloodGroupUpdate,
body: request,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
// final list = response['ListProject'];
// final appointmentsList = list.map((item) => HospitalsModel.fromJson(item as Map<String, dynamic>)).toList().cast<HospitalsModel>();
apiResponse = GenericApiModel<List<dynamic>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: response,
);
} 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()));
}
}
@override
Future<Either<Failure, GenericApiModel<List<dynamic>>>> getFreeBloodDonationSlots({required Map<String, dynamic> request}) async {
try {
GenericApiModel<List<dynamic>>? apiResponse;
Failure? failure;
await apiClient.post(
ApiConsts.getClinicsBDFreeSlots,
body: request,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
// final list = response['ListProject'];
// final appointmentsList = list.map((item) => HospitalsModel.fromJson(item as Map<String, dynamic>)).toList().cast<HospitalsModel>();
apiResponse = GenericApiModel<List<dynamic>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: response,
);
} 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()));
}
}
@override
Future<Either<Failure, GenericApiModel<List<dynamic>>>> addUserAgreementForBloodDonation({required Map<String, dynamic> request}) async {
try {
GenericApiModel<List<dynamic>>? apiResponse;
Failure? failure;
await apiClient.post(
ApiConsts.userAgreementForBloodGroupUpdate,
body: request,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
// final list = response['ListProject'];
// final appointmentsList = list.map((item) => HospitalsModel.fromJson(item as Map<String, dynamic>)).toList().cast<HospitalsModel>();
apiResponse = GenericApiModel<List<dynamic>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: response,
);
} 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,15 +1,25 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/core/utils/doctor_response_mapper.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart';
import 'package:hmg_patient_app_new/features/blood_donation/blood_donation_repo.dart';
import 'package:hmg_patient_app_new/features/blood_donation/models/blood_group_hospitals_model.dart';
import 'package:hmg_patient_app_new/features/blood_donation/models/blood_group_list_model.dart';
import 'package:hmg_patient_app_new/features/blood_donation/models/blood_group_response_model.dart';
import 'package:hmg_patient_app_new/features/blood_donation/models/cities_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/facility_selection.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/doctor_list_api_response.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/services/dialog_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/widgets/loader/bottomsheet_loader.dart';
class BloodDonationViewModel extends ChangeNotifier {
final DialogService dialogService;
@ -17,8 +27,21 @@ class BloodDonationViewModel extends ChangeNotifier {
ErrorHandlerService errorHandlerService;
final NavigationService navigationService;
final AppState appState;
bool isTermsAccepted = false;
BdGetProjectsHaveBdClinic? selectedHospital;
CitiesModel? selectedCity;
BloodGroupListModel? selectedBloodGroup;
int _selectedHospitalIndex = 0;
int _selectedBloodTypeIndex = 0;
GenderTypeEnum? selectedGender;
String? selectedBloodType;
final NavigationService navServices;
List<BdGetProjectsHaveBdClinic> hospitalList = [];
List<CitiesModel> citiesList = [];
List_BloodGroupDetailsModel patientBloodGroupDetailsModel = List_BloodGroupDetailsModel();
List<BloodGroupListModel> bloodGroupList = [
BloodGroupListModel("O+", 0),
BloodGroupListModel("O-", 1),
@ -30,35 +53,34 @@ class BloodDonationViewModel extends ChangeNotifier {
BloodGroupListModel("B-", 7),
];
List<BloodGroupListModel> genderList = [
BloodGroupListModel(LocaleKeys.malE.tr(), 1),
BloodGroupListModel("Female".needTranslation.tr(), 2),
];
late CitiesModel selectedCity;
late BloodGroupListModel selectedBloodGroup;
int _selectedHospitalIndex = 0;
int _selectedBloodTypeIndex = 0;
String selectedBloodType = '';
List_BloodGroupDetailsModel patientBloodGroupDetailsModel = List_BloodGroupDetailsModel();
BloodDonationViewModel({required this.bloodDonationRepo, required this.errorHandlerService, required this.navigationService, required this.dialogService, required this.appState});
BloodDonationViewModel({
required this.bloodDonationRepo,
required this.errorHandlerService,
required this.navigationService,
required this.dialogService,
required this.appState,
required this.navServices,
});
setSelectedCity(CitiesModel city) {
selectedCity = city;
notifyListeners();
}
void onGenderChange(String? status) {
selectedGender = GenderTypeExtension.fromType(status)!;
notifyListeners();
}
setSelectedBloodGroup(BloodGroupListModel bloodGroup) {
selectedBloodGroup = bloodGroup;
selectedBloodType = selectedBloodGroup.name;
selectedBloodType = selectedBloodGroup!.name;
notifyListeners();
}
Future<void> getRegionSelectedClinics({Function(dynamic)? onSuccess, Function(String)? onError}) async {
citiesList.clear();
selectedCity = CitiesModel();
selectedCity = null;
notifyListeners();
final result = await bloodDonationRepo.getAllCities();
@ -71,6 +93,7 @@ class BloodDonationViewModel extends ChangeNotifier {
onError!(apiResponse.errorMessage ?? 'An unexpected error occurred');
} else if (apiResponse.messageStatus == 1) {
citiesList = apiResponse.data!;
citiesList.sort((a, b) => a.description!.compareTo(b.description!));
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
@ -100,7 +123,7 @@ class BloodDonationViewModel extends ChangeNotifier {
citiesModel.descriptionN = citiesList[_selectedHospitalIndex].descriptionN;
selectedCity = citiesModel;
selectedBloodType = patientBloodGroupDetailsModel.bloodGroup!;
_selectedBloodTypeIndex = getBloodIndex(selectedBloodType);
_selectedBloodTypeIndex = getBloodIndex(selectedBloodType ?? '');
notifyListeners();
if (onSuccess != null) {
@ -113,11 +136,11 @@ class BloodDonationViewModel extends ChangeNotifier {
int getSelectedCityID() {
int cityID = 1;
citiesList.forEach((element) {
for (var element in citiesList) {
if (element.description == patientBloodGroupDetailsModel.city) {
cityID = element.iD!;
}
});
}
return cityID;
}
@ -144,4 +167,120 @@ class BloodDonationViewModel extends ChangeNotifier {
return 0;
}
}
void onTermAccepted() {
isTermsAccepted = !isTermsAccepted;
notifyListeners();
}
bool isUserAuthanticated() {
print("the app state is ${appState.isAuthenticated}");
if (!appState.isAuthenticated) {
return false;
} else {
return true;
}
}
Future<void> fetchHospitalsList() async {
// hospitalList.clear();
notifyListeners();
final result = await bloodDonationRepo.getBloodDonationProjectsList();
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),
(apiResponse) async {
if (apiResponse.messageStatus == 2) {
} else if (apiResponse.messageStatus == 1) {
hospitalList = apiResponse.data!;
hospitalList.sort((a, b) => a.projectName!.compareTo(b.projectName!));
notifyListeners();
}
},
);
}
Future<void> getFreeBloodDonationSlots({required Map<String, dynamic> request}) async {
final result = await bloodDonationRepo.getFreeBloodDonationSlots(request: request);
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),
(apiResponse) async {
if (apiResponse.messageStatus == 2) {
} else if (apiResponse.messageStatus == 1) {
// TODO: Handle free slots data
print(apiResponse.data['BD_FreeSlots']);
notifyListeners();
}
},
);
}
bool isLocationEnabled() {
return appState.userLong != 0.0 && appState.userLong != 0.0;
}
setSelectedHospital(BdGetProjectsHaveBdClinic hospital) {
selectedHospital = hospital;
notifyListeners();
}
Future<bool> validateSelections() async {
if (selectedCity == null) {
await dialogService.showErrorBottomSheet(
message: "Please choose city",
);
return false;
}
if (selectedBloodGroup == null) {
await dialogService.showErrorBottomSheet(
message: "Please choose Gender",
);
return false;
}
if (selectedBloodType == null) {
await dialogService.showErrorBottomSheet(
message: "Please choose Blood Group",
);
return false;
}
if (!isTermsAccepted) {
await dialogService.showErrorBottomSheet(
message: "Please accept Terms and Conditions to continue",
);
return false;
}
return true;
}
Future<void> updateBloodGroup() async {
LoaderBottomSheet.showLoader();
// body['City'] = detailsModel.city;
// body['cityCode'] = detailsModel.cityCode;
// body['Gender'] = detailsModel.gender;
// body['BloodGroup'] = detailsModel.bloodGroup;
// body['CellNumber'] = user.mobileNumber;
// body['LanguageID'] = languageID;
// body['NationalID'] = user.nationalityID;
// body['ZipCode'] = user.zipCode ?? "+966";
// body['isDentalAllowedBackend'] = false;
Map<String, dynamic> payload = {
"City": selectedCity?.description,
"cityCode": selectedCity?.iD,
"Gender": selectedGender?.value,
"isDentalAllowedBackend": false
// "Gender": selectedGender?.value,
};
await bloodDonationRepo.updateBloodGroup(request: payload);
await addUserAgreementForBloodDonation();
LoaderBottomSheet.hideLoader();
}
Future<void> addUserAgreementForBloodDonation() async {
Map<String, dynamic> payload = {"IsAgreed": true};
await bloodDonationRepo.addUserAgreementForBloodDonation(request: payload);
}
}

@ -0,0 +1,81 @@
import 'dart:convert';
class BdProjectsHaveBdClinicsModel {
List<BdGetProjectsHaveBdClinic>? bdGetProjectsHaveBdClinics;
BdProjectsHaveBdClinicsModel({
this.bdGetProjectsHaveBdClinics,
});
factory BdProjectsHaveBdClinicsModel.fromRawJson(String str) => BdProjectsHaveBdClinicsModel.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory BdProjectsHaveBdClinicsModel.fromJson(Map<String, dynamic> json) => BdProjectsHaveBdClinicsModel(
bdGetProjectsHaveBdClinics: json["BD_getProjectsHaveBDClinics"] == null ? [] : List<BdGetProjectsHaveBdClinic>.from(json["BD_getProjectsHaveBDClinics"]!.map((x) => BdGetProjectsHaveBdClinic.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"BD_getProjectsHaveBDClinics": bdGetProjectsHaveBdClinics == null ? [] : List<dynamic>.from(bdGetProjectsHaveBdClinics!.map((x) => x.toJson())),
};
}
class BdGetProjectsHaveBdClinic {
int? rowId;
int? id;
int? projectId;
int? numberOfRooms;
bool? isActive;
int? createdBy;
String? createdOn;
dynamic editedBy;
dynamic editedOn;
String? projectName;
dynamic projectNameN;
BdGetProjectsHaveBdClinic({
this.rowId,
this.id,
this.projectId,
this.numberOfRooms,
this.isActive,
this.createdBy,
this.createdOn,
this.editedBy,
this.editedOn,
this.projectName,
this.projectNameN,
});
factory BdGetProjectsHaveBdClinic.fromRawJson(String str) => BdGetProjectsHaveBdClinic.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory BdGetProjectsHaveBdClinic.fromJson(Map<String, dynamic> json) => BdGetProjectsHaveBdClinic(
rowId: json["RowID"],
id: json["ID"],
projectId: json["ProjectID"],
numberOfRooms: json["NumberOfRooms"],
isActive: json["IsActive"],
createdBy: json["CreatedBy"],
createdOn: json["CreatedOn"],
editedBy: json["EditedBy"],
editedOn: json["EditedON"],
projectName: json["ProjectName"],
projectNameN: json["ProjectNameN"],
);
Map<String, dynamic> toJson() => {
"RowID": rowId,
"ID": id,
"ProjectID": projectId,
"NumberOfRooms": numberOfRooms,
"IsActive": isActive,
"CreatedBy": createdBy,
"CreatedOn": createdOn,
"EditedBy": editedBy,
"EditedON": editedOn,
"ProjectName": projectName,
"ProjectNameN": projectNameN,
};
}

@ -0,0 +1,86 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/blood_donation/blood_donation_view_model.dart';
import 'package:hmg_patient_app_new/features/blood_donation/models/blood_group_hospitals_model.dart';
import 'package:hmg_patient_app_new/theme/colors.dart' show AppColors;
import 'package:provider/provider.dart';
class HospitalBottomSheetBodySelection extends StatelessWidget {
final Function(BdGetProjectsHaveBdClinic userSelection) onUserHospitalSelection;
const HospitalBottomSheetBodySelection({super.key, required this.onUserHospitalSelection(BdGetProjectsHaveBdClinic userSelection)});
@override
Widget build(BuildContext context) {
final bloodDonationVm = Provider.of<BloodDonationViewModel>(context, listen: false);
AppState appState = getIt.get<AppState>();
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Please select the hospital you want to make an appointment.".needTranslation,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: AppColors.greyTextColor,
),
),
SizedBox(height: 16.h),
SizedBox(
height: MediaQuery.sizeOf(context).height * .4,
child: ListView.separated(
itemBuilder: (_, index) {
return DecoratedBox(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: false,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 8.h,
children: [
hospitalName(bloodDonationVm.hospitalList[index]).onPress(() {
onUserHospitalSelection(bloodDonationVm.hospitalList[index]);
Navigator.of(context).pop();
})
],
),
),
Transform.flip(
flipX: appState.isArabic(),
child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, iconColor: AppColors.blackColor, width: 40.h, height: 40.h, fit: BoxFit.contain),
),
],
).paddingSymmetrical(16.h, 16.h),
).onPress(() {
bloodDonationVm.setSelectedHospital(bloodDonationVm.hospitalList[index]);
Navigator.of(context).pop();
});
},
separatorBuilder: (_, __) => SizedBox(height: 16.h),
itemCount: bloodDonationVm.hospitalList.length),
)
],
);
}
Widget hospitalName(dynamic hospital) => Row(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.hmg).paddingOnly(right: 10),
Expanded(
child: Text(hospital.projectName ?? "", style: TextStyle(fontWeight: FontWeight.w600, fontSize: 16, color: AppColors.blackColor)),
)
],
);
}

@ -49,6 +49,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
bool isLiveCareSchedule = false;
bool isGetDocForHealthCal = false;
bool showSortFilterButtons = false;
int? calculationID = 0;
bool isSortByClinic = true;
@ -200,8 +201,10 @@ class BookAppointmentsViewModel extends ChangeNotifier {
void filterClinics(String? query) {
if (query!.isEmpty) {
_filteredClinicsList = List.from(clinicsList);
showSortFilterButtons = false;
} else {
_filteredClinicsList = clinicsList.where((clinic) => clinic.clinicDescription?.toLowerCase().contains(query!.toLowerCase()) ?? false).toList();
showSortFilterButtons = query.length >= 3;
}
notifyListeners();
}

@ -293,14 +293,13 @@ class MedicalFileRepoImp implements MedicalFileRepo {
Failure? failure;
await apiClient.post(
ApiConsts.getAllSharedRecordsByStatus,
body: {if (status != null) "Status": status, "PatientID": patientID},
body: {if (status != null) "Status": status, "PatientID": patientID.toString()},
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['GetAllSharedRecordsByStatusList'];
final list = response['GetAllSharedRecordsByStatusList'] ?? [];
final familyLists = list.map((item) => FamilyFileResponseModelLists.fromJson(item as Map<String, dynamic>)).toList().cast<FamilyFileResponseModelLists>();
@ -336,7 +335,7 @@ class MedicalFileRepoImp implements MedicalFileRepo {
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['GetAllPendingRecordsList'];
final list = response['GetAllPendingRecordsList'] ?? [];
final familyLists = list.map((item) => FamilyFileResponseModelLists.fromJson(item as Map<String, dynamic>)).toList().cast<FamilyFileResponseModelLists>();
apiResponse = GenericApiModel<List<FamilyFileResponseModelLists>>(

@ -7,16 +7,26 @@ import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart';
import 'package:hmg_patient_app_new/features/blood_donation/blood_donation_view_model.dart';
import 'package:hmg_patient_app_new/features/blood_donation/models/blood_group_hospitals_model.dart';
import 'package:hmg_patient_app_new/features/blood_donation/widgets/hospital_selection.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/blood_donation/widgets/select_blood_group_widget.dart';
import 'package:hmg_patient_app_new/presentation/blood_donation/widgets/select_city_widget.dart';
import 'package:hmg_patient_app_new/presentation/blood_donation/widgets/select_gender_widget.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/select_clinic_page.dart';
import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart';
import 'package:hmg_patient_app_new/services/dialog_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:lottie/lottie.dart';
import 'package:provider/provider.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/hospital_bottom_sheet/hospital_bottom_sheet_body.dart';
class BloodDonationPage extends StatelessWidget {
BloodDonationPage({super.key});
@ -25,7 +35,7 @@ class BloodDonationPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
appState = getIt.get<AppState>();
appState = getIt<AppState>();
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: Consumer<BloodDonationViewModel>(builder: (context, bloodDonationVM, child) {
@ -34,15 +44,83 @@ class BloodDonationPage extends StatelessWidget {
Expanded(
child: CollapsingListView(
title: LocaleKeys.bloodDonation.tr(),
trailing: CustomButton(
text: "Book",
onPressed: () {
// if (bloodDonationVM.isUserAuthanticated()) {
bloodDonationVM.fetchHospitalsList().then((value) {
showCommonBottomSheetWithoutHeight(context, title: "Select Hospital", isDismissible: false, child: Consumer<BloodDonationViewModel>(builder: (_, data, __) {
return HospitalBottomSheetBodySelection(
onUserHospitalSelection: (BdGetProjectsHaveBdClinic userChoice) {
print("============User Choice===============");
bloodDonationVM.getFreeBloodDonationSlots(request: {"ClinicID": 134, "ProjectID": userChoice.projectId});
},
);
}), callBackFunc: () {});
});
// } else {
// return showCommonBottomSheetWithoutHeight(
// context,
// title: LocaleKeys.notice.tr(context: context),
// child: Column(
// mainAxisAlignment: MainAxisAlignment.center,
// crossAxisAlignment: CrossAxisAlignment.center,
// children: [
// Lottie.asset(AppAnimations.errorAnimation, repeat: true, reverse: false, frameRate: FrameRate(60), width: 100.h, height: 100.h, fit: BoxFit.fill),
// SizedBox(height: 8.h),
// (LocaleKeys.loginToUseService.tr()).toText16(color: AppColors.blackColor),
// SizedBox(height: 16.h),
// Row(
// children: [
// Expanded(
// child: CustomButton(
// text: LocaleKeys.cancel.tr(),
// onPressed: () {
// Navigator.of(context).pop();
// },
// backgroundColor: AppColors.secondaryLightRedColor,
// borderColor: AppColors.secondaryLightRedColor,
// textColor: AppColors.primaryRedColor,
// icon: AppAssets.cancel,
// iconColor: AppColors.primaryRedColor,
// ),
// ),
// SizedBox(width: 8.h),
// Expanded(
// child: CustomButton(
// text: LocaleKeys.confirm.tr(),
// onPressed: () async {
// Navigator.of(context).pop();
// // Navigator.pushAndRemoveUntil(context, CustomPageRoute(page: LandingNavigation()), (r) => false);
// await getIt<AuthenticationViewModel>().onLoginPressed();
// },
// backgroundColor: AppColors.bgGreenColor,
// borderColor: AppColors.bgGreenColor,
// textColor: Colors.white,
// icon: AppAssets.confirm,
// ),
// ),
// ],
// ),
// SizedBox(height: 16.h),
// ],
// ).center,
// callBackFunc: () {},
// isFullScreen: false,
// isCloseButtonVisible: true,
// );
// }
},
backgroundColor: AppColors.bgRedLightColor,
borderColor: AppColors.bgRedLightColor,
textColor: AppColors.primaryRedColor,
padding: EdgeInsetsGeometry.symmetric(vertical: 0.h, horizontal: 20.h)),
child: Padding(
padding: EdgeInsets.all(24.w),
child: SingleChildScrollView(
child: Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.r,
hasShadow: false,
),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: false),
child: Padding(
padding: EdgeInsets.all(16.h),
child: Column(
@ -60,8 +138,8 @@ class BloodDonationPage extends StatelessWidget {
children: [
LocaleKeys.city.tr().toText16(color: AppColors.textColor, weight: FontWeight.w500),
(appState.isArabic()
? (bloodDonationVM.selectedCity.descriptionN ?? LocaleKeys.select.tr())
: bloodDonationVM.selectedCity.description ?? LocaleKeys.select.tr(context: context))
? (bloodDonationVM.selectedCity?.descriptionN ?? LocaleKeys.select.tr())
: bloodDonationVM.selectedCity?.description ?? LocaleKeys.select.tr(context: context))
.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
],
),
@ -71,12 +149,7 @@ class BloodDonationPage extends StatelessWidget {
],
).onPress(() async {
showCommonBottomSheetWithoutHeight(context,
title: LocaleKeys.selectCity.tr(context: context),
isDismissible: true,
child: SelectCityWidget(
bloodDonationViewModel: bloodDonationVM,
),
callBackFunc: () {});
title: LocaleKeys.selectCity.tr(context: context), isDismissible: true, child: SelectCityWidget(bloodDonationViewModel: bloodDonationVM), callBackFunc: () {});
}),
SizedBox(height: 16.h),
Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h),
@ -86,13 +159,16 @@ class BloodDonationPage extends StatelessWidget {
children: [
Row(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.my_account_icon, width: 40.h, height: 40.h),
Utils.buildSvgWithAssets(icon: AppAssets.genderInputIcon, width: 40.h, height: 40.h),
SizedBox(width: 12.w),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.gender.tr().toText16(color: AppColors.textColor, weight: FontWeight.w500),
"Male".toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
(appState.isArabic()
? (bloodDonationVM.selectedGender?.typeAr ?? LocaleKeys.select.tr())
: bloodDonationVM.selectedGender?.type ?? LocaleKeys.select.tr(context: context))
.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
],
),
],
@ -103,10 +179,7 @@ class BloodDonationPage extends StatelessWidget {
showCommonBottomSheetWithoutHeight(context,
title: LocaleKeys.selectGender.tr(context: context),
isDismissible: true,
child: SelectGenderWidget(
isArabic: appState.isArabic(),
bloodDonationViewModel: bloodDonationVM,
),
child: SelectGenderWidget(isArabic: appState.isArabic(), bloodDonationViewModel: bloodDonationVM),
callBackFunc: () {});
}),
SizedBox(height: 16.h),
@ -117,13 +190,17 @@ class BloodDonationPage extends StatelessWidget {
children: [
Row(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.my_account_icon, width: 40.h, height: 40.h),
Utils.buildSvgWithAssets(icon: AppAssets.bloodType, width: 40.h, height: 40.h),
SizedBox(width: 12.w),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.bloodType.tr().toText16(color: AppColors.textColor, weight: FontWeight.w500),
bloodDonationVM.selectedBloodType.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
// bloodDonationVM.selectedBloodType?.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
(appState.isArabic()
? (bloodDonationVM.selectedBloodType ?? LocaleKeys.select.tr())
: bloodDonationVM.selectedBloodType ?? LocaleKeys.select.tr(context: context))
.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500)
],
),
],
@ -134,10 +211,7 @@ class BloodDonationPage extends StatelessWidget {
showCommonBottomSheetWithoutHeight(context,
title: LocaleKeys.select.tr(context: context),
isDismissible: true,
child: SelectBloodGroupWidget(
isArabic: appState.isArabic(),
bloodDonationViewModel: bloodDonationVM,
),
child: SelectBloodGroupWidget(isArabic: appState.isArabic(), bloodDonationViewModel: bloodDonationVM),
callBackFunc: () {});
}),
],
@ -149,19 +223,73 @@ class BloodDonationPage extends StatelessWidget {
),
),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.r,
hasShadow: true,
),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true),
child: SizedBox(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
GestureDetector(
onTap: bloodDonationVM.onTermAccepted,
child: Row(
children: [
Selector<BloodDonationViewModel, bool>(
selector: (_, viewModel) => viewModel.isTermsAccepted,
shouldRebuild: (previous, next) => previous != next,
builder: (context, isTermsAccepted, child) {
return AnimatedContainer(
duration: const Duration(milliseconds: 200),
height: 24.h,
width: 24.h,
decoration: BoxDecoration(
color: isTermsAccepted ? AppColors.primaryRedColor : Colors.transparent,
borderRadius: BorderRadius.circular(6),
border: Border.all(color: isTermsAccepted ? AppColors.primaryRedBorderColor : AppColors.greyColor, width: 2.h),
),
child: isTermsAccepted ? Icon(Icons.check, size: 16.f, color: Colors.white) : null,
);
},
),
SizedBox(width: 12.h),
Row(
children: [
Text(
LocaleKeys.iAcceptThe.tr(),
style: context.dynamicTextStyle(fontSize: 14.f, fontWeight: FontWeight.w500, color: Color(0xFF2E3039)),
),
GestureDetector(
onTap: () {
// Navigate to terms and conditions page
Navigator.of(context).pushNamed('/terms');
},
child: Text(
LocaleKeys.termsConditoins.tr(),
style: context.dynamicTextStyle(
fontSize: 14.f,
fontWeight: FontWeight.w500,
color: AppColors.primaryRedColor,
decoration: TextDecoration.underline,
decorationColor: AppColors.primaryRedBorderColor,
),
),
),
],
),
// Expanded(
// child: Text(
// LocaleKeys.iAcceptTermsConditions.tr().split("the").first,
// style: context.dynamicTextStyle(fontSize: 14.fSize, fontWeight: FontWeight.w500, color: Color(0xFF2E3039)),
// ),
// ),
],
),
).paddingOnly(left: 16.h, right: 16.h, top: 24.h),
CustomButton(
text: LocaleKeys.save.tr(),
onPressed: () {
// openDoctorScheduleCalendar();
onPressed: () async {
DialogService dialogService = getIt.get<DialogService>();
if (await bloodDonationVM.validateSelections()) {
bloodDonationVM.updateBloodGroup();
}
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,

@ -26,9 +26,7 @@ class SelectCityWidget extends StatelessWidget {
Navigator.of(context).pop();
});
},
separatorBuilder: (_, __) => SizedBox(
height: 8.h,
),
separatorBuilder: (_, __) => SizedBox(height: 8.h),
itemCount: bloodDonationViewModel.citiesList.length),
)
],

@ -1,5 +1,6 @@
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/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
@ -8,10 +9,10 @@ import 'package:hmg_patient_app_new/features/blood_donation/blood_donation_view_
import 'package:hmg_patient_app_new/theme/colors.dart';
class SelectGenderWidget extends StatelessWidget {
SelectGenderWidget({super.key, required this.bloodDonationViewModel, required this.isArabic});
const SelectGenderWidget({super.key, required this.bloodDonationViewModel, required this.isArabic});
BloodDonationViewModel bloodDonationViewModel;
bool isArabic;
final BloodDonationViewModel bloodDonationViewModel;
final bool isArabic;
@override
Widget build(BuildContext context) {
@ -20,46 +21,45 @@ class SelectGenderWidget extends StatelessWidget {
children: [
SizedBox(height: 8.h),
SizedBox(
height: MediaQuery.sizeOf(context).height * .4,
child: ListView.separated(
itemBuilder: (_, index) {
return DecoratedBox(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: false,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 8.h,
children: [bloodDonationViewModel.genderList[index].name.toText16(color: AppColors.textColor, isBold: true)],
height: MediaQuery.sizeOf(context).height * .4,
child: ListView.separated(
itemBuilder: (_, index) {
return DecoratedBox(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: false,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 8.h,
children: [GenderTypeEnum.values[index].name.toCamelCase.toText16(color: AppColors.textColor, isBold: true)],
),
),
),
Transform.flip(
flipX: isArabic,
child: Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon,
iconColor: AppColors.blackColor,
width: 40.h,
height: 40.h,
fit: BoxFit.contain,
Transform.flip(
flipX: isArabic,
child: Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon,
iconColor: AppColors.blackColor,
width: 40.h,
height: 40.h,
fit: BoxFit.contain,
),
),
),
],
).paddingSymmetrical(16.h, 16.h).onPress(() {
// bloodDonationViewModel.setSelectedCity(bloodDonationViewModel.citiesList[index]);
Navigator.of(context).pop();
}));
},
separatorBuilder: (_, __) => SizedBox(
height: 8.h,
),
itemCount: bloodDonationViewModel.genderList.length),
)
],
).paddingSymmetrical(16.h, 16.h).onPress(() {
bloodDonationViewModel.onGenderChange(GenderTypeEnum.values[index].name.toCamelCase);
Navigator.of(context).pop();
}));
},
separatorBuilder: (_, __) => SizedBox(
height: 8.h,
),
itemCount: GenderTypeEnum.values.length))
],
);
}

@ -112,10 +112,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
fit: BoxFit.cover,
).circle(100).toShimmer2(isShow: true, radius: 50.r),
SizedBox(height: 8.h),
("Dr. John Smith Smith Smith")
.toString()
.toText12(fontWeight: FontWeight.w500, isCenter: true, maxLine: 2)
.toShimmer2(isShow: true),
("Dr. John Smith Smith Smith").toString().toText12(fontWeight: FontWeight.w500, isCenter: true, maxLine: 2).toShimmer2(isShow: true),
],
)
: myAppointmentsVM.patientMyDoctorsList.isEmpty
@ -241,10 +238,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
),
],
),
Transform.flip(
flipX: appState.isArabic(),
child: Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)),
Transform.flip(flipX: appState.isArabic(), child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)),
],
).onPress(() {
bookAppointmentsViewModel.setIsClinicsListLoading(true);
@ -276,10 +270,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
),
],
),
Transform.flip(
flipX: appState.isArabic(),
child: Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)),
Transform.flip(flipX: appState.isArabic(), child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)),
],
).onPress(() {
bookAppointmentsViewModel.setIsDoctorSearchByNameStarted(false);
@ -309,10 +300,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
),
],
),
Transform.flip(
flipX: appState.isArabic(),
child: Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)),
Transform.flip(flipX: appState.isArabic(), child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)),
],
).onPress(() {
bookAppointmentsViewModel.setProjectID(null);
@ -332,124 +320,115 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
Column(
children: [
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.h,
hasShadow: false,
),
child: Padding(
padding: EdgeInsets.all(16.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.search_by_clinic_icon, width: 40.h, height: 40.h),
SizedBox(width: 12.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Immediate Consultation".needTranslation.toText14(color: AppColors.textColor, weight: FontWeight.w500),
"Tap to select clinic".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500),
],
),
],
),
Transform.flip(
flipX: appState.isArabic(),
child: Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)),
],
).onPress(() async {
//TODO Implement API to check for existing LiveCare Requests
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.h,
hasShadow: false,
),
child: Padding(
padding: EdgeInsets.all(16.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.search_by_clinic_icon, width: 40.h, height: 40.h),
SizedBox(width: 12.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Immediate Consultation".needTranslation.toText14(color: AppColors.textColor, weight: FontWeight.w500),
"Tap to select clinic".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500),
],
),
],
),
Transform.flip(flipX: appState.isArabic(), child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)),
],
).onPress(() async {
//TODO Implement API to check for existing LiveCare Requests
LoaderBottomSheet.showLoader();
await immediateLiveCareViewModel.getPatientLiveCareHistory();
LoaderBottomSheet.hideLoader();
LoaderBottomSheet.showLoader();
await immediateLiveCareViewModel.getPatientLiveCareHistory();
LoaderBottomSheet.hideLoader();
if (immediateLiveCareViewModel.patientHasPendingLiveCareRequest) {
Navigator.of(context).push(
CustomPageRoute(
page: ImmediateLiveCarePendingRequestPage(),
),
);
} else {
Navigator.of(context).push(
CustomPageRoute(
page: SelectImmediateLiveCareClinicPage(),
),
);
}
}),
SizedBox(height: 16.h),
Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h),
SizedBox(height: 16.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.search_by_doctor_icon, width: 40.h, height: 40.h),
SizedBox(width: 12.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Scheduled Consultation".needTranslation.toText14(color: AppColors.textColor, weight: FontWeight.w500),
"Tap to select clinic".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500),
],
),
],
),
Transform.flip(
flipX: appState.isArabic(),
child: Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)),
],
).onPress(() {
bookAppointmentsViewModel.setIsClinicsListLoading(true);
bookAppointmentsViewModel.setIsLiveCareSchedule(true);
Navigator.of(context).push(
CustomPageRoute(
page: SelectClinicPage(),
),
);
}),
SizedBox(height: 16.h),
Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h),
SizedBox(height: 16.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.search_by_region_icon, width: 40.h, height: 40.h),
SizedBox(width: 12.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Pharma LiveCare".needTranslation.toText14(color: AppColors.textColor, weight: FontWeight.w500),
"".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500),
],
),
],
),
Transform.flip(
flipX: appState.isArabic(),
child: Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)),
],
).onPress(() {
openRegionListBottomSheet(context, RegionBottomSheetType.FOR_REGION);
}),
],
),
),
),
],
).paddingSymmetrical(24.h, 0.h)
if (immediateLiveCareViewModel.patientHasPendingLiveCareRequest) {
Navigator.of(context).push(
CustomPageRoute(
page: ImmediateLiveCarePendingRequestPage(),
),
);
} else {
Navigator.of(context).push(
CustomPageRoute(
page: SelectImmediateLiveCareClinicPage(),
),
);
}
}),
SizedBox(height: 16.h),
Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h),
SizedBox(height: 16.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.search_by_doctor_icon, width: 40.h, height: 40.h),
SizedBox(width: 12.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Scheduled Consultation".needTranslation.toText14(color: AppColors.textColor, weight: FontWeight.w500),
"Tap to select clinic".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500),
],
),
],
),
Transform.flip(flipX: appState.isArabic(), child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)),
],
).onPress(() {
bookAppointmentsViewModel.setIsClinicsListLoading(true);
bookAppointmentsViewModel.setIsLiveCareSchedule(true);
Navigator.of(context).push(
CustomPageRoute(
page: SelectClinicPage(),
),
);
}),
SizedBox(height: 16.h),
Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h),
SizedBox(height: 16.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.search_by_region_icon, width: 40.h, height: 40.h),
SizedBox(width: 12.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Pharma LiveCare".needTranslation.toText14(color: AppColors.textColor, weight: FontWeight.w500),
"".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500),
],
),
],
),
Transform.flip(flipX: appState.isArabic(), child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)),
],
).onPress(() {
openRegionListBottomSheet(context, RegionBottomSheetType.FOR_REGION);
}),
],
),
),
),
],
).paddingSymmetrical(24.h, 0.h)
// : getLiveCareNotLoggedInUI()
;
default:
@ -493,10 +472,8 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
regionalViewModel.flush();
regionalViewModel.setBottomSheetType(type);
// AppointmentViaRegionViewmodel? viewmodel = null;
showCommonBottomSheetWithoutHeight(context,
title: "",
titleWidget: Consumer<AppointmentViaRegionViewmodel>(builder: (_, data, __) => getTitle(data)),
isDismissible: false, child: Consumer<AppointmentViaRegionViewmodel>(builder: (_, data, __) {
showCommonBottomSheetWithoutHeight(context, title: "", titleWidget: Consumer<AppointmentViaRegionViewmodel>(builder: (_, data, __) => getTitle(data)), isDismissible: false,
child: Consumer<AppointmentViaRegionViewmodel>(builder: (_, data, __) {
return getRegionalSelectionWidget(data);
}), callBackFunc: () {});
}
@ -582,9 +559,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Immediate service".needTranslation.toText18(color: AppColors.textColor, isBold: true),
"No need to wait, you will get medical consultation immediately via video call"
.needTranslation
.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
"No need to wait, you will get medical consultation immediately via video call".needTranslation.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
],
),
),
@ -616,9 +591,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Doctor will contact".needTranslation.toText18(color: AppColors.textColor, isBold: true),
"A specialised doctor will contact you and will be able to view your medical history"
.needTranslation
.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
"A specialised doctor will contact you and will be able to view your medical history".needTranslation.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
],
),
),
@ -634,9 +607,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Free medicine delivery".needTranslation.toText18(color: AppColors.textColor, isBold: true),
"Offers free medicine delivery for the LiveCare appointment"
.needTranslation
.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
"Offers free medicine delivery for the LiveCare appointment".needTranslation.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
],
),
),

@ -1,6 +1,7 @@
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/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart' show CapExtension;
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';

@ -1211,9 +1211,7 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
bookAppointmentsViewModel.setIsContinueDentalPlan(true);
Navigator.of(context).pop();
Navigator.of(context).push(
CustomPageRoute(
page: SelectDoctorPage(),
),
CustomPageRoute(page: SelectDoctorPage()),
);
},
backgroundColor: AppColors.bgGreenColor,

@ -40,9 +40,7 @@ class _SelectDoctorPageState extends State<SelectDoctorPage> {
late AppState appState;
late BookAppointmentsViewModel bookAppointmentsViewModel;
// Scroll controller to control page scrolling when a group expands
late ScrollController _scrollController;
// Map of keys for each item to allow scrolling to them
final Map<int, GlobalKey> _itemKeys = {};
@override
@ -79,6 +77,20 @@ class _SelectDoctorPageState extends State<SelectDoctorPage> {
backgroundColor: AppColors.bgScaffoldColor,
body: CollapsingListView(
title: "Choose Doctor".needTranslation,
// bottomChild: Container(
// decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, customBorder: BorderRadius.only(topLeft: Radius.circular(24.r), topRight: Radius.circular(24.r))),
// padding: EdgeInsets.symmetric(vertical: 20.h, horizontal: 20.h),
// child: CustomButton(
// text: LocaleKeys.search.tr(),
// onPressed: () {
// },
// icon: null,
// fontSize: 16.f,
// backgroundColor: AppColors.primaryRedColor,
// borderColor: AppColors.primaryRedColor,
// borderRadius: 12.r,
// fontWeight: FontWeight.w500),
// ),
child: SingleChildScrollView(
controller: _scrollController,
child: Padding(
@ -124,40 +136,42 @@ class _SelectDoctorPageState extends State<SelectDoctorPage> {
],
),
SizedBox(height: 16.h),
Row(
children: [
CustomButton(
text: LocaleKeys.byClinic.tr(context: context),
onPressed: () {
bookAppointmentsVM.setIsSortByClinic(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.setIsSortByClinic(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),
SizedBox(height: 16.h),
if (bookAppointmentsViewModel.isGetDocForHealthCal && bookAppointmentsVM.showSortFilterButtons)
Row(
children: [
CustomButton(
text: LocaleKeys.byClinic.tr(context: context),
onPressed: () {
bookAppointmentsVM.setIsSortByClinic(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.setIsSortByClinic(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 (bookAppointmentsViewModel.isGetDocForHealthCal && bookAppointmentsVM.showSortFilterButtons)
SizedBox(height: 16.h),
Row(
mainAxisSize: MainAxisSize.max,
children: [

Loading…
Cancel
Save