Merge branch 'master' into faiz_dev

# Conflicts:
#	lib/core/api/api_client.dart
#	lib/core/dependencies.dart
#	lib/main.dart
#	lib/presentation/appointments/appointment_payment_page.dart
pull/94/head
faizatflutter 5 months ago
commit 617b68021a

@ -176,6 +176,7 @@ class ApiClientImp implements ApiClient {
// body['TokenID'] = "@dm!n";
// body['PatientID'] = 4772429;
// body['PatientID'] = 1231755;
// body['PatientTypeID'] = 1;
//
// body['PatientOutSA'] = 0;

@ -717,7 +717,7 @@ var GET_PRESCRIPTION_INSTRUCTIONS_PDF = 'Services/ChatBot_Service.svc/REST/Chatb
class ApiConsts {
static const maxSmallScreen = 660;
static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.uat;
static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.prod;
// static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT

@ -8,6 +8,8 @@ import 'package:hmg_patient_app_new/features/authentication/authentication_view_
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_repo.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/common/common_repo.dart';
import 'package:hmg_patient_app_new/features/contact_us/contact_us_repo.dart';
import 'package:hmg_patient_app_new/features/contact_us/contact_us_view_model.dart';
import 'package:hmg_patient_app_new/features/doctor_filter/doctor_filter_view_model.dart';
import 'package:hmg_patient_app_new/features/emergency_services/emergency_services_repo.dart';
import 'package:hmg_patient_app_new/features/emergency_services/emergency_services_view_model.dart';
@ -106,6 +108,7 @@ class AppDependencies {
getIt.registerLazySingleton<ImmediateLiveCareRepo>(() => ImmediateLiveCareRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<EmergencyServicesRepo>(() => EmergencyServicesRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<TodoSectionRepo>(() => TodoSectionRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<ContactUsRepo>(() => ContactUsRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
// ViewModels
// Global/shared VMs LazySingleton
@ -216,6 +219,14 @@ class AppDependencies {
),
);
getIt.registerLazySingleton<ContactUsViewModel>(
() => ContactUsViewModel(
contactUsRepo: getIt(),
appState: getIt(),
errorHandlerService: getIt(),
),
);
getIt.registerLazySingleton<TodoSectionViewModel>(
() => TodoSectionViewModel(
todoSectionRepo: getIt(),

@ -18,6 +18,8 @@ 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/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/navigation_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
@ -809,6 +811,22 @@ class Utils {
return file.path;
}
///method to be used to get the text as per the langauge of the application
static String getTextWRTCurrentLanguage(String? englishText, String? arabicText) {
String? text = appState.isArabic() ? arabicText : englishText;
return text ?? '';
}
static String formatNumberToInternationalFormat(num number, {String? currencySymbol, int decimalDigit = 0}) {
return NumberFormat.currency(locale: 'en_US', symbol: currencySymbol ?? "", decimalDigits: decimalDigit).format(number);
}
static PatientDoctorAppointmentList? convertToPatientDoctorAppointmentList(HospitalsModel? hospital) {
if (hospital == null) return null;
return PatientDoctorAppointmentList(
filterName: hospital.name, distanceInKMs: hospital.distanceInKilometers?.toString(), projectTopName: hospital.name, projectBottomName: hospital.name, model: hospital, isHMC: hospital.isHMC);
}
static bool havePrivilege(int id) {
bool isHavePrivilege = false;
try {

@ -0,0 +1,95 @@
import 'package:dartz/dartz.dart';
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/contact_us/models/resp_models/get_hmg_locations.dart';
import 'package:hmg_patient_app_new/features/contact_us/models/resp_models/get_patient_ic_projects.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
abstract class ContactUsRepo {
Future<Either<Failure, GenericApiModel<List<GetHMGLocationsModel>>>> getHMGLocations();
Future<Either<Failure, GenericApiModel<List<GetPatientICProjectsModel>>>> getLiveChatProjectsList();
}
class ContactUsRepoImp implements ContactUsRepo {
final ApiClient apiClient;
final LoggerService loggerService;
ContactUsRepoImp({required this.apiClient, required this.loggerService});
@override
Future<Either<Failure, GenericApiModel<List<GetHMGLocationsModel>>>> getHMGLocations() async {
Map<String, dynamic> mapDevice = {};
try {
GenericApiModel<List<GetHMGLocationsModel>>? apiResponse;
Failure? failure;
await apiClient.post(
GET_FINDUS_REQUEST,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['ListHMGLocation'];
final hmgLocations = list.map((item) => GetHMGLocationsModel.fromJson(item as Map<String, dynamic>)).toList().cast<GetHMGLocationsModel>();
apiResponse = GenericApiModel<List<GetHMGLocationsModel>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: hmgLocations,
);
} 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<GetPatientICProjectsModel>>>> getLiveChatProjectsList() async {
Map<String, dynamic> mapDevice = {};
try {
GenericApiModel<List<GetPatientICProjectsModel>>? apiResponse;
Failure? failure;
await apiClient.post(
GET_LIVECHAT_REQUEST,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['List_PatientICProjects'];
final hmgLocations = list.map((item) => GetPatientICProjectsModel.fromJson(item as Map<String, dynamic>)).toList().cast<GetPatientICProjectsModel>();
apiResponse = GenericApiModel<List<GetPatientICProjectsModel>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: hmgLocations,
);
} 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()));
}
}
}

@ -0,0 +1,65 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/features/contact_us/contact_us_repo.dart';
import 'package:hmg_patient_app_new/features/contact_us/models/resp_models/get_hmg_locations.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
class ContactUsViewModel extends ChangeNotifier {
ContactUsRepo contactUsRepo;
ErrorHandlerService errorHandlerService;
AppState appState;
bool isHMGLocationsListLoading = false;
bool isHMGHospitalsListSelected = true;
List<GetHMGLocationsModel> hmgHospitalsLocationsList = [];
List<GetHMGLocationsModel> hmgPharmacyLocationsList = [];
ContactUsViewModel({required this.contactUsRepo, required this.errorHandlerService, required this.appState});
initContactUsViewModel() {
isHMGLocationsListLoading = true;
isHMGHospitalsListSelected = true;
hmgHospitalsLocationsList.clear();
hmgPharmacyLocationsList.clear();
getHMGLocations();
notifyListeners();
}
setHMGHospitalsListSelected(bool isSelected) {
isHMGHospitalsListSelected = isSelected;
notifyListeners();
}
Future<void> getHMGLocations({Function(dynamic)? onSuccess, Function(String)? onError}) async {
isHMGLocationsListLoading = true;
hmgHospitalsLocationsList.clear();
hmgPharmacyLocationsList.clear();
notifyListeners();
final result = await contactUsRepo.getHMGLocations();
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),
(apiResponse) {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
// hmgLocationsList = apiResponse.data!;
for (var location in apiResponse.data!) {
if (location.locationType == 1) {
hmgHospitalsLocationsList.add(location);
} else if (location.locationType == 2) {
hmgPharmacyLocationsList.add(location);
}
}
isHMGLocationsListLoading = false;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
}

@ -0,0 +1,80 @@
class GetHMGLocationsModel {
dynamic cityID;
String? cityName;
dynamic cityNameN;
dynamic distanceInKilometers;
bool? isActive;
String? latitude;
int? locationID;
String? locationName;
dynamic locationNameN;
dynamic locationType;
String? longitude;
int? pharmacyLocationID;
String? phoneNumber;
int? projectID;
String? projectImageURL;
int? setupID;
dynamic sortOrder;
GetHMGLocationsModel(
{this.cityID,
this.cityName,
this.cityNameN,
this.distanceInKilometers,
this.isActive,
this.latitude,
this.locationID,
this.locationName,
this.locationNameN,
this.locationType,
this.longitude,
this.pharmacyLocationID,
this.phoneNumber,
this.projectID,
this.projectImageURL,
this.setupID,
this.sortOrder});
GetHMGLocationsModel.fromJson(Map<String, dynamic> json) {
cityID = json['CityID'];
cityName = json['CityName'];
cityNameN = json['CityNameN'];
distanceInKilometers = json['DistanceInKilometers'];
isActive = json['IsActive'];
latitude = json['Latitude'];
locationID = json['LocationID'];
locationName = json['LocationName'];
locationNameN = json['LocationNameN'];
locationType = json['LocationType'];
longitude = json['Longitude'];
pharmacyLocationID = json['PharmacyLocationID'];
phoneNumber = json['PhoneNumber'];
projectID = json['ProjectID'];
projectImageURL = json['ProjectImageURL'];
setupID = json['SetupID'];
sortOrder = json['SortOrder'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['CityID'] = this.cityID;
data['CityName'] = this.cityName;
data['CityNameN'] = this.cityNameN;
data['DistanceInKilometers'] = this.distanceInKilometers;
data['IsActive'] = this.isActive;
data['Latitude'] = this.latitude;
data['LocationID'] = this.locationID;
data['LocationName'] = this.locationName;
data['LocationNameN'] = this.locationNameN;
data['LocationType'] = this.locationType;
data['Longitude'] = this.longitude;
data['PharmacyLocationID'] = this.pharmacyLocationID;
data['PhoneNumber'] = this.phoneNumber;
data['ProjectID'] = this.projectID;
data['ProjectImageURL'] = this.projectImageURL;
data['SetupID'] = this.setupID;
data['SortOrder'] = this.sortOrder;
return data;
}
}

@ -0,0 +1,48 @@
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
class GetPatientICProjectsModel {
int? id;
String? projectName;
String? projectNameN;
String? value;
dynamic languageId;
DateTime? createdOn;
String? createdBy;
dynamic editedOn;
dynamic editedBy;
bool? isActive;
dynamic distanceInKilometers;
GetPatientICProjectsModel(
{this.id, this.projectName, this.projectNameN, this.value, this.languageId, this.createdOn, this.createdBy, this.editedOn, this.editedBy, this.distanceInKilometers, this.isActive});
GetPatientICProjectsModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
projectName = json['ProjectName'];
projectNameN = json['ProjectNameN'];
value = json['Value'];
languageId = json['LanguageId'];
createdOn = DateUtil.convertStringToDate(json['CreatedOn']);
createdBy = json['CreatedBy'];
editedOn = json['EditedOn'];
editedBy = json['EditedBy'];
isActive = json['IsActive'];
distanceInKilometers = json['DistanceInKilometers'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['ProjectName'] = this.projectName;
data['ProjectNameN'] = this.projectNameN;
data['Value'] = this.value;
data['LanguageId'] = this.languageId;
data['CreatedOn'] = this.createdOn;
data['CreatedBy'] = this.createdBy;
data['EditedOn'] = this.editedOn;
data['EditedBy'] = this.editedBy;
data['IsActive'] = this.isActive;
data['DistanceInKilometers'] = this.distanceInKilometers;
return data;
}
}

@ -3,14 +3,33 @@ 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/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/features/authentication/models/resp_models/authenticated_user_resp_model.dart';
import 'package:hmg_patient_app_new/features/emergency_services/model/resp_model/EROnlineCheckInPaymentDetailsResponse.dart';
import 'package:hmg_patient_app_new/features/emergency_services/model/resp_model/ProjectAvgERWaitingTime.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_models/rrt_procedures_response_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 EmergencyServicesRepo {
Future<Either<Failure, GenericApiModel<List<RRTProceduresResponseModel>>>> getRRTProcedures();
Future<Either<Failure, GenericApiModel<List<ProjectAvgERWaitingTime>>>> getNearestEr({int? id, int? projectID});
Future<Either<Failure, GenericApiModel<dynamic>>> checkPatientERAdvanceBalance();
Future<Either<Failure, GenericApiModel<List<HospitalsModel>>>> getProjectList();
Future<Either<Failure, GenericApiModel<EROnlineCheckInPaymentDetailsResponse>>> checkPatientERPaymentInformation({int projectID});
Future<Either<Failure, GenericApiModel<dynamic>>> ER_CreateAdvancePayment(
{required int projectID, required AuthenticatedUser authUser, required num paymentAmount, required String paymentMethodName, required String paymentReference});
Future<Either<Failure, GenericApiModel<dynamic>>> addAdvanceNumberRequest({required String advanceNumber, required String paymentReference, required String appointmentNo});
Future<Either<Failure, GenericApiModel<dynamic>>> getProjectIDFromNFC({required String nfcCode});
Future<Either<Failure, GenericApiModel<dynamic>>> autoGenerateInvoiceERClinic({required int projectID});
}
class EmergencyServicesRepoImp implements EmergencyServicesRepo {
@ -91,4 +110,279 @@ class EmergencyServicesRepoImp implements EmergencyServicesRepo {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel>> checkPatientERAdvanceBalance() async {
Map<String, dynamic> mapDevice = {"ClinicID": 10};
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
CHECK_PATIENT_ER_ADVANCE_BALANCE,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final bool patientHasERBalance = response['BalanceAmount'] > 0;
print(patientHasERBalance);
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: patientHasERBalance,
);
} 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<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<EROnlineCheckInPaymentDetailsResponse>>> checkPatientERPaymentInformation({int? projectID}) async {
Map<String, dynamic> mapDevice = {"ClinicID": 10, "ProjectID": projectID ?? 0};
try {
GenericApiModel<EROnlineCheckInPaymentDetailsResponse>? apiResponse;
Failure? failure;
await apiClient.post(
GET_ER_ONLINE_PAYMENT_DETAILS,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final erOnlineCheckInPaymentDetailsResponse = EROnlineCheckInPaymentDetailsResponse.fromJson(response["ResponsePatientShare"]);
apiResponse = GenericApiModel<EROnlineCheckInPaymentDetailsResponse>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: erOnlineCheckInPaymentDetailsResponse,
);
} 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>> ER_CreateAdvancePayment(
{required int projectID, required AuthenticatedUser authUser, required num paymentAmount, required String paymentMethodName, required String paymentReference}) async {
Map<String, dynamic> mapDevice = {
"LanguageID": 1,
"ERAdvanceAmount": {
"ProjectId": projectID,
"PatientId": authUser.patientId,
"ClinicId": 10,
"DepositorName": "${authUser.firstName!} ${authUser.lastName!}",
"MemberId": authUser.patientId,
"NationalityID": authUser.nationalityId,
"PaymentAmount": paymentAmount,
"PaymentDate": DateUtil.convertDateToString(DateTime.now()),
"PaymentMethodName": paymentMethodName,
"PaymentReferenceNumber": paymentReference,
"SourceType": 2
}
};
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
ER_CREATE_ADVANCE_PAYMENT,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final vidaAdvanceNumber = response['ER_AdvancePaymentResponse']['AdvanceNumber'].toString();
print(vidaAdvanceNumber);
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: vidaAdvanceNumber,
);
} 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>> addAdvanceNumberRequest({required String advanceNumber, required String paymentReference, required String appointmentNo}) async {
Map<String, dynamic> requestBody = {
"AdvanceNumber": advanceNumber,
"AdvanceNumber_VP": advanceNumber,
"PaymentReferenceNumber": paymentReference,
"AppointmentID": appointmentNo,
};
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
ADD_ADVANCE_NUMBER_REQUEST,
body: requestBody,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
apiResponse = GenericApiModel<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<dynamic>>> getProjectIDFromNFC({required String nfcCode}) async {
Map<String, dynamic> mapDevice = {"nFC_Code": nfcCode};
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
GET_PROJECT_FROM_NFC,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final projectID = response['GetProjectByNFC'][0]["ProjectID"];
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: projectID,
);
} 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<dynamic>>> autoGenerateInvoiceERClinic({required int projectID}) async {
Map<String, dynamic> mapDevice = {
"ProjectID": projectID,
"ClinicID": "10",
"IsAdvanceAvailable": true,
"MemberID": 102,
"PaymentMethod": "VISA",
};
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
AUTO_GENERATE_INVOICE_ER,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: true,
);
} 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()));
}
}
}

@ -6,9 +6,14 @@ import 'package:google_maps_flutter/google_maps_flutter.dart' as GMSMapServices;
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/location_util.dart';
import 'package:hmg_patient_app_new/features/emergency_services/emergency_services_repo.dart';
import 'package:hmg_patient_app_new/features/emergency_services/model/resp_model/EROnlineCheckInPaymentDetailsResponse.dart';
import 'package:hmg_patient_app_new/features/emergency_services/model/resp_model/ProjectAvgERWaitingTime.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_models/rrt_procedures_response_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/hospital_model.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/call_ambulance_page.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/er_online_checkin/er_online_checkin_home.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/er_online_checkin/er_online_checkin_payment_details_page.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/nearest_er_page.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
@ -30,8 +35,22 @@ class EmergencyServicesViewModel extends ChangeNotifier {
List<RRTProceduresResponseModel> RRTProceduresList = [];
List<HospitalsModel>? hospitalList;
List<HospitalsModel>? hmgHospitalList;
List<HospitalsModel>? hmcHospitalList;
List<HospitalsModel>? displayList;
HospitalsModel? selectedHospital;
FacilitySelection selectedFacility = FacilitySelection.ALL;
int hmgCount = 0;
int hmcCount = 0;
bool pickupFromInsideTheLocation = true;
late RRTProceduresResponseModel selectedRRTProcedure;
bool patientHasAdvanceERBalance = false;
bool isERBookAppointment = false;
late EROnlineCheckInPaymentDetailsResponse erOnlineCheckInPaymentDetailsResponse;
BottomSheetType bottomSheetType = BottomSheetType.FIXED;
setSelectedRRTProcedure(RRTProceduresResponseModel procedure) {
@ -47,11 +66,14 @@ class EmergencyServicesViewModel extends ChangeNotifier {
required this.appState,
});
get isGMSAvailable
{
return appState.isGMSAvailable;
}
bool get isArabic => appState.isArabic();
get isGMSAvailable => appState.isGMSAvailable;
void setIsERBookAppointment(bool value) {
isERBookAppointment = value;
notifyListeners();
}
Future<void> getRRTProcedures({Function(dynamic)? onSuccess, Function(String)? onError}) async {
RRTProceduresList.clear();
@ -149,8 +171,7 @@ class EmergencyServicesViewModel extends ChangeNotifier {
}
GMSMapServices.CameraPosition getGMSLocation() {
return GMSMapServices.CameraPosition(
target: GMSMapServices.LatLng(appState.userLat, appState.userLong), zoom: 18);
return GMSMapServices.CameraPosition(target: GMSMapServices.LatLng(appState.userLat, appState.userLong), zoom: 18);
}
handleGMSMapCameraMoved(GMSMapServices.CameraPosition value) {
@ -158,37 +179,259 @@ class EmergencyServicesViewModel extends ChangeNotifier {
}
HMSCameraServices.CameraPosition getHMSLocation() {
return HMSCameraServices.CameraPosition(
target: HMSCameraServices.LatLng(appState.userLat, appState.userLong),zoom: 18);
return HMSCameraServices.CameraPosition(target: HMSCameraServices.LatLng(appState.userLat, appState.userLong), zoom: 18);
}
handleHMSMapCameraMoved(HMSCameraServices.CameraPosition value) {
//todo_section handle the camera moved position for HMS devices
}
FutureOr<void> getProjects() async {
// if (hospitalList.isNotEmpty) return;
var response = await emergencyServicesRepo.getProjectList();
response.fold(
(failure) async {},
(apiResponse) async {
List<HospitalsModel>? data = apiResponse.data;
if (data == null) return;
hospitalList = data;
hmgHospitalList = data.where((e) => e.isHMC == false).toList();
hmcHospitalList = data.where((e) => e.isHMC == true).toList();
hmgCount = hmgHospitalList?.length ?? 0;
hmcCount = hmcHospitalList?.length ?? 0;
notifyListeners();
},
);
}
setSelectedFacility(FacilitySelection selection) {
selectedFacility = selection;
notifyListeners();
}
searchHospitals(String query) {
if (query.isEmpty) {
getDisplayList();
return;
}
List<HospitalsModel>? sourceList;
switch (selectedFacility) {
case FacilitySelection.ALL:
sourceList = hospitalList;
break;
case FacilitySelection.HMG:
sourceList = hmgHospitalList;
break;
case FacilitySelection.HMC:
sourceList = hmcHospitalList;
break;
}
displayList = sourceList?.where((hospital) => hospital.name != null && hospital.name!.toLowerCase().contains(query.toLowerCase())).toList();
notifyListeners();
}
getDisplayList() {
switch (selectedFacility) {
case FacilitySelection.ALL:
displayList = hospitalList;
break;
case FacilitySelection.HMG:
displayList = hmgHospitalList;
break;
case FacilitySelection.HMC:
displayList = hmcHospitalList;
break;
}
notifyListeners();
}
void setSelectedHospital(HospitalsModel? hospital) {
selectedHospital = hospital;
notifyListeners();
}
String? getSelectedHospitalName() {
return selectedHospital?.getName(isArabic);
}
void navigateTOAmbulancePage() {
locationUtils!.getLocation(
isShowConfirmDialog: true,
onSuccess: (position) {
updateBottomSheetState(BottomSheetType.FIXED);
navServices.push(
CustomPageRoute(
page: CallAmbulancePage(), direction: AxisDirection.down
),
CustomPageRoute(page: CallAmbulancePage(), direction: AxisDirection.down),
);
});
}
void navigateToEROnlineCheckIn() {
navServices.push(
CustomPageRoute(page: ErOnlineCheckinHome()),
);
}
void navigateToEROnlineCheckInPaymentPage() {
navServices.push(
CustomPageRoute(page: ErOnlineCheckinPaymentDetailsPage()),
);
}
void updateBottomSheetState(BottomSheetType sheetType) {
bottomSheetType = sheetType;
notifyListeners();
}
void setIsGMSAvailable(bool value) {
notifyListeners();
}
Future<void> checkPatientERAdvanceBalance({Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await emergencyServicesRepo.checkPatientERAdvanceBalance();
result.fold(
// (failure) async => await errorHandlerService.handleError(failure: failure),
(failure) {
patientHasAdvanceERBalance = false;
isERBookAppointment = true;
if (onSuccess != null) {
onSuccess(failure.message);
}
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
patientHasAdvanceERBalance = false;
isERBookAppointment = true;
} else if (apiResponse.messageStatus == 1) {
patientHasAdvanceERBalance = apiResponse.data;
isERBookAppointment = !patientHasAdvanceERBalance;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
Future<void> getPatientERPaymentInformation({Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await emergencyServicesRepo.checkPatientERPaymentInformation(projectID: selectedHospital!.iD);
result.fold(
(failure) {
if (onError != null) {
onError(failure.message);
}
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
} else if (apiResponse.messageStatus == 1) {
erOnlineCheckInPaymentDetailsResponse = apiResponse.data!;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
Future<void> ER_CreateAdvancePayment({required String paymentMethodName, required String paymentReference, Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await emergencyServicesRepo.ER_CreateAdvancePayment(
projectID: selectedHospital!.iD,
authUser: appState.getAuthenticatedUser()!,
paymentAmount: erOnlineCheckInPaymentDetailsResponse.patientShareWithTax!,
paymentMethodName: paymentMethodName,
paymentReference: paymentReference);
result.fold(
(failure) {
if (onError != null) {
onError(failure.message);
}
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
} else if (apiResponse.messageStatus == 1) {
// erOnlineCheckInPaymentDetailsResponse = apiResponse.data!;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse.data);
}
}
},
);
}
Future<void> addAdvanceNumberRequest(
{required String advanceNumber, required String paymentReference, required String appointmentNo, Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await emergencyServicesRepo.addAdvanceNumberRequest(advanceNumber: advanceNumber, paymentReference: paymentReference, appointmentNo: appointmentNo);
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),
(apiResponse) {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
Future<void> getProjectIDFromNFC({required String nfcCode, Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await emergencyServicesRepo.getProjectIDFromNFC(nfcCode: nfcCode);
result.fold(
// (failure) async => await errorHandlerService.handleError(failure: failure),
(failure) {
if (onError != null) {
onError(failure.message);
}
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
if (onError != null) {
onError(apiResponse.errorMessage!);
}
} else if (apiResponse.messageStatus == 1) {
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse.data);
}
}
},
);
}
Future<void> autoGenerateInvoiceERClinic({required int projectID, Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await emergencyServicesRepo.autoGenerateInvoiceERClinic(projectID: projectID);
result.fold(
// (failure) async => await errorHandlerService.handleError(failure: failure),
(failure) {
if (onError != null) {
onError(failure.message);
}
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
if (onError != null) {
onError(apiResponse.data["InvoiceResponse"]["Message"]);
}
} else if (apiResponse.messageStatus == 1) {
patientHasAdvanceERBalance = false;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse.data);
}
}
},
);
}
}

@ -0,0 +1,108 @@
class EROnlineCheckInPaymentDetailsResponse {
num? cashPrice;
num? cashPriceTax;
num? cashPriceWithTax;
int? companyId;
String? companyName;
num? companyShareWithTax;
dynamic errCode;
int? groupID;
String? insurancePolicyNo;
String? message;
String? patientCardID;
num? patientShare;
num? patientShareWithTax;
num? patientTaxAmount;
int? policyId;
String? policyName;
String? procedureId;
String? procedureName;
dynamic setupID;
int? statusCode;
String? subPolicyNo;
bool? isCash;
bool? isEligible;
bool? isInsured;
EROnlineCheckInPaymentDetailsResponse(
{this.cashPrice,
this.cashPriceTax,
this.cashPriceWithTax,
this.companyId,
this.companyName,
this.companyShareWithTax,
this.errCode,
this.groupID,
this.insurancePolicyNo,
this.message,
this.patientCardID,
this.patientShare,
this.patientShareWithTax,
this.patientTaxAmount,
this.policyId,
this.policyName,
this.procedureId,
this.procedureName,
this.setupID,
this.statusCode,
this.subPolicyNo,
this.isCash,
this.isEligible,
this.isInsured});
EROnlineCheckInPaymentDetailsResponse.fromJson(Map<String, dynamic> json) {
cashPrice = json['CashPrice'];
cashPriceTax = json['CashPriceTax'];
cashPriceWithTax = json['CashPriceWithTax'];
companyId = json['CompanyId'];
companyName = json['CompanyName'];
companyShareWithTax = json['CompanyShareWithTax'];
errCode = json['ErrCode'];
groupID = json['GroupID'];
insurancePolicyNo = json['InsurancePolicyNo'];
message = json['Message'];
patientCardID = json['PatientCardID'];
patientShare = json['PatientShare'];
patientShareWithTax = json['PatientShareWithTax'];
patientTaxAmount = json['PatientTaxAmount'];
policyId = json['PolicyId'];
policyName = json['PolicyName'];
procedureId = json['ProcedureId'];
procedureName = json['ProcedureName'];
setupID = json['SetupID'];
statusCode = json['StatusCode'];
subPolicyNo = json['SubPolicyNo'];
isCash = json['IsCash'];
isEligible = json['IsEligible'];
isInsured = json['IsInsured'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['CashPrice'] = this.cashPrice;
data['CashPriceTax'] = this.cashPriceTax;
data['CashPriceWithTax'] = this.cashPriceWithTax;
data['CompanyId'] = this.companyId;
data['CompanyName'] = this.companyName;
data['CompanyShareWithTax'] = this.companyShareWithTax;
data['ErrCode'] = this.errCode;
data['GroupID'] = this.groupID;
data['InsurancePolicyNo'] = this.insurancePolicyNo;
data['Message'] = this.message;
data['PatientCardID'] = this.patientCardID;
data['PatientShare'] = this.patientShare;
data['PatientShareWithTax'] = this.patientShareWithTax;
data['PatientTaxAmount'] = this.patientTaxAmount;
data['PolicyId'] = this.policyId;
data['PolicyName'] = this.policyName;
data['ProcedureId'] = this.procedureId;
data['ProcedureName'] = this.procedureName;
data['SetupID'] = this.setupID;
data['StatusCode'] = this.statusCode;
data['SubPolicyNo'] = this.subPolicyNo;
data['IsCash'] = this.isCash;
data['IsEligible'] = this.isEligible;
data['IsInsured'] = this.isInsured;
return data;
}
}

@ -0,0 +1,92 @@
class AskDocRequestType {
String? setupID;
int? parameterGroup;
int? parameterType;
int? parameterCode;
String? description;
String? descriptionN;
String? alias;
String? aliasN;
String? prefix;
String? suffix;
String? isColorCodingRequired;
String? backColor;
String? foreColor;
bool? isBuiltIn;
bool? isActive;
int? createdBy;
String? createdOn;
String? editedBy;
String? editedOn;
String? rowVer;
AskDocRequestType(
{this.setupID,
this.parameterGroup,
this.parameterType,
this.parameterCode,
this.description,
this.descriptionN,
this.alias,
this.aliasN,
this.prefix,
this.suffix,
this.isColorCodingRequired,
this.backColor,
this.foreColor,
this.isBuiltIn,
this.isActive,
this.createdBy,
this.createdOn,
this.editedBy,
this.editedOn,
this.rowVer});
AskDocRequestType.fromJson(Map<String, dynamic> json) {
setupID = json['SetupID'];
parameterGroup = json['ParameterGroup'];
parameterType = json['ParameterType'];
parameterCode = json['ParameterCode'];
description = json['Description'];
descriptionN = json['DescriptionN'];
alias = json['Alias'];
aliasN = json['AliasN'];
prefix = json['Prefix'];
suffix = json['Suffix'];
isColorCodingRequired = json['IsColorCodingRequired'];
backColor = json['BackColor'];
foreColor = json['ForeColor'];
isBuiltIn = json['IsBuiltIn'];
isActive = json['IsActive'];
createdBy = json['CreatedBy'];
createdOn = json['CreatedOn'];
editedBy = json['EditedBy'];
editedOn = json['EditedOn'];
rowVer = json['RowVer'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['SetupID'] = this.setupID;
data['ParameterGroup'] = this.parameterGroup;
data['ParameterType'] = this.parameterType;
data['ParameterCode'] = this.parameterCode;
data['Description'] = this.description;
data['DescriptionN'] = this.descriptionN;
data['Alias'] = this.alias;
data['AliasN'] = this.aliasN;
data['Prefix'] = this.prefix;
data['Suffix'] = this.suffix;
data['IsColorCodingRequired'] = this.isColorCodingRequired;
data['BackColor'] = this.backColor;
data['ForeColor'] = this.foreColor;
data['IsBuiltIn'] = this.isBuiltIn;
data['IsActive'] = this.isActive;
data['CreatedBy'] = this.createdBy;
data['CreatedOn'] = this.createdOn;
data['EditedBy'] = this.editedBy;
data['EditedOn'] = this.editedOn;
data['RowVer'] = this.rowVer;
return data;
}
}

@ -55,8 +55,8 @@ class PatientAppointmentHistoryResponseModel {
bool? isMedicalReportRequested;
bool? isOnlineCheckedIN;
String? latitude;
dynamic listHISGetContactLensPerscription;
dynamic listHISGetGlassPerscription;
List<ListHISGetContactLensPrescription>? listHISGetContactLensPrescription;
List<ListHISGetGlassPrescription>? listHISGetGlassPrescription;
String? longitude;
dynamic nextAction;
dynamic noOfPatientsRate;
@ -130,8 +130,8 @@ class PatientAppointmentHistoryResponseModel {
this.isMedicalReportRequested,
this.isOnlineCheckedIN,
this.latitude,
this.listHISGetContactLensPerscription,
this.listHISGetGlassPerscription,
this.listHISGetContactLensPrescription,
this.listHISGetGlassPrescription,
this.longitude,
this.nextAction,
this.noOfPatientsRate,
@ -207,8 +207,18 @@ class PatientAppointmentHistoryResponseModel {
isMedicalReportRequested = json['IsMedicalReportRequested'];
isOnlineCheckedIN = json['IsOnlineCheckedIN'];
latitude = json['Latitude'];
listHISGetContactLensPerscription = json['List_HIS_GetContactLensPerscription'];
listHISGetGlassPerscription = json['List_HIS_GetGlassPerscription'];
if (json['List_HIS_GetContactLensPerscription'] != null) {
listHISGetContactLensPrescription = <ListHISGetContactLensPrescription>[];
json['List_HIS_GetContactLensPerscription'].forEach((v) {
listHISGetContactLensPrescription!.add(ListHISGetContactLensPrescription.fromJson(v));
});
}
if (json['List_HIS_GetGlassPerscription'] != null) {
listHISGetGlassPrescription = <ListHISGetGlassPrescription>[];
json['List_HIS_GetGlassPerscription'].forEach((v) {
listHISGetGlassPrescription!.add(ListHISGetGlassPrescription.fromJson(v));
});
}
longitude = json['Longitude'];
nextAction = json['NextAction'];
noOfPatientsRate = json['NoOfPatientsRate'];
@ -285,8 +295,8 @@ class PatientAppointmentHistoryResponseModel {
data['IsMedicalReportRequested'] = this.isMedicalReportRequested;
data['IsOnlineCheckedIN'] = this.isOnlineCheckedIN;
data['Latitude'] = this.latitude;
data['List_HIS_GetContactLensPerscription'] = this.listHISGetContactLensPerscription;
data['List_HIS_GetGlassPerscription'] = this.listHISGetGlassPerscription;
// data['List_HIS_GetContactLensPerscription'] = this.listHISGetContactLensPerscription;
// data['List_HIS_GetGlassPerscription'] = this.listHISGetGlassPerscription;
data['Longitude'] = this.longitude;
data['NextAction'] = this.nextAction;
data['NoOfPatientsRate'] = this.noOfPatientsRate;
@ -301,6 +311,196 @@ class PatientAppointmentHistoryResponseModel {
}
}
class ListHISGetContactLensPrescription {
String? setupId;
int? projectId;
int? patientType;
int? patientId;
int? encounterType;
int? encounterNo;
int? oDOS;
dynamic brand;
dynamic baseCurve;
dynamic power;
dynamic diameter;
dynamic oZ;
dynamic cT;
dynamic blend;
String? remarks;
int? status;
bool? isActive;
String? createdOn;
ListHISGetContactLensPrescription(
{this.setupId,
this.projectId,
this.patientType,
this.patientId,
this.encounterType,
this.encounterNo,
this.oDOS,
this.brand,
this.baseCurve,
this.power,
this.diameter,
this.oZ,
this.cT,
this.blend,
this.remarks,
this.status,
this.isActive,
this.createdOn});
ListHISGetContactLensPrescription.fromJson(Map<String, dynamic> json) {
setupId = json['SetupId'];
projectId = json['ProjectId'];
patientType = json['PatientType'];
patientId = json['PatientId'];
encounterType = json['EncounterType'];
encounterNo = json['EncounterNo'];
oDOS = json['OD_OS'];
brand = json['Brand'];
baseCurve = json['BaseCurve'];
power = json['Power'];
diameter = json['Diameter'];
oZ = json['OZ'];
cT = json['CT'];
blend = json['Blend'];
remarks = json['Remarks'];
status = json['Status'];
isActive = json['IsActive'];
createdOn = json['CreatedOn'];
}
Map<String?, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['SetupId'] = this.setupId;
data['ProjectId'] = this.projectId;
data['PatientType'] = this.patientType;
data['PatientId'] = this.patientId;
data['EncounterType'] = this.encounterType;
data['EncounterNo'] = this.encounterNo;
data['OD_OS'] = this.oDOS;
data['Brand'] = this.brand;
data['BaseCurve'] = this.baseCurve;
data['Power'] = this.power;
data['Diameter'] = this.diameter;
data['OZ'] = this.oZ;
data['CT'] = this.cT;
data['Blend'] = this.blend;
data['Remarks'] = this.remarks;
data['Status'] = this.status;
data['IsActive'] = this.isActive;
data['CreatedOn'] = this.createdOn;
return data;
}
}
class ListHISGetGlassPrescription {
dynamic projectID;
String? setupID;
dynamic patientId;
dynamic encounterType;
dynamic encounterNo;
String? visionType;
double? rightEyeSpherical;
dynamic rightEyeCylinder;
dynamic rightEyeAxis;
dynamic rightEyePrism;
dynamic rightEyeVA;
String? rightEyeRemarks;
dynamic leftEyeSpherical;
dynamic leftEyeCylinder;
dynamic leftEyeAxis;
dynamic leftEyePrism;
dynamic leftEyeVA;
String? leftEyeRemarks;
dynamic pD;
dynamic bVD;
dynamic status;
bool? isActive;
String? createdOn;
ListHISGetGlassPrescription(
{this.projectID,
this.setupID,
this.patientId,
this.encounterType,
this.encounterNo,
this.visionType,
this.rightEyeSpherical,
this.rightEyeCylinder,
this.rightEyeAxis,
this.rightEyePrism,
this.rightEyeVA,
this.rightEyeRemarks,
this.leftEyeSpherical,
this.leftEyeCylinder,
this.leftEyeAxis,
this.leftEyePrism,
this.leftEyeVA,
this.leftEyeRemarks,
this.pD,
this.bVD,
this.status,
this.isActive,
this.createdOn});
ListHISGetGlassPrescription.fromJson(Map<String, dynamic> json) {
projectID = json['ProjectID'];
setupID = json['SetupID'];
patientId = json['PatientId'];
encounterType = json['EncounterType'];
encounterNo = json['EncounterNo'];
visionType = json['VisionType'];
rightEyeSpherical = json['RightEyeSpherical'];
rightEyeCylinder = json['RightEyeCylinder'];
rightEyeAxis = json['RightEyeAxis'];
rightEyePrism = json['RightEyePrism'];
rightEyeVA = json['RightEyeVA'];
rightEyeRemarks = json['RightEyeRemarks'];
leftEyeSpherical = json['LeftEyeSpherical'];
leftEyeCylinder = json['LeftEyeCylinder'];
leftEyeAxis = json['LeftEyeAxis'];
leftEyePrism = json['LeftEyePrism'];
leftEyeVA = json['LeftEyeVA'];
leftEyeRemarks = json['LeftEyeRemarks'];
pD = json['PD'];
bVD = json['BVD'];
status = json['Status'];
isActive = json['IsActive'];
createdOn = json['CreatedOn'];
}
Map<String?, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['ProjectID'] = this.projectID;
data['SetupID'] = this.setupID;
data['PatientId'] = this.patientId;
data['EncounterType'] = this.encounterType;
data['EncounterNo'] = this.encounterNo;
data['VisionType'] = this.visionType;
data['RightEyeSpherical'] = this.rightEyeSpherical;
data['RightEyeCylinder'] = this.rightEyeCylinder;
data['RightEyeAxis'] = this.rightEyeAxis;
data['RightEyePrism'] = this.rightEyePrism;
data['RightEyeVA'] = this.rightEyeVA;
data['RightEyeRemarks'] = this.rightEyeRemarks;
data['LeftEyeSpherical'] = this.leftEyeSpherical;
data['LeftEyeCylinder'] = this.leftEyeCylinder;
data['LeftEyeAxis'] = this.leftEyeAxis;
data['LeftEyePrism'] = this.leftEyePrism;
data['LeftEyeVA'] = this.leftEyeVA;
data['LeftEyeRemarks'] = this.leftEyeRemarks;
data['PD'] = this.pD;
data['BVD'] = this.bVD;
data['Status'] = this.status;
data['IsActive'] = this.isActive;
data['CreatedOn'] = this.createdOn;
return data;
}
}
class PatientAppointmentList {
String? filterName = "";
List<PatientAppointmentHistoryResponseModel>? patientDoctorAppointmentList = [];

@ -6,7 +6,9 @@ import 'package:hmg_patient_app_new/core/api_consts.dart';
import 'package:hmg_patient_app_new/core/cache_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/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/ask_doctor_request_type_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/get_tamara_installments_details_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart' show HospitalsModel;
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
@ -14,7 +16,7 @@ import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/
import 'package:hmg_patient_app_new/services/logger_service.dart';
abstract class MyAppointmentsRepo {
Future<Either<Failure, GenericApiModel<List<PatientAppointmentHistoryResponseModel>>>> getPatientAppointments({required bool isActiveAppointment, required bool isArrivedAppointments});
Future<Either<Failure, GenericApiModel<List<PatientAppointmentHistoryResponseModel>>>> getPatientAppointments({required bool isActiveAppointment, required bool isArrivedAppointments, bool isForEyeMeasurement = false});
Future<Either<Failure, GenericApiModel<PatientAppointmentShareResponseModel>>> getPatientShareAppointment(
{required int projectID, required int clinicID, required String appointmentNo, required bool isLiveCareAppointment});
@ -49,6 +51,13 @@ abstract class MyAppointmentsRepo {
Future<Either<Failure, GenericApiModel<GetTamaraInstallmentsDetailsResponseModel>>> getTamaraInstallmentsDetails();
Future<Either<Failure, GenericApiModel<dynamic>>> getActiveAppointmentsCount();
Future<Either<Failure, GenericApiModel<List<AskDocRequestType>>>> getAskDoctorRequestTypes();
Future<Either<Failure, GenericApiModel<dynamic>>> isDoctorAvailable({required int projectID, required int clinicID, required int doctorID});
Future<Either<Failure, GenericApiModel<dynamic>>> sendAskDocCallRequest(
{required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, required String requestType, required String remarks, required String userMobileNumber});
}
class MyAppointmentsRepoImp implements MyAppointmentsRepo {
@ -58,13 +67,14 @@ class MyAppointmentsRepoImp implements MyAppointmentsRepo {
MyAppointmentsRepoImp({required this.loggerService, required this.apiClient});
@override
Future<Either<Failure, GenericApiModel<List<PatientAppointmentHistoryResponseModel>>>> getPatientAppointments({required bool isActiveAppointment, required bool isArrivedAppointments}) async {
Future<Either<Failure, GenericApiModel<List<PatientAppointmentHistoryResponseModel>>>> getPatientAppointments({required bool isActiveAppointment, required bool isArrivedAppointments, bool isForEyeMeasurement = false}) async {
Map<String, dynamic> mapDevice = {
"IsActiveAppointment": isActiveAppointment,
"IsComingFromCOC": false,
"isForUpcomming": false,
"IsForMedicalReport": false,
"IsForArrived": isArrivedAppointments,
"IsIrisPrescription": isForEyeMeasurement
};
try {
@ -618,4 +628,122 @@ class MyAppointmentsRepoImp implements MyAppointmentsRepo {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel>> isDoctorAvailable({required int projectID, required int clinicID, required int doctorID}) async {
Map<String, dynamic> mapDevice = {"isDentalAllowedBackend": false, "DoctorID": doctorID, "ProjectID": projectID, "ClinicID": clinicID};
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
IS_DOCTOR_AVAILABLE_BY_CALENDAR_SCHEDULE,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final isDoctorAvailable = response['IsDoctorAvailable'];
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: isDoctorAvailable,
);
} 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<AskDocRequestType>>>> getAskDoctorRequestTypes() async {
Map<String, dynamic> mapDevice = {};
try {
GenericApiModel<List<AskDocRequestType>>? apiResponse;
Failure? failure;
await apiClient.post(GET_CALL_REQUEST_TYPE, onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
}, onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['ListReqTypes'];
final askDoctorRequestTypesList = list.map((item) => AskDocRequestType.fromJson(item as Map<String, dynamic>)).toList().cast<AskDocRequestType>();
apiResponse = GenericApiModel<List<AskDocRequestType>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: askDoctorRequestTypesList,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
}, body: mapDevice);
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>> sendAskDocCallRequest(
{required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, required String requestType, required String remarks, required String userMobileNumber}) async {
Map<String, dynamic> body = {};
body['ProjectID'] = patientAppointmentHistoryResponseModel.projectID;
body['SetupID'] = patientAppointmentHistoryResponseModel.setupID;
body['DoctorID'] = patientAppointmentHistoryResponseModel.doctorID;
body['PatientMobileNumber'] = userMobileNumber;
body['IsMessageSent'] = false;
body['RequestDate'] = DateUtil.convertDateToString(DateTime.now());
body['RequestTime'] = DateUtil.convertDateToString(DateTime.now());
body['Remarks'] = remarks;
body['Status'] = 2; // 4 for testing only.."cancelled status insert" else should be changed to 1 in live version
body['CreatedBy'] = 102;
body['CreatedOn'] = DateUtil.convertDateToString(DateTime.now());
body['EditedBy'] = 102;
body['EditedOn'] = DateUtil.convertDateToString(DateTime.now());
body['isDentalAllowedBackend'] = false;
body['AppointmentNo'] = patientAppointmentHistoryResponseModel.appointmentNo;
body['ClinicID'] = patientAppointmentHistoryResponseModel.clinicID;
body['QuestionType'] = num.parse(requestType);
body['RequestType'] = num.parse(requestType);
body['RequestTypeID'] = num.parse(requestType);
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(INSERT_CALL_INFO, onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
}, onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: true,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
}, body: body);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
}

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/appointemnet_filters.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/ask_doctor_request_type_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/get_tamara_installments_details_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_share_response_model.dart';
@ -13,6 +14,8 @@ class MyAppointmentsViewModel extends ChangeNotifier {
int selectedTabIndex = 0;
int previouslySelectedTab = -1;
int eyeMeasurementsTabSelectedIndex = 0;
MyAppointmentsRepo myAppointmentsRepo;
ErrorHandlerService errorHandlerService;
AppState appState;
@ -26,6 +29,8 @@ class MyAppointmentsViewModel extends ChangeNotifier {
bool isAppointmentDataToBeLoaded = true;
bool isEyeMeasurementsAppointmentsLoading = false;
List<AppointmentListingFilters> availableFilters = [];
List<AppointmentListingFilters>? selectedFilter = [];
bool isDateFilterSelected = false;
@ -42,6 +47,10 @@ class MyAppointmentsViewModel extends ChangeNotifier {
List<PatientAppointmentHistoryResponseModel> patientMyDoctorsList = [];
List<PatientAppointmentHistoryResponseModel> patientEyeMeasurementsAppointmentsHistoryList = [];
List<AskDocRequestType> askDoctorRequestTypeList = [];
PatientAppointmentShareResponseModel? patientAppointmentShareResponseModel;
GetTamaraInstallmentsDetailsResponseModel? getTamaraInstallmentsDetailsResponseModel;
@ -57,18 +66,25 @@ class MyAppointmentsViewModel extends ChangeNotifier {
notifyListeners();
}
void onEyeMeasurementsTabChanged(int index) {
eyeMeasurementsTabSelectedIndex = index;
notifyListeners();
}
initAppointmentsViewModel() {
if (isAppointmentDataToBeLoaded) {
patientAppointmentsHistoryList.clear();
patientUpcomingAppointmentsHistoryList.clear();
patientArrivedAppointmentsHistoryList.clear();
patientTimelineAppointmentsList.clear();
patientEyeMeasurementsAppointmentsHistoryList.clear();
isMyAppointmentsLoading = true;
isTimeLineAppointmentsLoading = true;
patientMyDoctorsList.clear();
}
isTamaraDetailsLoading = true;
isAppointmentPatientShareLoading = true;
isEyeMeasurementsAppointmentsLoading = true;
notifyListeners();
}
@ -105,6 +121,11 @@ class MyAppointmentsViewModel extends ChangeNotifier {
notifyListeners();
}
setIsEyeMeasurementsAppointmentsLoading(bool val) {
isEyeMeasurementsAppointmentsLoading = val;
notifyListeners();
}
setAppointmentReminder(bool value, PatientAppointmentHistoryResponseModel item) {
int index = patientAppointmentsHistoryList.indexOf(item);
if (index != -1) {
@ -113,6 +134,29 @@ class MyAppointmentsViewModel extends ChangeNotifier {
}
}
Future<void> getPatientEyeMeasurementAppointments({Function(dynamic)? onSuccess, Function(String)? onError}) async {
patientEyeMeasurementsAppointmentsHistoryList.clear();
notifyListeners();
final result = await myAppointmentsRepo.getPatientAppointments(isActiveAppointment: false, isArrivedAppointments: true, isForEyeMeasurement: true);
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),
(apiResponse) {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
patientEyeMeasurementsAppointmentsHistoryList = apiResponse.data!;
isEyeMeasurementsAppointmentsLoading = false;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
Future<void> getPatientAppointments(bool isActiveAppointment, bool isArrivedAppointments, {Function(dynamic)? onSuccess, Function(String)? onError}) async {
if (!isAppointmentDataToBeLoaded) return;
@ -568,4 +612,71 @@ class MyAppointmentsViewModel extends ChangeNotifier {
},
);
}
Future<void> isDoctorAvailable({required int projectID, required int doctorId, required int clinicId, Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await myAppointmentsRepo.isDoctorAvailable(projectID: projectID, doctorID: doctorId, clinicID: clinicId);
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),
(apiResponse) {
if (apiResponse.messageStatus == 2) {
onError!(apiResponse.errorMessage!);
} else if (apiResponse.messageStatus == 1) {
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse.data);
}
}
},
);
}
Future<void> getAskDoctorRequestTypes({Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await myAppointmentsRepo.getAskDoctorRequestTypes();
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),
(apiResponse) {
if (apiResponse.messageStatus == 2) {
onError!(apiResponse.errorMessage!);
} else if (apiResponse.messageStatus == 1) {
askDoctorRequestTypeList = apiResponse.data!;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse.data);
}
}
},
);
}
Future<void> sendAskDocCallRequest({
required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel,
required String requestType,
required String remarks,
required String userMobileNumber,
Function(dynamic)? onSuccess,
Function(String)? onError,
}) async {
final result = await myAppointmentsRepo.sendAskDocCallRequest(
patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel, requestType: requestType, remarks: remarks, userMobileNumber: userMobileNumber);
result.fold(
// (failure) async => await errorHandlerService.handleError(failure: failure),
(failure) async {
await errorHandlerService.handleError(failure: failure);
if (onError != null) onError(failure.message);
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
onError!(apiResponse.errorMessage!);
} else if (apiResponse.messageStatus == 1) {
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse.data);
}
}
},
);
}
}

@ -4,6 +4,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/my_appointments/models/resp_models/get_tamara_installments_details_response_model.dart';
import 'package:hmg_patient_app_new/features/payfort/models/apple_pay_request_insert_model.dart';
import 'package:hmg_patient_app_new/features/payfort/models/payfort_check_payment_status_response_model.dart';
import 'package:hmg_patient_app_new/features/payfort/models/payfort_project_details_resp_model.dart';
@ -25,6 +26,8 @@ abstract class PayfortRepo {
Future<Either<Failure, GenericApiModel<dynamic>>> updateTamaraRequestStatus(
{required String responseMessage, required String status, required String clientRequestID, required String tamaraOrderID});
Future<Either<Failure, GenericApiModel<GetTamaraInstallmentsDetailsResponseModel>>> getTamaraInstallmentsDetails();
}
class PayfortRepoImp implements PayfortRepo {
@ -250,4 +253,42 @@ class PayfortRepoImp implements PayfortRepo {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<GetTamaraInstallmentsDetailsResponseModel>>> getTamaraInstallmentsDetails() async {
try {
GenericApiModel<GetTamaraInstallmentsDetailsResponseModel>? apiResponse;
Failure? failure;
await apiClient.get(
ApiConsts.GET_TAMARA_INSTALLMENTS_URL,
isExternal: true,
isAllowAny: true,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response;
final tamaraInstallmentsList = GetTamaraInstallmentsDetailsResponseModel.fromJson(list.first);
apiResponse = GenericApiModel<GetTamaraInstallmentsDetailsResponseModel>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: tamaraInstallmentsList,
);
} 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()));
}
}
}

@ -3,6 +3,7 @@ import 'dart:developer';
import 'package:amazon_payfort/amazon_payfort.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/api_consts.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/get_tamara_installments_details_response_model.dart';
import 'package:hmg_patient_app_new/features/payfort/models/apple_pay_request_insert_model.dart';
import 'package:hmg_patient_app_new/features/payfort/models/payfort_check_payment_status_response_model.dart';
import 'package:hmg_patient_app_new/features/payfort/models/payfort_project_details_resp_model.dart';
@ -23,6 +24,9 @@ class PayfortViewModel extends ChangeNotifier {
late AmazonPayfort _payfort;
final NetworkInfo _info = NetworkInfo();
GetTamaraInstallmentsDetailsResponseModel? getTamaraInstallmentsDetailsResponseModel;
bool isTamaraDetailsLoading = false;
PayfortViewModel({required this.payfortRepo, required this.errorHandlerService});
setIsApplePayConfigurationLoading(bool value) {
@ -260,4 +264,21 @@ class PayfortViewModel extends ChangeNotifier {
},
);
}
Future<void> getTamaraInstallmentsDetails({Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await payfortRepo.getTamaraInstallmentsDetails();
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),
(apiResponse) {
getTamaraInstallmentsDetailsResponseModel = apiResponse.data!;
isTamaraDetailsLoading = false;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
},
);
}
}

@ -10,6 +10,7 @@ import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/contact_us/contact_us_view_model.dart';
import 'package:hmg_patient_app_new/features/doctor_filter/doctor_filter_view_model.dart';
import 'package:hmg_patient_app_new/features/emergency_services/emergency_services_view_model.dart';
import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_view_model.dart';
@ -133,6 +134,9 @@ void main() async {
),
ChangeNotifierProvider<TodoSectionViewModel>(
create: (_) => getIt.get<TodoSectionViewModel>(),
),
ChangeNotifierProvider<ContactUsViewModel>(
create: (_) => getIt.get<ContactUsViewModel>(),
)
], child: MyApp()),
),

@ -20,6 +20,7 @@ import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/appointment_payment_page.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_checkin_bottom_sheet.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_doctor_card.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/ask_doctor_request_type_select.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/appointment_calendar.dart';
import 'package:hmg_patient_app_new/presentation/prescriptions/prescription_detail_page.dart';
import 'package:hmg_patient_app_new/presentation/prescriptions/prescriptions_list_page.dart';
@ -81,7 +82,35 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
children: [
AppointmentDoctorCard(
patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel,
onAskDoctorTap: () {},
onAskDoctorTap: () async {
LoaderBottomSheet.showLoader(loadingText: "Checking doctor availability...".needTranslation);
await myAppointmentsViewModel.isDoctorAvailable(
projectID: widget.patientAppointmentHistoryResponseModel.projectID,
doctorId: widget.patientAppointmentHistoryResponseModel.doctorID,
clinicId: widget.patientAppointmentHistoryResponseModel.clinicID,
onSuccess: (value) async {
if (value) {
print("Doctor is available");
await myAppointmentsViewModel.getAskDoctorRequestTypes(onSuccess: (val) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
title: LocaleKeys.askDoctor.tr(context: context),
child: AskDoctorRequestTypeSelect(
askDoctorRequestTypeList: myAppointmentsViewModel.askDoctorRequestTypeList,
myAppointmentsViewModel: myAppointmentsViewModel,
patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel,
),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
} else {
print("Doctor is not available");
}
});
},
onCancelTap: () async {
myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true);
LoaderBottomSheet.showLoader(loadingText: "Cancelling Appointment, Please Wait...".needTranslation);
@ -219,7 +248,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
),
const Spacer(),
Switch(
activeThumbColor: AppColors.successColor,
// activeThumbColor: AppColors.successColor,
activeTrackColor: AppColors.successColor.withValues(alpha: .15),
value: widget.patientAppointmentHistoryResponseModel.hasReminder!,
onChanged: (newValue) {

@ -57,22 +57,20 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
void initState() {
scheduleMicrotask(() {
payfortViewModel.initPayfortViewModel();
myAppointmentsViewModel.getTamaraInstallmentsDetails().then((val) {
if (myAppointmentsViewModel.patientAppointmentShareResponseModel!.patientShareWithTax! >=
myAppointmentsViewModel.getTamaraInstallmentsDetailsResponseModel!.minLimit!.amount! &&
myAppointmentsViewModel.patientAppointmentShareResponseModel!.patientShareWithTax! <=
myAppointmentsViewModel.getTamaraInstallmentsDetailsResponseModel!.maxLimit!.amount!) {
setState(() {
isShowTamara = true;
});
}
});
payfortViewModel.setIsApplePayConfigurationLoading(false);
myAppointmentsViewModel.getPatientShareAppointment(
widget.patientAppointmentHistoryResponseModel.projectID,
widget.patientAppointmentHistoryResponseModel.clinicID,
widget.patientAppointmentHistoryResponseModel.appointmentNo.toString(),
widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false, onError: (err) {
widget.patientAppointmentHistoryResponseModel.projectID,
widget.patientAppointmentHistoryResponseModel.clinicID,
widget.patientAppointmentHistoryResponseModel.appointmentNo.toString(), widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false, onSuccess: (val) {
myAppointmentsViewModel.getTamaraInstallmentsDetails().then((val) {
if (myAppointmentsViewModel.patientAppointmentShareResponseModel!.patientShareWithTax! >= myAppointmentsViewModel.getTamaraInstallmentsDetailsResponseModel!.minLimit!.amount! &&
myAppointmentsViewModel.patientAppointmentShareResponseModel!.patientShareWithTax! <= myAppointmentsViewModel.getTamaraInstallmentsDetailsResponseModel!.maxLimit!.amount!) {
setState(() {
isShowTamara = true;
});
}
});
}, onError: (err) {
Navigator.of(context).pop();
Navigator.of(context).pop();
});
@ -658,7 +656,6 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
);
},
onSucceeded: (successResult) async {
Navigator.of(context).pop();
log("successResult: ${successResult.responseMessage.toString()}");
selectedPaymentMethod = successResult.paymentOption ?? "VISA";
checkPaymentStatus();

@ -16,7 +16,9 @@ import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_vie
import 'package:hmg_patient_app_new/features/my_appointments/utils/appointment_type.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/appointment_details_page.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/ask_doctor_request_type_select.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/appointment_calendar.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/eye_measurement_details_page.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/chip/app_custom_chip_widget.dart';
@ -30,6 +32,7 @@ class AppointmentCard extends StatelessWidget {
final bool isLoading;
final bool isFromHomePage;
final bool isFromMedicalReport;
final bool isForEyeMeasurements;
final MedicalFileViewModel? medicalFileViewModel;
final BookAppointmentsViewModel bookAppointmentsViewModel;
@ -41,6 +44,7 @@ class AppointmentCard extends StatelessWidget {
this.isLoading = false,
this.isFromHomePage = false,
this.isFromMedicalReport = false,
this.isForEyeMeasurements = false,
this.medicalFileViewModel,
});
@ -169,24 +173,28 @@ class AppointmentCard extends StatelessWidget {
Widget _buildActionArea(BuildContext context, AppState appState) {
if (isFromMedicalReport) {
return CustomButton(
text: 'Select appointment'.needTranslation,
onPressed: () {
medicalFileViewModel!.setSelectedMedicalReportAppointment(patientAppointmentHistoryResponseModel);
Navigator.pop(context, false);
},
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
fontSize: 14.f,
fontWeight: FontWeight.w500,
borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w),
height: isTablet || isFoldable ? 46.h : 40.h,
icon: AppAssets.checkmark_icon,
iconColor: AppColors.primaryRedColor,
iconSize: 16.h,
);
if (isForEyeMeasurements) {
return SizedBox.shrink();
} else {
return CustomButton(
text: 'Select appointment'.needTranslation,
onPressed: () {
medicalFileViewModel!.setSelectedMedicalReportAppointment(patientAppointmentHistoryResponseModel);
Navigator.pop(context, false);
},
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
fontSize: 14.f,
fontWeight: FontWeight.w500,
borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w),
height: isTablet || isFoldable ? 46.h : 40.h,
icon: AppAssets.checkmark_icon,
iconColor: AppColors.primaryRedColor,
iconSize: 16.h,
);
}
}
return Row(
@ -244,7 +252,35 @@ class AppointmentCard extends StatelessWidget {
if (isRecent) {
return CustomButton(
text: LocaleKeys.askDoctor.tr(context: context),
onPressed: () {},
onPressed: () async {
LoaderBottomSheet.showLoader(loadingText: "Checking doctor availability...".needTranslation);
await myAppointmentsViewModel.isDoctorAvailable(
projectID: patientAppointmentHistoryResponseModel.projectID,
doctorId: patientAppointmentHistoryResponseModel.doctorID,
clinicId: patientAppointmentHistoryResponseModel.clinicID,
onSuccess: (value) async {
if (value) {
print("Doctor is available");
await myAppointmentsViewModel.getAskDoctorRequestTypes(onSuccess: (val) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
title: LocaleKeys.askDoctor.tr(context: context),
child: AskDoctorRequestTypeSelect(
askDoctorRequestTypeList: myAppointmentsViewModel.askDoctorRequestTypeList,
myAppointmentsViewModel: myAppointmentsViewModel,
patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel,
),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
} else {
print("Doctor is not available");
}
});
},
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
@ -277,16 +313,24 @@ class AppointmentCard extends StatelessWidget {
}
void _goToDetails(BuildContext context) {
Navigator.of(context)
.push(
CustomPageRoute(
page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel),
),
)
.then((_) {
myAppointmentsViewModel.initAppointmentsViewModel();
myAppointmentsViewModel.getPatientAppointments(true, false);
});
if (isForEyeMeasurements) {
Navigator.of(context).push(
CustomPageRoute(
page: EyeMeasurementDetailsPage(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel),
),
);
} else {
Navigator.of(context)
.push(
CustomPageRoute(
page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel),
),
)
.then((_) {
myAppointmentsViewModel.initAppointmentsViewModel();
myAppointmentsViewModel.getPatientAppointments(true, false);
});
}
}
void openDoctorScheduleCalendar(BuildContext context) async {

@ -18,6 +18,7 @@ import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:barcode_scan2/barcode_scan2.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/nfc/nfc_reader_sheet.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
@ -139,14 +140,13 @@ class AppointmentCheckinBottomSheet extends StatelessWidget {
}
void sendCheckInRequest(String scannedCode, BuildContext context) async {
showCommonBottomSheet(context,
child: Utils.getLoadingWidget(), callBackFunc: (str) {}, title: "", height: ResponsiveExtension.screenHeight * 0.3, isCloseButtonVisible: false, isDismissible: false, isFullScreen: false);
LoaderBottomSheet.showLoader(loadingText: "Processing Check-In...".needTranslation);
await myAppointmentsViewModel.sendCheckInNfcRequest(
patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel,
scannedCode: scannedCode,
checkInType: 2,
onSuccess: (apiResponse) {
Navigator.of(context).pop();
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(context, title: "Success".needTranslation, child: Utils.getSuccessWidget(loadingText: LocaleKeys.success.tr()), callBackFunc: () {
Navigator.of(context).pop();
Navigator.pushAndRemoveUntil(
@ -161,7 +161,7 @@ class AppointmentCheckinBottomSheet extends StatelessWidget {
}, isFullScreen: false);
},
onError: (error) {
Navigator.of(context).pop();
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(context, title: "Error".needTranslation, child: Utils.getErrorWidget(loadingText: error), callBackFunc: () {
Navigator.of(context).pop();
}, isFullScreen: false);

@ -113,7 +113,9 @@ class AppointmentDoctorCard extends StatelessWidget {
return DateTime.now().difference(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate)).inDays <= 15
? CustomButton(
text: LocaleKeys.askDoctor.tr(),
onPressed: () {},
onPressed: () {
onAskDoctorTap();
},
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,

@ -0,0 +1,138 @@
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/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/ask_doctor_request_type_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_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';
class AskDoctorRequestTypeSelect extends StatelessWidget {
AskDoctorRequestTypeSelect({super.key, required this.askDoctorRequestTypeList, required this.myAppointmentsViewModel, required this.patientAppointmentHistoryResponseModel});
final MyAppointmentsViewModel myAppointmentsViewModel;
final PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel;
List<AskDocRequestType> askDoctorRequestTypeList = [];
int selectedParameterCodeValue = 2;
int selectedParameterCode = 0;
final ValueNotifier<int> requestTypeSelectNotifier = ValueNotifier<int>(0);
@override
Widget build(BuildContext context) {
return Column(
children: [
Container(
width: double.infinity,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24),
child: ListView.builder(
itemCount: askDoctorRequestTypeList.length,
physics: NeverScrollableScrollPhysics(),
padding: EdgeInsets.only(top: 8, bottom: 8),
shrinkWrap: true,
itemBuilder: (context, index) {
return ValueListenableBuilder<int>(
valueListenable: requestTypeSelectNotifier,
builder: (context, duration, child) {
return Theme(
data: Theme.of(context).copyWith(
listTileTheme: ListTileThemeData(horizontalTitleGap: 4),
),
child: RadioListTile<int>(
title: (askDoctorRequestTypeList[index].description ?? '').toText14(weight: FontWeight.w500),
value: index,
fillColor: WidgetStateProperty.resolveWith((states) {
if (states.contains(WidgetState.selected)) {
return AppColors.primaryRedColor;
}
return Color(0xffEEEEEE);
}),
contentPadding: EdgeInsets.only(left: 12.h, right: 12.h),
groupValue: selectedParameterCode,
onChanged: (int? newValue) {
selectedParameterCode = newValue!;
selectedParameterCodeValue = askDoctorRequestTypeList[index].parameterCode!;
requestTypeSelectNotifier.value = selectedParameterCode;
debugPrint(selectedParameterCodeValue.toString());
},
),
);
},
);
},
),
),
SizedBox(height: 16.h),
Row(
children: [
Expanded(
child: CustomButton(
text: LocaleKeys.cancel.tr(),
onPressed: () {
Navigator.pop(context);
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
textColor: AppColors.whiteColor,
icon: AppAssets.cancel,
iconColor: AppColors.whiteColor,
borderRadius: 12.r,
iconSize: 14.h,
fontSize: 14.f,
height: 40.h,
),
),
SizedBox(width: 8.h),
Expanded(
child: CustomButton(
text: LocaleKeys.confirm.tr(),
onPressed: () async {
Navigator.pop(context);
LoaderBottomSheet.showLoader(loadingText: "Sending Request...");
await myAppointmentsViewModel.sendAskDocCallRequest(
patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel,
requestType: selectedParameterCodeValue.toString(),
remarks: "",
userMobileNumber: myAppointmentsViewModel.appState.getAuthenticatedUser()!.mobileNumber!,
onSuccess: (val) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getSuccessWidget(loadingText: "Request has been sent successfully, you will be contacted soon.".needTranslation),
callBackFunc: () {
Navigator.of(context).pop();
},
title: "",
isCloseButtonVisible: true,
isDismissible: false,
isFullScreen: false,
);
},
onError: (errMessage) {
LoaderBottomSheet.hideLoader();
});
},
backgroundColor: AppColors.bgGreenColor,
borderColor: AppColors.bgGreenColor,
textColor: Colors.white,
icon: AppAssets.confirm,
iconSize: 14.h,
borderRadius: 12.r,
fontSize: 14.f,
height: 40.h,
),
),
],
)
],
);
}
}

@ -0,0 +1,114 @@
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';
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/contact_us/contact_us_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.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/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:provider/provider.dart';
class ContactUs extends StatelessWidget {
ContactUs({super.key});
late AppState appState;
late ContactUsViewModel contactUsViewModel;
late LocationUtils locationUtils;
@override
Widget build(BuildContext context) {
appState = getIt.get<AppState>();
locationUtils = getIt.get<LocationUtils>();
locationUtils.isShowConfirmDialog = true;
contactUsViewModel = Provider.of<ContactUsViewModel>(context);
return Column(
children: [
checkInOptionCard(
AppAssets.checkin_location_icon,
LocaleKeys.findUs.tr(),
"View your nearest HMG locations".needTranslation,
).onPress(() {
locationUtils.getCurrentLocation(onSuccess: (value) {
contactUsViewModel.initContactUsViewModel();
Navigator.pop(context);
Navigator.of(context).push(
CustomPageRoute(
page: FindUsPage(),
),
);
});
}),
SizedBox(height: 16.h),
checkInOptionCard(
AppAssets.checkin_location_icon,
LocaleKeys.feedback.tr(),
"Provide your feedback on our services".needTranslation,
),
SizedBox(height: 16.h),
checkInOptionCard(
AppAssets.checkin_location_icon,
LocaleKeys.liveChat.tr(),
"Live chat option with HMG".needTranslation,
).onPress(() {
locationUtils.getCurrentLocation(onSuccess: (value) {
Navigator.pop(context);
Navigator.of(context).push(
CustomPageRoute(
page: LiveChatPage(),
),
);
});
}),
],
);
}
Widget checkInOptionCard(String icon, String title, String subTitle) {
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.r,
hasShadow: false,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Utils.buildSvgWithAssets(icon: icon, width: 40.h, height: 40.h, fit: BoxFit.fill),
SizedBox(height: 16.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
title.toText16(isBold: true, color: AppColors.textColor),
subTitle.toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor),
],
),
),
Transform.flip(
flipX: appState.isArabic(),
child: Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon_small,
iconColor: AppColors.blackColor,
width: 18.h,
height: 13.h,
fit: BoxFit.contain,
),
),
],
),
],
).paddingAll(16.h),
);
}
}

@ -0,0 +1,165 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.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/contact_us/contact_us_view_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/models/patient_sickleave_response_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/contact_us/widgets/find_us_item_card.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/widgets/patient_sick_leave_card.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart';
import 'package:provider/provider.dart';
class FindUsPage extends StatelessWidget {
FindUsPage({super.key});
late AppState appState;
late ContactUsViewModel contactUsViewModel;
@override
Widget build(BuildContext context) {
contactUsViewModel = Provider.of<ContactUsViewModel>(context);
appState = getIt.get<AppState>();
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: CollapsingListView(
title: LocaleKeys.location.tr(),
child: Consumer<ContactUsViewModel>(builder: (context, contactUsVM, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 16.h),
contactUsVM.isHMGLocationsListLoading
? SizedBox.shrink()
: CustomTabBar(
activeTextColor: AppColors.primaryRedColor,
activeBackgroundColor: AppColors.primaryRedColor.withValues(alpha: .1),
tabs: [
CustomTabBarModel(null, LocaleKeys.hmgHospitals.tr()),
CustomTabBarModel(null, LocaleKeys.pharmaciesList.tr()),
],
onTabChange: (index) {
contactUsVM.setHMGHospitalsListSelected(index == 0);
},
).paddingSymmetrical(24.h, 0.h),
ListView.separated(
padding: EdgeInsets.only(top: 16.h),
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: contactUsVM.isHMGLocationsListLoading
? 5
: contactUsVM.isHMGHospitalsListSelected
? contactUsVM.hmgHospitalsLocationsList.length
: contactUsVM.hmgPharmacyLocationsList.length,
itemBuilder: (context, index) {
return contactUsVM.isHMGLocationsListLoading
? Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true),
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: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
"https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png",
width: 63.h,
height: 63.h,
fit: BoxFit.cover,
).circle(100).toShimmer2(isShow: true),
SizedBox(width: 16.h),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Dr John Smith".toText16(isBold: true).toShimmer2(isShow: true),
SizedBox(height: 8.h),
Wrap(
direction: Axis.horizontal,
spacing: 3.h,
runSpacing: 4.h,
children: [
AppCustomChipWidget(labelText: "").toShimmer2(isShow: true, width: 16.h),
AppCustomChipWidget(labelText: "").toShimmer2(isShow: true, width: 16.h),
],
),
],
),
),
],
),
],
),
),
),
).paddingSymmetrical(24.h, 0.h)
: contactUsVM.isHMGHospitalsListSelected
// ? contactUsVM.hmgHospitalsLocationsList.isNotEmpty
? AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 500),
child: SlideAnimation(
verticalOffset: 100.0,
child: FadeInAnimation(
child: AnimatedContainer(
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true),
child: FindUsItemCard(
getHMGLocationsModel: contactUsVM.hmgHospitalsLocationsList[index],
),
).paddingSymmetrical(24.h, 0.h),
),
),
)
: AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 500),
child: SlideAnimation(
verticalOffset: 100.0,
child: FadeInAnimation(
child: AnimatedContainer(
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true),
child: FindUsItemCard(
getHMGLocationsModel: contactUsVM.hmgPharmacyLocationsList[index],
),
).paddingSymmetrical(24.h, 0.h),
),
),
);
// : Utils.getNoDataWidget(
// context,
// noDataText: "No any locations yet.".needTranslation,
// );
},
separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h),
),
SizedBox(height: 24.h),
// FindUsItemCard(),
// FindUsItemCard(),
// FindUsItemCard(),
],
);
}),
),
);
}
}

