pull/28/head
haroon amjad 2 months ago
parent 6b2ec5aa2c
commit ccd29f0cf9

@ -26,6 +26,7 @@ abstract class ApiClient {
bool isAllowAny,
bool isExternal,
bool isRCService,
bool isPaymentServices,
bool bypassConnectionCheck,
});
@ -97,6 +98,7 @@ class ApiClientImp implements ApiClient {
bool isAllowAny = false,
bool isExternal = false,
bool isRCService = false,
bool isPaymentServices = false,
bool bypassConnectionCheck = false,
}) async {
String url;
@ -204,7 +206,12 @@ class ApiClientImp implements ApiClient {
} else {
var parsed = json.decode(utf8.decode(response.bodyBytes));
if (isAllowAny) {
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage']);
if (isPaymentServices) {
onSuccess(parsed, statusCode, messageStatus: 1, errorMessage: "");
} else {
onSuccess(parsed, statusCode,
messageStatus: parsed.contains('MessageStatus') ? parsed['MessageStatus'] : 1, errorMessage: parsed.contains('ErrorEndUserMessage') ? parsed['ErrorEndUserMessage'] : "");
}
} else {
if (parsed['Response_Message'] != null) {
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);

@ -7,6 +7,8 @@ import 'package:hmg_patient_app_new/features/authentication/authentication_repo.
import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_repo.dart';
import 'package:hmg_patient_app_new/features/common/common_repo.dart';
import 'package:hmg_patient_app_new/features/habib_wallet/models/habib_wallet_repo.dart';
import 'package:hmg_patient_app_new/features/habib_wallet/models/habib_wallet_view_model.dart';
import 'package:hmg_patient_app_new/features/insurance/insurance_repo.dart';
import 'package:hmg_patient_app_new/features/insurance/insurance_view_model.dart';
import 'package:hmg_patient_app_new/features/lab/lab_repo.dart';
@ -85,6 +87,7 @@ class AppDependencies {
getIt.registerLazySingleton<InsuranceRepo>(() => InsuranceRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<PayfortRepo>(() => PayfortRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<LocalAuthService>(() => LocalAuthService(loggerService: getIt<LoggerService>(), localAuth: getIt<LocalAuthentication>()));
getIt.registerLazySingleton<HabibWalletRepo>(() => HabibWalletRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
// ViewModels
// Global/shared VMs LazySingleton
@ -125,24 +128,24 @@ class AppDependencies {
);
getIt.registerLazySingleton<PayfortViewModel>(
() => PayfortViewModel(
() => PayfortViewModel(
payfortRepo: getIt(),
errorHandlerService: getIt(),
),
);
getIt.registerLazySingleton<AuthenticationViewModel>(
() => AuthenticationViewModel(
authenticationRepo: getIt(),
cacheService: getIt(),
navigationService: getIt(),
dialogService: getIt(),
appState: getIt(),
getIt.registerLazySingleton<HabibWalletViewModel>(
() => HabibWalletViewModel(
habibWalletRepo: getIt(),
errorHandlerService: getIt(),
localAuthService: getIt()
),
);
getIt.registerLazySingleton<AuthenticationViewModel>(
() => AuthenticationViewModel(
authenticationRepo: getIt(), cacheService: getIt(), navigationService: getIt(), dialogService: getIt(), appState: getIt(), errorHandlerService: getIt(), localAuthService: getIt()),
);
// Screen-specific VMs Factory
// getIt.registerFactory<BookAppointmentsViewModel>(
// () => BookAppointmentsViewModel(

@ -568,9 +568,10 @@ class Utils {
);
}
static Widget getPaymentAmountWithSymbol(Widget paymentAmountWidget, Color iconColor, double iconSize, {bool isSaudiCurrency = true}) {
static Widget getPaymentAmountWithSymbol(Widget paymentAmountWidget, Color iconColor, double iconSize, {bool isSaudiCurrency = true, bool isExpanded = true}) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisAlignment: isExpanded ? MainAxisAlignment.spaceBetween : MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
appState.isArabic()
? Container()

@ -39,6 +39,8 @@ extension WidgetExtensions on Widget {
child: this,
);
//TODO: @Sikander to make shimmer widget width dynamic
Widget toShimmer2({bool isShow = true, double radius = 20}) => isShow
? Shimmer.fromColors(
baseColor: const Color(0xffe8eff0),

@ -525,7 +525,7 @@ class AuthenticationViewModel extends ChangeNotifier {
if (!_appState.isAuthenticated) {
loginTypeEnum = (_appState.deviceTypeID == 1 ? LoginTypeEnum.face : LoginTypeEnum.fingerprint);
print(loginTypeEnum);
checkActivationCode(otpTypeEnum: OTPTypeEnum.faceIDFingerprint, activationCode: null, onWrongActivationCode: (String? message) {});
await checkActivationCode(otpTypeEnum: OTPTypeEnum.faceIDFingerprint, activationCode: null, onWrongActivationCode: (String? message) {});
insertPatientIMEIData((_appState.deviceTypeID == 1 ? LoginTypeEnum.face.toInt : LoginTypeEnum.fingerprint.toInt));
} else {
// authenticated = true;

@ -0,0 +1,58 @@
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/services/logger_service.dart';
abstract class HabibWalletRepo {
Future<Either<Failure, GenericApiModel<dynamic>>> getPatientBalanceAmount();
}
class HabibWalletRepoImp implements HabibWalletRepo {
final ApiClient apiClient;
final LoggerService loggerService;
HabibWalletRepoImp({required this.loggerService, required this.apiClient});
@override
Future<Either<Failure, GenericApiModel<dynamic>>> getPatientBalanceAmount() async {
Map<String, dynamic> mapDevice = {};
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
GET_PATIENT_AdVANCE_BALANCE_AMOUNT,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
// final list = response['ListPLO'];
// if (list == null || list.isEmpty) {
// throw Exception("lab list is empty");
// }
// final labOrders = list.map((item) => PatientLabOrdersResponseModel.fromJson(item as Map<String, dynamic>)).toList().cast<PatientLabOrdersResponseModel>();
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: response["TotalAdvanceBalanceAmount"],
);
} 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,39 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/features/habib_wallet/models/habib_wallet_repo.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
class HabibWalletViewModel extends ChangeNotifier {
bool isWalletAmountLoading = false;
num habibWalletAmount = 0;
HabibWalletRepo habibWalletRepo;
ErrorHandlerService errorHandlerService;
HabibWalletViewModel({required this.habibWalletRepo, required this.errorHandlerService});
initHabibWalletProvider() {
isWalletAmountLoading = true;
habibWalletAmount = 0;
notifyListeners();
}
Future<void> getPatientBalanceAmount({Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await habibWalletRepo.getPatientBalanceAmount();
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) {
habibWalletAmount = apiResponse.data!;
isWalletAmountLoading = false;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
}

@ -7,7 +7,7 @@ import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_
import 'package:hmg_patient_app_new/services/logger_service.dart';
abstract class LabRepo {
Future<Either<Failure, GenericApiModel<List<PatientLabOrdersResponseModel>>>> getPatientLabOrders({required String patientId});
Future<Either<Failure, GenericApiModel<List<PatientLabOrdersResponseModel>>>> getPatientLabOrders();
}
class LabRepoImp implements LabRepo {
@ -17,7 +17,7 @@ class LabRepoImp implements LabRepo {
LabRepoImp({required this.loggerService, required this.apiClient});
@override
Future<Either<Failure, GenericApiModel<List<PatientLabOrdersResponseModel>>>> getPatientLabOrders({required String patientId}) async {
Future<Either<Failure, GenericApiModel<List<PatientLabOrdersResponseModel>>>> getPatientLabOrders() async {
Map<String, dynamic> mapDevice = {};
try {

@ -29,7 +29,7 @@ class LabViewModel extends ChangeNotifier {
}
Future<void> getPatientLabOrders({Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await labRepo.getPatientLabOrders(patientId: "1231755");
final result = await labRepo.getPatientLabOrders();
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),

@ -53,7 +53,7 @@ class PayfortRepoImp implements PayfortRepo {
} catch (e) {
failure = DataParsingFailure(e.toString());
}
}, isAllowAny: true);
}, isAllowAny: true, isPaymentServices: true);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
@ -80,7 +80,7 @@ class PayfortRepoImp implements PayfortRepo {
} catch (e) {
failure = DataParsingFailure(e.toString());
}
}, isAllowAny: true);
}, isAllowAny: true, isPaymentServices: true);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
@ -109,7 +109,7 @@ class PayfortRepoImp implements PayfortRepo {
} catch (e) {
failure = DataParsingFailure(e.toString());
}
}, isAllowAny: true, isExternal: true);
}, isAllowAny: true, isExternal: true, isPaymentServices: true);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
@ -139,7 +139,7 @@ class PayfortRepoImp implements PayfortRepo {
} catch (e) {
failure = DataParsingFailure(e.toString());
}
}, isAllowAny: true);
}, isAllowAny: true, isPaymentServices: true);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);

@ -9,6 +9,7 @@ import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart';
import 'package:hmg_patient_app_new/features/habib_wallet/models/habib_wallet_view_model.dart';
import 'package:hmg_patient_app_new/features/insurance/insurance_view_model.dart';
import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/medical_file_view_model.dart';
@ -109,6 +110,12 @@ void main() async {
errorHandlerService: getIt(),
),
),
ChangeNotifierProvider<HabibWalletViewModel>(
create: (_) => HabibWalletViewModel(
habibWalletRepo: getIt(),
errorHandlerService: getIt(),
),
),
ChangeNotifierProvider<AuthenticationViewModel>(
create: (_) => AuthenticationViewModel(
authenticationRepo: getIt(),

@ -55,6 +55,7 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
void initState() {
scheduleMicrotask(() {
payfortViewModel.initPayfortViewModel();
payfortViewModel.setIsApplePayConfigurationLoading(false);
myAppointmentsViewModel.getPatientShareAppointment(
widget.patientAppointmentHistoryResponseModel.projectID,
widget.patientAppointmentHistoryResponseModel.clinicID,
@ -283,7 +284,7 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
height: 80.h,
fit: BoxFit.contain,
).paddingSymmetrical(24.h, 0.h).onPress(() {
payfortVM.setIsApplePayConfigurationLoading(true);
// payfortVM.setIsApplePayConfigurationLoading(true);
startApplePay();
}),
SizedBox(height: 12.h),
@ -344,62 +345,74 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
// updateTamaraRequestStatus("Failed", "00", Utils.getAppointmentTransID(appo.projectID, appo.clinicID, appo.appointmentNo), tamaraOrderID, num.parse(selectedInstallments), appo);
// }
} else {
showCommonBottomSheet(context,
child: Utils.getLoadingWidget(), callBackFunc: (str) {}, title: "", height: ResponsiveExtension.screenHeight * 0.3, isCloseButtonVisible: false, isDismissible: false, isFullScreen: false);
await payfortViewModel.checkPaymentStatus(
transactionID: transID,
onSuccess: (apiResponse) async {
print(apiResponse.data);
if (payfortViewModel.payfortCheckPaymentStatusResponseModel!.responseMessage!.toLowerCase() == "success") {
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(appState, 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,
FadePage(
page: LandingNavigation(),
),
(r) => false);
Navigator.of(context).push(
FadePage(page: MyAppointmentsPage()),
);
});
});
}
});
});
} else {}
});
checkPaymentStatus();
// checkPaymentStatus(appo);
}
}
void checkPaymentStatus() async {
showCommonBottomSheet(context,
child: Utils.getLoadingWidget(), callBackFunc: (str) {}, title: "", height: ResponsiveExtension.screenHeight * 0.3, isCloseButtonVisible: false, isDismissible: false, isFullScreen: false);
await payfortViewModel.checkPaymentStatus(
transactionID: transID,
onSuccess: (apiResponse) async {
print(apiResponse.data);
if (payfortViewModel.payfortCheckPaymentStatusResponseModel!.responseMessage!.toLowerCase() == "success") {
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(appState, 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,
FadePage(
page: LandingNavigation(),
),
(r) => false);
Navigator.of(context).push(
FadePage(page: MyAppointmentsPage()),
);
});
});
}
});
});
} else {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: "Payment Failed! Please try again.".needTranslation),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
}
});
}
openPaymentURL(String paymentMethod) {
browser = MyInAppBrowser(onExitCallback: onBrowserExit, onLoadStartCallback: onBrowserLoadStart, context: context);
transID = Utils.getAppointmentTransID(
@ -433,6 +446,8 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
}
startApplePay() async {
showCommonBottomSheet(context,
child: Utils.getLoadingWidget(), callBackFunc: (str) {}, title: "", height: ResponsiveExtension.screenHeight * 0.3, isCloseButtonVisible: false, isDismissible: false, isFullScreen: false);
transID = Utils.getAppointmentTransID(
widget.patientAppointmentHistoryResponseModel.projectID,
widget.patientAppointmentHistoryResponseModel.clinicID,
@ -447,8 +462,7 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
applePayInsertRequest.clientRequestID = transID;
applePayInsertRequest.clinicID = widget.patientAppointmentHistoryResponseModel.clinicID;
//TODO: Need to pass dynamic params to the payment request instead of static values
applePayInsertRequest.currency = "SAR";
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}";
@ -460,8 +474,8 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
applePayInsertRequest.serviceID = ServiceTypeEnum.appointmentPayment.getIdFromServiceEnum().toString();
applePayInsertRequest.channelID = 3;
applePayInsertRequest.patientID = appState.getAuthenticatedUser()!.patientId.toString();
applePayInsertRequest.patientTypeID = 1;
applePayInsertRequest.patientOutSA = 0;
applePayInsertRequest.patientTypeID = appState.getAuthenticatedUser()!.patientType;
applePayInsertRequest.patientOutSA = appState.getAuthenticatedUser()!.outSa;
applePayInsertRequest.appointmentDate = widget.patientAppointmentHistoryResponseModel.appointmentDate;
applePayInsertRequest.appointmentNo = widget.patientAppointmentHistoryResponseModel.appointmentNo;
applePayInsertRequest.orderDescription = "Appointment Payment";
@ -472,7 +486,7 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
applePayInsertRequest.isSchedule = widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment! ? "1" : "0";
applePayInsertRequest.language = appState.isArabic() ? 'ar' : 'en';
applePayInsertRequest.languageID = appState.isArabic() ? 1 : 2;
applePayInsertRequest.userName = 3628599;
applePayInsertRequest.userName = appState.getAuthenticatedUser()!.patientId;
applePayInsertRequest.responseContinueURL = "http://hmg.com/Documents/success.html";
applePayInsertRequest.backClickUrl = "http://hmg.com/Documents/success.html";
applePayInsertRequest.paymentOption = "ApplePay";
@ -499,12 +513,22 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
merchantIdentifier: payfortViewModel.payfortProjectDetailsRespModel!.merchantIdentifier,
applePayAccessCode: payfortViewModel.payfortProjectDetailsRespModel!.accessCode,
applePayShaRequestPhrase: payfortViewModel.payfortProjectDetailsRespModel!.shaRequest,
currency: "SAR",
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 {
Navigator.of(context).pop();
log("successResult: ${successResult.responseMessage.toString()}");
checkPaymentStatus();
},
// projectId: appo.projectID,
// serviceTypeEnum: ServiceTypeEnum.appointmentPayment,

@ -0,0 +1,111 @@
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/habib_wallet/models/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/recharge_wallet_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/transitions/fade_page.dart';
import 'package:provider/provider.dart';
class HabibWalletPage extends StatefulWidget {
const HabibWalletPage({super.key});
@override
State<HabibWalletPage> createState() => _HabibWalletState();
}
class _HabibWalletState extends State<HabibWalletPage> {
@override
Widget build(BuildContext context) {
AppState _appState = getIt.get<AppState>();
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
appBar: AppBar(
title: LocaleKeys.myWallet.tr(context: context).toText18(),
backgroundColor: AppColors.bgScaffoldColor,
),
body: Padding(
padding: EdgeInsets.all(24.h),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.myWallet.tr(context: context).toText24(isBold: true),
SizedBox(height: 24.h),
Container(
width: double.infinity,
height: 180.h,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.blackBgColor,
borderRadius: 24,
),
child: Padding(
padding: EdgeInsets.all(16.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"${_appState.getAuthenticatedUser()!.firstName!} ${_appState.getAuthenticatedUser()!.lastName!}".toText19(isBold: true, color: AppColors.whiteColor),
"MRN: ${_appState.getAuthenticatedUser()!.patientId!}".toText14(weight: FontWeight.w500, color: AppColors.greyTextColor),
],
),
Utils.buildSvgWithAssets(icon: AppAssets.habiblogo, width: 24.h, height: 24.h),
],
),
Spacer(),
LocaleKeys.balanceAmount.tr(context: context).toText14(weight: FontWeight.w500, color: AppColors.whiteColor),
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);
}),
],
),
),
),
SizedBox(height: 16.h),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CustomButton(
icon: AppAssets.recharge_icon,
iconSize: 21.h,
text: "Recharge".needTranslation,
onPressed: () {
Navigator.of(context).push(
FadePage(
page: RechargeWalletPage(),
),
);
},
backgroundColor: AppColors.infoColor,
borderColor: AppColors.infoColor,
textColor: AppColors.whiteColor,
fontSize: 14,
fontWeight: FontWeight.bold,
borderRadius: 12,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h,
),
],
),
],
),
),
),
);
}
}

