haroon_dev #317

Merged
Haroon6138 merged 13 commits from haroon_dev into master 1 month ago

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 13 KiB

@ -0,0 +1,5 @@
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 10.75C0 4.81294 4.81294 0 10.75 0C15.5683 0 19.597 3.1682 20.9655 7.52526C21.037 7.75307 20.9958 8.00133 20.8545 8.19382C20.7133 8.3863 20.4887 8.5 20.25 8.5H17.75C17.3357 8.5 17 8.16421 17 7.75C17 7.33579 17.3357 7 17.75 7H19.1673C17.7335 3.75655 14.5197 1.5 10.75 1.5C5.64137 1.5 1.5 5.64137 1.5 10.75C1.5 15.8586 5.64133 20 10.75 20C11.1642 20 11.5 20.3358 11.5 20.75C11.5 21.1642 11.1642 21.5 10.75 21.5C4.8129 21.5 0 16.6871 0 10.75Z" fill="white"/>
<path d="M10.75 6C11.1642 6 11.5 6.33579 11.5 6.75V10.4393L13.2803 12.2197C13.5732 12.5126 13.5732 12.9874 13.2803 13.2803C12.9874 13.5732 12.5125 13.5732 12.2196 13.2803L10.2196 11.2803C10.079 11.1397 9.99996 10.9489 9.99996 10.75V6.75C9.99996 6.33579 10.3357 6 10.75 6Z" fill="white"/>
<path d="M15.2803 14.2197C14.9874 13.9268 14.5126 13.9268 14.2197 14.2197C13.9268 14.5126 13.9268 14.9874 14.2197 15.2803L16.6893 17.75L14.2197 20.2197C13.9268 20.5126 13.9268 20.9874 14.2197 21.2803C14.5126 21.5732 14.9874 21.5732 15.2803 21.2803L17.75 18.8107L20.2197 21.2803C20.5126 21.5732 20.9874 21.5732 21.2803 21.2803C21.5732 20.9874 21.5732 20.5126 21.2803 20.2197L18.8107 17.75L21.2803 15.2803C21.5732 14.9874 21.5732 14.5126 21.2803 14.2197C20.9874 13.9268 20.5126 13.9268 20.2197 14.2197L17.75 16.6893L15.2803 14.2197Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

@ -220,7 +220,7 @@
"request": "الطلبات",
"memberName": "اسم العضو",
"switchLogin": "عرض الملف",
"removeMember": "إزالة",
"removeMember": "حذف",
"allowView": "السماح",
"rejectView": "رفض",
"deleteView": "حذف",

@ -208,8 +208,8 @@ class ApiClientImp implements ApiClient {
body['TokenID'] = "@dm!n";
}
body['TokenID'] = "@dm!n";
// body['PatientID'] = 5787639;
// body['TokenID'] = "@dm!n";
// body['PatientID'] = 1018977;
// body['PatientTypeID'] = 1;
// body['PatientOutSA'] = 0;
// body['SessionID'] = "45786230487560q";