@ -0,0 +1,27 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.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';
class LiveChatPage extends StatelessWidget {
const LiveChatPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: Column(
children: [
Expanded(
child: CollapsingListView(
title: LocaleKeys.liveChat.tr(),
child: SingleChildScrollView(),
),
),
Container()
],
),
);
}
}

@ -0,0 +1,106 @@
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/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/contact_us/models/resp_models/get_hmg_locations.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/chip/app_custom_chip_widget.dart';
import 'package:maps_launcher/maps_launcher.dart';
import 'package:url_launcher/url_launcher.dart';
class FindUsItemCard extends StatelessWidget {
FindUsItemCard({super.key, required this.getHMGLocationsModel});
late AppState appState;
GetHMGLocationsModel getHMGLocationsModel;
@override
Widget build(BuildContext context) {
appState = getIt.get<AppState>();
return DecoratedBox(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.r,
hasShadow: false,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 8.h,
children: [hospitalName, distanceInfo],
),
),
],
).paddingSymmetrical(16.h, 16.h),
);
}
Widget get hospitalName => Row(
children: [
Image.network(
getHMGLocationsModel.projectImageURL ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png",
width: 40.h,
height: 40.h,
fit: BoxFit.cover,
).circle(100).toShimmer2(isShow: false).paddingOnly(right: 10),
Expanded(
child: Text(
getHMGLocationsModel.locationName!,
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 16,
color: AppColors.blackColor,
),
),
)
],
);
Widget get distanceInfo => Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
AppCustomChipWidget(
labelText: "${getHMGLocationsModel.distanceInKilometers ?? ""} km".needTranslation,
icon: AppAssets.location_red,
iconColor: AppColors.primaryRedColor,
backgroundColor: AppColors.secondaryLightRedColor,
textColor: AppColors.errorColor,
),
Row(
children: [
AppCustomChipWidget(
labelText: "Get Directions".needTranslation,
icon: AppAssets.directions_icon,
iconColor: AppColors.whiteColor,
backgroundColor: AppColors.textColor.withValues(alpha: 0.8),
textColor: AppColors.whiteColor,
onChipTap: () {
MapsLauncher.launchCoordinates(double.parse(getHMGLocationsModel.latitude ?? "0.0"), double.parse(getHMGLocationsModel.longitude ?? "0.0"), getHMGLocationsModel.locationName!);
},
),
SizedBox(width: 4.w),
AppCustomChipWidget(
labelText: LocaleKeys.callNow.tr(),
icon: AppAssets.call_fill,
iconColor: AppColors.whiteColor,
backgroundColor: AppColors.primaryRedColor.withValues(alpha: 1.0),
textColor: AppColors.whiteColor,
onChipTap: () {
launchUrl(Uri.parse("tel://" + "${getHMGLocationsModel.phoneNumber}"));
},
),
],
),
],
);
}

