Advance payment module implementation contd.

pull/52/head
haroon amjad 1 month ago
parent a4854bbe4a
commit 6048b3b5f1

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 83 KiB

@ -132,6 +132,7 @@ class AppAssets {
static const String touch_face_id = '$svgBasePath/touch_face_id.svg';
static const String minus = '$svgBasePath/minus.svg';
static const String home_lab_result_icon = '$svgBasePath/home_lab_result_icon.svg';
static const String visa_mastercard_icon = '$svgBasePath/visa_mastercard.svg';
//bottom navigation//
static const String homeBottom = '$svgBasePath/home_bottom.svg';

@ -44,6 +44,7 @@ class AppState {
setIsAuthenticated = true;
_authenticatedRootUser = authenticatedUser;
}
}
AuthenticatedUser? getAuthenticatedUser({bool isFamily = false}) {
@ -97,7 +98,7 @@ class AppState {
set setDeviceTypeID(v) => deviceTypeID = v;
List<VidaPlusProjectListModel> vidaPlusProjectList = [];
List<PrivilegeModel> privilegeModelList = [];
List<ListPrivilege> privilegeModelList = [];
List<HMCProjectListModel> hMCProjectListModel = [];
List<ProjectDetailListModel> projectDetailListModel = [];
@ -105,7 +106,7 @@ class AppState {
vidaPlusProjectList = vidaPlusProjectListModelInput;
}
setPrivilegeModelList(List<PrivilegeModel> privilegeModelListInput) {
setPrivilegeModelList(List<ListPrivilege> privilegeModelListInput) {
privilegeModelList = privilegeModelListInput;
}

@ -650,7 +650,7 @@ class Utils {
);
}
static Widget getPaymentAmountWithSymbol2(num habibWalletAmount, Color iconColor, double iconSize, {bool isSaudiCurrency = true, bool isExpanded = true}) {
static Widget getPaymentAmountWithSymbol2(num habibWalletAmount, {double iconSize = 14, Color iconColor = AppColors.textColor, Color textColor = AppColors.blackColor, bool isSaudiCurrency = true, bool isExpanded = true}) {
return RichText(
maxLines: 1,
text: TextSpan(
@ -658,11 +658,11 @@ class Utils {
WidgetSpan(
alignment: PlaceholderAlignment.baseline,
baseline: TextBaseline.alphabetic,
child: Utils.buildSvgWithAssets(icon: AppAssets.saudi_riyal_icon, width: 14.h, height: 14.h, iconColor: Colors.black.withValues(alpha: 0.31)),
child: Utils.buildSvgWithAssets(icon: AppAssets.saudi_riyal_icon, width: iconSize.h, height: iconSize.h, iconColor: iconColor),
),
TextSpan(
text: " $habibWalletAmount",
style: TextStyle(color: AppColors.blackColor, fontSize: 32.fSize, letterSpacing: -4, fontWeight: FontWeight.w600, height: 1),
style: TextStyle(color: textColor, fontSize: 32.fSize, letterSpacing: -4, fontWeight: FontWeight.w600, height: 1),
),
],
),
@ -708,4 +708,16 @@ class Utils {
await file.writeAsBytes(bytes);
return file.path;
}
static bool havePrivilege(int id) {
bool isHavePrivilege = false;
try {
for (var element in appState.privilegeModelList) {
if (element.id == id) isHavePrivilege = element.previlege!;
}
} catch (e) {
print(e);
}
return isHavePrivilege;
}
}

@ -23,6 +23,7 @@ import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/features/authentication/authentication_repo.dart';
import 'package:hmg_patient_app_new/features/authentication/models/request_models/check_activation_code_register_request_model.dart';
import 'package:hmg_patient_app_new/features/authentication/models/request_models/registration_payload_model.dart';
import 'package:hmg_patient_app_new/features/authentication/models/resp_models/authenticated_user_resp_model.dart';
import 'package:hmg_patient_app_new/features/authentication/models/resp_models/check_activation_code_resp_model.dart';
import 'package:hmg_patient_app_new/features/authentication/models/resp_models/check_user_staus_nhic_response_model.dart';
import 'package:hmg_patient_app_new/features/authentication/models/resp_models/select_device_by_imei.dart';
@ -59,8 +60,7 @@ class AuthenticationViewModel extends ChangeNotifier {
required NavigationService navigationService,
required CacheService cacheService,
required LocalAuthService localAuthService,
})
: _navigationService = navigationService,
}) : _navigationService = navigationService,
_dialogService = dialogService,
_errorHandlerService = errorHandlerService,
_appState = appState,
@ -205,13 +205,13 @@ class AuthenticationViewModel extends ChangeNotifier {
final result = await _authenticationRepo.selectDeviceByImei(firebaseToken: firebaseToken);
result.fold(
(failure) async {
(failure) async {
// LoadingUtils.hideFullScreenLoader();
// await _errorHandlerService.handleError(failure: failure);
LoaderBottomSheet.hideLoader();
_navigationService.pushPage(page: LoginScreen());
},
(apiResponse) {
(apiResponse) {
// LoadingUtils.hideFullScreenLoader();
log("apiResponse: ${apiResponse.data.toString()}");
log("messageStatus: ${apiResponse.messageStatus.toString()}");
@ -301,8 +301,7 @@ class AuthenticationViewModel extends ChangeNotifier {
final result = await _authenticationRepo.checkPatientAuthentication(checkPatientAuthenticationReq: checkPatientAuthenticationReq);
result.fold(
(failure) async =>
await _errorHandlerService.handleError(
(failure) async => await _errorHandlerService.handleError(
failure: failure,
onUnHandledFailure: (failure) async {
LoaderBottomSheet.hideLoader();
@ -316,7 +315,7 @@ class AuthenticationViewModel extends ChangeNotifier {
_navigationService.pop();
});
}),
(apiResponse) async {
(apiResponse) async {
if (apiResponse.messageStatus == 2) {
LoaderBottomSheet.hideLoader();
await _dialogService.showErrorBottomSheet(message: apiResponse.errorMessage ?? "ErrorEmpty", onOkPressed: () {});
@ -359,8 +358,8 @@ class AuthenticationViewModel extends ChangeNotifier {
patientOutSA: isForRegister
? isPatientOutsideSA(request: payload)
: selectedCountrySignup.countryCode == CountryEnum.saudiArabia
? false
: true,
? false
: true,
payload: payload,
);
@ -374,8 +373,8 @@ class AuthenticationViewModel extends ChangeNotifier {
final resultEither = await _authenticationRepo.sendActivationCodeRepo(sendActivationCodeReq: request, isRegister: checkIsUserComingForRegister(request: payload), languageID: 'er');
resultEither.fold(
(failure) async => await _errorHandlerService.handleError(failure: failure),
(apiResponse) async {
(failure) async => await _errorHandlerService.handleError(failure: failure),
(apiResponse) async {
if (apiResponse.messageStatus == 2) {
LoaderBottomSheet.hideLoader();
await _dialogService.showCommonBottomSheetWithoutH(
@ -409,27 +408,27 @@ class AuthenticationViewModel extends ChangeNotifier {
bool isForRegister = (_appState.getUserRegistrationPayload.healthId != null || _appState.getUserRegistrationPayload.patientOutSa == true || _appState.getUserRegistrationPayload.patientOutSa == 1);
final request = RequestUtils.getCommonRequestWelcome(
phoneNumber: phoneNumberController.text,
otpTypeEnum: otpTypeEnum,
deviceToken: _appState.deviceToken,
// patientOutSA: _appState.getUserRegistrationPayload.projectOutSa == 1 ? true : false,
patientOutSA: isForRegister
? _appState.getUserRegistrationPayload.projectOutSa == true
? true
: false
: _appState.getSelectDeviceByImeiRespModelElement != null
? _appState.getSelectDeviceByImeiRespModelElement!.outSa!
: selectedCountrySignup == CountryEnum.saudiArabia
? false
: true,
loginTokenID: _appState.appAuthToken,
registeredData: isForRegister ? _appState.getUserRegistrationPayload : null,
nationIdText: nationalIdController.text,
countryCode: _appState.getSelectDeviceByImeiRespModelElement != null && _appState.getSelectDeviceByImeiRespModelElement!.outSa == true
? CountryEnum.unitedArabEmirates.countryCode
: selectedCountrySignup.countryCode,
//TODO: Error Here IN Zip Code.
loginType: loginTypeEnum.toInt)
phoneNumber: phoneNumberController.text,
otpTypeEnum: otpTypeEnum,
deviceToken: _appState.deviceToken,
// patientOutSA: _appState.getUserRegistrationPayload.projectOutSa == 1 ? true : false,
patientOutSA: isForRegister
? _appState.getUserRegistrationPayload.projectOutSa == true
? true
: false
: _appState.getSelectDeviceByImeiRespModelElement != null
? _appState.getSelectDeviceByImeiRespModelElement!.outSa!
: selectedCountrySignup == CountryEnum.saudiArabia
? false
: true,
loginTokenID: _appState.appAuthToken,
registeredData: isForRegister ? _appState.getUserRegistrationPayload : null,
nationIdText: nationalIdController.text,
countryCode: _appState.getSelectDeviceByImeiRespModelElement != null && _appState.getSelectDeviceByImeiRespModelElement!.outSa == true
? CountryEnum.unitedArabEmirates.countryCode
: selectedCountrySignup.countryCode,
//TODO: Error Here IN Zip Code.
loginType: loginTypeEnum.toInt)
.toJson();
LoaderBottomSheet.showLoader();
if (isForRegister) {
@ -445,8 +444,7 @@ class AuthenticationViewModel extends ChangeNotifier {
LoaderBottomSheet.hideLoader();
resultEither.fold(
(failure) async =>
await _errorHandlerService.handleError(
(failure) async => await _errorHandlerService.handleError(
failure: failure,
onUnHandledFailure: (failure) async {
LoaderBottomSheet.hideLoader();
@ -473,8 +471,7 @@ class AuthenticationViewModel extends ChangeNotifier {
final resultEither = await _authenticationRepo.checkActivationCodeRepo(newRequest: CheckActivationCodeRegisterReq.fromJson(request), activationCode: activationCode, isRegister: false);
resultEither.fold(
(failure) async =>
await _errorHandlerService.handleError(
(failure) async => await _errorHandlerService.handleError(
failure: failure,
onUnHandledFailure: (failure) async {
LoaderBottomSheet.hideLoader();
@ -504,6 +501,7 @@ class AuthenticationViewModel extends ChangeNotifier {
} else {
if (activation.list != null && activation.list!.isNotEmpty) {
_appState.setAuthenticatedUser(activation.list!.first);
_appState.setPrivilegeModelList(activation.list!.first.listPrivilege!);
}
_appState.setUserBloodGroup = (activation.patientBlodType ?? "");
_appState.setAppAuthToken = activation.authenticationTokenId;
@ -658,15 +656,15 @@ class AuthenticationViewModel extends ChangeNotifier {
bool isOutSidePatient = selectedCountrySignup.countryCode == CountryEnum.unitedArabEmirates.countryCode ? true : false;
LoaderBottomSheet.showLoader();
final request = await RequestUtils.getPatientAuthenticationRequest(
phoneNumber: phoneNumberController.text,
nationId: nationalIdController.text,
patientOutSA: isOutSidePatient,
otpTypeEnum: otpTypeEnum,
isForRegister: true,
patientId: 0,
zipCode: selectedCountrySignup.countryCode,
calenderType: calenderType,
dob: dob)
phoneNumber: phoneNumberController.text,
nationId: nationalIdController.text,
patientOutSA: isOutSidePatient,
otpTypeEnum: otpTypeEnum,
isForRegister: true,
patientId: 0,
zipCode: selectedCountrySignup.countryCode,
calenderType: calenderType,
dob: dob)
.toJson();
var nRequest = Map<String, dynamic>.from(request);
@ -802,22 +800,22 @@ class AuthenticationViewModel extends ChangeNotifier {
Future<void> insertPatientIMEIData(int loginType) async {
final resultEither = await _authenticationRepo.insertPatientIMEIData(
patientIMEIDataRequest: PatientInsertDeviceImei(
imei: _appState.deviceToken,
deviceTypeId: _appState.getDeviceTypeID(),
patientId: _appState.getAuthenticatedUser()!.patientId!,
patientIdentificationNo: _appState.getAuthenticatedUser()!.patientIdentificationNo!,
identificationNo: _appState.getAuthenticatedUser()!.patientIdentificationNo!,
firstName: _appState.getAuthenticatedUser()!.firstName!,
lastName: _appState.getAuthenticatedUser()!.lastName!,
patientTypeId: _appState.getAuthenticatedUser()!.patientType,
mobileNo: _appState.getAuthenticatedUser()!.mobileNumber!,
logInTypeId: loginType,
patientOutSa: _appState.getAuthenticatedUser()!.outSa!,
outSa: _appState.getAuthenticatedUser()!.outSa == 1 ? true : false,
biometricEnabled: loginType == 1 || loginType == 2 ? false : true,
firstNameN: _appState.getAuthenticatedUser()!.firstNameN,
lastNameN: _appState.getAuthenticatedUser()!.lastNameN,
).toJson());
imei: _appState.deviceToken,
deviceTypeId: _appState.getDeviceTypeID(),
patientId: _appState.getAuthenticatedUser()!.patientId!,
patientIdentificationNo: _appState.getAuthenticatedUser()!.patientIdentificationNo!,
identificationNo: _appState.getAuthenticatedUser()!.patientIdentificationNo!,
firstName: _appState.getAuthenticatedUser()!.firstName!,
lastName: _appState.getAuthenticatedUser()!.lastName!,
patientTypeId: _appState.getAuthenticatedUser()!.patientType,
mobileNo: _appState.getAuthenticatedUser()!.mobileNumber!,
logInTypeId: loginType,
patientOutSa: _appState.getAuthenticatedUser()!.outSa!,
outSa: _appState.getAuthenticatedUser()!.outSa == 1 ? true : false,
biometricEnabled: loginType == 1 || loginType == 2 ? false : true,
firstNameN: _appState.getAuthenticatedUser()!.firstNameN,
lastNameN: _appState.getAuthenticatedUser()!.lastNameN,
).toJson());
resultEither.fold((failure) async => await _errorHandlerService.handleError(failure: failure), (apiResponse) async {
if (apiResponse.messageStatus == 1) {
log("Insert IMEI Success");
@ -831,20 +829,20 @@ class AuthenticationViewModel extends ChangeNotifier {
Future<void> insertPatientDeviceData(int loginType) async {
final resultEither = await _authenticationRepo.insertPatientDeviceData(
patientDeviceDataRequest: InsertPatientMobileDeviceInfo(
deviceToken: _appState.deviceToken,
deviceTypeId: _appState.getDeviceTypeID(),
patientId: _appState.getAuthenticatedUser()!.patientId!,
patientTypeId: _appState.getAuthenticatedUser()!.patientType,
patientOutSa: _appState.getAuthenticatedUser()!.outSa!,
loginType: loginType,
languageId: _appState.getLanguageID(),
latitude: _appState.userLat,
longitude: _appState.userLong,
voipToken: "",
deviceType: _appState.deviceTypeID,
patientMobileNumber: _appState.getAuthenticatedUser()!.mobileNumber,
nationalId: _appState.getAuthenticatedUser()!.patientIdentificationNo,
gender: _appState.getAuthenticatedUser()!.gender)
deviceToken: _appState.deviceToken,
deviceTypeId: _appState.getDeviceTypeID(),
patientId: _appState.getAuthenticatedUser()!.patientId!,
patientTypeId: _appState.getAuthenticatedUser()!.patientType,
patientOutSa: _appState.getAuthenticatedUser()!.outSa!,
loginType: loginType,
languageId: _appState.getLanguageID(),
latitude: _appState.userLat,
longitude: _appState.userLong,
voipToken: "",
deviceType: _appState.deviceTypeID,
patientMobileNumber: _appState.getAuthenticatedUser()!.mobileNumber,
nationalId: _appState.getAuthenticatedUser()!.patientIdentificationNo,
gender: _appState.getAuthenticatedUser()!.gender)
.toJson());
resultEither.fold((failure) async => await _errorHandlerService.handleError(failure: failure), (apiResponse) async {
if (apiResponse.messageStatus == 1) {
@ -858,18 +856,18 @@ class AuthenticationViewModel extends ChangeNotifier {
Future<void> getPatientDeviceData(int loginType) async {
final resultEither = await _authenticationRepo.getPatientDeviceData(
patientDeviceDataRequest: GetUserMobileDeviceData(
deviceToken: _appState.deviceToken,
deviceTypeId: _appState.getDeviceTypeID(),
patientId: _appState.getSelectDeviceByImeiRespModelElement!.patientId!,
patientType: _appState.getSelectDeviceByImeiRespModelElement!.patientType,
patientOutSa: _appState.getSelectDeviceByImeiRespModelElement!.outSa == true ? 1 : 0,
loginType: loginType,
languageId: _appState.getLanguageID(),
latitude: _appState.userLat,
longitude: _appState.userLong,
mobileNo: _appState.getSelectDeviceByImeiRespModelElement!.mobile!,
patientMobileNumber: int.parse(_appState.getSelectDeviceByImeiRespModelElement!.mobile!),
nationalId: _appState.getSelectDeviceByImeiRespModelElement!.identificationNo)
deviceToken: _appState.deviceToken,
deviceTypeId: _appState.getDeviceTypeID(),
patientId: _appState.getSelectDeviceByImeiRespModelElement!.patientId!,
patientType: _appState.getSelectDeviceByImeiRespModelElement!.patientType,
patientOutSa: _appState.getSelectDeviceByImeiRespModelElement!.outSa == true ? 1 : 0,
loginType: loginType,
languageId: _appState.getLanguageID(),
latitude: _appState.userLat,
longitude: _appState.userLong,
mobileNo: _appState.getSelectDeviceByImeiRespModelElement!.mobile!,
patientMobileNumber: int.parse(_appState.getSelectDeviceByImeiRespModelElement!.mobile!),
nationalId: _appState.getSelectDeviceByImeiRespModelElement!.identificationNo)
.toJson());
resultEither.fold((failure) async => await _errorHandlerService.handleError(failure: failure), (apiResponse) async {
if (apiResponse.messageStatus == 1) {
@ -885,11 +883,15 @@ class AuthenticationViewModel extends ChangeNotifier {
message: apiResponse.errorMessage ?? "",
label: LocaleKeys.notice.tr(),
onOkPressed: () {
_dialogService.showPhoneNumberPickerSheet(label:"Where would you like to receive OTP?", message:"Please select from the below options to receive OTP.", onSMSPress: () {
checkUserAuthentication(otpTypeEnum: OTPTypeEnum.sms);
}, onWhatsappPress: () {
checkUserAuthentication(otpTypeEnum: OTPTypeEnum.whatsapp);
});
_dialogService.showPhoneNumberPickerSheet(
label: "Where would you like to receive OTP?",
message: "Please select from the below options to receive OTP.",
onSMSPress: () {
checkUserAuthentication(otpTypeEnum: OTPTypeEnum.sms);
},
onWhatsappPress: () {
checkUserAuthentication(otpTypeEnum: OTPTypeEnum.whatsapp);
});
},
onCancelPressed: () {
_navigationService.pop();
@ -908,21 +910,21 @@ class AuthenticationViewModel extends ChangeNotifier {
Future<void> getServicePrivilege() async {
final resultEither = await _authenticationRepo.getServicePrivilege();
List<PrivilegeModel> privilegeModelList = [];
List<ListPrivilege> privilegeModelList = [];
List<VidaPlusProjectListModel> vidaPlusProjectListModel = [];
List<HMCProjectListModel> hMCProjectListModel = [];
List<ProjectDetailListModel> projectDetailListModel = [];
resultEither.fold(
(failure) async => await _errorHandlerService.handleError(failure: failure),
(apiResponse) async {
(failure) async => await _errorHandlerService.handleError(failure: failure),
(apiResponse) async {
if (apiResponse.messageStatus == 2) {
await _dialogService.showErrorBottomSheet(message: apiResponse.errorMessage ?? "ErrorEmpty");
} else {
apiResponse.data["ServicePrivilegeList"].forEach((v) {
privilegeModelList.add(PrivilegeModel.fromJson(v));
privilegeModelList.add(ListPrivilege.fromJson(v));
});
_appState.setPrivilegeModelList(privilegeModelList);
_appState.setPrivilegeModelList(privilegeModelList.cast<ListPrivilege>());
apiResponse.data["ProjectListVidaPlus"].forEach((v) {
vidaPlusProjectListModel.add(VidaPlusProjectListModel.fromJson(v));

@ -613,35 +613,3 @@ class ListElement {
"status": listStatus,
};
}
class ListPrivilege {
int? id;
String? serviceName;
bool? previlege;
dynamic region;
ListPrivilege({
this.id,
this.serviceName,
this.previlege,
this.region,
});
factory ListPrivilege.fromRawJson(String str) => ListPrivilege.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory ListPrivilege.fromJson(Map<String, dynamic> json) => ListPrivilege(
id: json["ID"],
serviceName: json["ServiceName"],
previlege: json["Previlege"],
region: json["Region"],
);
Map<String, dynamic> toJson() => {
"ID": id,
"ServiceName": serviceName,
"Previlege": previlege,
"Region": region,
};
}

@ -42,11 +42,9 @@ abstract class BookAppointmentsRepo {
Function(dynamic)? onSuccess,
Function(String)? onError});
Future<Either<Failure, GenericApiModel<List<HospitalsModel>>>>
getProjectList();
Future<Either<Failure, GenericApiModel<List<HospitalsModel>>>> getProjectList();
Future<Either<Failure, GenericApiModel<List<GetClinicsListResponseModel>>>> getClinicsWithRespectToClinicId(String projectID);
}
class BookAppointmentsRepoImp implements BookAppointmentsRepo {
@ -371,8 +369,7 @@ class BookAppointmentsRepoImp implements BookAppointmentsRepo {
}
@override
Future<Either<Failure, GenericApiModel<List<HospitalsModel>>>>
getProjectList() async {
Future<Either<Failure, GenericApiModel<List<HospitalsModel>>>> getProjectList() async {
Map<String, dynamic> request = {};
try {
@ -388,11 +385,7 @@ class BookAppointmentsRepoImp implements BookAppointmentsRepo {
try {
final list = response['ListProject'];
final appointmentsList = list
.map((item) =>
HospitalsModel.fromJson(item as Map<String, dynamic>))
.toList()
.cast<HospitalsModel>();
final appointmentsList = list.map((item) => HospitalsModel.fromJson(item as Map<String, dynamic>)).toList().cast<HospitalsModel>();
apiResponse = GenericApiModel<List<HospitalsModel>>(
messageStatus: messageStatus,

@ -3,10 +3,20 @@ 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/hospital_model.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
abstract class HabibWalletRepo {
Future<Either<Failure, GenericApiModel<dynamic>>> getPatientBalanceAmount();
Future<Either<Failure, GenericApiModel<List<HospitalsModel>>>> getProjectList();
Future<Either<Failure, GenericApiModel<dynamic>>> HISCreateAdvancePayment(
{required String paymentMethodName, required num paidAmount, required String paymentReference, required String patientID, required int projectID, required String depositorName});
Future<Either<Failure, GenericApiModel<dynamic>>> addAdvanceNumberRequest({required String advanceNumber, required String paymentReference});
Future<Either<Failure, GenericApiModel<dynamic>>> getPatientInfoByPatientID({required String patientID});
}
class HabibWalletRepoImp implements HabibWalletRepo {
@ -55,4 +65,165 @@ class HabibWalletRepoImp implements HabibWalletRepo {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<List<HospitalsModel>>>> getProjectList() async {
Map<String, dynamic> request = {"IsOnlineCheckIn": true, "IsAdvancePayment": true};
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>> HISCreateAdvancePayment(
{required String paymentMethodName, required num paidAmount, required String paymentReference, required String patientID, required int projectID, required String depositorName}) async {
Map<String, dynamic> request = {
"CustName": depositorName,
"CustID": patientID,
"SetupID": "010266",
"ProjectID": projectID,
"PatientID": patientID,
"AccountID": patientID,
"PaymentAmount": paidAmount,
"NationalityID": null,
"DepositorName": depositorName,
"CreatedBy": 3,
"PaymentMethodName": paymentMethodName,
"PaymentReference": paymentReference,
"PaymentMethod": paymentMethodName,
"IsAncillaryOrder": false
};
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
HIS_CREATE_ADVANCE_PAYMENT,
body: request,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: errorMessage,
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>> addAdvanceNumberRequest({required String advanceNumber, required String paymentReference}) async {
Map<String, dynamic> requestBody = {
"AdvanceNumber": advanceNumber,
"AdvanceNumber_VP": advanceNumber,
"PaymentReferenceNumber": paymentReference,
"AppointmentID": 0,
};
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>> getPatientInfoByPatientID({required String patientID}) async {
Map<String, dynamic> requestBody = {"SearchPatientID": patientID};
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
GET_PATIENT_INFO_BY_ID,
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()));
}
}
}

@ -1,23 +1,66 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_repo.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
class HabibWalletViewModel extends ChangeNotifier {
bool isWalletAmountLoading = false;
num habibWalletAmount = 0;
num walletRechargeAmount = 0;
int currentIndex = 0;
List<HospitalsModel> advancePaymentHospitals = [];
HospitalsModel? selectedHospital;
HabibWalletRepo habibWalletRepo;
ErrorHandlerService errorHandlerService;
String fileNumber = '';
String depositorName = '';
String mobileNumber = '';
HabibWalletViewModel({required this.habibWalletRepo, required this.errorHandlerService});
initHabibWalletProvider() {
isWalletAmountLoading = true;
habibWalletAmount = 0;
walletRechargeAmount = 0;
advancePaymentHospitals.clear();
selectedHospital = null;
fileNumber = '';
depositorName = '';
mobileNumber = '';
notifyListeners();
}
setSelectedHospital(HospitalsModel hospital) {
selectedHospital = hospital;
notifyListeners();
}
setWalletRechargeAmount(num amount) {
walletRechargeAmount = amount;
notifyListeners();
}
setDepositorDetails(String fileNum, String depositor, String mobile) {
fileNumber = fileNum;
depositorName = depositor;
mobileNumber = mobile;
notifyListeners();
}
setCurrentIndex(int index) {
currentIndex = index;
notifyListeners();
}
Future<void> getPatientBalanceAmount({Function(dynamic)? onSuccess, Function(String)? onError}) async {
isWalletAmountLoading = true;
notifyListeners();
final result = await habibWalletRepo.getPatientBalanceAmount();
result.fold(
@ -36,4 +79,85 @@ class HabibWalletViewModel extends ChangeNotifier {
},
);
}
Future<void> getProjectsList() async {
advancePaymentHospitals.clear();
notifyListeners();
final result = await habibWalletRepo.getProjectList();
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),
(apiResponse) async {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
advancePaymentHospitals = apiResponse.data!;
notifyListeners();
}
},
);
}
Future<void> HISCreateAdvancePayment(
{required String paymentMethodName,
required num paidAmount,
required String paymentReference,
required String patientID,
required int projectID,
required String depositorName,
Function(dynamic)? onSuccess,
Function(String)? onError}) async {
final result = await habibWalletRepo.HISCreateAdvancePayment(
paymentMethodName: paymentMethodName, paidAmount: paidAmount, paymentReference: paymentReference, patientID: patientID, projectID: projectID, depositorName: depositorName);
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> addAdvanceNumberRequest({required String advanceNumber, required String paymentReference, Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await habibWalletRepo.addAdvanceNumberRequest(advanceNumber: advanceNumber, paymentReference: paymentReference);
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> getPatientInfoByPatientID({required String patientID, Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await habibWalletRepo.getPatientInfoByPatientID(patientID: patientID);
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);
}
}
},
);
}
}

@ -7,6 +7,7 @@ import 'package:hmg_patient_app_new/features/payfort/models/payfort_project_deta
import 'package:hmg_patient_app_new/features/payfort/models/sdk_token_response_model.dart';
import 'package:hmg_patient_app_new/features/payfort/payfort_repo.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:network_info_plus/network_info_plus.dart';
class PayfortViewModel extends ChangeNotifier {
@ -183,6 +184,7 @@ class PayfortViewModel extends ChangeNotifier {
isApplePayConfigurationLoading = false;
notifyListeners();
LoaderBottomSheet.hideLoader();
_payfort.callPayFortForApplePay(
request: request,

@ -273,7 +273,6 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
isSaudiCurrency: true),
],
).paddingSymmetrical(24.h, 0.h),
//TODO: Add Apple Pay Privileges
Platform.isIOS
? Utils.buildSvgWithAssets(
icon: AppAssets.apple_pay_button,
@ -282,7 +281,11 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
fit: BoxFit.contain,
).paddingSymmetrical(24.h, 0.h).onPress(() {
// payfortVM.setIsApplePayConfigurationLoading(true);
startApplePay();
if (Utils.havePrivilege(103)) {
startApplePay();
} else {
openPaymentURL(selectedPaymentMethod);
}
})
: SizedBox(height: 12.h),
SizedBox(height: 12.h),
@ -363,8 +366,8 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo.toString(),
payedAmount: payfortViewModel.payfortCheckPaymentStatusResponseModel!.amount!,
paymentReference: payfortViewModel.payfortCheckPaymentStatusResponseModel!.fortId!,
patientID: "4767477",
patientType: 1,
patientID: appState.getAuthenticatedUser()!.patientId.toString(),
patientType: appState.getAuthenticatedUser()!.patientType!,
onSuccess: (value) async {
print(value);
await myAppointmentsViewModel.addAdvanceNumberRequest(

@ -17,8 +17,7 @@ class HospitalListItem extends StatelessWidget {
late AppState appState;
HospitalListItem(
{super.key, required this.hospitalData, required this.isLocationEnabled});
HospitalListItem({super.key, required this.hospitalData, required this.isLocationEnabled});
@override
Widget build(BuildContext context) {
@ -70,24 +69,17 @@ class HospitalListItem extends StatelessWidget {
);
Widget get distanceInfo => Row(
children: [
Visibility(
visible: (hospitalData?.distanceInKMs != "0"),
child:
AppCustomChipWidget(
labelText:
"${hospitalData?.distanceInKMs ?? ""} km".needTranslation,
deleteIcon: AppAssets.location_red,
deleteIconSize: Size(9, 12),
backgroundColor: AppColors.secondaryLightRedColor,
textColor: AppColors.errorColor,
),
),
visible: (hospitalData?.distanceInKMs != "0"),
child: AppCustomChipWidget(
labelText: "${hospitalData?.distanceInKMs ?? ""} km".needTranslation,
deleteIcon: AppAssets.location_red,
deleteIconSize: Size(9, 12),
backgroundColor: AppColors.secondaryLightRedColor,
textColor: AppColors.errorColor,
),
),
Visibility(
visible: (hospitalData?.distanceInKMs == "0"),
child: Row(
@ -96,8 +88,9 @@ class HospitalListItem extends StatelessWidget {
labelText: "Distance not available".needTranslation,
textColor: AppColors.blackColor,
),
SizedBox(width: 8.h,)
SizedBox(
width: 8.h,
)
],
)),
Visibility(

@ -14,7 +14,6 @@ import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.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/routes/custom_page_route.dart';
import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
import 'package:provider/provider.dart';
class HabibWalletPage extends StatefulWidget {
@ -25,8 +24,11 @@ class HabibWalletPage extends StatefulWidget {
}
class _HabibWalletState extends State<HabibWalletPage> {
late HabibWalletViewModel habibWalletVM;
@override
Widget build(BuildContext context) {
habibWalletVM = Provider.of<HabibWalletViewModel>(context, listen: false);
AppState _appState = getIt.get<AppState>();
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
@ -66,10 +68,10 @@ class _HabibWalletState extends State<HabibWalletPage> {
),
Spacer(),
LocaleKeys.balanceAmount.tr(context: context).toText14(weight: FontWeight.w500, color: AppColors.whiteColor),
SizedBox(height: 4.h),
Consumer<HabibWalletViewModel>(builder: (context, habibWalletVM, child) {
return Utils.getPaymentAmountWithSymbol(habibWalletVM.habibWalletAmount.toString().toText32(isBold: true, color: AppColors.whiteColor), AppColors.whiteColor, 13.h,
isExpanded: false)
.toShimmer2(isShow: habibWalletVM.isWalletAmountLoading, radius: 12.h, width: 80.h, height: 40.h);
return Utils.getPaymentAmountWithSymbol2(habibWalletVM.habibWalletAmount, textColor: AppColors.whiteColor, iconColor: AppColors.whiteColor, iconSize: 13, isExpanded: false)
.toShimmer2(isShow: habibWalletVM.isWalletAmountLoading, radius: 12.h, width: 80.h, height: 24.h);
}),
],
),
@ -84,11 +86,15 @@ class _HabibWalletState extends State<HabibWalletPage> {
iconSize: 21.h,
text: "Recharge".needTranslation,
onPressed: () {
Navigator.of(context).push(
Navigator.of(context)
.push(
CustomPageRoute(
page: RechargeWalletPage(),
),
);
)
.then((val) {
habibWalletVM.getPatientBalanceAmount();
});
},
backgroundColor: AppColors.infoColor,
borderColor: AppColors.infoColor,

@ -1,3 +1,5 @@
import 'dart:async';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
@ -7,12 +9,17 @@ 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/habib_wallet/habib_wallet_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/habib_wallet/wallet_payment_confirm_page.dart';
import 'package:hmg_patient_app_new/presentation/habib_wallet/widgets/select_hospital_bottom_sheet.dart';
import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
import 'package:hmg_patient_app_new/widgets/input_widget.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:provider/provider.dart';
import 'widgets/select-medical_file.dart';
@ -26,8 +33,20 @@ class RechargeWalletPage extends StatefulWidget {
class _RechargeWalletPageState extends State<RechargeWalletPage> {
FocusNode textFocusNode = FocusNode();
late HabibWalletViewModel habibWalletVM;
final TextEditingController amountTextController = TextEditingController();
@override
void initState() {
scheduleMicrotask(() {
habibWalletVM.getProjectsList();
});
super.initState();
}
@override
Widget build(BuildContext context) {
habibWalletVM = Provider.of<HabibWalletViewModel>(context, listen: false);
AppState appState = getIt.get<AppState>();
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
@ -35,171 +54,197 @@ class _RechargeWalletPageState extends State<RechargeWalletPage> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: CollapsingListView(
title: LocaleKeys.createAdvancedPayment.tr(context: context),
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(24.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: 135.h,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.h,
hasShadow: false,
side: BorderSide(color: AppColors.textColor, width: 2.h),
),
child: Padding(
padding: EdgeInsets.all(16.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Enter an amount".needTranslation.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
Spacer(),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Utils.getPaymentAmountWithSymbol(
SizedBox(
width: 150.h,
child: TextInputWidget(
labelText: "",
hintText: "",
isEnable: true,
prefix: null,
isAllowRadius: true,
isBorderAllowed: false,
isAllowLeadingIcon: true,
autoFocus: true,
fontSize: 40,
padding: EdgeInsets.symmetric(horizontal: 8.h, vertical: 0.h),
focusNode: textFocusNode,
isWalletAmountInput: true,
// leadingIcon: AppAssets.student_card,
child: CollapsingListView(
title: LocaleKeys.createAdvancedPayment.tr(context: context),
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(24.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: 135.h,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.h,
hasShadow: false,
side: BorderSide(color: AppColors.textColor, width: 2.h),
),
child: Padding(
padding: EdgeInsets.all(16.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
//TODO: Check with hussain to show AED or SAR
"Enter an amount".needTranslation.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
Spacer(),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Utils.getPaymentAmountWithSymbol(
SizedBox(
width: 150.h,
child: TextInputWidget(
controller: amountTextController,
labelText: "",
hintText: "",
isEnable: true,
prefix: null,
isAllowRadius: true,
isBorderAllowed: false,
isAllowLeadingIcon: true,
autoFocus: true,
fontSize: 40,
padding: EdgeInsets.symmetric(horizontal: 8.h, vertical: 0.h),
focusNode: textFocusNode,
isWalletAmountInput: true,
keyboardType: TextInputType.numberWithOptions(signed: false, decimal: true),
// leadingIcon: AppAssets.student_card,
),
),
),
AppColors.textColor,
13.h,
isExpanded: false),
const Spacer(),
"SAR".needTranslation.toText20(color: AppColors.greyTextColor, weight: FontWeight.w500),
],
),
],
AppColors.textColor,
13.h,
isExpanded: false),
const Spacer(),
"SAR".needTranslation.toText20(color: AppColors.greyTextColor, weight: FontWeight.w500),
],
),
],
),
),
),
),
SizedBox(height: 24.h),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.h,
hasShadow: false,
),
child: Padding(
padding: EdgeInsets.all(16.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
SizedBox(height: 24.h),
Consumer<HabibWalletViewModel>(builder: (context, habibWalletVM, child) {
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.h,
hasShadow: false,
),
child: Padding(
padding: EdgeInsets.all(16.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Utils.buildSvgWithAssets(icon: AppAssets.my_account_icon, width: 40.h, height: 40.h),
SizedBox(width: 8.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
Row(
children: [
LocaleKeys.myAccount.tr(context: context).toText16(color: AppColors.textColor, weight: FontWeight.w500),
"${LocaleKeys.medicalFile.tr(context: context)}: ${appState.getAuthenticatedUser()!.patientId}"
.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
Utils.buildSvgWithAssets(icon: AppAssets.my_account_icon, width: 40.h, height: 40.h),
SizedBox(width: 8.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.myAccount.tr(context: context).toText16(color: AppColors.textColor, weight: FontWeight.w500),
"${LocaleKeys.medicalFile.tr(context: context)}: ${appState.getAuthenticatedUser()!.patientId}"
.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
],
),
],
),
Utils.buildSvgWithAssets(icon: AppAssets.arrow_down, width: 25.h, height: 25.h),
],
),
Utils.buildSvgWithAssets(icon: AppAssets.arrow_down, width: 25.h, height: 25.h),
],
).onPress(() async {
// showCommonBottomSheetWithoutHeight(context, title: "Select Medical File".needTranslation, child: SelectMedicalFile(), callBackFunc: () {}, isFullScreen: false);
showCommonBottomSheetWithoutHeight(context, title: "Select Medical File".needTranslation, child: const MultiPageBottomSheet(), callBackFunc: () {}, isFullScreen: false);
}),
SizedBox(height: 16.h),
Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h),
SizedBox(height: 16.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
).onPress(() async {
habibWalletVM.setCurrentIndex(0);
showCommonBottomSheetWithoutHeight(context, title: "Select Medical File".needTranslation,
titleWidget: Consumer<HabibWalletViewModel>(builder: (context, habibWalletVM, child) {
return habibWalletVM.currentIndex != 0
? IconButton(
icon: Utils.buildSvgWithAssets(icon: AppAssets.arrow_back, width: 24.h, height: 24.h),
padding: EdgeInsets.zero,
onPressed: () => habibWalletVM.setCurrentIndex(0),
highlightColor: Colors.transparent,
)
: "Select Medical File".needTranslation.toText20(weight: FontWeight.w600);
}), child: Consumer<HabibWalletViewModel>(builder: (context, habibWalletVM, child) {
return MultiPageBottomSheet();
}), callBackFunc: () {}, isFullScreen: false, isCloseButtonVisible: true);
}),
SizedBox(height: 16.h),
Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h),
SizedBox(height: 16.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Utils.buildSvgWithAssets(icon: AppAssets.select_hospital_icon, width: 40.h, height: 40.h),
SizedBox(width: 8.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
Row(
children: [
LocaleKeys.hospital.tr(context: context).toText16(color: AppColors.textColor, weight: FontWeight.w500),
"Olaya".toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
Utils.buildSvgWithAssets(icon: AppAssets.select_hospital_icon, width: 40.h, height: 40.h),
SizedBox(width: 8.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.hospital.tr(context: context).toText16(color: AppColors.textColor, weight: FontWeight.w500),
SizedBox(
width: MediaQuery.of(context).size.width * 0.55,
child: (habibWalletVM.selectedHospital != null ? habibWalletVM.selectedHospital!.name : LocaleKeys.selectHospital.tr(context: context))!
.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
),
],
),
],
),
).onPress(() {
showCommonBottomSheetWithoutHeight(context,
title: LocaleKeys.selectHospital.tr(context: context), isDismissible: false, child: SelectHospitalBottomSheet(), callBackFunc: () {});
}),
Utils.buildSvgWithAssets(icon: AppAssets.arrow_down, width: 25.h, height: 25.h),
],
),
Utils.buildSvgWithAssets(icon: AppAssets.arrow_down, width: 25.h, height: 25.h),
],
),
SizedBox(height: 16.h),
Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h),
SizedBox(height: 16.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(height: 16.h),
Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h),
SizedBox(height: 16.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Utils.buildSvgWithAssets(icon: AppAssets.email_icon, width: 40.h, height: 40.h),
SizedBox(width: 8.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
Row(
children: [
LocaleKeys.email.tr(context: context).toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500),
"${appState.getAuthenticatedUser()!.emailAddress}".toText16(color: AppColors.textColor, weight: FontWeight.w500),
Utils.buildSvgWithAssets(icon: AppAssets.email_icon, width: 40.h, height: 40.h),
SizedBox(width: 8.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.email.tr(context: context).toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500),
"${appState.getAuthenticatedUser()!.emailAddress}".toText16(color: AppColors.textColor, weight: FontWeight.w500),
],
),
],
),
],
),
],
),
SizedBox(height: 16.h),
Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h),
SizedBox(height: 16.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(height: 16.h),
Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h),
SizedBox(height: 16.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Utils.buildSvgWithAssets(icon: AppAssets.notes_icon, width: 40.h, height: 40.h),
SizedBox(width: 8.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
Row(
children: [
LocaleKeys.notes.tr(context: context).toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500),
"Lorem Ipsum".toText16(color: AppColors.textColor, weight: FontWeight.w500),
Utils.buildSvgWithAssets(icon: AppAssets.notes_icon, width: 40.h, height: 40.h),
SizedBox(width: 8.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.notes.tr(context: context).toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500),
"Lorem Ipsum".toText16(color: AppColors.textColor, weight: FontWeight.w500),
],
),
],
),
],
),
SizedBox(height: 8.h),
],
),
SizedBox(height: 8.h),
],
),
),
),
],
),
);
}),
],
),
),
),
),
)),
),
//TODO: Handle Family member selection & Other Account Selection
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
@ -208,7 +253,38 @@ class _RechargeWalletPageState extends State<RechargeWalletPage> {
),
child: CustomButton(
text: LocaleKeys.next.tr(context: context),
onPressed: () {},
onPressed: () {
if (amountTextController.text.isEmpty) {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: "Please enter amount to continue.".needTranslation),
callBackFunc: () {
textFocusNode.requestFocus();
},
isFullScreen: false,
isCloseButtonVisible: true,
);
} else if (habibWalletVM.selectedHospital == null) {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: "Please select hospital to continue.".needTranslation),
callBackFunc: () {
textFocusNode.requestFocus();
},
isFullScreen: false,
isCloseButtonVisible: true,
);
} else {
habibWalletVM.setWalletRechargeAmount(num.parse(amountTextController.text));
habibWalletVM.setDepositorDetails(appState.getAuthenticatedUser()!.patientId.toString(), "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}",
appState.getAuthenticatedUser()!.mobileNumber!);
Navigator.of(context).push(
CustomPageRoute(
page: WalletPaymentConfirmPage(),
),
);
}
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
textColor: AppColors.whiteColor,

@ -0,0 +1,385 @@
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/habib_wallet/habib_wallet_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/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.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:provider/provider.dart';
class WalletPaymentConfirmPage extends StatefulWidget {
const WalletPaymentConfirmPage({super.key});
@override
State<WalletPaymentConfirmPage> createState() => _WalletPaymentConfirmPageState();
}
class _WalletPaymentConfirmPageState extends State<WalletPaymentConfirmPage> {
late PayfortViewModel payfortViewModel;
late AppState appState;
late HabibWalletViewModel habibWalletVM;
MyInAppBrowser? browser;
String selectedPaymentMethod = "";
String transID = "";
@override
void initState() {
scheduleMicrotask(() {
payfortViewModel.initPayfortViewModel();
});
super.initState();
}
@override
Widget build(BuildContext context) {
appState = getIt.get<AppState>();
habibWalletVM = Provider.of<HabibWalletViewModel>(context, listen: false);
payfortViewModel = Provider.of<PayfortViewModel>(context, listen: false);
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: CollapsingListView(
title: "Select Payment Method",
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
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).toShimmer2(isShow: false),
SizedBox(height: 16.h),
"Mada".needTranslation.toText16(isBold: true).toShimmer2(isShow: false),
],
),
SizedBox(width: 8.h),
const Spacer(),
Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon,
iconColor: AppColors.blackColor,
width: 18.h,
height: 13.h,
fit: BoxFit.contain,
).toShimmer2(isShow: false),
],
).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: 40.h, height: 40.h),
SizedBox(width: 8.h),
Image.asset(AppAssets.Mastercard, width: 40.h, height: 40.h),
],
).toShimmer2(isShow: false),
SizedBox(height: 16.h),
"Visa or Mastercard".needTranslation.toText16(isBold: true).toShimmer2(isShow: false),
],
),
SizedBox(width: 8.h),
const Spacer(),
Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon,
iconColor: AppColors.blackColor,
width: 18.h,
height: 13.h,
fit: BoxFit.contain,
).toShimmer2(isShow: false),
],
).paddingSymmetrical(16.h, 16.h),
).paddingSymmetrical(24.h, 0.h).onPress(() {
selectedPaymentMethod = "VISA";
// openPaymentURL("visa");
}),
],
),
),
),
),
Container(
// height: 200.h,
width: MediaQuery.of(context).size.width,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.h,
hasShadow: true,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 24.h),
habibWalletVM.depositorName.toText18(isBold: true).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 12.h),
Wrap(
direction: Axis.horizontal,
spacing: 4.h,
runSpacing: 4.h,
children: [
AppCustomChipWidget(labelText: "${LocaleKeys.fileno.tr(context: context)}.: ${habibWalletVM.fileNumber}"),
AppCustomChipWidget(labelText: "${LocaleKeys.mobileNumber.tr(context: context)}: ${habibWalletVM.mobileNumber}"),
AppCustomChipWidget(labelText: "${habibWalletVM.selectedHospital!.name}"),
],
).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 16.h),
Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 16.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"Total amount to pay".needTranslation.toText16(isBold: true),
Utils.getPaymentAmountWithSymbol(habibWalletVM.walletRechargeAmount.toString().toText24(isBold: true), AppColors.blackColor, 15.h, isSaudiCurrency: true),
],
).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 12.h),
Platform.isIOS
? Utils.buildSvgWithAssets(
icon: AppAssets.apple_pay_button,
width: 200.h,
height: 56.h,
fit: BoxFit.contain,
).paddingSymmetrical(24.h, 0.h).onPress(() {
if (Utils.havePrivilege(103)) {
startApplePay();
} else {}
})
: SizedBox(height: 12.h),
SizedBox(height: 32.h),
],
),
),
],
),
);
}
startApplePay() async {
LoaderBottomSheet.showLoader();
ApplePayInsertRequest applePayInsertRequest = ApplePayInsertRequest();
transID = Utils.getAdvancePaymentTransID(habibWalletVM.selectedHospital!.iD!, int.parse(habibWalletVM.fileNumber));
await payfortViewModel.getPayfortConfigurations(serviceId: ServiceTypeEnum.advancePayment.getIdFromServiceEnum(), projectId: habibWalletVM.selectedHospital!.iD!, integrationId: 2);
applePayInsertRequest.clientRequestID = transID;
applePayInsertRequest.clinicID = 0;
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 = habibWalletVM.selectedHospital!.iD!.toString();
applePayInsertRequest.serviceID = ServiceTypeEnum.appointmentPayment.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 = "Advance Payment";
applePayInsertRequest.liveServiceID = "0";
applePayInsertRequest.latitude = "0.0";
applePayInsertRequest.longitude = "0.0";
applePayInsertRequest.amount = habibWalletVM.walletRechargeAmount.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(habibWalletVM.walletRechargeAmount.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()}");
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();
await payfortViewModel.checkPaymentStatus(
transactionID: transID,
onSuccess: (apiResponse) async {
print(apiResponse.data);
if (payfortViewModel.payfortCheckPaymentStatusResponseModel!.responseMessage!.toLowerCase() == "success") {
await habibWalletVM.HISCreateAdvancePayment(
paymentMethodName: selectedPaymentMethod,
paidAmount: habibWalletVM.walletRechargeAmount,
paymentReference: payfortViewModel.payfortCheckPaymentStatusResponseModel!.fortId!,
patientID: habibWalletVM.fileNumber,
projectID: habibWalletVM.selectedHospital!.iD!,
depositorName: habibWalletVM.depositorName,
onSuccess: (value) async {
await habibWalletVM.addAdvanceNumberRequest(
advanceNumber: Utils.isVidaPlusProject(habibWalletVM.selectedHospital!.iD)
? value.data['OnlineCheckInAppointments'][0]['AdvanceNumber_VP'].toString()
: value.data['OnlineCheckInAppointments'][0]['AdvanceNumber'].toString(),
paymentReference: payfortViewModel.payfortCheckPaymentStatusResponseModel!.fortId!,
onSuccess: (value) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getSuccessWidget(loadingText: "Payment Successful!".needTranslation),
callBackFunc: () {
Navigator.of(context).pop();
Navigator.of(context).pop();
},
isFullScreen: false,
isCloseButtonVisible: true,
);
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: "Payment Failed - ${err}".needTranslation),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
},
onError: (err) {});
// await myAppointmentsViewModel.createAdvancePayment(
// paymentMethodName: selectedPaymentMethod,
// projectID: widget.patientAppointmentHistoryResponseModel.projectID,
// clinicID: widget.patientAppointmentHistoryResponseModel.clinicID,
// appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo.toString(),
// payedAmount: payfortViewModel.payfortCheckPaymentStatusResponseModel!.amount!,
// paymentReference: payfortViewModel.payfortCheckPaymentStatusResponseModel!.fortId!,
// patientID: "4767477",
// patientType: 1,
// onSuccess: (value) async {
// print(value);
// await myAppointmentsViewModel.addAdvanceNumberRequest(
// advanceNumber: Utils.isVidaPlusProject(widget.patientAppointmentHistoryResponseModel.projectID)
// ? value.data['OnlineCheckInAppointments'][0]['AdvanceNumber_VP'].toString()
// : value.data['OnlineCheckInAppointments'][0]['AdvanceNumber'].toString(),
// paymentReference: payfortViewModel.payfortCheckPaymentStatusResponseModel!.fortId!,
// appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo.toString(),
// onSuccess: (value) async {
// if (widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment!) {
// //TODO: Implement LiveCare Check-In API Call
// } else {
// await myAppointmentsViewModel.generateAppointmentQR(
// clinicID: widget.patientAppointmentHistoryResponseModel.clinicID,
// projectID: widget.patientAppointmentHistoryResponseModel.projectID,
// appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo.toString(),
// isFollowUp: myAppointmentsViewModel.patientAppointmentShareResponseModel!.isFollowup!,
// onSuccess: (apiResponse) {
// Future.delayed(Duration(milliseconds: 500), () {
// Navigator.of(context).pop();
// Navigator.pushAndRemoveUntil(
// context,
// CustomPageRoute(
// page: LandingNavigation(),
// ),
// (r) => false);
// Navigator.of(context).push(
// CustomPageRoute(page: MyAppointmentsPage()),
// );
// });
// });
// }
// });
// });
} else {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: "Payment Failed! Please try again.".needTranslation),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
}
});
}
}