@ -4,7 +4,7 @@ import 'package:hmg_patient_app_new/core/enums.dart';
class ApiConsts {
static const maxSmallScreen = 660;
static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.prod;
static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.uat;
// static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT
@ -867,6 +867,7 @@ var GET_DOCTOR_LIST_CALCULATION = "Services/Doctors.svc/REST/GetCallculationDoct
// var GET_ALL_APPOINTMENTS_FOR_DENTAL_CLINIC = "Services/Patients.svc/REST/GetDentalAppointments";
var GET_ALL_APPOINTMENTS_FOR_DENTAL_CLINIC = 'Services/Patients.svc/REST/GetAllInvoices';
var GET_ALL_PHARMACY_INVOICES = 'Services/Patients.svc/REST/GetAllPharmacyInvoices';
var GET_DENTAL_APPOINTMENT_INVOICE = "Services/Patients.svc/REST/HIS_eInvoiceForDentalByAppointmentNo";
var SEND_DENTAL_APPOINTMENT_INVOICE_EMAIL = "Services/Notifications.svc/REST/SendInvoiceForDental";
@ -990,6 +991,8 @@ const UPLOAD_PROFILE_IMAGE = 'Services/Patients.svc/REST/Patient_InsertProfileIm
const DOWNLOAD_INVOICE_PDF = 'Services/Notifications.svc/REST/DownloadInvoiceReport';
const DOWNLOAD_PHARMACY_INVOICE_PDF = 'Services/Notifications.svc/REST/DownloadInvoiceReport';
class ApiKeyConstants {
static final String googleMapsApiKey = 'AIzaSyB6TERnxIr0yJ3qG4ULBZbu0sAD4tGqtng';
}

@ -379,6 +379,7 @@ class AppAssets {
static const String online_checkin_icon = '$svgBasePath/online_checkin_icon.svg';
static const String hmg_pharmacy_logo = '$svgBasePath/hmg_pharmacy_logo.svg';
static const String redeem_icon = '$svgBasePath/redeem_icon.svg';
static const String expired_icon = '$svgBasePath/expired_icon.svg';
//Health Calculators
static const String bodyfatcalc = '$svgBasePath/bfc.svg';

@ -44,6 +44,8 @@ class AppState {
AuthenticatedUser? _authenticatedRootUser;
AuthenticatedUser? _authenticatedChildUser;
bool isPaytabsEnabled = false;
int? _superUserID;
bool isChildLoggedIn = false;
bool isGMSAvailable = true;

@ -48,6 +48,7 @@ import 'package:hmg_patient_app_new/features/notifications/notifications_repo.da
import 'package:hmg_patient_app_new/features/notifications/notifications_view_model.dart';
import 'package:hmg_patient_app_new/features/payfort/payfort_repo.dart';
import 'package:hmg_patient_app_new/features/payfort/payfort_view_model.dart';
import 'package:hmg_patient_app_new/features/paytabs/paytabs_view_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_repo.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart';
import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_repo.dart';
@ -327,5 +328,7 @@ class AppDependencies {
getIt.registerLazySingleton<ServicesPriceListViewModel>(() => ServicesPriceListViewModel(servicesPriceListRepo: getIt(), errorHandlerService: getIt()));
getIt.registerLazySingleton<DateRangCalenderModel>(() => DateRangCalenderModel(appState: getIt(), navigationService: getIt(), dialogService: getIt()));
getIt.registerLazySingleton<PayTabsViewModel>(() => PayTabsViewModel(appState: getIt()));
}
}

@ -0,0 +1,12 @@
/// Default configuration values for PayTabs Payment SDK
class PaymentSdkDefaultConfig {
static const String profileID = "119730";
static const String serverKey = "SWJ9LD22MT-JLJZLBKTLK-WGWTLWGTWR";
static const String clientKey = "C7K2DQ-PDDN6B-69B2K7-P9GB9T";
static const String defaultCurrency = "SAR";
static const double defaultAmount = 10.0;
static const String defaultMerchantCountryCode = "SA";
static const String defaultMerchantName = "Sulaiman Al Habib Medical Group";
static const String defaultMerchantAppleBundleID = "merchant.com.hmgwebservices";
static const String defaultMerchantAppleBundleIDUAT = "merchant.com.hmgwebservices.uat";
}

@ -22,7 +22,6 @@ class PenguinMethodChannel {
"baseURL": "https://eagleiq.hmg.com",
"dataURL": "https://eagleiq.hmg.com",
"positionURL": "https://eagleiq.hmg.com",
"dataServiceName": "api",
"positionServiceName": "pe",
"clientID": "HMG",

@ -876,25 +876,25 @@ class Utils {
);
}
static Widget getPaymentMethods() {
static Widget getPaymentMethods({num spacing = 3, num width = 35, num height = 35}) {
return Row(
spacing: 6.w,
spacing: spacing.w,
mainAxisSize: MainAxisSize.max,
children: [
Image.asset(AppAssets.mada, width: 35.h, height: 35.h),
Image.asset(AppAssets.mada, width: width.h, height: height.h),
Image.asset(
AppAssets.tamaraEng,
width: 35.h,
height: 35.h,
width: width.h,
height: height.h,
fit: BoxFit.contain,
errorBuilder: (context, error, stackTrace) {
debugPrint('Failed to load Tamara PNG in payment methods: $error');
return Utils.buildSvgWithAssets(icon: AppAssets.tamara, width: 35.h, height: 35.h, fit: BoxFit.contain);
},
),
Image.asset(AppAssets.visa, width: 35.h, height: 35.h),
Image.asset(AppAssets.mastercard, width: 35.h, height: 25.h),
Image.asset(AppAssets.applePay, width: 35.h, height: 35.h),
Image.asset(AppAssets.visa, width: width.h, height: height.h),
Image.asset(AppAssets.mastercard, width: width.h, height: height.h),
Platform.isIOS ? Image.asset(AppAssets.applePay, width: width.h, height: height.h) : SizedBox.shrink(),
],
);
}

@ -866,6 +866,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
initialSlotDuration = apiResponse.data["InitialSlotDuration"];
freeSlotsResponse = apiResponse.data['FreeTimeSlots'];
isWaitingAppointmentAvailable = apiResponse.data["IsAllowToBookWaitingAppointment"];
// isWaitingAppointmentAvailable = true;
freeSlotsResponse.forEach((element) {

@ -345,7 +345,7 @@ class ContactUsViewModel extends ChangeNotifier {
}
} else if (apiResponse.messageStatus == 1) {
cocItemsList = apiResponse.data!;
cocItemsList.sort((a, b) => a.date!.compareTo(b.date!));
cocItemsList.sort((a, b) => b.date!.compareTo(a.date!));
isCOCItemsListLoading = false;
notifyListeners();
if (onSuccess != null) {

@ -48,18 +48,18 @@ class HabibWalletViewModel extends ChangeNotifier {
String yahalaAccountNumber = '';
bool isLakumAccountInfoLoading = false;
late LakumInquiryInformationResponseModel lakumAccountInfo;
LakumInquiryInformationResponseModel? lakumAccountInfo;
// Get all flattened transactions sorted by date descending
List<PointsDetails> getAllLakumTransactions() {
if (lakumAccountInfo.gainedPointsAmountPerYear == null) {
if (lakumAccountInfo?.gainedPointsAmountPerYear == null) {
return [];
}
List<PointsDetails> allTransactions = [];
// Flatten the nested structure
for (var yearData in lakumAccountInfo.gainedPointsAmountPerYear!) {
for (var yearData in lakumAccountInfo!.gainedPointsAmountPerYear!) {
if (yearData.pointsAmountPerMonth != null) {
for (var monthData in yearData.pointsAmountPerMonth!) {
if (monthData.pointsAmountPerday != null) {
@ -280,7 +280,12 @@ class HabibWalletViewModel extends ChangeNotifier {
paymentMethodName: paymentMethodName, paidAmount: paidAmount, paymentReference: paymentReference, patientID: patientID, projectID: projectID, depositorName: depositorName);
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),
// (failure) async => await errorHandlerService.handleError(failure: failure),
(failure) async {
if(onError != null) {
onError(failure.message);
}
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});

@ -0,0 +1,99 @@
class GetPharmacyInvoicesResponseModel {
String? setupId;
int? projectID;
int? pharmacyProjectID;
int? patientID;
int? appointmentNo;
String? appointmentDate;
dynamic appointmentDateN;
int? clinicID;
int? doctorID;
int? invoiceNo;
int? status;
String? arrivedOn;
String? doctorName;
String? doctorNameN;
String? displayInvoiceNo;
String? clinicName;
num? decimalDoctorRate;
String? doctorImageURL;
num? doctorRate;
num? patientNumber;
String? projectName;
dynamic locationID;
GetPharmacyInvoicesResponseModel(
{this.setupId,
this.projectID,
this.pharmacyProjectID,
this.patientID,
this.appointmentNo,
this.appointmentDate,
this.appointmentDateN,
this.clinicID,
this.doctorID,
this.invoiceNo,
this.status,
this.arrivedOn,
this.doctorName,
this.doctorNameN,
this.displayInvoiceNo,
this.clinicName,
this.decimalDoctorRate,
this.doctorImageURL,
this.doctorRate,
this.patientNumber,
this.projectName, this.locationID});
GetPharmacyInvoicesResponseModel.fromJson(Map<String, dynamic> json) {
setupId = json['SetupId'];
projectID = json['ProjectID'];
pharmacyProjectID = json['PharmacyProjectID'];
patientID = json['PatientID'];
appointmentNo = json['AppointmentNo'];
appointmentDate = json['AppointmentDate'];
appointmentDateN = json['AppointmentDateN'];
clinicID = json['ClinicID'];
doctorID = json['DoctorID'];
invoiceNo = json['InvoiceNo'];
status = json['Status'];
arrivedOn = json['ArrivedOn'];
doctorName = json['DoctorName'];
doctorNameN = json['DoctorNameN'];
displayInvoiceNo = json['DisplayInvoiceNo'];
clinicName = json['ClinicName'];
decimalDoctorRate = json['DecimalDoctorRate'];
doctorImageURL = json['DoctorImageURL'];
doctorRate = json['DoctorRate'];
patientNumber = json['PatientNumber'];
projectName = json['ProjectName'];
locationID = json['LocationId'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['SetupId'] = this.setupId;
data['ProjectID'] = this.projectID;
data['PharmacyProjectID'] = this.pharmacyProjectID;
data['PatientID'] = this.patientID;
data['AppointmentNo'] = this.appointmentNo;
data['AppointmentDate'] = this.appointmentDate;
data['AppointmentDateN'] = this.appointmentDateN;
data['ClinicID'] = this.clinicID;
data['DoctorID'] = this.doctorID;
data['InvoiceNo'] = this.invoiceNo;
data['Status'] = this.status;
data['ArrivedOn'] = this.arrivedOn;
data['DoctorName'] = this.doctorName;
data['DoctorNameN'] = this.doctorNameN;
data['DisplayInvoiceNo'] = this.displayInvoiceNo;
data['ClinicName'] = this.clinicName;
data['DecimalDoctorRate'] = this.decimalDoctorRate;
data['DoctorImageURL'] = this.doctorImageURL;
data['DoctorRate'] = this.doctorRate;
data['PatientNumber'] = this.patientNumber;
data['ProjectName'] = this.projectName;
data['LocationId'] = this.locationID;
return data;
}
}

@ -5,16 +5,21 @@ 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_invoices/models/get_invoice_details_response_model.dart';
import 'package:hmg_patient_app_new/features/my_invoices/models/get_invoices_list_response_model.dart';
import 'package:hmg_patient_app_new/features/my_invoices/models/get_pharmacy_invoices_response_model.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
abstract class MyInvoicesRepo {
Future<Either<Failure, GenericApiModel<List<GetInvoicesListResponseModel>>>> getAllInvoicesList();
Future<Either<Failure, GenericApiModel<List<GetPharmacyInvoicesResponseModel>>>> getAllPharmacyInvoices();
Future<Either<Failure, GenericApiModel<GetInvoiceDetailsResponseModel>>> getInvoiceDetails({required num appointmentNo, required num invoiceNo, required int projectID});
Future<Either<Failure, GenericApiModel<dynamic>>> sendInvoiceEmail({required num appointmentNo, required int projectID});
Future<Either<Failure, GenericApiModel<dynamic>>> downloadInvoice({required String setupId, required int invoiceNo, required int projectID});
Future<Either<Failure, GenericApiModel<dynamic>>> downloadPharmacyInvoice({required String setupId, required int invoiceNo, required int projectID, required dynamic locationID});
}
class MyInvoicesRepoImp implements MyInvoicesRepo {
@ -61,6 +66,47 @@ class MyInvoicesRepoImp implements MyInvoicesRepo {
}
}
@override
Future<Either<Failure, GenericApiModel<List<GetPharmacyInvoicesResponseModel>>>> getAllPharmacyInvoices() async {
Map<String, dynamic> mapDevice = {};
try {
GenericApiModel<List<GetPharmacyInvoicesResponseModel>>? apiResponse;
Failure? failure;
await apiClient.post(
GET_ALL_PHARMACY_INVOICES,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['List_AllPharmacyInvoices'] ?? response['PharmacyInvoicesList'] ?? [];
final invoicesList = list
.map((item) => GetPharmacyInvoicesResponseModel.fromJson(item as Map<String, dynamic>))
.toList()
.cast<GetPharmacyInvoicesResponseModel>();
apiResponse = GenericApiModel<List<GetPharmacyInvoicesResponseModel>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: invoicesList,
);
} 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<GetInvoiceDetailsResponseModel>>> getInvoiceDetails({required num appointmentNo, required num invoiceNo, required int projectID}) async {
Map<String, dynamic> mapDevice = {
@ -178,4 +224,43 @@ class MyInvoicesRepoImp implements MyInvoicesRepo {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel>> downloadPharmacyInvoice({required String setupId, required int invoiceNo, required int projectID, required dynamic locationID}) async {
Map<String, dynamic> mapDevice = {
"SetupID": setupId,
"ProjectID": projectID,
"InvoiceNo": invoiceNo,
"LocationID": locationID,
};
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
DOWNLOAD_PHARMACY_INVOICE_PDF,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
apiResponse = GenericApiModel(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: response["InvoiceReportPDFContent"],
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
}

@ -3,6 +3,7 @@ import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/features/my_invoices/models/get_invoice_details_response_model.dart';
import 'package:hmg_patient_app_new/features/my_invoices/models/get_invoices_list_response_model.dart';
import 'package:hmg_patient_app_new/features/my_invoices/models/get_pharmacy_invoices_response_model.dart';
import 'package:hmg_patient_app_new/features/my_invoices/my_invoices_repo.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
@ -12,6 +13,7 @@ enum InvoiceFilterType { all, hospital, clinic, doctor }
class MyInvoicesViewModel extends ChangeNotifier {
bool isInvoicesListLoading = false;
bool isInvoiceDetailsLoading = false;
bool isPharmacyInvoicesLoading = false;
MyInvoicesRepo myInvoicesRepo;
ErrorHandlerService errorHandlerService;
@ -19,6 +21,8 @@ class MyInvoicesViewModel extends ChangeNotifier {
List<GetInvoicesListResponseModel> allInvoicesList = [];
List<GetInvoicesListResponseModel> _originalInvoicesList = [];
List<GetPharmacyInvoicesResponseModel> allPharmacyInvoicesList = [];
List<GetPharmacyInvoicesResponseModel> _originalPharmacyInvoicesList = [];
InvoiceFilterType currentFilter = InvoiceFilterType.all;
late GetInvoiceDetailsResponseModel invoiceDetailsResponseModel;
@ -29,6 +33,7 @@ class MyInvoicesViewModel extends ChangeNotifier {
String? selectedFilterItem;
String? downloadInvoicePDFBase64 = "";
String? downloadPharmacyInvoicePDFBase64 = "";
int selectedTabIndex = 0;
@ -36,9 +41,12 @@ class MyInvoicesViewModel extends ChangeNotifier {
setInvoicesListLoading() {
isInvoicesListLoading = true;
isPharmacyInvoicesLoading = true;
allInvoicesList.clear();
allPharmacyInvoicesList.clear();
_originalInvoicesList.clear();
currentFilter = InvoiceFilterType.all;
onTabChanged(0);
notifyListeners();
}
@ -79,6 +87,40 @@ class MyInvoicesViewModel extends ChangeNotifier {
);
}
Future<void> getAllPharmacyInvoices({Function(dynamic)? onSuccess, Function(String)? onError}) async {
isPharmacyInvoicesLoading = true;
allPharmacyInvoicesList.clear();
notifyListeners();
final result = await myInvoicesRepo.getAllPharmacyInvoices();
result.fold(
(failure) async {
isPharmacyInvoicesLoading = false;
notifyListeners();
if (onError != null) {
onError(failure.message);
}
},
(apiResponse) {
_originalPharmacyInvoicesList = [];
allPharmacyInvoicesList = [];
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
_originalPharmacyInvoicesList = apiResponse.data ?? [];
_originalPharmacyInvoicesList.sort((a, b) => (b.appointmentDate ?? '').compareTo(a.appointmentDate ?? ''));
allPharmacyInvoicesList = List.from(_originalPharmacyInvoicesList);
isPharmacyInvoicesLoading = false;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
Future<void> getInvoiceDetails({required num appointmentNo, required num invoiceNo, required int projectID, Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await myInvoicesRepo.getInvoiceDetails(appointmentNo: appointmentNo, invoiceNo: invoiceNo, projectID: projectID);
result.fold(
@ -151,6 +193,32 @@ class MyInvoicesViewModel extends ChangeNotifier {
);
}
Future<void> downloadPharmacyInvoicePDF({required String setupId, required int invoiceNo, required int projectID, required dynamic locationID, Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await myInvoicesRepo.downloadPharmacyInvoice(setupId: setupId, invoiceNo: invoiceNo, projectID: projectID, locationID: locationID);
result.fold(
(failure) async {
if (onError != null) {
onError(failure.message);
}
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
if (apiResponse.data != null && apiResponse.data!.isNotEmpty) {
downloadPharmacyInvoicePDFBase64 = apiResponse.data!;
} else {
downloadPharmacyInvoicePDFBase64 = "";
}
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
void filterInvoices(InvoiceFilterType filterType) {
currentFilter = filterType;

@ -0,0 +1,133 @@
class PaytabsTransactionResponseModel {
int? tranTotal;
String? transactionReference;
String? cartCurrency;
String? cartDescription;
String? cartID;
String? tranCurrency;
String? payResponseReturn;
bool? isPending;
bool? isOnHold;
String? token;
String? transactionType;
bool? isAuthorized;
String? trace;
dynamic cartAmount;
int? merchantId;
int? profileId;
bool? isProcessed;
int? serviceId;
PaymentInfo? paymentInfo;
bool? isSuccess;
PaytabsTransactionResponseModel(
{this.tranTotal,
this.transactionReference,
this.cartCurrency,
this.cartDescription,
this.cartID,
this.tranCurrency,
this.payResponseReturn,
this.isPending,
this.isOnHold,
this.token,
this.transactionType,
this.isAuthorized,
this.trace,
this.cartAmount,
this.merchantId,
this.profileId,
this.isProcessed,
this.serviceId,
this.paymentInfo,
this.isSuccess});
PaytabsTransactionResponseModel.fromJson(Map<String, dynamic> json) {
tranTotal = json['tran_total'];
transactionReference = json['transactionReference'];
cartCurrency = json['cartCurrency'];
cartDescription = json['cartDescription'];
cartID = json['cartID'];
tranCurrency = json['tran_currency'];
payResponseReturn = json['payResponseReturn'];
isPending = json['isPending'];
isOnHold = json['isOnHold'];
token = json['token'];
transactionType = json['transactionType'];
isAuthorized = json['isAuthorized'];
trace = json['trace'];
cartAmount = json['cartAmount'];
merchantId = json['merchantId'];
profileId = json['profileId'];
isProcessed = json['isProcessed'];
serviceId = json['serviceId'];
paymentInfo = json['paymentInfo'] != null
? PaymentInfo.fromJson(Map<String, dynamic>.from(json['paymentInfo'] as Map))
: null;
isSuccess = json['isSuccess'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['tran_total'] = this.tranTotal;
data['transactionReference'] = this.transactionReference;
data['cartCurrency'] = this.cartCurrency;
data['cartDescription'] = this.cartDescription;
data['cartID'] = this.cartID;
data['tran_currency'] = this.tranCurrency;
data['payResponseReturn'] = this.payResponseReturn;
data['isPending'] = this.isPending;
data['isOnHold'] = this.isOnHold;
data['token'] = this.token;
data['transactionType'] = this.transactionType;
data['isAuthorized'] = this.isAuthorized;
data['trace'] = this.trace;
data['cartAmount'] = this.cartAmount;
data['merchantId'] = this.merchantId;
data['profileId'] = this.profileId;
data['isProcessed'] = this.isProcessed;
data['serviceId'] = this.serviceId;
if (this.paymentInfo != null) {
data['paymentInfo'] = this.paymentInfo!.toJson();
}
data['isSuccess'] = this.isSuccess;
return data;
}
}
class PaymentInfo {
String? cardScheme;
String? cardType;
int? expiryMonth;
int? expiryYear;
String? paymentDescription;
String? paymentMethod;
PaymentInfo(
{this.cardScheme,
this.cardType,
this.expiryMonth,
this.expiryYear,
this.paymentDescription,
this.paymentMethod});
PaymentInfo.fromJson(Map<String, dynamic> json) {
cardScheme = json['cardScheme'];
cardType = json['cardType'];
expiryMonth = json['expiryMonth'];
expiryYear = json['expiryYear'];
paymentDescription = json['paymentDescription'];
paymentMethod = json['payment_method'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['cardScheme'] = this.cardScheme;
data['cardType'] = this.cardType;
data['expiryMonth'] = this.expiryMonth;
data['expiryYear'] = this.expiryYear;
data['paymentDescription'] = this.paymentDescription;
data['payment_method'] = this.paymentMethod;
return data;
}
}

@ -0,0 +1,23 @@
import 'package:dartz/dartz.dart';
import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart';
abstract class PaytabsService {
Future<Either<Failure, dynamic>> getAskDoctorAppointmentsList();
Future<Either<Failure, dynamic>> getDoctorResponse();
}
class PaytabsServiceImp implements PaytabsService {
@override
Future<Either<Failure, dynamic>> getAskDoctorAppointmentsList() {
// TODO: implement getAskDoctorAppointmentsList
throw UnimplementedError();
}
@override
Future<Either<Failure, dynamic>> getDoctorResponse() {
// TODO: implement getDoctorResponse
throw UnimplementedError();
}
}

@ -0,0 +1,136 @@
import 'package:flutter/material.dart';
import 'package:flutter_paytabs_bridge/BaseBillingShippingInfo.dart';
import 'package:flutter_paytabs_bridge/IOSThemeConfiguration.dart';
import 'package:flutter_paytabs_bridge/PaymentSdkConfigurationDetails.dart';
import 'package:flutter_paytabs_bridge/PaymentSdkLocale.dart';
import 'package:flutter_paytabs_bridge/PaymentSdkTokeniseType.dart';
import 'package:flutter_paytabs_bridge/PaymentSdkTransactionType.dart';
import 'package:flutter_paytabs_bridge/flutter_paytabs_bridge.dart';
import 'package:hmg_patient_app_new/core/api_consts.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/paytabs_config.dart';
import 'package:hmg_patient_app_new/features/paytabs/models/paytabs_transaction_response_model.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
class PayTabsViewModel extends ChangeNotifier {
late PaymentSdkConfigurationDetails paymentConfiguration;
final AppState appState;
late PaytabsTransactionResponseModel paytabsTransactionResponseModel;
PayTabsViewModel({
required this.appState,
});
setPaymentConfiguration(String paymentDescription, num amount) {
String cartID = DateTime.now().millisecondsSinceEpoch.toString();
paymentConfiguration = PaymentSdkConfigurationDetails(
profileId: PaymentSdkDefaultConfig.profileID,
serverKey: PaymentSdkDefaultConfig.serverKey,
clientKey: PaymentSdkDefaultConfig.clientKey,
transactionType: PaymentSdkTransactionType.SALE,
cartId: cartID.substring((cartID.length - 5), cartID.length),
cartDescription: paymentDescription,
merchantName: PaymentSdkDefaultConfig.defaultMerchantName,
locale: appState.isArabic() ? PaymentSdkLocale.AR : PaymentSdkLocale.EN,
merchantApplePayIndentifier:
ApiConsts.appEnvironmentType == AppEnvironmentTypeEnum.uat ? PaymentSdkDefaultConfig.defaultMerchantAppleBundleIDUAT : PaymentSdkDefaultConfig.defaultMerchantAppleBundleID,
// merchantApplePayIndentifier: PaymentSdkDefaultConfig.defaultMerchantAppleBundleIDUAT,
screentTitle: paymentDescription,
amount: amount.toDouble(),
showBillingInfo: false,
forceShippingInfo: false,
currencyCode: PaymentSdkDefaultConfig.defaultCurrency,
merchantCountryCode: PaymentSdkDefaultConfig.defaultMerchantCountryCode,
billingDetails: BillingDetails(
"${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}" ?? "HMG Patient", "CustID_${appState.getAuthenticatedUser()!.patientId.toString()}@HMG.com",
appState.getAuthenticatedUser()!.mobileNumber ?? "0000000000", "Riyadh", "SA", "Riyadh", "Riyadh", "12626"),
shippingDetails: ShippingDetails("${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}" ?? "HMG Patient", "CustID_${appState.getAuthenticatedUser()!.patientId.toString()}@HMG.com",
appState.getAuthenticatedUser()!.mobileNumber ?? "0000000000", "Riyadh", "SA", "Riyadh", "Riyadh", "12626"),
alternativePaymentMethods: [],
linkBillingNameWithCardHolderName: true,
simplifyApplePayValidation: true);
paymentConfiguration.iOSThemeConfigurations = IOSThemeConfigurations(
// logoImage: "assets/images/png/hmg_logo.png",
backgroundColor: "ffffff",
backgroundColorDark: "ffffff",
secondaryColor: "191919",
secondaryColorDark: "191919",
primaryColor: "ffffff",
primaryColorDark: "ffffff",
// primaryFont: "Poppins",
titleFontColor: "2E3039",
titleFontColorDark: "2E3039",
// titleFont: "Poppins",
primaryFontColor: "2E3039",
primaryFontColorDark: "2E3039",
inputFieldBackgroundColor: "ffffff",
inputFieldBackgroundColorDark: "ffffff",
placeholderColor: "2E3039",
placeholderColorDark: "2E3039",
buttonColor: "ED1C2B",
buttonColorDark: "ED1C2B",
// buttonFont: "Poppins",
);
paymentConfiguration.tokeniseType = PaymentSdkTokeniseType.MERCHANT_MANDATORY;
notifyListeners();
}
startApplePayPayment({Function(PaytabsTransactionResponseModel)? onSuccess, Function(String)? onError}) {
FlutterPaytabsBridge.startApplePayPayment(paymentConfiguration, (event) {
final transactionDetails = event["data"] as Map<Object?, Object?>?;
if (event["status"] == "success") {
// Cast Map<Object?, Object?> to Map<String, dynamic>
final data = Map<String, dynamic>.from(event["data"] as Map);
paytabsTransactionResponseModel = PaytabsTransactionResponseModel.fromJson(data);
if (paytabsTransactionResponseModel.isSuccess!) {
onSuccess!(paytabsTransactionResponseModel);
} else {
// Transaction was processed but failed
final reason = transactionDetails?["payResponseReturn"] ?? transactionDetails?["responseMessage"] ?? transactionDetails?["message"] ?? "Unknown error";
final responseCode = transactionDetails?["responseCode"] ?? "";
final errorMessage = responseCode.toString().isNotEmpty ? "Transaction failed (Code: $responseCode): $reason" : "Transaction failed: $reason";
onError!(errorMessage);
}
} else if (event["status"] == "error") {
final errorMessage = event["message"] ?? "An error occurred";
debugPrint("Error occurred in transaction: $errorMessage");
debugPrint("Full error event: $event");
onError!(errorMessage);
} else if (event["status"] == "event") {
final eventMessage = event["message"] ?? "Event occurred";
debugPrint("Event occurred: $eventMessage");
}
});
}
startCardPayment({Function(PaytabsTransactionResponseModel)? onSuccess, Function(String)? onError}) {
FlutterPaytabsBridge.startCardPayment(paymentConfiguration, (event) {
final transactionDetails = event["data"] as Map<Object?, Object?>?;
if (event["status"] == "success") {
// Cast Map<Object?, Object?> to Map<String, dynamic>
final data = Map<String, dynamic>.from(event["data"] as Map);
paytabsTransactionResponseModel = PaytabsTransactionResponseModel.fromJson(data);
if (paytabsTransactionResponseModel.isSuccess!) {
onSuccess!(paytabsTransactionResponseModel);
} else {
// Transaction was processed but failed
final reason = transactionDetails?["payResponseReturn"] ?? transactionDetails?["responseMessage"] ?? transactionDetails?["message"] ?? "Unknown error";
final responseCode = transactionDetails?["responseCode"] ?? "";
final errorMessage = responseCode.toString().isNotEmpty ? "Transaction failed (Code: $responseCode): $reason" : "Transaction failed: $reason";
onError!(errorMessage);
}
} else if (event["status"] == "error") {
final errorMessage = event["message"] ?? "An error occurred";
debugPrint("Error occurred in transaction: $errorMessage");
debugPrint("Full error event: $event");
onError!(errorMessage);
} else if (event["status"] == "event") {
final eventMessage = event["message"] ?? "Event occurred";
debugPrint("Event occurred: $eventMessage");
}
});
}
}

@ -51,8 +51,12 @@ class TodoSectionViewModel extends ChangeNotifier {
// if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
// } else if (apiResponse.messageStatus == 1) {
notificationsCount =
apiResponse['List_PatientDashboard'][0]['UnreadPatientNotificationCount'] > 99 ? '99+' : apiResponse['List_PatientDashboard'][0]['UnreadPatientNotificationCount'].toString();
if (apiResponse['List_PatientDashboard'] != null && apiResponse['List_PatientDashboard'] is List && (apiResponse['List_PatientDashboard'] as List).isNotEmpty) {
notificationsCount =
apiResponse['List_PatientDashboard'][0]['UnreadPatientNotificationCount'] > 99 ? '99+' : apiResponse['List_PatientDashboard'][0]['UnreadPatientNotificationCount'].toString();
} else {
notificationsCount = "0";
}
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);

@ -10,6 +10,7 @@ import 'package:flutter/services.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/features/paytabs/paytabs_view_model.dart';
import 'package:hmg_patient_app_new/features/weather/weather_view_model.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/features/ask_doctor/ask_doctor_view_model.dart';
@ -98,7 +99,7 @@ Future<void> callAppStateInitializations() async {
PlatformDispatcher.instance.onError = (error, stack) {
if (!kDebugMode) {
FirebaseCrashlytics.instance.recordError(error, stack,
fatal: false,
fatal: true,
printDetails: true,
reason:
"${appState.isAuthenticated ? "Authenticated User ID: ${appState.getAuthenticatedUser()!.patientId} - ${appState.getAuthenticatedUser()!.mobileNumber}" : "Unauthenticated User"} - Uncaught asynchronous error");
@ -262,6 +263,8 @@ void main() async {
create: (_) => getIt.get<WeatherMonitorViewModel>(),
), ChangeNotifierProvider<DateRangCalenderModel>(
create: (_) => getIt.get<DateRangCalenderModel>(),
), ChangeNotifierProvider<PayTabsViewModel>(
create: (_) => getIt.get<PayTabsViewModel>(),
)
], child: MyApp()),
), // Wrap your app

@ -17,6 +17,8 @@ import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_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/features/paytabs/models/paytabs_transaction_response_model.dart';
import 'package:hmg_patient_app_new/features/paytabs/paytabs_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart';
import 'package:hmg_patient_app_new/presentation/insurance/insurance_home_page.dart';
@ -43,6 +45,7 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
late MyAppointmentsViewModel myAppointmentsViewModel;
late PayfortViewModel payfortViewModel;
late AppState appState;
late PayTabsViewModel paytabsViewModel;
MyInAppBrowser? browser;
String selectedPaymentMethod = "";
@ -83,6 +86,7 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
appState = getIt.get<AppState>();
myAppointmentsViewModel = Provider.of<MyAppointmentsViewModel>(context);
payfortViewModel = Provider.of<PayfortViewModel>(context);
paytabsViewModel = Provider.of<PayTabsViewModel>(context, listen: false);
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: Consumer<MyAppointmentsViewModel>(builder: (context, myAppointmentsVM, child) {
@ -130,7 +134,86 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
).paddingSymmetrical(16.h, 16.h),
).paddingSymmetrical(24.h, 0.h).onPress(() {
selectedPaymentMethod = "MADA";
openPaymentURL("mada");
if (appState.isPaytabsEnabled) {
paytabsViewModel.setPaymentConfiguration(
"Appointment Payment",
num.parse(myAppointmentsViewModel.patientAppointmentShareResponseModel!.patientShareWithTax!.toString()),
);
paytabsViewModel.startCardPayment(onSuccess: (PaytabsTransactionResponseModel transactionData) async {
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingPaymentStatusPleaseWait.tr(context: context));
await myAppointmentsViewModel.createAdvancePayment(
paymentMethodName: selectedPaymentMethod,
projectID: widget.patientAppointmentHistoryResponseModel.projectID,
clinicID: widget.patientAppointmentHistoryResponseModel.clinicID,
appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo.toString(),
payedAmount: num.parse(myAppointmentsViewModel.patientAppointmentShareResponseModel!.patientShareWithTax!.toString()),
paymentReference: transactionData.transactionReference!,
patientID: appState.getAuthenticatedUser()!.patientId.toString(),
patientType: appState.getAuthenticatedUser()!.patientType!,
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: transactionData.transactionReference!,
appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo.toString(),
onSuccess: (value) async {
if (widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment!) {
//TODO: Implement LiveCare Check-In API Call
await myAppointmentsViewModel.insertLiveCareVIDARequest(
clientRequestID: transID,
patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel,
onSuccess: (apiResponse) {
Future.delayed(Duration(milliseconds: 500), () {
myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true);
myAppointmentsViewModel.initAppointmentsViewModel();
myAppointmentsViewModel.getPatientAppointments(true, false);
LoaderBottomSheet.hideLoader();
Navigator.pushAndRemoveUntil(
context,
CustomPageRoute(
page: LandingNavigation(),
),
(r) => false);
});
},
onError: (error) {});
} 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), () {
myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true);
myAppointmentsViewModel.initAppointmentsViewModel();
myAppointmentsViewModel.getPatientAppointments(true, false);
LoaderBottomSheet.hideLoader();
Navigator.pushAndRemoveUntil(
context,
CustomPageRoute(
page: LandingNavigation(),
),
(r) => false);
});
});
}
});
});
}, onError: (err) {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err.toString()),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
} else {
openPaymentURL("mada");
}
}),
SizedBox(height: 16.h),
Container(
@ -174,7 +257,86 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
).paddingSymmetrical(16.h, 16.h),
).paddingSymmetrical(24.h, 0.h).onPress(() {
selectedPaymentMethod = "VISA";
openPaymentURL("visa");
if (appState.isPaytabsEnabled) {
paytabsViewModel.setPaymentConfiguration(
"Appointment Payment",
num.parse(myAppointmentsViewModel.patientAppointmentShareResponseModel!.patientShareWithTax!.toString()),
);
paytabsViewModel.startCardPayment(onSuccess: (PaytabsTransactionResponseModel transactionData) async {
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingPaymentStatusPleaseWait.tr(context: context));
await myAppointmentsViewModel.createAdvancePayment(
paymentMethodName: selectedPaymentMethod,
projectID: widget.patientAppointmentHistoryResponseModel.projectID,
clinicID: widget.patientAppointmentHistoryResponseModel.clinicID,
appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo.toString(),
payedAmount: num.parse(myAppointmentsViewModel.patientAppointmentShareResponseModel!.patientShareWithTax!.toString()),
paymentReference: transactionData.transactionReference!,
patientID: appState.getAuthenticatedUser()!.patientId.toString(),
patientType: appState.getAuthenticatedUser()!.patientType!,
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: transactionData.transactionReference!,
appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo.toString(),
onSuccess: (value) async {
if (widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment!) {
//TODO: Implement LiveCare Check-In API Call
await myAppointmentsViewModel.insertLiveCareVIDARequest(
clientRequestID: transID,
patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel,
onSuccess: (apiResponse) {
Future.delayed(Duration(milliseconds: 500), () {
myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true);
myAppointmentsViewModel.initAppointmentsViewModel();
myAppointmentsViewModel.getPatientAppointments(true, false);
LoaderBottomSheet.hideLoader();
Navigator.pushAndRemoveUntil(
context,
CustomPageRoute(
page: LandingNavigation(),
),
(r) => false);
});
},
onError: (error) {});
} 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), () {
myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true);
myAppointmentsViewModel.initAppointmentsViewModel();
myAppointmentsViewModel.getPatientAppointments(true, false);
LoaderBottomSheet.hideLoader();
Navigator.pushAndRemoveUntil(
context,
CustomPageRoute(
page: LandingNavigation(),
),
(r) => false);
});
});
}
});
});
}, onError: (err) {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err.toString()),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
} else {
openPaymentURL("visa");
}
}),
SizedBox(height: 16.h),
isShowTamara
@ -632,37 +794,117 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
//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(myAppointmentsViewModel.patientAppointmentShareResponseModel!.patientShareWithTax!.toString()),
merchantReference: transID,
merchantIdentifier: payfortViewModel.payfortProjectDetailsRespModel!.merchantIdentifier,
applePayAccessCode: payfortViewModel.payfortProjectDetailsRespModel!.accessCode,
applePayShaRequestPhrase: payfortViewModel.payfortProjectDetailsRespModel!.shaRequest,
currency: appState.getAuthenticatedUser()!.outSa! == 0 ? "SAR" : "AED",
onFailed: (failureResult) async {
log("failureResult: ${failureResult.message.toString()}");
LoaderBottomSheet.hideLoader();
if (appState.isPaytabsEnabled) {
LoaderBottomSheet.hideLoader();
paytabsViewModel.setPaymentConfiguration(
"Appointment Payment",
num.parse(myAppointmentsViewModel.patientAppointmentShareResponseModel!.patientShareWithTax!.toString()),
);
paytabsViewModel.startApplePayPayment(onSuccess: (PaytabsTransactionResponseModel transactionData) async {
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingPaymentStatusPleaseWait.tr(context: context));
await myAppointmentsViewModel.createAdvancePayment(
paymentMethodName: selectedPaymentMethod,
projectID: widget.patientAppointmentHistoryResponseModel.projectID,
clinicID: widget.patientAppointmentHistoryResponseModel.clinicID,
appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo.toString(),
payedAmount: num.parse(myAppointmentsViewModel.patientAppointmentShareResponseModel!.patientShareWithTax!.toString()),
paymentReference: transactionData.transactionReference!,
patientID: appState.getAuthenticatedUser()!.patientId.toString(),
patientType: appState.getAuthenticatedUser()!.patientType!,
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: transactionData.transactionReference!,
appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo.toString(),
onSuccess: (value) async {
if (widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment!) {
//TODO: Implement LiveCare Check-In API Call
await myAppointmentsViewModel.insertLiveCareVIDARequest(
clientRequestID: transID,
patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel,
onSuccess: (apiResponse) {
Future.delayed(Duration(milliseconds: 500), () {
myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true);
myAppointmentsViewModel.initAppointmentsViewModel();
myAppointmentsViewModel.getPatientAppointments(true, false);
LoaderBottomSheet.hideLoader();
Navigator.pushAndRemoveUntil(
context,
CustomPageRoute(
page: LandingNavigation(),
),
(r) => false);
});
},
onError: (error) {});
} 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), () {
myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true);
myAppointmentsViewModel.initAppointmentsViewModel();
myAppointmentsViewModel.getPatientAppointments(true, false);
LoaderBottomSheet.hideLoader();
Navigator.pushAndRemoveUntil(
context,
CustomPageRoute(
page: LandingNavigation(),
),
(r) => false);
});
});
}
});
});
}, onError: (err) {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: failureResult.message.toString()),
child: Utils.getErrorWidget(loadingText: err.toString()),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
},
onSucceeded: (successResult) async {
LoaderBottomSheet.hideLoader();
log("successResult: ${successResult.responseMessage.toString()}");
selectedPaymentMethod = successResult.paymentOption ?? "VISA";
checkPaymentStatus();
},
// projectId: appo.projectID,
// serviceTypeEnum: ServiceTypeEnum.appointmentPayment,
);
});
} else {
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(myAppointmentsViewModel.patientAppointmentShareResponseModel!.patientShareWithTax!.toString()),
merchantReference: transID,
merchantIdentifier: payfortViewModel.payfortProjectDetailsRespModel!.merchantIdentifier,
applePayAccessCode: payfortViewModel.payfortProjectDetailsRespModel!.accessCode,
applePayShaRequestPhrase: payfortViewModel.payfortProjectDetailsRespModel!.shaRequest,
currency: appState.getAuthenticatedUser()!.outSa! == 0 ? "SAR" : "AED",
onFailed: (failureResult) async {
log("failureResult: ${failureResult.message.toString()}");
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: failureResult.message.toString()),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
},
onSucceeded: (successResult) async {
LoaderBottomSheet.hideLoader();
log("successResult: ${successResult.responseMessage.toString()}");
selectedPaymentMethod = successResult.paymentOption ?? "VISA";
checkPaymentStatus();
},
// projectId: appo.projectID,
// serviceTypeEnum: ServiceTypeEnum.appointmentPayment,
);
}
});
}
}