@ -441,7 +441,26 @@ class CallAmbulancePage extends StatelessWidget {
title:
LocaleKeys.selectHospital.tr(),
context,
child: HospitalBottomSheetBody(),
child: Consumer<EmergencyServicesViewModel>(
builder:(_,vm,__)=> HospitalBottomSheetBody(
displayList: vm.displayList,
onFacilityClicked: (value) {
vm.setSelectedFacility(value);
vm.getDisplayList();
},
onHospitalClicked: (hospital) {
Navigator.pop(context);
vm.setSelectedHospital(hospital);
},
onHospitalSearch: (value) {
vm.searchHospitals(value ?? "");
},
selectedFacility:
vm.selectedFacility,
hmcCount: vm.hmcCount,
hmgCount: vm.hmgCount,
),
),
isFullScreen: false,
isCloseButtonVisible: true,
hasBottomPadding: false,

@ -2,12 +2,17 @@ import 'package:easy_localization/easy_localization.dart'
show tr, StringTranslateExtension;
import 'package:flutter/material.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/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/book_appointments/book_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/emergency_services/emergency_services_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/features/my_appointments/models/resp_models/hospital_model.dart' show HospitalsModel;
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/hospital_bottom_sheet/hospital_list_items.dart';
@ -20,8 +25,25 @@ import 'package:provider/provider.dart';
class HospitalBottomSheetBody extends StatelessWidget {
final TextEditingController searchText = TextEditingController();
final Debouncer debouncer = Debouncer(milliseconds: 500);
HospitalBottomSheetBody({super.key});
final int hmcCount;
final int hmgCount;
final List<HospitalsModel>? displayList;
final FacilitySelection selectedFacility;
final Function(FacilitySelection) onFacilityClicked;
final Function(HospitalsModel) onHospitalClicked;
final Function(String) onHospitalSearch;
HospitalBottomSheetBody(
{super.key,
required this.hmcCount,
required this.hmgCount,
this.displayList,
required this.selectedFacility,
required this.onFacilityClicked,
required this.onHospitalClicked,
required this.onHospitalSearch});
@override
Widget build(BuildContext context) {
@ -29,13 +51,14 @@ class HospitalBottomSheetBody extends StatelessWidget {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextInputWidget(
labelText: LocaleKeys.search.tr(),
hintText: LocaleKeys.searchHospital.tr(),
controller: searchText,
onChange: (value) {
debouncer.run(() {
onHospitalSearch(value ?? "");
});
},
isEnable: true,
prefix: null,
@ -51,30 +74,31 @@ class HospitalBottomSheetBody extends StatelessWidget {
),
SizedBox(height: 24.h),
TypeSelectionWidget(
hmcCount: "0",
hmgCount: "0",
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(
height: MediaQuery.sizeOf(context).height * .4,
child: ListView.separated(
itemBuilder: (_, index)
{
var hospital = null;
var hospital = displayList?[index];
return HospitalListItem(
hospitalData: hospital,
isLocationEnabled: false,
).onPress(() {
hospitalData: Utils.convertToPatientDoctorAppointmentList(hospital),
isLocationEnabled: true,
).onPress(() {
onHospitalClicked(hospital!);
});},
separatorBuilder: (_, __) => SizedBox(
height: 16.h,
),
itemCount: 0,
))
height: 16.h,
),
itemCount: displayList?.length ?? 0,
))
],
);
}

@ -12,10 +12,15 @@ import 'package:provider/provider.dart' show Consumer;
class TypeSelectionWidget extends StatelessWidget {
final String hmcCount;
final String hmgCount;
final Function(String) onitemClicked;
final FacilitySelection selectedFacility;
final Function(FacilitySelection) onitemClicked;
const TypeSelectionWidget(
{super.key, required this.hmcCount, required this.hmgCount, required this.onitemClicked});
{super.key,
required this.hmcCount,
required this.hmgCount,
required this.onitemClicked,
required this.selectedFacility});
@override
Widget build(BuildContext context) {
@ -28,51 +33,69 @@ class TypeSelectionWidget extends StatelessWidget {
labelText: "All Facilities".needTranslation,
shape: RoundedRectangleBorder(
side: BorderSide(
color: AppColors.errorColor
,
color: selectedFacility == FacilitySelection.ALL
? AppColors.errorColor
: AppColors.chipBorderColorOpacity20,
width: 1,
),
borderRadius: BorderRadius.circular(10)),
backgroundColor:
AppColors.secondaryLightRedColor
,
textColor: AppColors.errorColor
,
selectedFacility == FacilitySelection.ALL
?AppColors.secondaryLightRedColor: AppColors.whiteColor,
textColor: selectedFacility == FacilitySelection.ALL
? AppColors.errorColor:AppColors.blackColor
,
).onPress((){
onitemClicked(FacilitySelection.ALL.name);
}),
AppCustomChipWidget(
icon: AppAssets.hmg,
iconHasColor: false,
labelText: "Hospitals".needTranslation,
shape: RoundedRectangleBorder(
side: BorderSide(
color: AppColors.chipBorderColorOpacity20,
width: 1,
),
borderRadius: BorderRadius.circular(10)),
backgroundColor:
AppColors.whiteColor,
textColor: AppColors.blackColor,
).onPress((){
onitemClicked(FacilitySelection.HMG.name);
}),
AppCustomChipWidget(
icon: AppAssets.hmc,
iconHasColor: false,
labelText: "Medical Centers".needTranslation,
shape: RoundedRectangleBorder(
side: BorderSide(
color:AppColors.chipBorderColorOpacity20,
width: 1,
),
borderRadius: BorderRadius.circular(10)),
backgroundColor:
AppColors.whiteColor,
textColor: AppColors.blackColor,
).onPress((){
onitemClicked(FacilitySelection.HMC.name);
onitemClicked(FacilitySelection.ALL);
}),
Visibility(
visible: hmgCount != "0",
child: AppCustomChipWidget(
icon: AppAssets.hmg,
iconHasColor: false,
labelText: "Hospitals".needTranslation,
shape: RoundedRectangleBorder(
side: BorderSide(
color: selectedFacility == FacilitySelection.HMG
? AppColors.errorColor
: AppColors.chipBorderColorOpacity20,
width: 1,
),
borderRadius: BorderRadius.circular(10)),
backgroundColor:
selectedFacility == FacilitySelection.HMG
?AppColors.secondaryLightRedColor: AppColors.whiteColor,
textColor: selectedFacility == FacilitySelection.HMG
? AppColors.errorColor
: AppColors.blackColor,
).onPress((){
onitemClicked(FacilitySelection.HMG);
}),
),
Visibility(
visible: hmcCount != "0",
child: AppCustomChipWidget(
icon: AppAssets.hmc,
iconHasColor: false,
labelText: "Medical Centers".needTranslation,
shape: RoundedRectangleBorder(
side: BorderSide(
color: selectedFacility == FacilitySelection.HMC
? AppColors.errorColor
: AppColors.chipBorderColorOpacity20,
width: 1,
),
borderRadius: BorderRadius.circular(10)),
backgroundColor:
selectedFacility == FacilitySelection.HMC
?AppColors.secondaryLightRedColor: AppColors.whiteColor,
textColor: selectedFacility == FacilitySelection.HMC
? AppColors.errorColor
: AppColors.blackColor,
).onPress((){
onitemClicked(FacilitySelection.HMC);
}),
),
],
);
}