@ -0,0 +1,103 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_export.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
class HospitalListItemAdvancePayment extends StatelessWidget {
final HospitalsModel hospitalModel;
final bool isLocationEnabled;
late AppState appState;
HospitalListItemAdvancePayment({super.key, required this.hospitalModel, required this.isLocationEnabled});
@override
Widget build(BuildContext context) {
appState = getIt.get<AppState>();
return DecoratedBox(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: false,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 8.h,
children: [hospitalName],
),
),
Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon,
iconColor: AppColors.blackColor,
width: 18,
height: 13,
fit: BoxFit.contain,
),
],
).paddingSymmetrical(16.h, 16.h),
);
}
Widget get hospitalName => Row(
children: [
Utils.buildSvgWithAssets(
icon: (hospitalModel.isHMC == true) ? AppAssets.hmc : AppAssets.hmg,
).paddingOnly(right: 10),
Expanded(
child: Text(
hospitalModel.name ?? "",
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 16,
color: AppColors.blackColor,
),
),
)
],
);
// Widget get distanceInfo => Row(
// children: [
// Visibility(
// visible: (hospitalModel.distanceInKMs != "0"),
// child: AppCustomChipWidget(
// labelText: "${hospitalData?.distanceInKMs ?? ""} km".needTranslation,
// deleteIcon: AppAssets.location_red,
// deleteIconSize: Size(9, 12),
// backgroundColor: AppColors.secondaryLightRedColor,
// textColor: AppColors.errorColor,
// ),
// ),
// Visibility(
// visible: (hospitalData?.distanceInKMs == "0"),
// child: Row(
// children: [
// AppCustomChipWidget(
// labelText: "Distance not available".needTranslation,
// textColor: AppColors.blackColor,
// ),
// SizedBox(
// width: 8.h,
// )
// ],
// )),
// Visibility(
// visible: !isLocationEnabled,
// child: AppCustomChipWidget(
// labelText: "Location turned off".needTranslation,
// deleteIcon: AppAssets.location_unavailable,
// deleteIconSize: Size(9, 12),
// textColor: AppColors.blackColor,
// )),
// ],
// );
}