@ -444,7 +444,8 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
// cameraGranted = newStatuses[Permission.camera]?.isGranted ?? cameraGranted;
// micGranted = newStatuses[Permission.microphone]?.isGranted ?? micGranted;
notifGranted = newStatuses[Permission.notification]?.isGranted ?? notifGranted;
alertWindowGranted = newStatuses[Permission.systemAlertWindow]?.isGranted ?? alertWindowGranted;
// alertWindowGranted = newStatuses[Permission.systemAlertWindow]?.isGranted ?? alertWindowGranted;
alertWindowGranted = true;
// If any requested permission is now permanently denied -> open settings
final newlyPermanent = missing.where((p) => (newStatuses[p]?.isPermanentlyDenied ?? false) || (newStatuses[p]?.isRestricted ?? false)).toList();

@ -19,6 +19,8 @@ import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/payfort/payfort_view_model.dart';
import 'package:hmg_patient_app_new/features/paytabs/models/paytabs_transaction_response_model.dart';
import 'package:hmg_patient_app_new/features/paytabs/paytabs_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/livecare/immediate_livecare_pending_request_page.dart';
import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart';
@ -45,6 +47,7 @@ class _ImmediateLiveCarePaymentPageState extends State<ImmediateLiveCarePaymentP
late ImmediateLiveCareViewModel immediateLiveCareViewModel;
late MyAppointmentsViewModel myAppointmentsViewModel;
late AppState appState;
late PayTabsViewModel paytabsViewModel;
MyInAppBrowser? browser;
String selectedPaymentMethod = "";
@ -77,6 +80,7 @@ class _ImmediateLiveCarePaymentPageState extends State<ImmediateLiveCarePaymentP
myAppointmentsViewModel = Provider.of<MyAppointmentsViewModel>(context, listen: false);
immediateLiveCareViewModel = Provider.of<ImmediateLiveCareViewModel>(context, listen: false);
payfortViewModel = Provider.of<PayfortViewModel>(context, listen: false);
paytabsViewModel = Provider.of<PayTabsViewModel>(context, listen: false);
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: Consumer<MyAppointmentsViewModel>(builder: (context, myAppointmentsVM, child) {
@ -121,9 +125,52 @@ class _ImmediateLiveCarePaymentPageState extends State<ImmediateLiveCarePaymentP
),
],
).paddingSymmetrical(16.h, 16.h),
).paddingSymmetrical(24.h, 0.h).onPress(() {
).paddingSymmetrical(24.h, 0.h).onPress(() async {
selectedPaymentMethod = "MADA";
openPaymentURL("mada");
if (appState.isPaytabsEnabled) {
paytabsViewModel.setPaymentConfiguration(
"LiveCare Payment",
num.parse(immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.total ?? "0.0"),
);
paytabsViewModel.startCardPayment(onSuccess: (PaytabsTransactionResponseModel transactionData) async {
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingPaymentStatusPleaseWait.tr());
await immediateLiveCareViewModel.addNewCallRequestForImmediateLiveCare(transactionData.transactionReference!);
await immediateLiveCareViewModel.getPatientLiveCareHistory();
LoaderBottomSheet.hideLoader();
if (immediateLiveCareViewModel.patientHasPendingLiveCareRequest) {
Navigator.pushAndRemoveUntil(
context,
CustomPageRoute(
page: LandingNavigation(),
),
(r) => false);
Navigator.of(context).push(
CustomPageRoute(
page: ImmediateLiveCarePendingRequestPage(),
),
);
} else {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: "Unknown error occurred..."),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
}
}, onError: (err) {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err.toString()),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
} else {
openPaymentURL("mada");
}
}),
SizedBox(height: 16.h),
Container(
@ -165,7 +212,50 @@ class _ImmediateLiveCarePaymentPageState extends State<ImmediateLiveCarePaymentP
).paddingSymmetrical(16.h, 16.h),
).paddingSymmetrical(24.h, 0.h).onPress(() {
selectedPaymentMethod = "VISA";
openPaymentURL("visa");
if (appState.isPaytabsEnabled) {
paytabsViewModel.setPaymentConfiguration(
"LiveCare Payment",
num.parse(immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.total ?? "0.0"),
);
paytabsViewModel.startCardPayment(onSuccess: (PaytabsTransactionResponseModel transactionData) async {
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingPaymentStatusPleaseWait.tr());
await immediateLiveCareViewModel.addNewCallRequestForImmediateLiveCare(transactionData.transactionReference!);
await immediateLiveCareViewModel.getPatientLiveCareHistory();
LoaderBottomSheet.hideLoader();
if (immediateLiveCareViewModel.patientHasPendingLiveCareRequest) {
Navigator.pushAndRemoveUntil(
context,
CustomPageRoute(
page: LandingNavigation(),
),
(r) => false);
Navigator.of(context).push(
CustomPageRoute(
page: ImmediateLiveCarePendingRequestPage(),
),
);
} else {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: "Unknown error occurred..."),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
}
}, onError: (err) {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err.toString()),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
} else {
openPaymentURL("visa");
}
}),
SizedBox(height: 16.h),
isShowTamara
@ -357,7 +447,6 @@ class _ImmediateLiveCarePaymentPageState extends State<ImmediateLiveCarePaymentP
void checkPaymentStatus() async {
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingPaymentStatusPleaseWait.tr());
if (selectedPaymentMethod == "TAMARA") {
await payfortViewModel.checkTamaraPaymentStatus(
transactionID: transID,
@ -510,7 +599,7 @@ class _ImmediateLiveCarePaymentPageState extends State<ImmediateLiveCarePaymentP
applePayInsertRequest.voipToken = await Utils.getStringFromPrefs(CacheConst.voipToken);
applePayInsertRequest.doctorID = 0;
applePayInsertRequest.projectID = "12";
applePayInsertRequest.serviceID = ServiceTypeEnum.appointmentPayment.getIdFromServiceEnum().toString();
applePayInsertRequest.serviceID = ServiceTypeEnum.liveCareAppointment.getIdFromServiceEnum().toString();
applePayInsertRequest.channelID = 3;
applePayInsertRequest.patientID = appState.getAuthenticatedUser()!.patientId.toString();
applePayInsertRequest.patientTypeID = appState.getAuthenticatedUser()!.patientType;
@ -542,37 +631,78 @@ class _ImmediateLiveCarePaymentPageState extends State<ImmediateLiveCarePaymentP
//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: "LiveCare Payment",
orderAmount: double.parse((immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.total ?? "0.0")),
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()}");
if (appState.isPaytabsEnabled) {
LoaderBottomSheet.hideLoader();
paytabsViewModel.setPaymentConfiguration("Advance Payment", num.parse((immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.total ?? "0.0")));
paytabsViewModel.startApplePayPayment(onSuccess: (PaytabsTransactionResponseModel transactionData) async {
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingPaymentStatusPleaseWait.tr());
await immediateLiveCareViewModel.addNewCallRequestForImmediateLiveCare(transactionData.transactionReference!);
await immediateLiveCareViewModel.getPatientLiveCareHistory();
LoaderBottomSheet.hideLoader();
if (immediateLiveCareViewModel.patientHasPendingLiveCareRequest) {
Navigator.pushAndRemoveUntil(
context,
CustomPageRoute(
page: LandingNavigation(),
),
(r) => false);
Navigator.of(context).push(
CustomPageRoute(
page: ImmediateLiveCarePendingRequestPage(),
),
);
} else {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: "Unknown error occurred..."),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
}
}, onError: (err) {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: failureResult.message.toString()),
child: Utils.getErrorWidget(loadingText: err.toString()),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
},
onSucceeded: (successResult) async {
LoaderBottomSheet.hideLoader();
log("successResult: ${successResult.responseMessage.toString()}");
selectedPaymentMethod = successResult.paymentOption ?? "VISA";
checkPaymentStatus();
},
// projectId: appo.projectID,
// serviceTypeEnum: ServiceTypeEnum.appointmentPayment,
);
});
} else {
payfortViewModel.paymentWithApplePay(
customerName: "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}",
// customerEmail: projectViewModel.authenticatedUserObject.user.emailAddress,
customerEmail: "CustID_${appState.getAuthenticatedUser()!.patientId.toString()}@HMG.com",
orderDescription: "LiveCare Payment",
orderAmount: num.parse((immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.total ?? "0.0")),
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()}");
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: failureResult.message.toString()),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
},
onSucceeded: (successResult) async {
LoaderBottomSheet.hideLoader();
log("successResult: ${successResult.responseMessage.toString()}");
selectedPaymentMethod = successResult.paymentOption ?? "VISA";
checkPaymentStatus();
},
// projectId: appo.projectID,
// serviceTypeEnum: ServiceTypeEnum.appointmentPayment,
);
}
});
}
}