@ -34,7 +34,7 @@ class EmergencyServicesPage extends StatelessWidget {
locationUtils = getIt.get<LocationUtils>();
locationUtils!.isShowConfirmDialog = true;
return CollapsingListView(
title: "Emergency Services".needTranslation,
title: LocaleKeys.emergencyServices.tr(),
requests: () {},
child: Padding(
padding: EdgeInsets.all(24.h),
@ -57,7 +57,7 @@ class EmergencyServicesPage extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Call Ambulance".needTranslation.toText16(isBold: true, color: AppColors.blackColor),
"Request and ambulance in emergency from home or hospital".needTranslation.toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500),
"Request an ambulance in emergency from home or hospital".needTranslation.toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500),
],
),
),
@ -101,8 +101,7 @@ class EmergencyServicesPage extends StatelessWidget {
height: 120.h,
fit: BoxFit.contain),
SizedBox(height: 8.h),
"Confirmation".needTranslation.toText28(
color: AppColors.whiteColor, isBold: true),
LocaleKeys.confirm.tr().toText28(color: AppColors.whiteColor, isBold: true),
SizedBox(height: 8.h),
"Are you sure you want to call an ambulance?"
.needTranslation
@ -234,7 +233,7 @@ class EmergencyServicesPage extends StatelessWidget {
),
Lottie.asset(AppAnimations.ambulance_alert, repeat: false, reverse: false, frameRate: FrameRate(60), width: 120.h, height: 120.h, fit: BoxFit.contain),
SizedBox(height: 8.h),
"Confirmation".needTranslation.toText28(color: AppColors.whiteColor, isBold: true),
LocaleKeys.confirm.tr().toText28(color: AppColors.whiteColor, isBold: true),
SizedBox(height: 8.h),
"Are you sure you want to call Rapid Response Team (RRT)?".needTranslation.toText14(color: AppColors.whiteColor, weight: FontWeight.w500),
SizedBox(height: 24.h),
@ -257,7 +256,93 @@ class EmergencyServicesPage extends StatelessWidget {
callBackFunc: () {},
);
});
},
backgroundColor: AppColors.whiteColor,
borderColor: AppColors.whiteColor,
textColor: AppColors.primaryRedColor,
icon: AppAssets.checkmark_icon,
iconColor: AppColors.primaryRedColor,
),
SizedBox(height: 8.h),
],
),
),
),
isFullScreen: false,
isCloseButtonVisible: false,
hasBottomPadding: false,
backgroundColor: AppColors.primaryRedColor,
callBackFunc: () {},
);
}),
),
SizedBox(height: 16.h),
Container(
padding: EdgeInsets.all(16.h),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: false,
),
child: Row(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.rrt_icon, width: 40.h, height: 40.h),
SizedBox(width: 12.h),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Emergency Check-In".needTranslation.toText16(isBold: true, color: AppColors.blackColor),
"Prior ER Check-In to skip the line & payment at the reception.".needTranslation.toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500),
],
),
),
SizedBox(width: 12.h),
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: AppColors.whiteColor,
width: 24.h,
height: 24.h,
fit: BoxFit.contain,
).onPress(() {
Navigator.of(context).pop();
}),
],
),
Lottie.asset(AppAnimations.ambulance_alert, 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: AppColors.whiteColor, isBold: true),
SizedBox(height: 8.h),
"Are you sure you want to make ER Check-In?".needTranslation.toText14(color: AppColors.whiteColor, weight: FontWeight.w500),
SizedBox(height: 24.h),
CustomButton(
text: LocaleKeys.confirm.tr(context: context),
onPressed: () async {
Navigator.of(context).pop();
LoaderBottomSheet.showLoader(loadingText: "Checking your ER Appointment status...".needTranslation);
await context.read<EmergencyServicesViewModel>().checkPatientERAdvanceBalance(onSuccess: (dynamic response) {
LoaderBottomSheet.hideLoader();
context.read<EmergencyServicesViewModel>().navigateToEROnlineCheckIn();
});
},
backgroundColor: AppColors.whiteColor,
borderColor: AppColors.whiteColor,

@ -0,0 +1,180 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_nfc_kit/flutter_nfc_kit.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/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/emergency_services/emergency_services_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/er_online_checkin/er_online_checkin_select_checkin_bottom_sheet.dart';
import 'package:hmg_patient_app_new/presentation/home/navigation_screen.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/nfc/nfc_reader_sheet.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:provider/provider.dart';
import '../call_ambulance/widgets/HospitalBottomSheetBody.dart';
class ErOnlineCheckinHome extends StatelessWidget {
ErOnlineCheckinHome({super.key});
late EmergencyServicesViewModel emergencyServicesViewModel;
bool _supportsNFC = false;
@override
Widget build(BuildContext context) {
emergencyServicesViewModel = Provider.of<EmergencyServicesViewModel>(context, listen: false);
FlutterNfcKit.nfcAvailability.then((value) {
_supportsNFC = (value == NFCAvailability.available);
});
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: Column(
children: [
Expanded(
child: CollapsingListView(
title: "Emergency Check-In".needTranslation,
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(24.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.immediate_service_icon, width: 58.h, height: 58.h),
SizedBox(width: 18.h),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Online Check-In".needTranslation.toText18(color: AppColors.textColor, isBold: true),
"This service lets patients to register their ER appointment prior to arrival.".needTranslation.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
],
),
),
],
),
],
),
),
),
),
),
CustomButton(
text: emergencyServicesViewModel.patientHasAdvanceERBalance ? LocaleKeys.checkinOption.tr() : LocaleKeys.bookAppo.tr(),
onPressed: () async {
if (emergencyServicesViewModel.patientHasAdvanceERBalance) {
Future.delayed(const Duration(milliseconds: 500), () {
showNfcReader(context, onNcfScan: (String nfcId) {
Future.delayed(const Duration(milliseconds: 100), () async {
print(nfcId);
LoaderBottomSheet.showLoader(loadingText: "Processing check-in...".needTranslation);
await emergencyServicesViewModel.getProjectIDFromNFC(
nfcCode: nfcId,
onSuccess: (value) async {
await emergencyServicesViewModel.autoGenerateInvoiceERClinic(
projectID: value,
onSuccess: (value) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(context,
title: LocaleKeys.onlineCheckIn.tr(),
child: Utils.getSuccessWidget(loadingText: "Your ER Online Check-In has been successfully done. Please proceed to the waiting area.".needTranslation),
callBackFunc: () {
Navigator.pushAndRemoveUntil(
context,
CustomPageRoute(
page: LandingNavigation(),
),
(r) => false);
}, isFullScreen: false);
},
onError: (errMessage) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: "Unexpected error occurred during check-in. Please contact support.".needTranslation),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
},
onError: (err) {});
});
}, onCancel: () {});
});
// showCommonBottomSheetWithoutHeight(context,
// title: LocaleKeys.onlineCheckIn.tr(),
// child: ErOnlineCheckinSelectCheckinBottomSheet(
// projectID: 15,
// ),
// callBackFunc: () {},
// isFullScreen: false);
} else {
LoaderBottomSheet.showLoader(loadingText: "Fetching hospitals list...".needTranslation);
await context.read<EmergencyServicesViewModel>().getProjects();
LoaderBottomSheet.hideLoader();
//Project Selection Dropdown
showHospitalBottomSheet(context);
}
},
backgroundColor: emergencyServicesViewModel.patientHasAdvanceERBalance ? AppColors.alertColor : AppColors.primaryRedColor,
borderColor: emergencyServicesViewModel.patientHasAdvanceERBalance ? AppColors.alertColor : AppColors.primaryRedColor,
textColor: AppColors.whiteColor,
fontSize: 16.f,
fontWeight: FontWeight.w500,
borderRadius: 10.r,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 50.h,
icon: emergencyServicesViewModel.patientHasAdvanceERBalance ? AppAssets.appointment_checkin_icon : AppAssets.bookAppoBottom,
iconColor: AppColors.whiteColor,
iconSize: 18.h,
).paddingSymmetrical(24.h, 24.h),
],
),
);
}
showHospitalBottomSheet(BuildContext context) {
showCommonBottomSheetWithoutHeight(
title: LocaleKeys.selectHospital.tr(),
context,
child: Consumer<EmergencyServicesViewModel>(
builder: (_, vm, __) => HospitalBottomSheetBody(
displayList: vm.displayList,
onFacilityClicked: (value) {
vm.setSelectedFacility(value);
vm.getDisplayList();
},
onHospitalClicked: (hospital) async {
Navigator.pop(context);
vm.setSelectedHospital(hospital);
LoaderBottomSheet.showLoader(loadingText: "Fetching payment information...".needTranslation);
await vm.getPatientERPaymentInformation(onSuccess: (response) {
LoaderBottomSheet.hideLoader();
vm.navigateToEROnlineCheckInPaymentPage();
});
},
onHospitalSearch: (value) {
vm.searchHospitals(value ?? "");
},
selectedFacility: vm.selectedFacility,
hmcCount: vm.hmcCount,
hmgCount: vm.hmgCount,
),
),
isFullScreen: false,
isCloseButtonVisible: true,
hasBottomPadding: false,
backgroundColor: AppColors.bottomSheetBgColor,
callBackFunc: () {},
);
}
}