@ -27,8 +27,12 @@ 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/habib_wallet/habib_wallet_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/input_widget.dart';
import 'package:provider/provider.dart';
class MultiPageBottomSheet extends StatefulWidget {
const MultiPageBottomSheet({Key? key}) : super(key: key);
@ -40,80 +44,139 @@ class MultiPageBottomSheet extends StatefulWidget {
class _MultiPageBottomSheetState extends State<MultiPageBottomSheet> {
late AppState appState;
TextEditingController fileNumberEditingController = TextEditingController();
@override
Widget build(BuildContext context) {
appState = getIt.get<AppState>();
return SizedBox(
height: MediaQuery.of(context).size.height * 0.38,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 16.h,
hasShadow: false,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.myMedicalFile.tr(context: context).toText16(color: AppColors.textColor, weight: FontWeight.w500),
"${LocaleKeys.fileno.tr(context: context)}: ${appState.getAuthenticatedUser()!.patientId}".toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500),
],
),
Utils.buildSvgWithAssets(icon: AppAssets.forward_chevron_icon, iconColor: AppColors.textColor, width: 15.h, height: 15.h),
],
).paddingAll(16.h),
).onPress(() {
Navigator.of(context).pop();
}),
SizedBox(height: 16.h),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 16.h,
hasShadow: false,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.familyTitle.tr(context: context).toText16(color: AppColors.textColor, weight: FontWeight.w500),
"Select a medical file from your family".needTranslation.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
],
),
Utils.buildSvgWithAssets(icon: AppAssets.forward_chevron_icon, iconColor: AppColors.textColor, width: 15.h, height: 15.h),
],
).paddingAll(16.h),
return Consumer<HabibWalletViewModel>(builder: (context, habibWalletVM, child) {
return Padding(
padding: MediaQuery.of(context).viewInsets,
child: getCurrentIndexWidget(habibWalletVM),
);
});
}
Widget getCurrentIndexWidget(HabibWalletViewModel habibWalletVM) {
switch (habibWalletVM.currentIndex) {
case 0:
return getSelectMedicalFileContent(habibWalletVM);
case 1:
return getOtherAccountContent(habibWalletVM);
case 2:
return getOtherAccountContent(habibWalletVM);
default:
return getSelectMedicalFileContent(habibWalletVM);
}
}
Widget getOtherAccountContent(HabibWalletViewModel habibWalletVM) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Enter File Number".needTranslation.toText20(weight: FontWeight.w600),
SizedBox(height: 12.h),
TextInputWidget(
labelText: LocaleKeys.fileNumber.tr(),
hintText: "xxxxxxxxx",
controller: fileNumberEditingController,
// focusNode: _nationalIdFocusNode,
isEnable: true,
prefix: null,
isAllowRadius: true,
isBorderAllowed: false,
isAllowLeadingIcon: true,
autoFocus: true,
padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 8.h),
leadingIcon: AppAssets.requests,
).withVerticalPadding(8),
SizedBox(height: 12.h),
CustomButton(
text: LocaleKeys.submit.tr(),
onPressed: () async {
await habibWalletVM.getPatientInfoByPatientID(patientID: fileNumberEditingController.text, onSuccess: (response) {
print(response.data["GetPatientInfoByPatientIDList"][0]["FullName"]);
}, onError: (error) {});
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedBorderColor,
textColor: AppColors.whiteColor,
),
],
);
}
Widget getSelectMedicalFileContent(HabibWalletViewModel habibWalletVM) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 16.h,
hasShadow: false,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.myMedicalFile.tr(context: context).toText16(color: AppColors.textColor, weight: FontWeight.w500),
"${LocaleKeys.fileno.tr(context: context)}: ${appState.getAuthenticatedUser()!.patientId}".toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500),
],
),
Utils.buildSvgWithAssets(icon: AppAssets.forward_chevron_icon, iconColor: AppColors.textColor, width: 15.h, height: 15.h),
],
).paddingAll(16.h),
).onPress(() {
Navigator.of(context).pop();
}),
SizedBox(height: 16.h),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 16.h,
hasShadow: false,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.familyTitle.tr(context: context).toText16(color: AppColors.textColor, weight: FontWeight.w500),
"Select a medical file from your family".needTranslation.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
],
),
Utils.buildSvgWithAssets(icon: AppAssets.forward_chevron_icon, iconColor: AppColors.textColor, width: 15.h, height: 15.h),
],
).paddingAll(16.h),
),
SizedBox(height: 16.h),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 16.h,
hasShadow: false,
),
SizedBox(height: 16.h),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 16.h,
hasShadow: false,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.otherAccount.tr(context: context).toText16(color: AppColors.textColor, weight: FontWeight.w500),
"Any active medical file from HMG".toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
],
),
Utils.buildSvgWithAssets(icon: AppAssets.forward_chevron_icon, iconColor: AppColors.textColor, width: 15.h, height: 15.h),
],
).paddingAll(16.h),
).onPress(() {}),
],
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.otherAccount.tr(context: context).toText16(color: AppColors.textColor, weight: FontWeight.w500),
"Any active medical file from HMG".toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
],
),
Utils.buildSvgWithAssets(icon: AppAssets.forward_chevron_icon, iconColor: AppColors.textColor, width: 15.h, height: 15.h),
],
).paddingAll(16.h),
).onPress(() {
habibWalletVM.setCurrentIndex(2);
}),
],
);
}
}