@ -19,6 +19,8 @@ import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_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/features/paytabs/models/paytabs_transaction_response_model.dart';
import 'package:hmg_patient_app_new/features/paytabs/paytabs_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart';
import 'package:hmg_patient_app_new/presentation/insurance/insurance_home_page.dart';
@ -45,6 +47,7 @@ class _WaitingAppointmentPaymentPageState extends State<WaitingAppointmentPaymen
late BookAppointmentsViewModel bookAppointmentsViewModel;
late MyAppointmentsViewModel myAppointmentsViewModel;
late PayfortViewModel payfortViewModel;
late PayTabsViewModel paytabsViewModel;
late AppState appState;
MyInAppBrowser? browser;
@ -87,6 +90,7 @@ class _WaitingAppointmentPaymentPageState extends State<WaitingAppointmentPaymen
bookAppointmentsViewModel = Provider.of<BookAppointmentsViewModel>(context);
myAppointmentsViewModel = Provider.of<MyAppointmentsViewModel>(context);
payfortViewModel = Provider.of<PayfortViewModel>(context);
paytabsViewModel = Provider.of<PayTabsViewModel>(context, listen: false);
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: Consumer<BookAppointmentsViewModel>(builder: (context, bookAppointmentsVM, child) {
@ -133,7 +137,50 @@ class _WaitingAppointmentPaymentPageState extends State<WaitingAppointmentPaymen
).paddingSymmetrical(16.h, 16.h),
).paddingSymmetrical(24.h, 0.h).onPress(() {
selectedPaymentMethod = "MADA";
openPaymentURL("mada");
if (appState.isPaytabsEnabled) {
paytabsViewModel.setPaymentConfiguration(
"Appointment Payment",
bookAppointmentsViewModel.patientWalkInAppointmentShareResponseModel!.patientShareWithTax!,
);
paytabsViewModel.startCardPayment(onSuccess: (PaytabsTransactionResponseModel transactionData) async {
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.bookingWaitingAppointment.tr(context: context));
await bookAppointmentsViewModel.insertSpecificAppointmentForWalkIn(onSuccess: (val) async {
String appointmentNo = val.data['AppointmentNo'].toString();
await myAppointmentsViewModel.createAdvancePayment(
paymentMethodName: selectedPaymentMethod,
projectID: bookAppointmentsViewModel.waitingAppointmentProjectID,
clinicID: bookAppointmentsViewModel.selectedDoctor.clinicID!,
appointmentNo: appointmentNo,
payedAmount: bookAppointmentsViewModel.patientWalkInAppointmentShareResponseModel!.patientShareWithTax!,
paymentReference: transactionData.transactionReference!,
patientID: appState.getAuthenticatedUser()!.patientId.toString(),
patientType: appState.getAuthenticatedUser()!.patientType!,
onSuccess: (value) async {
print(value);
await myAppointmentsViewModel.addAdvanceNumberRequest(
advanceNumber: Utils.isVidaPlusProject(bookAppointmentsViewModel.waitingAppointmentProjectID)
? value.data['OnlineCheckInAppointments'][0]['AdvanceNumber_VP'].toString()
: value.data['OnlineCheckInAppointments'][0]['AdvanceNumber'].toString(),
paymentReference: transactionData.transactionReference!,
appointmentNo: appointmentNo,
onSuccess: (value) async {
LoaderBottomSheet.hideLoader();
sendCheckInRequest(bookAppointmentsViewModel.waitingAppointmentNFCCode, appointmentNo, context);
});
});
});
}, onError: (err) {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err.toString()),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
} else {
openPaymentURL("mada");
}
}),
SizedBox(height: 16.h),
Container(
@ -175,7 +222,50 @@ class _WaitingAppointmentPaymentPageState extends State<WaitingAppointmentPaymen
).paddingSymmetrical(16.h, 16.h),
).paddingSymmetrical(24.h, 0.h).onPress(() {
selectedPaymentMethod = "VISA";
openPaymentURL("visa");
if (appState.isPaytabsEnabled) {
paytabsViewModel.setPaymentConfiguration(
"Appointment Payment",
bookAppointmentsViewModel.patientWalkInAppointmentShareResponseModel!.patientShareWithTax!,
);
paytabsViewModel.startCardPayment(onSuccess: (PaytabsTransactionResponseModel transactionData) async {
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.bookingWaitingAppointment.tr(context: context));
await bookAppointmentsViewModel.insertSpecificAppointmentForWalkIn(onSuccess: (val) async {
String appointmentNo = val.data['AppointmentNo'].toString();
await myAppointmentsViewModel.createAdvancePayment(
paymentMethodName: selectedPaymentMethod,
projectID: bookAppointmentsViewModel.waitingAppointmentProjectID,
clinicID: bookAppointmentsViewModel.selectedDoctor.clinicID!,
appointmentNo: appointmentNo,
payedAmount: bookAppointmentsViewModel.patientWalkInAppointmentShareResponseModel!.patientShareWithTax!,
paymentReference: transactionData.transactionReference!,
patientID: appState.getAuthenticatedUser()!.patientId.toString(),
patientType: appState.getAuthenticatedUser()!.patientType!,
onSuccess: (value) async {
print(value);
await myAppointmentsViewModel.addAdvanceNumberRequest(
advanceNumber: Utils.isVidaPlusProject(bookAppointmentsViewModel.waitingAppointmentProjectID)
? value.data['OnlineCheckInAppointments'][0]['AdvanceNumber_VP'].toString()
: value.data['OnlineCheckInAppointments'][0]['AdvanceNumber'].toString(),
paymentReference: transactionData.transactionReference!,
appointmentNo: appointmentNo,
onSuccess: (value) async {
LoaderBottomSheet.hideLoader();
sendCheckInRequest(bookAppointmentsViewModel.waitingAppointmentNFCCode, appointmentNo, context);
});
});
});
}, onError: (err) {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err.toString()),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
} else {
openPaymentURL("visa");
}
}),
SizedBox(height: 16.h),
isShowTamara
@ -531,14 +621,7 @@ class _WaitingAppointmentPaymentPageState extends State<WaitingAppointmentPaymen
}
startApplePay() async {
showCommonBottomSheet(context,
child: Utils.getLoadingWidget(),
callBackFunc: (str) {},
title: "",
height: ResponsiveExtension.screenHeight * 0.3,
isCloseButtonVisible: false,
isDismissible: false,
isFullScreen: false);
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.loadingText.tr(context: context));
transID = Utils.getAppointmentTransID(
bookAppointmentsViewModel.selectedDoctor.projectID!,
bookAppointmentsViewModel.selectedDoctor.clinicID!,
@ -596,36 +679,80 @@ class _WaitingAppointmentPaymentPageState extends State<WaitingAppointmentPaymen
//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(bookAppointmentsViewModel.patientWalkInAppointmentShareResponseModel!.patientShareWithTax!.toString()),
merchantReference: transID,
merchantIdentifier: payfortViewModel.payfortProjectDetailsRespModel!.merchantIdentifier,
applePayAccessCode: payfortViewModel.payfortProjectDetailsRespModel!.accessCode,
applePayShaRequestPhrase: payfortViewModel.payfortProjectDetailsRespModel!.shaRequest,
currency: appState.getAuthenticatedUser()!.outSa! == 0 ? "SAR" : "AED",
onFailed: (failureResult) async {
log("failureResult: ${failureResult.message.toString()}");
Navigator.of(context).pop();
if (appState.isPaytabsEnabled) {
LoaderBottomSheet.hideLoader();
paytabsViewModel.setPaymentConfiguration(
"Appointment Payment",
bookAppointmentsViewModel.patientWalkInAppointmentShareResponseModel!.patientShareWithTax!,
);
paytabsViewModel.startApplePayPayment(onSuccess: (PaytabsTransactionResponseModel transactionData) async {
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.bookingWaitingAppointment.tr(context: context));
await bookAppointmentsViewModel.insertSpecificAppointmentForWalkIn(onSuccess: (val) async {
String appointmentNo = val.data['AppointmentNo'].toString();
await myAppointmentsViewModel.createAdvancePayment(
paymentMethodName: selectedPaymentMethod,
projectID: bookAppointmentsViewModel.waitingAppointmentProjectID,
clinicID: bookAppointmentsViewModel.selectedDoctor.clinicID!,
appointmentNo: appointmentNo,
payedAmount: bookAppointmentsViewModel.patientWalkInAppointmentShareResponseModel!.patientShareWithTax!,
paymentReference: transactionData.transactionReference!,
patientID: appState.getAuthenticatedUser()!.patientId.toString(),
patientType: appState.getAuthenticatedUser()!.patientType!,
onSuccess: (value) async {
print(value);
await myAppointmentsViewModel.addAdvanceNumberRequest(
advanceNumber: Utils.isVidaPlusProject(bookAppointmentsViewModel.waitingAppointmentProjectID)
? value.data['OnlineCheckInAppointments'][0]['AdvanceNumber_VP'].toString()
: value.data['OnlineCheckInAppointments'][0]['AdvanceNumber'].toString(),
paymentReference: transactionData.transactionReference!,
appointmentNo: appointmentNo,
onSuccess: (value) async {
LoaderBottomSheet.hideLoader();
sendCheckInRequest(bookAppointmentsViewModel.waitingAppointmentNFCCode, appointmentNo, context);
});
});
});
}, onError: (err) {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: failureResult.message.toString()),
child: Utils.getErrorWidget(loadingText: err.toString()),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
},
onSucceeded: (successResult) async {
log("successResult: ${successResult.responseMessage.toString()}");
selectedPaymentMethod = successResult.paymentOption ?? "VISA";
checkPaymentStatus();
},
// projectId: appo.projectID,
// serviceTypeEnum: ServiceTypeEnum.appointmentPayment,
);
});
} else {
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(bookAppointmentsViewModel.patientWalkInAppointmentShareResponseModel!.patientShareWithTax!.toString()),
merchantReference: transID,
merchantIdentifier: payfortViewModel.payfortProjectDetailsRespModel!.merchantIdentifier,
applePayAccessCode: payfortViewModel.payfortProjectDetailsRespModel!.accessCode,
applePayShaRequestPhrase: payfortViewModel.payfortProjectDetailsRespModel!.shaRequest,
currency: appState.getAuthenticatedUser()!.outSa! == 0 ? "SAR" : "AED",
onFailed: (failureResult) async {
log("failureResult: ${failureResult.message.toString()}");
Navigator.of(context).pop();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: failureResult.message.toString()),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
},
onSucceeded: (successResult) async {
log("successResult: ${successResult.responseMessage.toString()}");
selectedPaymentMethod = successResult.paymentOption ?? "VISA";
checkPaymentStatus();
},
// projectId: appo.projectID,
// serviceTypeEnum: ServiceTypeEnum.appointmentPayment,
);
}
});
}