@ -0,0 +1,177 @@
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/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/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/emergency_services/emergency_services_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/my_appointments_page.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/er_online_checkin/er_online_checkin_payment_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';
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:provider/provider.dart';
class ErOnlineCheckinPaymentDetailsPage extends StatelessWidget {
ErOnlineCheckinPaymentDetailsPage({super.key});
late AppState appState;
late EmergencyServicesViewModel emergencyServicesViewModel;
@override
Widget build(BuildContext context) {
appState = getIt.get<AppState>();
emergencyServicesViewModel = Provider.of<EmergencyServicesViewModel>(context, listen: false);
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: Column(
children: [
Expanded(
child: CollapsingListView(
title: "Emergency Check-In".needTranslation,
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(24.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
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: [
"ER Visit Details".needTranslation.toText18(color: AppColors.textColor, isBold: true),
SizedBox(height: 24.h),
Row(
children: [
"${appState.getAuthenticatedUser()!.firstName!} ${appState.getAuthenticatedUser()!.lastName!}".toText14(color: AppColors.textColor, isBold: true),
],
),
SizedBox(height: 12.h),
Wrap(
direction: Axis.horizontal,
spacing: 6.w,
runSpacing: 6.h,
children: [
AppCustomChipWidget(
labelText: "File No.: ${appState.getAuthenticatedUser()!.patientId!.toString()}",
labelPadding: EdgeInsetsDirectional.only(start: 4.w, end: 4.w),
),
AppCustomChipWidget(
labelText: "ER Clinic".needTranslation,
labelPadding: EdgeInsetsDirectional.only(start: 4.w, end: 4.w),
),
AppCustomChipWidget(
labelText: emergencyServicesViewModel.selectedHospital!.name,
labelPadding: EdgeInsetsDirectional.only(start: 4.w, end: 4.w),
),
AppCustomChipWidget(
icon: AppAssets.calendar,
labelText: DateUtil.formatDateToDate(DateTime.now(), false),
labelPadding: EdgeInsetsDirectional.only(start: 4.w, end: 4.w),
),
],
),
SizedBox(height: 12.h),
],
),
),
)
],
),
),
),
),
),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.r,
hasShadow: true,
),
child: SizedBox(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"Amount before tax".needTranslation.toText18(isBold: true),
Utils.getPaymentAmountWithSymbol(emergencyServicesViewModel.erOnlineCheckInPaymentDetailsResponse.patientShare.toString().toText16(isBold: true), AppColors.blackColor, 13,
isSaudiCurrency: true),
],
),
SizedBox(height: 4.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(child: "".toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor)),
"VAT 15% (${emergencyServicesViewModel.erOnlineCheckInPaymentDetailsResponse.patientTaxAmount})"
.needTranslation
.toText14(isBold: true, color: AppColors.greyTextColor, letterSpacing: -1),
],
),
SizedBox(height: 18.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
width: 150.h,
child: Utils.getPaymentMethods(),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Utils.getPaymentAmountWithSymbol(
emergencyServicesViewModel.erOnlineCheckInPaymentDetailsResponse.patientShareWithTax.toString().toText24(isBold: true), AppColors.blackColor, 17,
isSaudiCurrency: true),
],
),
],
)
],
).paddingOnly(left: 16.h, top: 24.h, right: 16.h, bottom: 0.h),
CustomButton(
text: LocaleKeys.payNow.tr(),
onPressed: () {
Navigator.of(context).push(
CustomPageRoute(page: ErOnlineCheckinPaymentPage()),
);
},
backgroundColor: AppColors.infoColor,
borderColor: AppColors.infoColor.withOpacity(0.01),
textColor: AppColors.whiteColor,
fontSize: 16.f,
fontWeight: FontWeight.w500,
borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w),
height: 56.h,
icon: AppAssets.appointment_pay_icon,
iconColor: AppColors.whiteColor,
iconSize: 18.h,
).paddingSymmetrical(16.h, 24.h),
],
),
),
),
],
),
);
}
}