@ -0,0 +1,105 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.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/input_widget.dart';
class RechargeWalletPage extends StatefulWidget {
const RechargeWalletPage({super.key});
@override
State<RechargeWalletPage> createState() => _RechargeWalletPageState();
}
class _RechargeWalletPageState extends State<RechargeWalletPage> {
FocusNode textFocusNode = FocusNode();
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
appBar: AppBar(
title: LocaleKeys.createAdvancedPayment.tr(context: context).toText18(),
backgroundColor: AppColors.bgScaffoldColor,
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(24.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.createAdvancedPayment.tr(context: context).toText20(isBold: true),
SizedBox(height: 24.h),
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,
),
),
AppColors.textColor,
13.h,
isExpanded: false),
const Spacer(),
"SAR".needTranslation.toText20(color: AppColors.greyTextColor, weight: FontWeight.w500),
],
),
],
),
),
),
],
),
),
)),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.h,
hasShadow: false,
),
),
],
),
);
}
}

@ -1,3 +1,5 @@
import 'dart:async';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
@ -10,6 +12,7 @@ import 'package:hmg_patient_app_new/extensions/int_extensions.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart';
import 'package:hmg_patient_app_new/features/habib_wallet/models/habib_wallet_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/authentication/quick_login.dart';
import 'package:hmg_patient_app_new/presentation/home/data/landing_page_data.dart';
@ -35,22 +38,32 @@ class LandingPage extends StatefulWidget {
class _LandingPageState extends State<LandingPage> {
late final AuthenticationViewModel authVM;
late final HabibWalletViewModel habibWalletVM;
late AppState appState;
@override
void initState() {
authVM = context.read<AuthenticationViewModel>();
habibWalletVM = context.read<HabibWalletViewModel>();
authVM.savePushTokenToAppState();
if (mounted) {
authVM.checkLastLoginStatus(() {
showQuickLogin(context, false);
});
}
scheduleMicrotask(() {
if (appState.isAuthenticated) {
habibWalletVM.initHabibWalletProvider();
habibWalletVM.getPatientBalanceAmount();
}
});
super.initState();
}
@override
Widget build(BuildContext context) {
AppState appState = getIt.get<AppState>();
appState = getIt.get<AppState>();
NavigationService navigationService = getIt.get<NavigationService>();
return Scaffold(

@ -4,8 +4,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/models/habib_wallet_view_model.dart';
import 'package:hmg_patient_app_new/presentation/habib_wallet/habib_wallet_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/transitions/fade_page.dart';
import 'package:provider/provider.dart';
class HabibWalletCard extends StatelessWidget {
const HabibWalletCard({super.key});
@ -69,19 +73,21 @@ class HabibWalletCard extends StatelessWidget {
],
),
SizedBox(height: 4.h),
Row(
children: [
Utils.buildSvgWithAssets(
icon: AppAssets.saudi_riyal_icon,
iconColor: AppColors.dividerColor,
width: 24.h,
height: 24.h,
fit: BoxFit.contain,
),
SizedBox(width: 8.h),
"200.18".toText32(isBold: true),
],
),
Consumer<HabibWalletViewModel>(builder: (context, habibWalletVM, child) {
return Row(
children: [
Utils.buildSvgWithAssets(
icon: AppAssets.saudi_riyal_icon,
iconColor: AppColors.dividerColor,
width: 24.h,
height: 24.h,
fit: BoxFit.contain,
),
SizedBox(width: 8.h),
habibWalletVM.habibWalletAmount.toString().toText32(isBold: true).toShimmer2(isShow: habibWalletVM.isWalletAmountLoading, radius: 12.h),
],
);
}),
Padding(
padding: EdgeInsets.symmetric(horizontal: 50.h),
child: Row(
@ -90,7 +96,13 @@ class HabibWalletCard extends StatelessWidget {
SizedBox(width: 2.h),
Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 10.h),
],
),
).onPress(() {
Navigator.of(context).push(
FadePage(
page: HabibWalletPage(),
),
);
}),
),
SizedBox(height: 16.h),
Row(
@ -103,7 +115,7 @@ class HabibWalletCard extends StatelessWidget {
CustomButton(
icon: AppAssets.recharge_icon,
iconSize: 18.h,
text: "Recharge",
text: "Recharge".needTranslation,
onPressed: () {},
backgroundColor: AppColors.infoColor,
borderColor: AppColors.infoColor,

@ -5,9 +5,11 @@ 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/enums.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/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/dropdown/country_dropdown_widget.dart';
import 'package:keyboard_actions/keyboard_actions.dart';
import '../core/dependencies.dart';
@ -36,6 +38,8 @@ class TextInputWidget extends StatelessWidget {
final String? errorMessage;
Function(CountryEnum)? onCountryChange;
final SelectionTypeEnum? selectionType;
final num? fontSize;
final bool? isWalletAmountInput;
// final List<Country> countryList;
// final Function(Country)? onCountryChange;
@ -63,10 +67,37 @@ class TextInputWidget extends StatelessWidget {
this.errorMessage,
this.onCountryChange,
this.selectionType,
this.fontSize = 14,
this.isWalletAmountInput = false,
// this.countryList = const [],
// this.onCountryChange,
});
final FocusNode _focusNode = FocusNode();
KeyboardActionsConfig get _keyboardActionsConfig {
return KeyboardActionsConfig(
keyboardActionsPlatform: KeyboardActionsPlatform.ALL,
keyboardBarColor: const Color(0xFFCAD1D9), //Apple keyboard color
actions: [
KeyboardActionsItem(
focusNode: focusNode ?? _focusNode,
toolbarButtons: [
(node) {
return GestureDetector(
onTap: () => node.unfocus(),
child: Container(
padding: const EdgeInsets.all(12.0),
child: "Done".toText16(weight: FontWeight.w500, color: AppColors.infoColor),
),
);
}
],
),
],
);
}
@override
Widget build(BuildContext context) {
final errorColor = AppColors.primaryRedColor;
@ -184,40 +215,46 @@ class TextInputWidget extends StatelessWidget {
}
Widget _buildTextField(BuildContext context) {
return TextField(
enabled: isEnable,
scrollPadding: EdgeInsets.zero,
keyboardType: keyboardType,
controller: controller,
readOnly: isReadOnly,
textAlignVertical: TextAlignVertical.top,
textAlign: TextAlign.left,
textDirection: TextDirection.ltr,
onChanged: onChange,
focusNode: focusNode,
autofocus: autoFocus,
style: TextStyle(fontSize: 14.fSize, height: 21 / 14, fontWeight: FontWeight.w500, color: AppColors.textColor, letterSpacing: -0.2),
decoration: InputDecoration(
isDense: true,
hintText: hintText,
hintStyle: TextStyle(fontSize: 14.fSize, height: 21 / 16, fontWeight: FontWeight.w500, color: Color(0xff898A8D), letterSpacing: -0.2),
prefixIconConstraints: BoxConstraints(minWidth: 45.h),
prefixIcon: prefix == null
? null
: Text(
"+" + prefix!,
style: TextStyle(
fontSize: 14.fSize,
height: 21 / 14,
fontWeight: FontWeight.w500,
color: Color(0xff2E303A),
letterSpacing: -0.2,
return KeyboardActions(
config: _keyboardActionsConfig,
disableScroll: true,
child: TextField(
enabled: isEnable,
scrollPadding: EdgeInsets.zero,
keyboardType: keyboardType,
controller: controller,
readOnly: isReadOnly,
textAlignVertical: TextAlignVertical.top,
textAlign: TextAlign.left,
textDirection: TextDirection.ltr,
onChanged: onChange,
focusNode: focusNode ?? _focusNode,
autofocus: autoFocus,
textInputAction: TextInputAction.done,
cursorHeight: isWalletAmountInput! ? 40.h : 18.h,
style: TextStyle(fontSize: fontSize!.fSize, height: isWalletAmountInput! ? 1 / 4 : 21 / 14, fontWeight: FontWeight.w500, color: AppColors.textColor, letterSpacing: -0.2),
decoration: InputDecoration(
isDense: true,
hintText: hintText,
hintStyle: TextStyle(fontSize: 14.fSize, height: 21 / 16, fontWeight: FontWeight.w500, color: Color(0xff898A8D), letterSpacing: -0.2),
prefixIconConstraints: BoxConstraints(minWidth: 45.h),
prefixIcon: prefix == null
? null
: Text(
"+" + prefix!,
style: TextStyle(
fontSize: 14.fSize,
height: 21 / 14,
fontWeight: FontWeight.w500,
color: Color(0xff2E303A),
letterSpacing: -0.2,
),
),
),
contentPadding: EdgeInsets.zero,
border: InputBorder.none,
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
contentPadding: EdgeInsets.zero,
border: InputBorder.none,
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
),
),
);
}

@ -75,6 +75,7 @@ dependencies:
network_info_plus: ^6.1.4
flutter_nfc_kit: ^3.6.0
barcode_scan2: ^4.5.1
keyboard_actions: ^4.2.0
dev_dependencies:
flutter_test:

Loading…
Cancel
Save