@ -258,7 +258,7 @@ class LiveChatPage extends StatelessWidget {
workGroup: workGroup,
onSuccess: (response) {
debugPrint("Chat Request ID received: ${contactUsVM.chatRequestID}");
chatURL = "https://chat.hmg.com/Index.aspx?RequestedId=${contactUsVM.chatRequestID}";
chatURL = "https://chat.hmg.com/geneysChat/Index.aspx?RequestedId=${contactUsVM.chatRequestID}";
debugPrint("Chat URL: $chatURL");
},
onError: (error) {

@ -16,6 +16,8 @@ import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/emergency_services/emergency_services_view_model.dart';
import 'package:hmg_patient_app_new/features/payfort/models/apple_pay_request_insert_model.dart';
import 'package:hmg_patient_app_new/features/payfort/payfort_view_model.dart';
import 'package:hmg_patient_app_new/features/paytabs/models/paytabs_transaction_response_model.dart';
import 'package:hmg_patient_app_new/features/paytabs/paytabs_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart';
import 'package:hmg_patient_app_new/presentation/insurance/insurance_home_page.dart';
@ -39,6 +41,7 @@ class ErOnlineCheckinPaymentPage extends StatefulWidget {
class _ErOnlineCheckinPaymentPageState extends State<ErOnlineCheckinPaymentPage> {
late PayfortViewModel payfortViewModel;
late EmergencyServicesViewModel emergencyServicesViewModel;
late PayTabsViewModel paytabsViewModel;
late AppState appState;
@ -75,6 +78,7 @@ class _ErOnlineCheckinPaymentPageState extends State<ErOnlineCheckinPaymentPage>
appState = getIt.get<AppState>();
payfortViewModel = Provider.of<PayfortViewModel>(context, listen: false);
emergencyServicesViewModel = Provider.of<EmergencyServicesViewModel>(context, listen: false);
paytabsViewModel = Provider.of<PayTabsViewModel>(context, listen: false);
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: Column(
@ -119,7 +123,54 @@ class _ErOnlineCheckinPaymentPageState extends State<ErOnlineCheckinPaymentPage>
).paddingSymmetrical(16.h, 16.h),
).paddingSymmetrical(24.h, 0.h).onPress(() {
selectedPaymentMethod = "MADA";
openPaymentURL("mada");
if (appState.isPaytabsEnabled) {
paytabsViewModel.setPaymentConfiguration(
"ER Online Check-In Payment",
emergencyServicesViewModel.erOnlineCheckInPaymentDetailsResponse.patientShareWithTax!,
);
paytabsViewModel.startCardPayment(onSuccess: (PaytabsTransactionResponseModel transactionData) async {
if (emergencyServicesViewModel.isERBookAppointment) {
await emergencyServicesViewModel.ER_CreateAdvancePayment(
paymentMethodName: selectedPaymentMethod,
paymentReference: transactionData.transactionReference!,
onSuccess: (value) async {
await emergencyServicesViewModel.addAdvanceNumberRequest(
advanceNumber: value,
paymentReference: transactionData.transactionReference!,
appointmentNo: "0",
onSuccess: (val) {
LoaderBottomSheet.hideLoader();
if (emergencyServicesViewModel.isERBookAppointment) {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getSuccessWidget(loadingText: LocaleKeys.erAppointmentBookedSuccess.tr(context: context)),
callBackFunc: () {
Navigator.pushAndRemoveUntil(
context,
CustomPageRoute(
page: LandingNavigation(),
),
(r) => false);
},
isFullScreen: false,
isCloseButtonVisible: true,
);
} else {}
});
});
} else {}
}, onError: (errMsg) {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: errMsg.toString()),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
} else {
openPaymentURL("mada");
}
}),
SizedBox(height: 16.h),
Container(
@ -161,7 +212,54 @@ class _ErOnlineCheckinPaymentPageState extends State<ErOnlineCheckinPaymentPage>
).paddingSymmetrical(16.h, 16.h),
).paddingSymmetrical(24.h, 0.h).onPress(() {
selectedPaymentMethod = "VISA";
openPaymentURL("visa");
if (appState.isPaytabsEnabled) {
paytabsViewModel.setPaymentConfiguration(
"ER Online Check-In Payment",
emergencyServicesViewModel.erOnlineCheckInPaymentDetailsResponse.patientShareWithTax!,
);
paytabsViewModel.startCardPayment(onSuccess: (PaytabsTransactionResponseModel transactionData) async {
if (emergencyServicesViewModel.isERBookAppointment) {
await emergencyServicesViewModel.ER_CreateAdvancePayment(
paymentMethodName: selectedPaymentMethod,
paymentReference: transactionData.transactionReference!,
onSuccess: (value) async {
await emergencyServicesViewModel.addAdvanceNumberRequest(
advanceNumber: value,
paymentReference: transactionData.transactionReference!,
appointmentNo: "0",
onSuccess: (val) {
LoaderBottomSheet.hideLoader();
if (emergencyServicesViewModel.isERBookAppointment) {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getSuccessWidget(loadingText: LocaleKeys.erAppointmentBookedSuccess.tr(context: context)),
callBackFunc: () {
Navigator.pushAndRemoveUntil(
context,
CustomPageRoute(
page: LandingNavigation(),
),
(r) => false);
},
isFullScreen: false,
isCloseButtonVisible: true,
);
} else {}
});
});
} else {}
}, onError: (errMsg) {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: errMsg.toString()),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
} else {
openPaymentURL("visa");
}
}),
SizedBox(height: 16.h),
isShowTamara
@ -393,35 +491,84 @@ class _ErOnlineCheckinPaymentPageState extends State<ErOnlineCheckinPaymentPage>
//TODO: Need to pass dynamic params to the Apple Pay instead of static values
await payfortViewModel.applePayRequestInsert(applePayInsertRequest: applePayInsertRequest).then((value) {
payfortViewModel.paymentWithApplePay(
customerName: "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}",
// customerEmail: projectViewModel.authenticatedUserObject.user.emailAddress,
customerEmail: "CustID_${appState.getAuthenticatedUser()!.patientId.toString()}@HMG.com",
orderDescription: "Appointment Payment",
orderAmount: double.parse(emergencyServicesViewModel.erOnlineCheckInPaymentDetailsResponse.patientShareWithTax!.toString()),
merchantReference: transID,
merchantIdentifier: payfortViewModel.payfortProjectDetailsRespModel!.merchantIdentifier,
applePayAccessCode: payfortViewModel.payfortProjectDetailsRespModel!.accessCode,
applePayShaRequestPhrase: payfortViewModel.payfortProjectDetailsRespModel!.shaRequest,
currency: appState.getAuthenticatedUser()!.outSa! == 0 ? "SAR" : "AED",
onFailed: (failureResult) async {
LoaderBottomSheet.hideLoader();
log("failureResult: ${failureResult.message.toString()}");
if (appState.isPaytabsEnabled) {
LoaderBottomSheet.hideLoader();
paytabsViewModel.setPaymentConfiguration(
"ER Online Check-In Payment",
emergencyServicesViewModel.erOnlineCheckInPaymentDetailsResponse.patientShareWithTax!,
);
paytabsViewModel.startApplePayPayment(onSuccess: (PaytabsTransactionResponseModel transactionData) async {
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingPaymentStatusPleaseWait.tr(context: context));
if (emergencyServicesViewModel.isERBookAppointment) {
await emergencyServicesViewModel.ER_CreateAdvancePayment(
paymentMethodName: selectedPaymentMethod,
paymentReference: transactionData.transactionReference!,
onSuccess: (value) async {
await emergencyServicesViewModel.addAdvanceNumberRequest(
advanceNumber: value,
paymentReference: transactionData.transactionReference!,
appointmentNo: "0",
onSuccess: (val) {
LoaderBottomSheet.hideLoader();
if (emergencyServicesViewModel.isERBookAppointment) {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getSuccessWidget(loadingText: LocaleKeys.erAppointmentBookedSuccess.tr(context: context)),
callBackFunc: () {
Navigator.pushAndRemoveUntil(
context,
CustomPageRoute(
page: LandingNavigation(),
),
(r) => false);
},
isFullScreen: false,
isCloseButtonVisible: true,
);
} else {}
});
});
} else {}
}, onError: (err) {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: failureResult.message.toString()),
child: Utils.getErrorWidget(loadingText: err.toString()),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
},
onSucceeded: (successResult) async {
LoaderBottomSheet.hideLoader();
log("successResult: ${successResult.responseMessage.toString()}");
selectedPaymentMethod = successResult.paymentOption ?? "VISA";
checkPaymentStatus();
},
);
});
} else {
payfortViewModel.paymentWithApplePay(
customerName: "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}",
// customerEmail: projectViewModel.authenticatedUserObject.user.emailAddress,
customerEmail: "CustID_${appState.getAuthenticatedUser()!.patientId.toString()}@HMG.com",
orderDescription: "ER Online Check-In Payment",
orderAmount: double.parse(emergencyServicesViewModel.erOnlineCheckInPaymentDetailsResponse.patientShareWithTax!.toString()),
merchantReference: transID,
merchantIdentifier: payfortViewModel.payfortProjectDetailsRespModel!.merchantIdentifier,
applePayAccessCode: payfortViewModel.payfortProjectDetailsRespModel!.accessCode,
applePayShaRequestPhrase: payfortViewModel.payfortProjectDetailsRespModel!.shaRequest,
currency: appState.getAuthenticatedUser()!.outSa! == 0 ? "SAR" : "AED",
onFailed: (failureResult) async {
LoaderBottomSheet.hideLoader();
log("failureResult: ${failureResult.message.toString()}");
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: failureResult.message.toString()),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
},
onSucceeded: (successResult) async {
LoaderBottomSheet.hideLoader();
log("successResult: ${successResult.responseMessage.toString()}");
selectedPaymentMethod = successResult.paymentOption ?? "VISA";
checkPaymentStatus();
},
);
}
});
}