@ -0,0 +1,510 @@
import 'dart:async';
import 'dart:developer';
import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/cache_consts.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/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';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/emergency_services/emergency_services_view_model.dart';
import 'package:hmg_patient_app_new/features/payfort/models/apple_pay_request_insert_model.dart';
import 'package:hmg_patient_app_new/features/payfort/payfort_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/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/in_app_browser/InAppBrowser.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:provider/provider.dart';
import 'package:smooth_corner/smooth_corner.dart';
class ErOnlineCheckinPaymentPage extends StatefulWidget {
ErOnlineCheckinPaymentPage({super.key});
@override
State<ErOnlineCheckinPaymentPage> createState() => _ErOnlineCheckinPaymentPageState();
}
class _ErOnlineCheckinPaymentPageState extends State<ErOnlineCheckinPaymentPage> {
late PayfortViewModel payfortViewModel;
late EmergencyServicesViewModel emergencyServicesViewModel;
late AppState appState;
MyInAppBrowser? browser;
String selectedPaymentMethod = "";
String transID = "";
bool isShowTamara = false;
String tamaraPaymentStatus = "";
String tamaraOrderID = "";
@override
void initState() {
scheduleMicrotask(() {
payfortViewModel.initPayfortViewModel();
// payfortViewModel.getTamaraInstallmentsDetails().then((val) {
// if (emergencyServicesViewModel.erOnlineCheckInPaymentDetailsResponse.patientShareWithTax! >= payfortViewModel.getTamaraInstallmentsDetailsResponseModel!.minLimit!.amount! &&
// emergencyServicesViewModel.erOnlineCheckInPaymentDetailsResponse.patientShareWithTax! <= payfortViewModel.getTamaraInstallmentsDetailsResponseModel!.maxLimit!.amount!) {
// setState(() {
// isShowTamara = true;
// });
// }
// });
});
super.initState();
}
@override
Widget build(BuildContext context) {
appState = getIt.get<AppState>();
payfortViewModel = Provider.of<PayfortViewModel>(context, listen: false);
emergencyServicesViewModel = Provider.of<EmergencyServicesViewModel>(context, listen: false);
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: Column(
children: [
Expanded(
child: CollapsingListView(
title: "Emergency Check-In".needTranslation,
child: SingleChildScrollView(
child: Column(
children: [
SizedBox(height: 24.h),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: false,
),
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset(AppAssets.mada, width: 72.h, height: 25.h),
SizedBox(height: 16.h),
"Mada".needTranslation.toText16(isBold: true),
],
),
SizedBox(width: 8.h),
const Spacer(),
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),
).paddingSymmetrical(24.h, 0.h).onPress(() {
selectedPaymentMethod = "MADA";
openPaymentURL("mada");
}),
SizedBox(height: 16.h),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: false,
),
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Image.asset(AppAssets.visa, width: 50.h, height: 50.h),
SizedBox(width: 8.h),
Image.asset(AppAssets.Mastercard, width: 40.h, height: 40.h),
],
),
SizedBox(height: 16.h),
"Visa or Mastercard".needTranslation.toText16(isBold: true),
],
),
SizedBox(width: 8.h),
const Spacer(),
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),
).paddingSymmetrical(24.h, 0.h).onPress(() {
selectedPaymentMethod = "VISA";
openPaymentURL("visa");
}),
SizedBox(height: 16.h),
isShowTamara
? Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: false,
),
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset(AppAssets.tamara_en, width: 72.h, height: 25.h),
SizedBox(height: 16.h),
"Tamara".needTranslation.toText16(isBold: true),
],
),
SizedBox(width: 8.h),
const Spacer(),
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),
).paddingSymmetrical(24.h, 0.h).onPress(() {
selectedPaymentMethod = "TAMARA";
openPaymentURL("tamara");
})
: SizedBox.shrink(),
],
),
),
),
),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.h,
hasShadow: false,
),
child: Consumer<PayfortViewModel>(builder: (context, payfortVM, child) {
//TODO: Need to add loading state & animation for Apple Pay Configuration
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
(emergencyServicesViewModel.erOnlineCheckInPaymentDetailsResponse.isCash ?? true)
? Container(
height: 50.h,
decoration: ShapeDecoration(
color: AppColors.secondaryLightRedBorderColor,
shape: SmoothRectangleBorder(
borderRadius: BorderRadius.only(topLeft: Radius.circular(24), topRight: Radius.circular(24)),
smoothness: 1,
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"Insurance expired or inactive".needTranslation.toText14(color: AppColors.primaryRedColor, weight: FontWeight.w500).paddingSymmetrical(24.h, 0.h),
CustomButton(
text: LocaleKeys.updateInsurance.tr(context: context),
onPressed: () {
Navigator.of(context).push(
CustomPageRoute(
page: InsuranceHomePage(),
),
);
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.secondaryLightRedBorderColor,
textColor: AppColors.whiteColor,
fontSize: 10,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(15, 0, 15, 0),
height: 30.h,
).paddingSymmetrical(24.h, 0.h),
],
),
)
: const SizedBox(),
SizedBox(height: 24.h),
"Total amount to pay".needTranslation.toText18(isBold: true).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 17.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"Amount before tax".needTranslation.toText14(isBold: true),
Utils.getPaymentAmountWithSymbol(emergencyServicesViewModel.erOnlineCheckInPaymentDetailsResponse.patientShare.toString().toText16(isBold: true), AppColors.blackColor, 13,
isSaudiCurrency: true),
],
).paddingSymmetrical(24.h, 0.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"VAT 15%".needTranslation.toText14(isBold: true, color: AppColors.greyTextColor),
Utils.getPaymentAmountWithSymbol(
emergencyServicesViewModel.erOnlineCheckInPaymentDetailsResponse.patientTaxAmount.toString().toText14(isBold: true, color: AppColors.greyTextColor), AppColors.greyTextColor, 13,
isSaudiCurrency: true),
],
).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 17.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"".needTranslation.toText14(isBold: true),
Utils.getPaymentAmountWithSymbol(emergencyServicesViewModel.erOnlineCheckInPaymentDetailsResponse.patientShareWithTax.toString().toText24(isBold: true), AppColors.blackColor, 17,
isSaudiCurrency: true),
],
).paddingSymmetrical(24.h, 0.h),
Platform.isIOS
? Utils.buildSvgWithAssets(
icon: AppAssets.apple_pay_button,
width: 200.h,
height: 80.h,
fit: BoxFit.contain,
).paddingSymmetrical(24.h, 0.h).onPress(() {
if (Utils.havePrivilege(103)) {
startApplePay();
} else {
openPaymentURL("ApplePay");
}
})
: SizedBox(height: 12.h),
SizedBox(height: 12.h),
],
);
}),
),
],
),
);
}
openPaymentURL(String paymentMethod) {
browser = MyInAppBrowser(onExitCallback: onBrowserExit, onLoadStartCallback: onBrowserLoadStart, context: context);
transID = Utils.getAdvancePaymentTransID(
emergencyServicesViewModel.selectedHospital!.iD,
appState.getAuthenticatedUser()!.patientId!,
);
//TODO: Need to pass dynamic params to the payment request instead of static values
browser?.openPaymentBrowser(
emergencyServicesViewModel.erOnlineCheckInPaymentDetailsResponse.patientShareWithTax!,
"ER Online Check-In Payment",
transID,
emergencyServicesViewModel.selectedHospital!.iD.toString(),
"CustID_${appState.getAuthenticatedUser()!.patientId.toString()}@HMG.com",
selectedPaymentMethod,
appState.getAuthenticatedUser()!.patientType.toString(),
"${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}",
appState.getAuthenticatedUser()!.patientId.toString(),
appState.getAuthenticatedUser()!,
browser!,
false,
"3",
"",
context,
null,
0,
10,
0,
"3");
}
startApplePay() async {
// showCommonBottomSheet(context,
// child: Utils.getLoadingWidget(), callBackFunc: (str) {}, title: "", height: ResponsiveExtension.screenHeight * 0.3, isCloseButtonVisible: false, isDismissible: false, isFullScreen: false);
LoaderBottomSheet.showLoader();
transID = Utils.getAdvancePaymentTransID(
emergencyServicesViewModel.selectedHospital!.iD,
appState.getAuthenticatedUser()!.patientId!,
);
ApplePayInsertRequest applePayInsertRequest = ApplePayInsertRequest();
await payfortViewModel.getPayfortConfigurations(serviceId: ServiceTypeEnum.erOnlineCheckIn.getIdFromServiceEnum(), projectId: emergencyServicesViewModel.selectedHospital!.iD);
applePayInsertRequest.clientRequestID = transID;
applePayInsertRequest.clinicID = 10;
applePayInsertRequest.currency = appState.getAuthenticatedUser()!.outSa! == 0 ? "SAR" : "AED";
applePayInsertRequest.customerEmail = "CustID_${appState.getAuthenticatedUser()!.patientId.toString()}@HMG.com";
applePayInsertRequest.customerID = appState.getAuthenticatedUser()!.patientId.toString();
applePayInsertRequest.customerName = "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}";
applePayInsertRequest.deviceToken = await Utils.getStringFromPrefs(CacheConst.pushToken);
applePayInsertRequest.voipToken = await Utils.getStringFromPrefs(CacheConst.voipToken);
applePayInsertRequest.doctorID = 0;
applePayInsertRequest.projectID = emergencyServicesViewModel.selectedHospital!.iD.toString();
applePayInsertRequest.serviceID = ServiceTypeEnum.erOnlineCheckIn.getIdFromServiceEnum().toString();
applePayInsertRequest.channelID = 3;
applePayInsertRequest.patientID = appState.getAuthenticatedUser()!.patientId.toString();
applePayInsertRequest.patientTypeID = appState.getAuthenticatedUser()!.patientType;
applePayInsertRequest.patientOutSA = appState.getAuthenticatedUser()!.outSa;
applePayInsertRequest.appointmentDate = null;
applePayInsertRequest.appointmentNo = 0;
applePayInsertRequest.orderDescription = "ER Online Check-In Payment";
applePayInsertRequest.liveServiceID = "0";
applePayInsertRequest.latitude = "0.0";
applePayInsertRequest.longitude = "0.0";
applePayInsertRequest.amount = emergencyServicesViewModel.erOnlineCheckInPaymentDetailsResponse.patientShareWithTax!.toString();
applePayInsertRequest.isSchedule = "0";
applePayInsertRequest.language = appState.isArabic() ? 'ar' : 'en';
applePayInsertRequest.languageID = appState.isArabic() ? 1 : 2;
applePayInsertRequest.userName = appState.getAuthenticatedUser()!.patientId;
applePayInsertRequest.responseContinueURL = "http://hmg.com/Documents/success.html";
applePayInsertRequest.backClickUrl = "http://hmg.com/Documents/success.html";
applePayInsertRequest.paymentOption = "ApplePay";
applePayInsertRequest.isMobSDK = true;
applePayInsertRequest.merchantReference = transID;
applePayInsertRequest.merchantIdentifier = payfortViewModel.payfortProjectDetailsRespModel!.merchantIdentifier;
applePayInsertRequest.commandType = "PURCHASE";
applePayInsertRequest.signature = payfortViewModel.payfortProjectDetailsRespModel!.signature;
applePayInsertRequest.accessCode = payfortViewModel.payfortProjectDetailsRespModel!.accessCode;
applePayInsertRequest.shaRequestPhrase = payfortViewModel.payfortProjectDetailsRespModel!.shaRequest;
applePayInsertRequest.shaResponsePhrase = payfortViewModel.payfortProjectDetailsRespModel!.shaResponse;
applePayInsertRequest.returnURL = "";
//TODO: Need to pass dynamic params to the Apple Pay instead of static values
await payfortViewModel.applePayRequestInsert(applePayInsertRequest: applePayInsertRequest).then((value) {
payfortViewModel.paymentWithApplePay(
customerName: "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}",
// customerEmail: projectViewModel.authenticatedUserObject.user.emailAddress,
customerEmail: "CustID_${appState.getAuthenticatedUser()!.patientId.toString()}@HMG.com",
orderDescription: "Appointment Payment",
orderAmount: double.parse(emergencyServicesViewModel.erOnlineCheckInPaymentDetailsResponse.patientShareWithTax!.toString()),
merchantReference: transID,
merchantIdentifier: payfortViewModel.payfortProjectDetailsRespModel!.merchantIdentifier,
applePayAccessCode: payfortViewModel.payfortProjectDetailsRespModel!.accessCode,
applePayShaRequestPhrase: payfortViewModel.payfortProjectDetailsRespModel!.shaRequest,
currency: appState.getAuthenticatedUser()!.outSa! == 0 ? "SAR" : "AED",
onFailed: (failureResult) async {
log("failureResult: ${failureResult.message.toString()}");
Navigator.of(context).pop();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: failureResult.message.toString()),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
},
onSucceeded: (successResult) async {
log("successResult: ${successResult.responseMessage.toString()}");
selectedPaymentMethod = successResult.paymentOption ?? "VISA";
checkPaymentStatus();
},
);
});
}
void checkPaymentStatus() async {
LoaderBottomSheet.showLoader(loadingText: "Checking payment status, Please wait...".needTranslation);
await payfortViewModel.checkPaymentStatus(
transactionID: transID,
onSuccess: (apiResponse) async {
print(apiResponse.data);
if (payfortViewModel.payfortCheckPaymentStatusResponseModel!.responseMessage!.toLowerCase() == "success") {
if (emergencyServicesViewModel.isERBookAppointment) {
await emergencyServicesViewModel.ER_CreateAdvancePayment(
paymentMethodName: selectedPaymentMethod,
paymentReference: payfortViewModel.payfortCheckPaymentStatusResponseModel!.fortId!,
onSuccess: (value) async {
await emergencyServicesViewModel.addAdvanceNumberRequest(
advanceNumber: value,
paymentReference: payfortViewModel.payfortCheckPaymentStatusResponseModel!.fortId!,
appointmentNo: "0",
onSuccess: (val) {
LoaderBottomSheet.hideLoader();
if (emergencyServicesViewModel.isERBookAppointment) {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getSuccessWidget(loadingText: "Your appointment has been booked successfully. Please perform Check-In once you arrive at the hospital.".needTranslation),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
} else {}
});
});
} else {}
} else {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: "Payment Failed! Please try again.".needTranslation),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
}
});
}
onBrowserLoadStart(String url) {
print("onBrowserLoadStart");
print(url);
if (selectedPaymentMethod == "tamara") {
if (Platform.isAndroid) {
Uri uri = new Uri.dataFromString(url);
tamaraPaymentStatus = uri.queryParameters['status']!;
tamaraOrderID = uri.queryParameters['AuthorizePaymentId']!;
} else {
Uri uri = new Uri.dataFromString(url);
tamaraPaymentStatus = uri.queryParameters['paymentStatus']!;
tamaraOrderID = uri.queryParameters['orderId']!;
}
}
// if(selectedPaymentMethod != "TAMARA") {
MyInAppBrowser.successURLS.forEach((element) {
if (url.contains(element)) {
browser?.close();
MyInAppBrowser.isPaymentDone = true;
return;
}
});
// }
// if(selectedPaymentMethod != "TAMARA") {
MyInAppBrowser.errorURLS.forEach((element) {
if (url.contains(element)) {
browser?.close();
MyInAppBrowser.isPaymentDone = false;
return;
}
});
// }
}
onBrowserExit(bool isPaymentMade) async {
checkPaymentStatus();
}
}