@ -0,0 +1,96 @@
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/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/habib_wallet/habib_wallet_view_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/appointment_via_region_viewmodel.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/facility_selection.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/hospital_bottom_sheet/hospital_list_items.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/hospital_bottom_sheet/type_selection_widget.dart';
import 'package:hmg_patient_app_new/presentation/habib_wallet/widgets/hospital_list_item.dart';
import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/theme/colors.dart' show AppColors;
import 'package:hmg_patient_app_new/widgets/input_widget.dart';
import 'package:provider/provider.dart';
class SelectHospitalBottomSheet extends StatelessWidget {
late HabibWalletViewModel habibWalletVM;
final TextEditingController searchText = TextEditingController();
SelectHospitalBottomSheet({super.key});
@override
Widget build(BuildContext context) {
habibWalletVM = Provider.of<HabibWalletViewModel>(context, listen: false);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Text(
// LocaleKeys.selectHospital.tr(),
// style: TextStyle(
// fontSize: 21,
// fontWeight: FontWeight.w600,
// color: AppColors.blackColor,
// ),
// ),
Text(
"Please select the hospital you want to make an advance payment for.".needTranslation,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: AppColors.greyTextColor,
),
),
SizedBox(height: 16.h),
// TextInputWidget(
// labelText: LocaleKeys.search.tr(),
// hintText: "Search Hospital".tr(),
// controller: searchText,
// onChange: (value) {
// // appointmentsViewModel.filterHospitalListByString(value, regionalViewModel.selectedRegionId , regionalViewModel.selectedFacilityType ==
// // FacilitySelection.HMG.name);
// },
// isEnable: true,
// prefix: null,
// autoFocus: false,
// isBorderAllowed: false,
// keyboardType: TextInputType.text,
// isAllowLeadingIcon: true,
// selectionType: SelectionTypeEnum.search,
// padding: EdgeInsets.symmetric(
// vertical: ResponsiveExtension(10).h,
// horizontal: ResponsiveExtension(15).h,
// ),
// ),
// SizedBox(height: 24.h),
// TypeSelectionWidget(
// hmcCount: "0",
// hmgCount: "0",
// ),
// SizedBox(height: 21.h),
SizedBox(
height: MediaQuery.sizeOf(context).height * .4,
child: ListView.separated(
itemBuilder: (_, index) {
return HospitalListItemAdvancePayment(
hospitalModel: habibWalletVM.advancePaymentHospitals[index],
isLocationEnabled: false,
).onPress(() {
habibWalletVM.setSelectedHospital(habibWalletVM.advancePaymentHospitals[index]);
Navigator.of(context).pop();
});
},
separatorBuilder: (_, __) => SizedBox(
height: 16.h,
),
itemCount: habibWalletVM.advancePaymentHospitals.length),
)
],
);
}
}