@ -16,6 +16,8 @@ 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/features/paytabs/models/paytabs_transaction_response_model.dart';
import 'package:hmg_patient_app_new/features/paytabs/paytabs_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
@ -35,6 +37,7 @@ class WalletPaymentConfirmPage extends StatefulWidget {
class _WalletPaymentConfirmPageState extends State<WalletPaymentConfirmPage> {
late PayfortViewModel payfortViewModel;
late PayTabsViewModel paytabsViewModel;
late AppState appState;
late HabibWalletViewModel habibWalletVM;
@ -56,6 +59,7 @@ class _WalletPaymentConfirmPageState extends State<WalletPaymentConfirmPage> {
appState = getIt.get<AppState>();
habibWalletVM = Provider.of<HabibWalletViewModel>(context, listen: false);
payfortViewModel = Provider.of<PayfortViewModel>(context, listen: false);
paytabsViewModel = Provider.of<PayTabsViewModel>(context, listen: false);
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: Column(
@ -102,7 +106,66 @@ class _WalletPaymentConfirmPageState extends State<WalletPaymentConfirmPage> {
).paddingSymmetrical(16.h, 16.h),
).paddingSymmetrical(24.h, 0.h).onPress(() {
selectedPaymentMethod = "MADA";
openPaymentURL("mada");
if (appState.isPaytabsEnabled) {
paytabsViewModel.setPaymentConfiguration("Advance Payment", habibWalletVM.walletRechargeAmount);
paytabsViewModel.startCardPayment(onSuccess: (PaytabsTransactionResponseModel transactionData) async {
LoaderBottomSheet.showLoader();
await habibWalletVM.HISCreateAdvancePayment(
paymentMethodName: selectedPaymentMethod,
paidAmount: habibWalletVM.walletRechargeAmount,
paymentReference: transactionData.transactionReference!,
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: transactionData.transactionReference!,
onSuccess: (value) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(getIt.get<NavigationService>().navigatorKey.currentContext!, child: Utils.getSuccessWidget(loadingText: "Payment Successful!"),
callBackFunc: () {
habibWalletVM.initHabibWalletProvider();
habibWalletVM.getPatientBalanceAmount();
Navigator.of(getIt.get<NavigationService>().navigatorKey.currentContext!).pop();
Navigator.of(getIt.get<NavigationService>().navigatorKey.currentContext!).pop();
}, isFullScreen: false, isCloseButtonVisible: true, isAutoDismiss: true);
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: LocaleKeys.paymentFailedPleaseTryAgain.tr(context: context)),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
}, onError: (err) {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err.toString()),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
} else {
openPaymentURL("mada");
}
}),
SizedBox(height: 16.h),
Container(
@ -144,7 +207,66 @@ class _WalletPaymentConfirmPageState extends State<WalletPaymentConfirmPage> {
).paddingSymmetrical(16.h, 16.h),
).paddingSymmetrical(24.h, 0.h).onPress(() {
selectedPaymentMethod = "VISA";
openPaymentURL("visa");
if (appState.isPaytabsEnabled) {
paytabsViewModel.setPaymentConfiguration("Advance Payment", habibWalletVM.walletRechargeAmount);
paytabsViewModel.startCardPayment(onSuccess: (PaytabsTransactionResponseModel transactionData) async {
LoaderBottomSheet.showLoader();
await habibWalletVM.HISCreateAdvancePayment(
paymentMethodName: selectedPaymentMethod,
paidAmount: habibWalletVM.walletRechargeAmount,
paymentReference: transactionData.transactionReference!,
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: transactionData.transactionReference!,
onSuccess: (value) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(getIt.get<NavigationService>().navigatorKey.currentContext!, child: Utils.getSuccessWidget(loadingText: "Payment Successful!"),
callBackFunc: () {
habibWalletVM.initHabibWalletProvider();
habibWalletVM.getPatientBalanceAmount();
Navigator.of(getIt.get<NavigationService>().navigatorKey.currentContext!).pop();
Navigator.of(getIt.get<NavigationService>().navigatorKey.currentContext!).pop();
}, isFullScreen: false, isCloseButtonVisible: true, isAutoDismiss: true);
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: LocaleKeys.paymentFailedPleaseTryAgain.tr(context: context)),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
}, onError: (err) {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err.toString()),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
} else {
openPaymentURL("visa");
}
}),
],
),
@ -197,9 +319,7 @@ class _WalletPaymentConfirmPageState extends State<WalletPaymentConfirmPage> {
).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, applyThemeColor: false).paddingSymmetrical(24.h, 0.h).onPress(() {
? Utils.buildSvgWithAssets(icon: AppAssets.apple_pay_button, width: 200.h, height: 56.h, fit: BoxFit.contain, applyThemeColor: false).paddingSymmetrical(24.h, 0.h).onPress(() {
if (Utils.havePrivilege(103)) {
startApplePay();
} else {
@ -268,33 +388,93 @@ class _WalletPaymentConfirmPageState extends State<WalletPaymentConfirmPage> {
//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()}");
if(appState.isPaytabsEnabled) {
LoaderBottomSheet.hideLoader();
paytabsViewModel.setPaymentConfiguration("Advance Payment", habibWalletVM.walletRechargeAmount);
paytabsViewModel.startApplePayPayment(onSuccess: (PaytabsTransactionResponseModel transactionData) async {
LoaderBottomSheet.showLoader();
await habibWalletVM.HISCreateAdvancePayment(
paymentMethodName: selectedPaymentMethod,
paidAmount: habibWalletVM.walletRechargeAmount,
paymentReference: transactionData.transactionReference!,
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: transactionData.transactionReference!,
onSuccess: (value) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(getIt.get<NavigationService>().navigatorKey.currentContext!, child: Utils.getSuccessWidget(loadingText: "Payment Successful!"),
callBackFunc: () {
habibWalletVM.initHabibWalletProvider();
habibWalletVM.getPatientBalanceAmount();
Navigator.of(getIt.get<NavigationService>().navigatorKey.currentContext!).pop();
Navigator.of(getIt.get<NavigationService>().navigatorKey.currentContext!).pop();
}, isFullScreen: false, isCloseButtonVisible: true, isAutoDismiss: true);
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: LocaleKeys.paymentFailedPleaseTryAgain.tr(context: context)),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
}, onError: (err) {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: failureResult.message.toString()),
child: Utils.getErrorWidget(loadingText: err.toString()),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
},
onSucceeded: (successResult) async {
log("successResult: ${successResult.responseMessage.toString()}");
selectedPaymentMethod = successResult.paymentOption ?? "VISA";
checkPaymentStatus();
},
);
});
} else {
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();
},
);
}
});
}
@ -321,16 +501,12 @@ class _WalletPaymentConfirmPageState extends State<WalletPaymentConfirmPage> {
onSuccess: (value) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(getIt.get<NavigationService>().navigatorKey.currentContext!, child: Utils.getSuccessWidget(loadingText: "Payment Successful!"),
callBackFunc: () {
habibWalletVM.initHabibWalletProvider();
habibWalletVM.getPatientBalanceAmount();
callBackFunc: () {
habibWalletVM.initHabibWalletProvider();
habibWalletVM.getPatientBalanceAmount();
Navigator.of(getIt.get<NavigationService>().navigatorKey.currentContext!).pop();
Navigator.of(getIt.get<NavigationService>().navigatorKey.currentContext!).pop();
},
isFullScreen: false,
isCloseButtonVisible: true,
isAutoDismiss: true
);
}, isFullScreen: false, isCloseButtonVisible: true, isAutoDismiss: true);
},
onError: (err) {
LoaderBottomSheet.hideLoader();
@ -343,7 +519,16 @@ class _WalletPaymentConfirmPageState extends State<WalletPaymentConfirmPage> {
);
});
},
onError: (err) {});
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
} else {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(

@ -77,7 +77,7 @@ class LakumWalletDetails extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.transactions.tr(context: context).toText16(isBold: true),
if (transactions.isNotEmpty) "${transactions.length} Records".toText12(color: AppColors.greyTextColor),
// if (transactions.isNotEmpty) "${transactions.length} Records".toText12(color: AppColors.greyTextColor),
],
),
SizedBox(height: 12.h),
@ -95,7 +95,7 @@ class LakumWalletDetails extends StatelessWidget {
);
}
Widget _buildLakumMainCard(LakumInquiryInformationResponseModel accountInfo, AppState appState) {
Widget _buildLakumMainCard(LakumInquiryInformationResponseModel? accountInfo, AppState appState) {
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
@ -134,7 +134,7 @@ class LakumWalletDetails extends StatelessWidget {
color: Colors.white,
),
SizedBox(height: 4.h),
(accountInfo.accountNumber ?? 0).toString().toText14(
(accountInfo?.accountNumber ?? 0).toString().toText14(
color: Colors.white.withAlpha(230),
),
],
@ -142,8 +142,8 @@ class LakumWalletDetails extends StatelessWidget {
),
Utils.buildImgWithAssets(
icon: AppAssets.lakumLogoWhite,
width: 80.h,
height: 80.h,
width: 110.h,
height: 100.h,
),
],
),
@ -155,7 +155,7 @@ class LakumWalletDetails extends StatelessWidget {
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
(accountInfo.pointsBalance?.toString() ?? "0").toText44(
(accountInfo?.pointsBalance?.toString() ?? "0").toText44(
isBold: true,
color: Colors.white,
),
@ -172,7 +172,7 @@ class LakumWalletDetails extends StatelessWidget {
SizedBox(height: 4.h),
// Balance Amount in SAR
"${accountInfo.pointsBalanceAmount?.toStringAsFixed(2) ?? "0.00"} SAR".toText18(
"${accountInfo?.pointsBalanceAmount?.toStringAsFixed(2) ?? "0.00"} SAR".toText18(
color: Colors.white.withAlpha(204),
),
SizedBox(height: 20.h),
@ -183,7 +183,7 @@ class LakumWalletDetails extends StatelessWidget {
Expanded(
child: _buildStatChip(
LocaleKeys.gained.tr(),
accountInfo.gainedPoints?.toString() ?? "0",
accountInfo?.gainedPoints?.toString() ?? "0",
Icons.arrow_circle_up,
),
),
@ -191,10 +191,17 @@ class LakumWalletDetails extends StatelessWidget {
Expanded(
child: _buildStatChip(
LocaleKeys.consumed.tr(),
accountInfo.consumedPoints?.toString() ?? "0",
accountInfo?.consumedPoints?.toString() ?? "0",
Icons.arrow_circle_down,
),
),
SizedBox(width: 8.w),
Expanded(
child: _buildStatChip(
LocaleKeys.expired.tr(), accountInfo?.expiredPoints?.toString() ?? "0", Icons.calendar_month,
isSvg: true
),
),
],
),
],
@ -203,7 +210,7 @@ class LakumWalletDetails extends StatelessWidget {
);
}
Widget _buildStatChip(String label, String value, IconData icon) {
Widget _buildStatChip(String label, String value, IconData icon, {bool isSvg = false}) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 10.h),
decoration: BoxDecoration(
@ -213,7 +220,7 @@ class LakumWalletDetails extends StatelessWidget {
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, color: Colors.white, size: 16.f),
isSvg ? Utils.buildSvgWithAssets(icon: AppAssets.expired_icon, width: 15.w, height: 15.h, applyThemeColor: false) : Icon(icon, color: Colors.white, size: 16.f),
SizedBox(width: 6.w),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -318,20 +325,20 @@ class LakumWalletDetails extends StatelessWidget {
return Row(
children: [
// Transaction Icon
Container(
width: 44.w,
height: 44.h,
decoration: BoxDecoration(
color: transactionColor.withAlpha(25),
borderRadius: BorderRadius.circular(12.r),
),
child: Icon(
isGained ? Icons.add_rounded : Icons.remove_rounded,
color: transactionColor,
size: 24.f,
),
),
SizedBox(width: 12.w),
// Container(
// width: 44.w,
// height: 44.h,
// decoration: BoxDecoration(
// color: transactionColor.withAlpha(25),
// borderRadius: BorderRadius.circular(12.r),
// ),
// child: Icon(
// isGained ? Icons.add_rounded : Icons.remove_rounded,
// color: transactionColor,
// size: 24.f,
// ),
// ),
// SizedBox(width: 12.w),
// Transaction Details
Expanded(

@ -29,6 +29,7 @@ import 'package:hmg_patient_app_new/features/my_appointments/appointment_rating_
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/notifications/notifications_view_model.dart';
import 'package:hmg_patient_app_new/features/paytabs/paytabs_view_model.dart';
import 'package:hmg_patient_app_new/features/todo_section/todo_section_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/appointment_queue_page.dart';
@ -148,11 +149,14 @@ class _LandingPageState extends State<LandingPage> {
notificationsViewModel.initNotificationsViewModel();
insuranceViewModel.initInsuranceProvider();
if(appState.isRatedVisible) {
appointmentRatingViewModel.getLastRatingAppointment(onSuccess: (response) {
if (appointmentRatingViewModel.appointmentRatedList.isNotEmpty) {
appointmentRatingViewModel.getAppointmentDetails(appointmentRatingViewModel.appointmentRatedList.last.appointmentNo!, appointmentRatingViewModel.appointmentRatedList.last.projectID!,
onSuccess: ((response) {
if (!appState.isRatedVisible) {
appointmentRatingViewModel.getLastRatingAppointment(
onSuccess: (response) {
if (appointmentRatingViewModel.appointmentRatedList.isNotEmpty) {
appointmentRatingViewModel.getAppointmentDetails(
appointmentRatingViewModel.appointmentRatedList.last.appointmentNo!,
appointmentRatingViewModel.appointmentRatedList.last.projectID!,
onSuccess: ((response) {
appointmentRatingViewModel.setClinicOrDoctor(false);
appointmentRatingViewModel.setTitle(LocaleKeys.rateDoctor.tr(context: context));
appointmentRatingViewModel.setSubTitle(LocaleKeys.howWasYourLastVisitWithDoctor.tr(context: context));
@ -212,10 +216,7 @@ class _LandingPageState extends State<LandingPage> {
controller: _scrollController,
physics: const AlwaysScrollableScrollPhysics(),
padding: EdgeInsets.only(
top: (appState.isAuthenticated &&
!insuranceVM.isInsuranceLoading &&
insuranceVM.isInsuranceExpired &&
insuranceVM.isInsuranceExpiryBannerShown)
top: (appState.isAuthenticated && !insuranceVM.isInsuranceLoading && insuranceVM.isInsuranceExpired && insuranceVM.isInsuranceExpiryBannerShown)
? (MediaQuery.paddingOf(context).top + 70.h)
: kToolbarHeight + 0.h,
bottom: 24),
@ -338,9 +339,7 @@ class _LandingPageState extends State<LandingPage> {
SizedBox(
width: 24.w,
),
Utils.buildSvgWithAssets(
icon: appState.isArabic() ? AppAssets.enLangIcon : AppAssets.arLangIcon, height: 24.h, width: 24.h)
.onPress(() {
Utils.buildSvgWithAssets(icon: appState.isArabic() ? AppAssets.enLangIcon : AppAssets.arLangIcon, height: 24.h, width: 24.h).onPress(() {
context.setLocale(appState.isArabic() ? Locale('en', 'US') : Locale('ar', 'SA'));
})
])
@ -415,6 +414,9 @@ class _LandingPageState extends State<LandingPage> {
myAppointmentsViewModel.onTabChange(0);
myAppointmentsViewModel.updateListWRTTab(0);
Navigator.of(context).push(CustomPageRoute(page: MyAppointmentsPage()));
// getIt.get<PayTabsViewModel>().setPaymentConfiguration("Appointment Payment", 15.5);
// getIt.get<PayTabsViewModel>().startCardPayment();
}),
Consumer3<MyAppointmentsViewModel, ImmediateLiveCareViewModel, TodoSectionViewModel>(
builder: (context, myAppointmentsVM, immediateLiveCareVM, todoSectionVM, child) {
@ -484,9 +486,7 @@ class _LandingPageState extends State<LandingPage> {
),
)
: SizedBox(
height: 255.h +
20 +
30, // itemHeight + shadow padding (10 top + 10 bottom) + pagination dots space
height: 255.h + 20 + 30, // itemHeight + shadow padding (10 top + 10 bottom) + pagination dots space
child: Builder(
builder: (context) {
final int swiperItemCount = myAppointmentsVM.isMyAppointmentsLoading
@ -531,8 +531,7 @@ class _LandingPageState extends State<LandingPage> {
? _buildLiveCareRequestCard().paddingSymmetrical(24.h, 16.h)
: Container(
width: double.infinity,
decoration: RoundedRectangleBorder()
.toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true),
child: Padding(
padding: EdgeInsets.all(16.h),
child: Column(
@ -632,9 +631,7 @@ class _LandingPageState extends State<LandingPage> {
LocaleKeys.quickLinks.tr(context: context).toText16(isBold: true),
Row(
children: [
LocaleKeys.viewMedicalFileLandingPage
.tr(context: context)
.toText14(color: AppColors.primaryRedColor, isBold: true),
LocaleKeys.viewMedicalFileLandingPage.tr(context: context).toText14(color: AppColors.primaryRedColor, isBold: true),
SizedBox(width: 2.h),
Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 14.h),
],
@ -662,10 +659,7 @@ class _LandingPageState extends State<LandingPage> {
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.pendingAncillaryOrders
.tr(context: context)
.toText14(color: AppColors.eReferralCardColor, isBold: true)
.paddingSymmetrical(24.h, 0.h),
LocaleKeys.pendingAncillaryOrders.tr(context: context).toText14(color: AppColors.eReferralCardColor, isBold: true).paddingSymmetrical(24.h, 0.h),
CustomButton(
text: LocaleKeys.view.tr(context: context),
onPressed: () {
@ -696,10 +690,7 @@ class _LandingPageState extends State<LandingPage> {
trackColor: Color(0xffD9D9D9),
trackBorderColor: Colors.transparent,
trackRadius: Radius.circular(10.0),
padding: EdgeInsets.only(
top: 92.h + 32.h,
left: MediaQuery.sizeOf(context).width / 2.5 - 10,
right: MediaQuery.sizeOf(context).width / 2.5 - 10),
padding: EdgeInsets.only(top: 92.h + 32.h, left: MediaQuery.sizeOf(context).width / 2.5 - 10, right: MediaQuery.sizeOf(context).width / 2.5 - 10),
child: ListView.separated(
scrollDirection: Axis.horizontal,
itemCount: LandingPageData().getLoggedInServiceCardsList.length,
@ -753,10 +744,7 @@ class _LandingPageState extends State<LandingPage> {
trackColor: Color(0xffD9D9D9),
trackBorderColor: Colors.transparent,
trackRadius: Radius.circular(10.0),
padding: EdgeInsets.only(
top: 92.h + 32.h,
left: MediaQuery.sizeOf(context).width / 2.5 - 10,
right: MediaQuery.sizeOf(context).width / 2.5 - 10),
padding: EdgeInsets.only(top: 92.h + 32.h, left: MediaQuery.sizeOf(context).width / 2.5 - 10, right: MediaQuery.sizeOf(context).width / 2.5 - 10),
child: ListView.separated(
scrollDirection: Axis.horizontal,
itemCount: LandingPageData.getNotLoggedInServiceCardsList.length,
@ -842,6 +830,7 @@ class _LandingPageState extends State<LandingPage> {
children: [
LocaleKeys.myBalanceSubtitle.tr(context: context).toText16(isBold: true).paddingSymmetrical(24.h, 0.h),
SizedBox(
// height: 200.h,
height: 170.h,
child: ListView.separated(
scrollDirection: Axis.horizontal,
@ -879,10 +868,7 @@ class _LandingPageState extends State<LandingPage> {
),
),
),
(appState.isAuthenticated &&
!insuranceVM.isInsuranceLoading &&
insuranceVM.isInsuranceExpired &&
insuranceVM.isInsuranceExpiryBannerShown)
(appState.isAuthenticated && !insuranceVM.isInsuranceLoading && insuranceVM.isInsuranceExpired && insuranceVM.isInsuranceExpiryBannerShown)
? Container(
height: MediaQuery.paddingOf(context).top + 50.h,
decoration: ShapeDecoration(
@ -899,24 +885,17 @@ class _LandingPageState extends State<LandingPage> {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.insuranceExpiredOrInactive
.tr(context: context)
.toText14(color: AppColors.primaryRedColor, isBold: true)
.paddingSymmetrical(0.h, 0.h),
LocaleKeys.insuranceExpiredOrInactive.tr(context: context).toText14(color: AppColors.primaryRedColor, isBold: true).paddingSymmetrical(0.h, 0.h),
Row(
children: [
CustomButton(
text: LocaleKeys.updateInsurance.tr(context: context),
onPressed: () {
insuranceVM.setIsInsuranceUpdateDetailsLoading(true);
insuranceVM.getPatientInsuranceDetailsForUpdate(appState.getAuthenticatedUser()!.patientId.toString(),
appState.getAuthenticatedUser()!.patientIdentificationNo.toString());
insuranceVM.getPatientInsuranceDetailsForUpdate(
appState.getAuthenticatedUser()!.patientId.toString(), appState.getAuthenticatedUser()!.patientIdentificationNo.toString());
showCommonBottomSheetWithoutHeight(context,
child: PatientInsuranceCardUpdateCard(),
callBackFunc: () {},
title: "",
isCloseButtonVisible: false,
isFullScreen: false);
child: PatientInsuranceCardUpdateCard(), callBackFunc: () {}, title: "", isCloseButtonVisible: false, isFullScreen: false);
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.secondaryLightRedBorderColor,
@ -1066,8 +1045,7 @@ class _LandingPageState extends State<LandingPage> {
SizedBox(height: 6.h),
_buildServingNowSection(),
SizedBox(height: 5.h),
_buildQueueActionButton(currentStatus, currentQueue.roomNo ?? "")
.toShimmer2(isShow: myAppointmentsViewModel.patientQueueDetailsList.isEmpty),
_buildQueueActionButton(currentStatus, currentQueue.roomNo ?? "").toShimmer2(isShow: myAppointmentsViewModel.patientQueueDetailsList.isEmpty),
],
),
),
@ -1096,8 +1074,7 @@ class _LandingPageState extends State<LandingPage> {
hasShadow: false,
),
padding: EdgeInsets.all(6.h),
child: Lottie.asset(AppAnimations.hourGlass,
repeat: true, reverse: false, frameRate: FrameRate(60), width: 40.h, height: 40.h, fit: BoxFit.fill)),
child: Lottie.asset(AppAnimations.hourGlass, repeat: true, reverse: false, frameRate: FrameRate(60), width: 40.h, height: 40.h, fit: BoxFit.fill)),
],
);
}
@ -1276,8 +1253,7 @@ class _LandingPageState extends State<LandingPage> {
hasShadow: false,
),
padding: EdgeInsets.all(6.h),
child: Lottie.asset(AppAnimations.hourGlass,
repeat: true, reverse: false, frameRate: FrameRate(60), width: 40.h, height: 40.h, fit: BoxFit.fill)),
child: Lottie.asset(AppAnimations.hourGlass, repeat: true, reverse: false, frameRate: FrameRate(60), width: 40.h, height: 40.h, fit: BoxFit.fill)),
// Utils.buildSvgWithAssets(
// icon: AppAssets.waiting_icon,
// width: 24.h,
@ -1325,8 +1301,7 @@ class _LandingPageState extends State<LandingPage> {
// Appointment Card Wrapper (reusable)
Widget _buildAppointmentCardWrapper(appointment) {
return Container(
decoration:
RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true, hasDenseShadow: true),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true, hasDenseShadow: true),
child: AppointmentCard(
patientAppointmentHistoryResponseModel: appointment,
myAppointmentsViewModel: myAppointmentsViewModel,

@ -105,8 +105,8 @@ class HabibWalletCard extends StatelessWidget {
.toShimmer2(isShow: habibWalletVM.isWalletAmountLoading, radius: 12.h, width: 80.h, height: 40.h),
],
),
// Spacer(),
Utils.getPaymentMethods(),
Spacer(),
Utils.getPaymentMethods(spacing: 3, width: 30, height: 30),
],
);
}),

@ -99,7 +99,11 @@ class LakumWalletCard extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.end,
children: [
NumberFormat.decimalPattern()
.format(habibWalletVM.isLakumAccountInfoLoading ? 123 : habibWalletVM.yahalaAccountNumber == "0" ? 0 : habibWalletVM.lakumAccountInfo.pointsBalance)
.format(habibWalletVM.isLakumAccountInfoLoading
? 123
: habibWalletVM.yahalaAccountNumber == "0"
? 0
: (habibWalletVM.lakumAccountInfo?.pointsBalance ?? 0))
.toString()
.toText32(isBold: true, isEnglishOnly: true)
.toShimmer2(isShow: habibWalletVM.isLakumAccountInfoLoading, radius: 12.h, width: 80.h, height: 40.h),
@ -179,7 +183,7 @@ class LakumWalletCard extends StatelessWidget {
).paddingSymmetrical(0.h, 0.h).onPress(() {
Navigator.of(context).push(
CustomPageRoute(
page: HabibWalletPage(),
page: LakumWalletDetails(),
),
);
}),

@ -584,7 +584,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
)
: Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.bgRedLightColor,
// color: AppColors.bgRedLightColor,
borderRadius: 12.r,
hasShadow: false,
),

@ -83,27 +83,19 @@ class _FamilyCardsState extends State<FamilyCards> {
false, // Don't show files option, only camera and gallery
(base64String, file) async {
try {
print('=== Starting image processing ===');
print('File path: ${file.path}');
print('File exists: ${await file.exists()}');
print('Original file size: ${await file.length() / 1024} KB');
// Compress and resize the image
print('Calling compressAndResizeImage...');
final compressedFile = await ImageCompressionHelper.compressAndResizeImage(file);
File finalFile;
String finalBase64;
if (compressedFile == null) {
print('⚠️ Compression failed - using original file as fallback');
// Fallback: use original image if compression fails
final originalSize = await file.length();
final maxSize = 1048576; // 1MB
if (originalSize > maxSize) {
print('❌ Original file is too large: ${originalSize / 1024} KB');
if (mounted) {
Utils.showToast(
LocaleKeys.imageSizeTooLarge.tr(context: context),
@ -111,8 +103,6 @@ class _FamilyCardsState extends State<FamilyCards> {
}
return;
}
print('✅ Using original file (${originalSize / 1024} KB)');
finalFile = file;
var bytes = await file.readAsBytes();
finalBase64 = base64.encode(bytes);
@ -120,10 +110,8 @@ class _FamilyCardsState extends State<FamilyCards> {
// Check compressed file size
final fileSize = await compressedFile.length();
final maxSize = 1048576; // 1MB
print('✅ Compression successful: ${fileSize / 1024} KB');
if (fileSize > maxSize) {
print('❌ Compressed file still too large');
if (mounted) {
Utils.showToast(
LocaleKeys.imageSizeTooLarge.tr(context: context),
@ -137,22 +125,16 @@ class _FamilyCardsState extends State<FamilyCards> {
finalBase64 = base64.encode(bytes);
}
print('Converting to base64... Length: ${finalBase64.length}');
if (mounted) {
setState(() {
_selectedImage = finalFile;
});
print('📤 Starting upload...');
// Upload the image
_uploadImage(finalBase64);
}
print('=== Image processing complete ===');
} catch (e, stackTrace) {
print('❌ Error in _pickImage: $e');
print('Stack trace: $stackTrace');
if (mounted) {
Utils.showToast(
LocaleKeys.failedToProcessImage.tr(context: context),
@ -450,13 +432,14 @@ class _FamilyCardsState extends State<FamilyCards> {
// ),
// SizedBox(height: 24.h),
CustomExpandableList(
expansionMode: ExpansionMode.exactlyOne,
expansionMode: ExpansionMode.multiple,
dividerColor: AppColors.dividerColor,
itemPadding: EdgeInsets.symmetric(vertical: 16.h, horizontal: 14.h),
items: [
ExpandableListItem(
title: LocaleKeys.whoCanViewMyMedicalFile.tr(context: context).toText18(isBold: true),
expandedBackgroundColor: Colors.transparent,
initiallyExpanded: true,
children: [
SizedBox(height: 10.h),
manageFamily()
@ -901,6 +884,7 @@ class _FamilyCardsState extends State<FamilyCards> {
: Expanded(
child: CustomButton(
height: 40.h,
fontSize: 14.f,
text: LocaleKeys.acceptLbl.tr(),
onPressed: () {
navigationService.pop();
@ -917,6 +901,7 @@ class _FamilyCardsState extends State<FamilyCards> {
Expanded(
child: CustomButton(
height: 40.h,
fontSize: 14.f,
text: profile.status == FamilyFileEnum.active.toInt ? LocaleKeys.removeMember.tr() : LocaleKeys.rejectView.tr(),
onPressed: () {
navigationService.pop();

@ -5,22 +5,18 @@ import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
import 'package:hmg_patient_app_new/features/my_invoices/my_invoices_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_card.dart';
import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart';
import 'package:hmg_patient_app_new/presentation/my_invoices/my_invoices_details_page.dart';
import 'package:hmg_patient_app_new/presentation/my_invoices/widgets/invoice_filter_bottom_sheet.dart';
import 'package:hmg_patient_app_new/presentation/my_invoices/widgets/invoice_list_card.dart';
import 'package:hmg_patient_app_new/presentation/my_invoices/widgets/pharmacy_invoice_card.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:open_filex/open_filex.dart';
import 'package:provider/provider.dart';
@ -135,6 +131,10 @@ class _MyInvoicesListState extends State<MyInvoicesList> {
],
onTabChange: (index) {
myInvoicesVM.onTabChanged(index);
if (index == 1 && myInvoicesVM.allPharmacyInvoicesList.isEmpty) {
// Load pharmacy invoices when pharmacy tab is selected and list is empty
myInvoicesVM.getAllPharmacyInvoices();
}
},
).paddingSymmetrical(24.h, 0.h),
myInvoicesVM.selectedTabIndex == 0 ? Column(
@ -148,7 +148,7 @@ class _MyInvoicesListState extends State<MyInvoicesList> {
myInvoicesViewModel.filterInvoices(InvoiceFilterType.all);
},
backgroundColor: myInvoicesVM.currentFilter == InvoiceFilterType.all ? AppColors.bgRedLightColor : AppColors.whiteColor,
borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.all ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2),
borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.all ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2),
textColor: myInvoicesVM.currentFilter == InvoiceFilterType.all ? AppColors.primaryRedColor : AppColors.blackColor,
fontSize: 12,
fontWeight: FontWeight.w600,
@ -164,7 +164,7 @@ class _MyInvoicesListState extends State<MyInvoicesList> {
_showHospitalFilterBottomSheet(context);
},
backgroundColor: myInvoicesVM.currentFilter == InvoiceFilterType.hospital ? AppColors.bgRedLightColor : AppColors.whiteColor,
borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.hospital ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2),
borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.hospital ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2),
textColor: myInvoicesVM.currentFilter == InvoiceFilterType.hospital ? AppColors.primaryRedColor : AppColors.blackColor,
fontSize: 12,
fontWeight: FontWeight.w600,
@ -180,7 +180,7 @@ class _MyInvoicesListState extends State<MyInvoicesList> {
_showClinicFilterBottomSheet(context);
},
backgroundColor: myInvoicesVM.currentFilter == InvoiceFilterType.clinic ? AppColors.bgRedLightColor : AppColors.whiteColor,
borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.clinic ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2),
borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.clinic ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2),
textColor: myInvoicesVM.currentFilter == InvoiceFilterType.clinic ? AppColors.primaryRedColor : AppColors.blackColor,
fontSize: 12,
fontWeight: FontWeight.w600,
@ -196,7 +196,7 @@ class _MyInvoicesListState extends State<MyInvoicesList> {
_showDoctorFilterBottomSheet(context);
},
backgroundColor: myInvoicesVM.currentFilter == InvoiceFilterType.doctor ? AppColors.bgRedLightColor : AppColors.whiteColor,
borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.doctor ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2),
borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.doctor ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2),
textColor: myInvoicesVM.currentFilter == InvoiceFilterType.doctor ? AppColors.primaryRedColor : AppColors.blackColor,
fontSize: 12,
fontWeight: FontWeight.w600,
@ -329,7 +329,94 @@ class _MyInvoicesListState extends State<MyInvoicesList> {
: Utils.getNoDataWidget(context);
}).paddingSymmetrical(24.w, 0.h),
],
) : Container(),
)
: Column(
children: [
SizedBox(height: 16.h),
ListView.builder(
itemCount: myInvoicesVM.isPharmacyInvoicesLoading
? 4
: myInvoicesVM.allPharmacyInvoicesList.isEmpty
? 1
: myInvoicesVM.allPharmacyInvoicesList.length,
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: EdgeInsetsGeometry.zero,
itemBuilder: (context, index) {
return myInvoicesVM.isPharmacyInvoicesLoading
? LabResultItemView(onTap: () {}, labOrder: null, index: index, isLoading: true)
: myInvoicesVM.allPharmacyInvoicesList.isNotEmpty
? AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 500),
child: SlideAnimation(
verticalOffset: 100.0,
child: FadeInAnimation(
child: AnimatedContainer(
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
child: PharmacyInvoiceCard(
pharmacyInvoice: myInvoicesVM.allPharmacyInvoicesList[index],
onTap: () async {
// if (Utils.isVidaPlusProject(myInvoicesVM.allPharmacyInvoicesList[index].projectID ?? 0)) {
// // For Vida+ projects, send email (if API is available)
// showCommonBottomSheetWithoutHeight(
// context,
// child: Utils.getSuccessWidget(
// loadingText: LocaleKeys.comingSoon.tr(context: context),
// ),
// callBackFunc: () {},
// isFullScreen: false,
// isCloseButtonVisible: true,
// isAutoDismiss: true,
// );
// } else {
// Download pharmacy invoice PDF
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.loadingText.tr(context: context));
myInvoicesViewModel.downloadPharmacyInvoicePDF(
setupId: myInvoicesVM.allPharmacyInvoicesList[index].setupId ?? "",
invoiceNo: myInvoicesVM.allPharmacyInvoicesList[index].invoiceNo ?? 0,
projectID: myInvoicesVM.allPharmacyInvoicesList[index].pharmacyProjectID ?? 0,
locationID: myInvoicesVM.allPharmacyInvoicesList[index].locationID ?? 0,
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
},
onSuccess: (value) async {
LoaderBottomSheet.hideLoader();
if (myInvoicesViewModel.downloadPharmacyInvoicePDFBase64!.isNotEmpty) {
String path = await Utils.createFileFromString(myInvoicesViewModel.downloadPharmacyInvoicePDFBase64!, "pdf");
try {
OpenFilex.open(path);
} catch (ex) {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: "Cannot open file"),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
}
}
},
);
// }
},
),
),
),
),
)
: Utils.getNoDataWidget(context);
}).paddingSymmetrical(24.w, 0.h),
],
),
],
);
}),

@ -0,0 +1,186 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/my_invoices/models/get_pharmacy_invoices_response_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/chip/app_custom_chip_widget.dart';
import 'dart:ui' as ui;
class PharmacyInvoiceCard extends StatelessWidget {
final GetPharmacyInvoicesResponseModel pharmacyInvoice;
final VoidCallback onTap;
const PharmacyInvoiceCard({
super.key,
required this.pharmacyInvoice,
required this.onTap,
});
@override
Widget build(BuildContext context) {
final isArabic = getIt<AppState>().isArabic();
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: true,
),
child: Padding(
padding: EdgeInsets.all(14.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Type chips
// Wrap(
// alignment: WrapAlignment.start,
// direction: Axis.horizontal,
// spacing: 6.w,
// runSpacing: 6.h,
// children: [
// AppCustomChipWidget(
// icon: AppAssets.pharmacy_icon,
// iconColor: AppColors.primaryRedColor,
// labelText: LocaleKeys.pharmacy.tr(context: context),
// textColor: AppColors.primaryRedColor,
// ),
// if (pharmacyInvoice.totalAmount != null)
// AppCustomChipWidget(
// labelText: '${pharmacyInvoice.totalAmount!.toStringAsFixed(2)} ${LocaleKeys.sar.tr(context: context)}',
// backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.1),
// textColor: AppColors.primaryRedColor,
// isEnglishOnly: true,
// ),
// ],
// ),
SizedBox(height: 16.h),
// Main content row
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
children: [
Image.network(
pharmacyInvoice.doctorImageURL ?? 'https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png',
width: 63.h,
height: 63.h,
fit: BoxFit.cover,
).circle(100.r),
Transform.translate(
offset: Offset(0.0, -20.h),
child: Container(
width: 40.w,
height: 40.h,
decoration: BoxDecoration(
color: AppColors.whiteColor,
shape: BoxShape.circle,
border: Border.all(
color: AppColors.scaffoldBgColor,
width: 1.5.w,
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Utils.buildSvgWithAssets(icon: AppAssets.rating_icon, width: 15.w, height: 15.h, applyThemeColor: false),
SizedBox(height: 2.h),
"${pharmacyInvoice.decimalDoctorRate ?? '0.0'}".toText11(isBold: true, color: AppColors.textColor),
],
),
).circle(100),
),
],
),
SizedBox(width: 16.w),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
(getIt<AppState>().isArabic()
? (pharmacyInvoice.doctorNameN ?? pharmacyInvoice.doctorName ?? LocaleKeys.doctor.tr(context: context))
: (pharmacyInvoice.doctorName ?? pharmacyInvoice.doctorNameN ?? LocaleKeys.doctor.tr(context: context))
).toText16(isBold: true),
SizedBox(height: 8.h),
Wrap(
direction: Axis.horizontal,
spacing: 6.w,
runSpacing: 6.h,
children: [
AppCustomChipWidget(
labelText: "${LocaleKeys.invoiceNo.tr(context: context)}: ${pharmacyInvoice.invoiceNo ?? '-'}",
labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w),
isEnglishOnly: true,
),
AppCustomChipWidget(
labelText: ((pharmacyInvoice.clinicName ?? LocaleKeys.clinic.tr(context: context)).length > 15
? '${(pharmacyInvoice.clinicName ?? LocaleKeys.clinic.tr(context: context)).substring(0, 12)}...'
: (pharmacyInvoice.clinicName ?? LocaleKeys.clinic.tr(context: context))),
labelPadding: EdgeInsetsDirectional.only(start: 4.w, end: 4.w),
),
AppCustomChipWidget(
labelText: pharmacyInvoice.projectName ?? LocaleKeys.hospital.tr(context: context),
labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w),
),
if (pharmacyInvoice.appointmentDate != null)
Directionality(
textDirection: ui.TextDirection.ltr,
child: AppCustomChipWidget(
labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: 6.w),
icon: AppAssets.doctor_calendar_icon,
labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(pharmacyInvoice.appointmentDate), false),
isEnglishOnly: true,
),
),
],
),
],
),
),
],
),
SizedBox(height: 16.h),
// Action button
CustomButton(
text: Utils.isVidaPlusProject(pharmacyInvoice.projectID ?? 0)
? LocaleKeys.sendEmail.tr(context: context)
: LocaleKeys.downloadInvoice.tr(context: context),
onPressed: onTap,
backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.1),
borderColor: AppColors.primaryRedColor.withValues(alpha: 0.01),
textColor: AppColors.primaryRedColor,
fontSize: 14.f,
fontWeight: FontWeight.w600,
borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w),
height: 40.h,
iconSize: 14.h,
),
],
),
),
).paddingOnly(bottom: 16.h);
}
String _formatDate(String? dateString) {
if (dateString == null || dateString.isEmpty) return '-';
try {
final date = DateUtil.convertStringToDate(dateString);
return DateUtil.formatDateToDate(date, false);
} catch (e) {
return dateString;
}
}
}

@ -16,6 +16,8 @@ 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/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/features/paytabs/models/paytabs_transaction_response_model.dart';
import 'package:hmg_patient_app_new/features/paytabs/paytabs_view_model.dart';
import 'package:hmg_patient_app_new/features/todo_section/models/resp_models/ancillary_order_procedures_detail_response_model.dart';
import 'package:hmg_patient_app_new/features/todo_section/todo_section_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
@ -55,6 +57,7 @@ class _AncillaryOrderPaymentPageState extends State<AncillaryOrderPaymentPage> {
late PayfortViewModel payfortViewModel;
late AppState appState;
late TodoSectionViewModel todoSectionViewModel;
late PayTabsViewModel paytabsViewModel;
MyInAppBrowser? browser;
String selectedPaymentMethod = "";
@ -74,6 +77,7 @@ class _AncillaryOrderPaymentPageState extends State<AncillaryOrderPaymentPage> {
appState = getIt.get<AppState>();
todoSectionViewModel = Provider.of<TodoSectionViewModel>(context);
payfortViewModel = Provider.of<PayfortViewModel>(context);
paytabsViewModel = Provider.of<PayTabsViewModel>(context, listen: false);
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
@ -125,7 +129,34 @@ class _AncillaryOrderPaymentPageState extends State<AncillaryOrderPaymentPage> {
).paddingSymmetrical(24.h, 0.h).onPress(() {
if (!todoVM.isProcessingPayment) {
selectedPaymentMethod = "MADA";
_openPaymentURL("mada");
if (appState.isPaytabsEnabled) {
paytabsViewModel.setPaymentConfiguration(
"Ancillary Orders Payment",
widget.totalAmount,
);
paytabsViewModel.startCardPayment(onSuccess: (PaytabsTransactionResponseModel transactionData) async {
final paymentAmount = widget.totalAmount;
final fortId = transactionData.transactionReference;
final paymentMethod = selectedPaymentMethod;
// Call createAdvancePayment with the payment details
_createAdvancePayment(
paymentAmount: paymentAmount.toDouble(),
paymentReference: fortId!,
paymentMethod: paymentMethod,
);
}, onError: (err) {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err.toString()),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
} else {
_openPaymentURL("mada");
}
}
}),
@ -172,7 +203,34 @@ class _AncillaryOrderPaymentPageState extends State<AncillaryOrderPaymentPage> {
).paddingSymmetrical(24.h, 0.h).onPress(() {
if (!todoVM.isProcessingPayment) {
selectedPaymentMethod = "VISA";
_openPaymentURL("visa");
if (appState.isPaytabsEnabled) {
paytabsViewModel.setPaymentConfiguration(
"Ancillary Orders Payment",
widget.totalAmount,
);
paytabsViewModel.startCardPayment(onSuccess: (PaytabsTransactionResponseModel transactionData) async {
final paymentAmount = widget.totalAmount;
final fortId = transactionData.transactionReference;
final paymentMethod = selectedPaymentMethod;
// Call createAdvancePayment with the payment details
_createAdvancePayment(
paymentAmount: paymentAmount.toDouble(),
paymentReference: fortId!,
paymentMethod: paymentMethod,
);
}, onError: (err) {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err.toString()),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
} else {
_openPaymentURL("visa");
}
}
}),
],
@ -573,33 +631,61 @@ class _AncillaryOrderPaymentPageState extends State<AncillaryOrderPaymentPage> {
return;
}
// Only proceed with Apple Pay if insert was successful
payfortViewModel.paymentWithApplePay(
customerName: "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}",
customerEmail: "CustID_${appState.getAuthenticatedUser()!.patientId.toString()}@HMG.com",
orderDescription: "Ancillary Order Payment",
orderAmount: widget.totalAmount,
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()}");
LoaderBottomSheet.hideLoader();
if(appState.isPaytabsEnabled) {
LoaderBottomSheet.hideLoader();
paytabsViewModel.setPaymentConfiguration(
"Ancillary Orders Payment",
widget.totalAmount,
);
paytabsViewModel.startApplePayPayment(onSuccess: (PaytabsTransactionResponseModel transactionData) async {
final paymentAmount = widget.totalAmount;
final fortId = transactionData.transactionReference;
final paymentMethod = selectedPaymentMethod;
// Call createAdvancePayment with the payment details
_createAdvancePayment(
paymentAmount: paymentAmount.toDouble(),
paymentReference: fortId!,
paymentMethod: paymentMethod,
);
}, onError: (err) {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: failureResult.message.toString()),
child: Utils.getErrorWidget(loadingText: err.toString()),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
},
onSucceeded: (successResult) async {
LoaderBottomSheet.hideLoader();
log("successResult: ${successResult.responseMessage.toString()}");
selectedPaymentMethod = successResult.paymentOption ?? "VISA";
_checkPaymentStatus();
},
);
});
} else {
payfortViewModel.paymentWithApplePay(
customerName: "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}",
customerEmail: "CustID_${appState.getAuthenticatedUser()!.patientId.toString()}@HMG.com",
orderDescription: "Ancillary Order Payment",
orderAmount: widget.totalAmount,
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()}");
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: failureResult.message.toString()),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
},
onSucceeded: (successResult) async {
LoaderBottomSheet.hideLoader();
log("successResult: ${successResult.responseMessage.toString()}");
selectedPaymentMethod = successResult.paymentOption ?? "VISA";
_checkPaymentStatus();
},
);
}
}
}

@ -5,6 +5,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/emergency_services/emergency_services_view_model.dart';
import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_view_model.dart';
import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_livecare_view_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/todo_section/todo_section_view_model.dart';
@ -29,6 +30,7 @@ class _AppLanguageChangeState extends State<AppLanguageChange> {
late ImmediateLiveCareViewModel immediateLiveCareViewModel;
late EmergencyServicesViewModel emergencyServicesViewModel;
late TodoSectionViewModel todoSectionViewModel;
late HabibWalletViewModel habibWalletVM;
@override
void initState() {
@ -48,6 +50,7 @@ class _AppLanguageChangeState extends State<AppLanguageChange> {
immediateLiveCareViewModel = Provider.of<ImmediateLiveCareViewModel>(context, listen: false);
emergencyServicesViewModel = Provider.of<EmergencyServicesViewModel>(context, listen: false);
todoSectionViewModel = Provider.of<TodoSectionViewModel>(context, listen: false);
habibWalletVM = context.read<HabibWalletViewModel>();
return Column(
spacing: 24.h,
@ -72,6 +75,10 @@ class _AppLanguageChangeState extends State<AppLanguageChange> {
myAppointmentsViewModel.initAppointmentsViewModel();
myAppointmentsViewModel.getPatientAppointments(true, false);
habibWalletVM.initHabibWalletProvider();
habibWalletVM.getPatientBalanceAmount();
habibWalletVM.getLakumAccountInformation();
//Reload Immediate LiveCare Data
immediateLiveCareViewModel.initImmediateLiveCare();
immediateLiveCareViewModel.getPatientLiveCareHistory();

@ -2,8 +2,8 @@ name: hmg_patient_app_new
description: "New HMG Patient App"
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
#version: 0.0.30+29
version: 0.0.4+1
#version: 0.0.32+31
version: 0.0.5+2
environment:
sdk: ">=3.6.0 <4.0.0"
@ -101,11 +101,11 @@ dependencies:
flutter_widget_from_html: ^0.17.1
huawei_map: ^6.12.0+301
flutter_image_compress: ^2.3.0
scrollable_positioned_list: ^0.3.8
in_app_review: ^2.0.11
flutter_paytabs_bridge: ^2.7.13
dev_dependencies:
flutter_test:
sdk: flutter

Loading…
Cancel
Save