@ -0,0 +1,169 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_nfc_kit/flutter_nfc_kit.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/common_models/privilege/ProjectDetailListModel.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';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/my_appointments_page.dart';
import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:barcode_scan2/barcode_scan2.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
import 'package:hmg_patient_app_new/widgets/nfc/nfc_reader_sheet.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
class ErOnlineCheckinSelectCheckinBottomSheet extends StatelessWidget {
ErOnlineCheckinSelectCheckinBottomSheet({super.key, required this.projectID});
bool _supportsNFC = false;
int projectID = 0;
late LocationUtils locationUtils;
late AppState appState;
ProjectDetailListModel projectDetailListModel = ProjectDetailListModel();
@override
Widget build(BuildContext context) {
appState = getIt.get<AppState>();
FlutterNfcKit.nfcAvailability.then((value) {
_supportsNFC = (value == NFCAvailability.available);
});
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
checkInOptionCard(
AppAssets.checkin_location_icon,
"Live Location".needTranslation,
"Verify your location to be at hospital to check in".needTranslation,
).onPress(() {
// locationUtils = LocationUtils(
// isShowConfirmDialog: false,
// navigationService: myAppointmentsViewModel.navigationService,
// appState: myAppointmentsViewModel.appState,
// );
locationUtils.getCurrentLocation(onSuccess: (value) {
projectDetailListModel = Utils.getProjectDetailObj(appState, projectID);
double dist = Utils.distance(value.latitude, value.longitude, double.parse(projectDetailListModel.latitude!), double.parse(projectDetailListModel.longitude!)).ceilToDouble() * 1000;
print(dist);
if (dist <= projectDetailListModel.geofenceRadius!) {
sendCheckInRequest(projectDetailListModel.checkInQrCode!, context);
} else {
showCommonBottomSheetWithoutHeight(context,
title: "Error".needTranslation,
child: Utils.getErrorWidget(loadingText: "Please ensure you're within the hospital location to perform online check-in.".needTranslation), callBackFunc: () {
Navigator.of(context).pop();
}, isFullScreen: false);
}
});
}),
SizedBox(height: 16.h),
checkInOptionCard(
AppAssets.checkin_nfc_icon,
"NFC (Near Field Communication)".needTranslation,
"Scan your phone via NFC board to check in".needTranslation,
).onPress(() {
Future.delayed(const Duration(milliseconds: 500), () {
showNfcReader(context, onNcfScan: (String nfcId) {
Future.delayed(const Duration(milliseconds: 100), () {
sendCheckInRequest(nfcId, context);
});
}, onCancel: () {});
});
}),
SizedBox(height: 16.h),
checkInOptionCard(
AppAssets.checkin_qr_icon,
"QR Code".needTranslation,
"Scan QR code with your camera to check in".needTranslation,
).onPress(() async {
String onlineCheckInQRCode = (await BarcodeScanner.scan().then((value) => value.rawContent));
if (onlineCheckInQRCode != "") {
sendCheckInRequest(onlineCheckInQRCode, context);
} else {}
}),
],
);
}
Widget checkInOptionCard(String icon, String title, String subTitle) {
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: false,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Utils.buildSvgWithAssets(icon: icon, width: 40.h, height: 40.h, fit: BoxFit.fill),
SizedBox(height: 16.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
title.toText16(isBold: true, color: AppColors.textColor),
subTitle.toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor),
],
),
),
Transform.flip(
flipX: appState.isArabic(),
child: Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon_small,
iconColor: AppColors.blackColor,
width: 18.h,
height: 13.h,
fit: BoxFit.contain,
),
),
],
),
],
).paddingAll(16.h),
);
}
void sendCheckInRequest(String scannedCode, BuildContext context) async {
showCommonBottomSheet(context,
child: Utils.getLoadingWidget(), callBackFunc: (str) {}, title: "", height: ResponsiveExtension.screenHeight * 0.3, isCloseButtonVisible: false, isDismissible: false, isFullScreen: false);
// await myAppointmentsViewModel.sendCheckInNfcRequest(
// patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel,
// scannedCode: scannedCode,
// checkInType: 2,
// onSuccess: (apiResponse) {
// Navigator.of(context).pop();
// showCommonBottomSheetWithoutHeight(context, title: "Success".needTranslation, child: Utils.getSuccessWidget(loadingText: LocaleKeys.success.tr()), callBackFunc: () {
// Navigator.of(context).pop();
// Navigator.pushAndRemoveUntil(
// context,
// CustomPageRoute(
// page: LandingNavigation(),
// ),
// (r) => false);
// Navigator.of(context).push(
// CustomPageRoute(page: MyAppointmentsPage()),
// );
// }, isFullScreen: false);
// },
// onError: (error) {
// Navigator.of(context).pop();
// showCommonBottomSheetWithoutHeight(context, title: "Error".needTranslation, child: Utils.getErrorWidget(loadingText: error), callBackFunc: () {
// Navigator.of(context).pop();
// }, isFullScreen: false);
// },
// );
}
}