@ -22,6 +22,7 @@ import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_mo
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/appointments/my_doctors_page.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/book_appointment_page.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/appointment_calendar.dart';
import 'package:hmg_patient_app_new/presentation/insurance/insurance_home_page.dart';
import 'package:hmg_patient_app_new/presentation/insurance/widgets/patient_insurance_card.dart';
@ -117,6 +118,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
child: Padding(
padding: EdgeInsets.all(16.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
@ -132,35 +134,19 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
children: [
"${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}".toText18(isBold: true),
SizedBox(height: 4.h),
Row(
Wrap(
direction: Axis.horizontal,
spacing: 4.h,
runSpacing: 4.h,
children: [
CustomButton(
AppCustomChipWidget(
icon: AppAssets.file_icon,
iconColor: AppColors.blackColor,
iconSize: 12.h,
text: "File no: ${appState.getAuthenticatedUser()!.patientId}",
onPressed: () {},
backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor,
textColor: AppColors.blackColor,
fontSize: 10,
fontWeight: FontWeight.normal,
borderRadius: 12,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 30.h,
labelText: "File no: ${appState.getAuthenticatedUser()!.patientId}",
),
SizedBox(width: 4.h),
CustomButton(
text: LocaleKeys.verified.tr(context: context),
onPressed: () {},
backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor,
textColor: AppColors.blackColor,
fontSize: 10,
fontWeight: FontWeight.normal,
borderRadius: 12,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 30.h,
AppCustomChipWidget(
icon: AppAssets.checkmark_icon,
labelText: LocaleKeys.verified.tr(context: context),
iconColor: AppColors.successColor,
),
],
),
@ -171,55 +157,21 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
SizedBox(height: 16.h),
Divider(color: AppColors.dividerColor, height: 1.h),
SizedBox(height: 16.h),
Row(
Wrap(
direction: Axis.horizontal,
spacing: 4.h,
runSpacing: 4.h,
children: [
CustomButton(
text: "${appState.getAuthenticatedUser()!.age} Years Old",
onPressed: () {},
backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor,
textColor: AppColors.blackColor,
fontSize: 10,
fontWeight: FontWeight.normal,
borderRadius: 12,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 30.h,
AppCustomChipWidget(
labelText: "${appState.getAuthenticatedUser()!.age} Years Old",
),
SizedBox(width: 4.h),
CustomButton(
AppCustomChipWidget(
icon: AppAssets.blood_icon,
labelText: "Blood: ${appState.getUserBloodGroup}",
iconColor: AppColors.primaryRedColor,
iconSize: 13.h,
text: "Blood: ${appState.getUserBloodGroup}",
onPressed: () {},
backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor,
textColor: AppColors.blackColor,
fontSize: 10,
fontWeight: FontWeight.normal,
borderRadius: 12,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 30.h,
),
// SizedBox(width: 4.h),
// CustomButton(
// icon: AppAssets.insurance_active_icon,
// iconColor: AppColors.successColor,
// iconSize: 13.h,
// text: "Insurance Active",
// onPressed: () {},
// backgroundColor: AppColors.bgGreenColor.withOpacity(0.20),
// borderColor: AppColors.bgGreenColor.withOpacity(0.0),
// textColor: AppColors.blackColor,
// fontSize: 10,
// fontWeight: FontWeight.normal,
// borderRadius: 12,
// padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
// height: 30.h,
// ),
],
),
SizedBox(height: 8.h),
],
),
),
@ -327,7 +279,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
scrollDirection: Axis.horizontal,
padding: EdgeInsets.only(top: 16.h, left: 24.h, right: 24.h, bottom: 0.h),
shrinkWrap: true,
itemCount: myAppointmentsVM.isMyAppointmentsLoading ? 5 : myAppointmentsVM.patientAppointmentsHistoryList.length,
itemCount: myAppointmentsVM.isMyAppointmentsLoading ? 5 : (myAppointmentsVM.patientAppointmentsHistoryList.isNotEmpty ? myAppointmentsVM.patientAppointmentsHistoryList.length : 1),
itemBuilder: (context, index) {
return AnimationConfiguration.staggeredList(
position: index,
@ -345,14 +297,50 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
onRescheduleTap: () {},
onAskDoctorTap: () {},
)
: MedicalFileAppointmentCard(
patientAppointmentHistoryResponseModel: myAppointmentsVM.patientAppointmentsHistoryList[index],
myAppointmentsViewModel: myAppointmentsViewModel,
onRescheduleTap: () {
openDoctorScheduleCalendar(myAppointmentsVM.patientAppointmentsHistoryList[index]);
},
onAskDoctorTap: () {},
),
: myAppointmentsVM.patientAppointmentsHistoryList.isNotEmpty
? MedicalFileAppointmentCard(
patientAppointmentHistoryResponseModel: myAppointmentsVM.patientAppointmentsHistoryList[index],
myAppointmentsViewModel: myAppointmentsViewModel,
onRescheduleTap: () {
openDoctorScheduleCalendar(myAppointmentsVM.patientAppointmentsHistoryList[index]);
},
onAskDoctorTap: () {},
)
: Container(
width: MediaQuery.of(context).size.width - 48.h,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24, hasShadow: true),
child: Padding(
padding: EdgeInsets.all(12.h),
child: Column(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.home_calendar_icon, width: 32.h, height: 32.h),
SizedBox(height: 12.h),
"You do not have any appointments. Please book an appointment".needTranslation.toText12(isCenter: true),
SizedBox(height: 12.h),
CustomButton(
text: LocaleKeys.bookAppo.tr(context: context),
onPressed: () {
Navigator.of(context).push(
CustomPageRoute(
page: BookAppointmentPage(),
),
);
},
backgroundColor: Color(0xffFEE9EA),
borderColor: Color(0xffFEE9EA),
textColor: Color(0xffED1C2B),
fontSize: 14,
fontWeight: FontWeight.w500,
borderRadius: 12,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40,
icon: AppAssets.add_icon,
iconColor: AppColors.primaryRedColor,
),
],
),
),
),
),
),
),

@ -106,7 +106,7 @@ class _ProfileSettingsState extends State<ProfileSettings> {
),
Spacer(),
Consumer<HabibWalletViewModel>(builder: (context, habibWalletVM, child) {
return Utils.getPaymentAmountWithSymbol2(habibWalletVM.habibWalletAmount, AppColors.whiteColor, 13.h, isExpanded: false)
return Utils.getPaymentAmountWithSymbol2(habibWalletVM.habibWalletAmount, isExpanded: false)
.toShimmer2(isShow: habibWalletVM.isWalletAmountLoading, radius: 12.h, width: 80.h, height: 24.h);
}),
CustomButton(

@ -55,7 +55,7 @@ dependencies:
uuid: ^4.5.1
health: ^13.1.3
# health: 12.0.1
fl_chart: ^1.0.0
fl_chart: ^1.1.1
geolocator: ^14.0.2
dropdown_search: ^6.0.2
google_maps_flutter: ^2.12.3

Loading…
Cancel
Save