@ -40,8 +40,8 @@ class HospitalListItemAdvancePayment extends StatelessWidget {
child: Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon,
iconColor: AppColors.blackColor,
width: 18,
height: 13,
width: 40.h,
height: 40.h,
fit: BoxFit.contain,
),
),

@ -16,6 +16,7 @@ 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/book_appointments/book_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/emergency_services/emergency_services_view_model.dart';
import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_view_model.dart';
import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_livecare_view_model.dart';
import 'package:hmg_patient_app_new/features/insurance/insurance_view_model.dart';
@ -28,6 +29,8 @@ import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointmen
import 'package:hmg_patient_app_new/presentation/authentication/quick_login.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/book_appointment_page.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/livecare/immediate_livecare_pending_request_page.dart';
import 'package:hmg_patient_app_new/presentation/contact_us/contact_us.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/home/data/landing_page_data.dart';
import 'package:hmg_patient_app_new/presentation/home/widgets/habib_wallet_card.dart';
import 'package:hmg_patient_app_new/presentation/home/widgets/large_service_card.dart';
@ -64,6 +67,7 @@ class _LandingPageState extends State<LandingPage> {
late InsuranceViewModel insuranceViewModel;
late ImmediateLiveCareViewModel immediateLiveCareViewModel;
late BookAppointmentsViewModel bookAppointmentsViewModel;
late EmergencyServicesViewModel emergencyServicesViewModel;
final SwiperController _controller = SwiperController();
@ -93,6 +97,7 @@ class _LandingPageState extends State<LandingPage> {
insuranceViewModel.initInsuranceProvider();
immediateLiveCareViewModel.initImmediateLiveCare();
immediateLiveCareViewModel.getPatientLiveCareHistory();
emergencyServicesViewModel.checkPatientERAdvanceBalance();
}
});
super.initState();
@ -105,6 +110,7 @@ class _LandingPageState extends State<LandingPage> {
prescriptionsViewModel = Provider.of<PrescriptionsViewModel>(context, listen: false);
insuranceViewModel = Provider.of<InsuranceViewModel>(context, listen: false);
immediateLiveCareViewModel = Provider.of<ImmediateLiveCareViewModel>(context, listen: false);
emergencyServicesViewModel = Provider.of<EmergencyServicesViewModel>(context, listen: false);
appState = getIt.get<AppState>();
return PopScope(
canPop: false,
@ -162,11 +168,12 @@ class _LandingPageState extends State<LandingPage> {
);
}),
Utils.buildSvgWithAssets(icon: AppAssets.contact_icon, height: 18.h, width: 18.h).onPress(() {
Navigator.of(context).push(
CustomPageRoute(
page: MedicalFilePage(),
// page: LoginScreen(),
),
showCommonBottomSheetWithoutHeight(
context,
title: LocaleKeys.contactUs.tr(),
child: ContactUs(),
callBackFunc: () {},
isFullScreen: false,
);
}),
],
@ -296,6 +303,8 @@ class _LandingPageState extends State<LandingPage> {
).paddingSymmetrical(24.h, 0.h);
},
),
// Consumer for LiveCare pending request
Consumer<ImmediateLiveCareViewModel>(
builder: (context, immediateLiveCareVM, child) {
return immediateLiveCareVM.patientHasPendingLiveCareRequest
@ -353,6 +362,66 @@ class _LandingPageState extends State<LandingPage> {
: SizedBox(height: 12.h);
},
),
// Consumer for ER Online Check-In pending request
Consumer<EmergencyServicesViewModel>(
builder: (context, emergencyServicesVM, child) {
return emergencyServicesVM.patientHasAdvanceERBalance
? Column(
children: [
SizedBox(height: 4.h),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.r,
hasShadow: true,
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: "ER Online Check-In Request",
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: [
"You have ER Online Check-In Request".needTranslation.toText12(isBold: true),
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: 12.h);
},
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [

@ -0,0 +1,198 @@
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/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/main.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_card.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart';
import 'package:provider/provider.dart';
class EyeMeasurementDetailsPage extends StatelessWidget {
EyeMeasurementDetailsPage({super.key, required this.patientAppointmentHistoryResponseModel});
final PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel;
late BookAppointmentsViewModel bookAppointmentsViewModel;
@override
Widget build(BuildContext context) {
bookAppointmentsViewModel = Provider.of<BookAppointmentsViewModel>(context, listen: false);
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: CollapsingListView(
title: LocaleKeys.eyeMeasurements.tr(),
child: SingleChildScrollView(
child: Consumer<MyAppointmentsViewModel>(builder: (context, myAppointmentsVM, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 16.h),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true),
child: AppointmentCard(
patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel,
myAppointmentsViewModel: myAppointmentsVM,
bookAppointmentsViewModel: bookAppointmentsViewModel,
isLoading: false,
isFromHomePage: false,
isFromMedicalReport: true,
isForEyeMeasurements: true,
),
),
SizedBox(height: 16.h),
CustomTabBar(
activeTextColor: AppColors.primaryRedColor,
activeBackgroundColor: AppColors.primaryRedColor.withValues(alpha: .1),
tabs: [
CustomTabBarModel(null, LocaleKeys.classes.tr()),
CustomTabBarModel(null, LocaleKeys.contactLens.tr()),
],
onTabChange: (index) {
myAppointmentsVM.onEyeMeasurementsTabChanged(index);
},
),
SizedBox(height: 12.h),
getSelectedTabContent(myAppointmentsVM),
],
).paddingSymmetrical(24.w, 0);
}),
),
),
);
}
Widget getSelectedTabContent(MyAppointmentsViewModel myAppointmentsVM) {
switch (myAppointmentsVM.eyeMeasurementsTabSelectedIndex) {
case 0:
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.all(16.h),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.r, hasShadow: true),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.rightEye.tr().toText14(isBold: true),
SizedBox(height: 16.h),
getRow(LocaleKeys.sphere.tr(), '${patientAppointmentHistoryResponseModel.listHISGetGlassPrescription![0].rightEyeSpherical}', '-'),
getRow(LocaleKeys.cylinder.tr(), '${patientAppointmentHistoryResponseModel.listHISGetGlassPrescription![0].rightEyeCylinder}', '-'),
getRow(LocaleKeys.axis.tr(), '${patientAppointmentHistoryResponseModel.listHISGetGlassPrescription![0].rightEyeAxis}', '-'),
getRow(LocaleKeys.prism.tr(), '${patientAppointmentHistoryResponseModel.listHISGetGlassPrescription![0].rightEyePrism}', '-'),
getRow(LocaleKeys.va.tr(), '${patientAppointmentHistoryResponseModel.listHISGetGlassPrescription![0].rightEyeVA}', '-'),
getRow(LocaleKeys.remarks.tr(), '${patientAppointmentHistoryResponseModel.listHISGetGlassPrescription![0].rightEyeRemarks}', '-', isLast: true),
],
),
),
SizedBox(height: 16.h),
Container(
padding: EdgeInsets.all(16.h),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.r, hasShadow: true),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.leftEye.tr().needTranslation.toText14(isBold: true),
SizedBox(height: 16.h),
getRow(LocaleKeys.sphere.tr(), '${patientAppointmentHistoryResponseModel.listHISGetGlassPrescription![0].leftEyeSpherical}', '-'),
getRow(LocaleKeys.cylinder.tr(), '${patientAppointmentHistoryResponseModel.listHISGetGlassPrescription![0].leftEyeCylinder}', '-'),
getRow(LocaleKeys.axis.tr(), '${patientAppointmentHistoryResponseModel.listHISGetGlassPrescription![0].leftEyeAxis}', '-'),
getRow(LocaleKeys.prism.tr(), '${patientAppointmentHistoryResponseModel.listHISGetGlassPrescription![0].leftEyePrism}', '-'),
getRow(LocaleKeys.va.tr(), '${patientAppointmentHistoryResponseModel.listHISGetGlassPrescription![0].leftEyeVA}', '-'),
getRow(LocaleKeys.remarks.tr(), '${patientAppointmentHistoryResponseModel.listHISGetGlassPrescription![0].leftEyeRemarks}', '-', isLast: true),
],
),
),
SizedBox(height: 24.h),
],
);
case 1:
return Column(
children: [
Container(
padding: EdgeInsets.all(16.h),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.r, hasShadow: true),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.rightEye.tr().toText14(isBold: true),
SizedBox(height: 16.h),
getRow(LocaleKeys.brand.tr(), '${patientAppointmentHistoryResponseModel.listHISGetContactLensPrescription![0].brand}', ''),
getRow('B.C', '${patientAppointmentHistoryResponseModel.listHISGetContactLensPrescription![0].baseCurve}', ''),
getRow(LocaleKeys.power.tr(), '${patientAppointmentHistoryResponseModel.listHISGetContactLensPrescription![0].power}', ''),
getRow(LocaleKeys.diameter.tr(), '${patientAppointmentHistoryResponseModel.listHISGetContactLensPrescription![0].diameter}', ''),
getRow('OZ', '${patientAppointmentHistoryResponseModel.listHISGetContactLensPrescription![0].oZ}', ''),
getRow('CT', '${patientAppointmentHistoryResponseModel.listHISGetContactLensPrescription![0].cT}', ''),
getRow('Blend', '${patientAppointmentHistoryResponseModel.listHISGetContactLensPrescription![0].blend}', ''),
getRow(LocaleKeys.remarks.tr(), '${patientAppointmentHistoryResponseModel.listHISGetContactLensPrescription![0].remarks}', '', isLast: true),
],
),
),
SizedBox(height: 16.h),
Container(
padding: EdgeInsets.all(16.h),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.r, hasShadow: true),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.leftEye.tr().needTranslation.toText14(isBold: true),
SizedBox(height: 16.h),
getRow(LocaleKeys.brand.tr(), '${patientAppointmentHistoryResponseModel.listHISGetContactLensPrescription![1].brand}', ''),
getRow('B.C', '${patientAppointmentHistoryResponseModel.listHISGetContactLensPrescription![1].baseCurve}', ''),
getRow(LocaleKeys.power.tr(), '${patientAppointmentHistoryResponseModel.listHISGetContactLensPrescription![1].power}', ''),
getRow(LocaleKeys.diameter.tr(), '${patientAppointmentHistoryResponseModel.listHISGetContactLensPrescription![1].diameter}', ''),
getRow('OZ', '${patientAppointmentHistoryResponseModel.listHISGetContactLensPrescription![1].oZ}', ''),
getRow('CT', '${patientAppointmentHistoryResponseModel.listHISGetContactLensPrescription![1].cT}', ''),
getRow('Blend', '${patientAppointmentHistoryResponseModel.listHISGetContactLensPrescription![1].blend}', ''),
getRow(LocaleKeys.remarks.tr(), '${patientAppointmentHistoryResponseModel.listHISGetContactLensPrescription![1].remarks}', '', isLast: true),
],
),
),
SizedBox(height: 24.h),
],
);
default:
return Container();
}
}
Widget getRow(String title, String val1, String val2, {bool isLast = false}) => Padding(
padding: EdgeInsets.only(left: 8.w, right: 8.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.all(8.h),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(flex: 2, child: title.toText11(weight: FontWeight.w500)),
Expanded(
flex: 2,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
SizedBox(width: 120.w, child: (val1 == 'null' ? '-' : val1).toText10(isBold: true, textOverflow: TextOverflow.clip)),
(val2 == 'null' ? '-' : val2).toText10(isBold: true, textOverflow: TextOverflow.ellipsis),
],
),
)
],
),
),
isLast
? Container(
height: 4,
)
: Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 2.h)
],
),
);
}

@ -0,0 +1,90 @@
import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.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/book_appointments/book_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_card.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:provider/provider.dart';
class EyeMeasurementsAppointmentsPage extends StatelessWidget {
EyeMeasurementsAppointmentsPage({super.key});
late BookAppointmentsViewModel bookAppointmentsViewModel;
@override
Widget build(BuildContext context) {
bookAppointmentsViewModel = Provider.of<BookAppointmentsViewModel>(context, listen: false);
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: CollapsingListView(
title: "Eye Measurements",
child: SingleChildScrollView(
child: Consumer<MyAppointmentsViewModel>(builder: (context, myAppointmentsVM, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 16.h),
ListView.separated(
scrollDirection: Axis.vertical,
itemCount: myAppointmentsVM.isEyeMeasurementsAppointmentsLoading
? 5
: myAppointmentsVM.patientEyeMeasurementsAppointmentsHistoryList.isNotEmpty
? myAppointmentsVM.patientEyeMeasurementsAppointmentsHistoryList.length
: 1,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
padding: EdgeInsets.only(left: 24.h, right: 24.h),
itemBuilder: (context, index) {
return myAppointmentsVM.isEyeMeasurementsAppointmentsLoading
? Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true),
child: AppointmentCard(
patientAppointmentHistoryResponseModel: PatientAppointmentHistoryResponseModel(),
myAppointmentsViewModel: myAppointmentsVM,
bookAppointmentsViewModel: bookAppointmentsViewModel,
isLoading: true,
isFromHomePage: false,
),
)
: myAppointmentsVM.patientEyeMeasurementsAppointmentsHistoryList.isNotEmpty
? AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 1000),
child: SlideAnimation(
verticalOffset: 100.0,
child: FadeInAnimation(
child: AnimatedContainer(
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true),
child: AppointmentCard(
patientAppointmentHistoryResponseModel: myAppointmentsVM.patientEyeMeasurementsAppointmentsHistoryList[index],
myAppointmentsViewModel: myAppointmentsVM,
bookAppointmentsViewModel: bookAppointmentsViewModel,
isLoading: false,
isFromHomePage: false,
isForEyeMeasurements: true,
),
),
),
),
)
: Utils.getNoDataWidget(context, noDataText: "No Ophthalmology appointments found...".needTranslation);
},
separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h),
),
SizedBox(height: 60.h),
],
);
}),
),
),
);
}
}

@ -35,6 +35,7 @@ import 'package:hmg_patient_app_new/presentation/insurance/widgets/insurance_upd
import 'package:hmg_patient_app_new/presentation/insurance/widgets/patient_insurance_card.dart';
import 'package:hmg_patient_app_new/presentation/lab/lab_orders_page.dart';
import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/eye_measurements_appointments_page.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/patient_sickleaves_list_page.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/vaccine_list_page.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/widgets/lab_rad_card.dart';
@ -751,7 +752,16 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
svgIcon: AppAssets.eye_result_icon,
isLargeText: true,
iconSize: 36.w,
),
).onPress(() {
myAppointmentsViewModel.setIsEyeMeasurementsAppointmentsLoading(true);
myAppointmentsViewModel.onEyeMeasurementsTabChanged(0);
myAppointmentsViewModel.getPatientEyeMeasurementAppointments();
Navigator.of(context).push(
CustomPageRoute(
page: EyeMeasurementsAppointmentsPage(),
),
);
}),
MedicalFileCard(
label: "Allergy Info".needTranslation,
textColor: AppColors.blackColor,

@ -54,7 +54,7 @@ class CollapsingListView extends StatelessWidget {
SliverAppBar(
automaticallyImplyLeading: false,
pinned: true,
expandedHeight: 100.h,
expandedHeight: MediaQuery.of(context).size.height * 0.12.h,
stretch: true,
systemOverlayStyle: SystemUiOverlayStyle(statusBarBrightness: Brightness.light),
surfaceTintColor: Colors.transparent,

Loading…
Cancel
Save