WalkIn Appointment implementation done

pull/107/head
haroon amjad 1 month ago
parent 2b7379c1c3
commit 581a4a5a74

@ -14,6 +14,7 @@ import 'package:hmg_patient_app_new/features/book_appointments/models/resp_model
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/get_patient_dental_plan_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_share_response_model.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
import 'models/resp_models/laser_body_parts.dart';
@ -84,6 +85,22 @@ abstract class BookAppointmentsRepo {
Future<Either<Failure, GenericApiModel<List<LaserBodyPart>>>> getLaserClinics(int laserCategoryID, int projectID, int languageID,
{Function(dynamic)? onSuccess, Function(String)? onError});
Future<Either<Failure, GenericApiModel<dynamic>>> checkScannedNFCAndQRCode(String nfcCode, int projectId, {Function(dynamic)? onSuccess, Function(String)? onError});
Future<Either<Failure, GenericApiModel<PatientAppointmentShareResponseModel>>> getPatientShareWalkInAppointment({required int projectID, required int clinicID, required int doctorID});
Future<Either<Failure, GenericApiModel<dynamic>>> insertSpecificAppointmentForWalkIn(
{required int docID,
required int clinicID,
required int projectID,
required String selectedTime,
required String selectedDate,
required int initialSlotDuration,
required int genderID,
required int userAge,
Function(dynamic)? onSuccess,
Function(String)? onError});
}
class BookAppointmentsRepoImp implements BookAppointmentsRepo {
@ -848,4 +865,144 @@ class BookAppointmentsRepoImp implements BookAppointmentsRepo {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel>> checkScannedNFCAndQRCode(String nfcCode, int projectId, {Function(dynamic)? onSuccess, Function(String)? onError}) async {
Map<String, dynamic> mapDevice = {"NFC_Code": nfcCode, "ProjectID": projectId};
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
CHECK_SCANNED_NFC_QR_CODE,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: response,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<PatientAppointmentShareResponseModel>>> getPatientShareWalkInAppointment({required int projectID, required int clinicID, required int doctorID}) async {
Map<String, dynamic> mapRequest = {"ProjectID": projectID, "ClinicID": clinicID, "DoctorID": doctorID};
try {
GenericApiModel<PatientAppointmentShareResponseModel>? apiResponse;
Failure? failure;
await apiClient.post(
GET_PATIENT_SHARE_FOR_WALKIN_APPOINTMENT,
body: mapRequest,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['OnlineCheckInAppointmentsWalkInModel'];
if (list == null || list.isEmpty) {
throw Exception("patient share list is empty");
}
final patientShareObj = PatientAppointmentShareResponseModel.fromJson(list);
patientShareObj.isCash = response["IsCash"];
patientShareObj.isEligible = response["IsEligible"];
patientShareObj.isInsured = response["IsInsured"];
apiResponse = GenericApiModel<PatientAppointmentShareResponseModel>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: patientShareObj,
);
} 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>> insertSpecificAppointmentForWalkIn(
{required int docID,
required int clinicID,
required int projectID,
required String selectedTime,
required String selectedDate,
required int initialSlotDuration,
required int genderID,
required int userAge,
Function(dynamic)? onSuccess,
Function(String)? onError}) async {
Map<String, dynamic> mapDevice = {
"IsForLiveCare": true,
"ProjectID": projectID,
"ClinicID": clinicID,
"DoctorID": docID,
"StartTime": selectedTime,
"SelectedTime": selectedTime,
"EndTime": selectedTime,
"InitialSlotDuration": initialSlotDuration,
"StrAppointmentDate": selectedDate,
"IsVirtual": false,
"BookedBy": 102,
"VisitType": 1,
"VisitFor": 1,
"GenderID": genderID,
"Age": userAge
};
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
INSERT_WALKIN_APPOINTMENT,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final appointmentNo = response['AppointmentNo'];
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: response["ErrorEndUserMessage"],
data: response,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
}

@ -24,6 +24,7 @@ import 'package:hmg_patient_app_new/features/book_appointments/models/timeslots.
import 'package:hmg_patient_app_new/features/my_appointments/models/facility_selection.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/doctor_list_api_response.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_share_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart';
@ -114,6 +115,13 @@ class BookAppointmentsViewModel extends ChangeNotifier {
bool isWaitingAppointmentAvailable = false;
bool isWaitingAppointmentSelected = false;
int waitingAppointmentProjectID = 0;
DoctorsListResponseModel? waitingAppointmentDoctor;
String waitingAppointmentNFCCode = "";
PatientAppointmentShareResponseModel? patientWalkInAppointmentShareResponseModel;
///variables for laser clinic
List<LaserCategoryType> femaleLaserCategory = [
LaserCategoryType(1, 'bodyString'),
@ -173,11 +181,32 @@ class BookAppointmentsViewModel extends ChangeNotifier {
dentalChiefComplaintsList.clear();
isContinueDentalPlan = false;
isChiefComplaintsListLoading = true;
isWaitingAppointmentSelected = false;
bodyTypes = [maleLaserCategory, femaleLaserCategory];
// getLocation();
notifyListeners();
}
setIsWaitingAppointmentSelected(bool isWaitingAppointmentSelected) {
this.isWaitingAppointmentSelected = isWaitingAppointmentSelected;
notifyListeners();
}
setWaitingAppointmentDoctor(DoctorsListResponseModel waitingAppointmentDoctor) {
this.waitingAppointmentDoctor = waitingAppointmentDoctor;
notifyListeners();
}
setWaitingAppointmentNFCCode(String waitingAppointmentNFCCode) {
this.waitingAppointmentNFCCode = waitingAppointmentNFCCode;
notifyListeners();
}
setWaitingAppointmentProjectID(int projectID) {
waitingAppointmentProjectID = projectID;
notifyListeners();
}
setIsDoctorsListLoading(bool value) {
if (value) {
doctorsList.clear();
@ -470,6 +499,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
freeSlotsResponse = apiResponse.data['FreeTimeSlots'];
// isWaitingAppointmentAvailable = apiResponse.data["IsAllowToBookWaitingAppointment"];
isWaitingAppointmentAvailable = true;
freeSlotsResponse.forEach((element) {
// date = (isLiveCareSchedule != null && isLiveCareSchedule)
// ? DateUtil.convertStringToDate(element)
@ -1167,4 +1197,95 @@ class BookAppointmentsViewModel extends ChangeNotifier {
laserBodyPartsList = [];
duration = 0;
}
Future<void> checkScannedNFCAndQRCode(String nfcCode, int projectId, {Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await bookAppointmentsRepo.checkScannedNFCAndQRCode(nfcCode, projectId);
result.fold(
(failure) async {
onError!("Invalid verification point scanned.".needTranslation);
},
(apiResponse) {
// if (apiResponse.data['returnValue'] == 0) {
// onError!("Invalid verification point scanned.".needTranslation);
// } else if (apiResponse.data['returnValue'] == 1) {
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
// }
},
);
}
Future<void> getWalkInPatientShareAppointment({Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await bookAppointmentsRepo.getPatientShareWalkInAppointment(projectID: waitingAppointmentProjectID, clinicID: selectedDoctor.clinicID!, doctorID: selectedDoctor.doctorID!);
result.fold(
(failure) async {
if (onError != null) {
onError(failure.message);
}
// await errorHandlerService.handleError(
// failure: failure,
// onOkPressed: () {
// onError!(failure.message);
// });
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
onError!(apiResponse.errorMessage!);
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
patientWalkInAppointmentShareResponseModel = apiResponse.data!;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
Future<void> insertSpecificAppointmentForWalkIn({Function(dynamic p1)? onSuccess, Function(dynamic p1)? onError}) async {
_appState = getIt<AppState>();
final result = await bookAppointmentsRepo.insertSpecificAppointmentForWalkIn(
docID: selectedDoctor.doctorID!,
clinicID: selectedDoctor.clinicID!,
projectID: selectedDoctor.projectID!,
selectedDate: selectedAppointmentDate,
selectedTime: selectedAppointmentTime,
initialSlotDuration: initialSlotDuration,
genderID: _appState.getAuthenticatedUser()!.gender!,
userAge: _appState.getAuthenticatedUser()!.age!,
onError: onError);
result.fold(
(failure) async {
print(failure);
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
LoadingUtils.hideFullScreenLoader();
showCommonBottomSheetWithoutHeight(
title: LocaleKeys.notice.tr(context: navigationService.navigatorKey.currentContext!),
navigationService.navigatorKey.currentContext!,
child: Utils.getErrorWidget(loadingText: apiResponse.errorMessage),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
} else if (apiResponse.messageStatus == 1) {
if (apiResponse.data == null || apiResponse.data!.isEmpty) {
onError!("Unexpected Error Occurred".needTranslation);
return;
}
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
}

@ -141,7 +141,7 @@ class PatientAppointmentShareResponseModel {
doctorID = json['DoctorID'];
doctorImageURL = json['DoctorImageURL'];
doctorNameObj = json['DoctorNameObj'];
doctorSpeciality = json['DoctorSpeciality'].cast<String>();
// doctorSpeciality = json['DoctorSpeciality'].cast<String>();
errCode = json['ErrCode'];
groupID = json['GroupID'];
iSAllowOnlineCheckedIN = json['ISAllowOnlineCheckedIN'];

@ -3,6 +3,7 @@ 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/loading_utils.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
@ -12,11 +13,15 @@ import 'package:hmg_patient_app_new/features/authentication/authentication_view_
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/waiting_appointment/waiting_appointment_payment_page.dart';
import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:hmg_patient_app_new/widgets/loading_dialog.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:provider/provider.dart';
@ -113,10 +118,14 @@ class _ReviewAppointmentPageState extends State<ReviewAppointmentPage> {
labelText: "${LocaleKeys.branch.tr(context: context)} ${bookAppointmentsViewModel.selectedDoctor.projectName}".needTranslation,
),
AppCustomChipWidget(
labelText: "${LocaleKeys.date.tr(context: context)}: ${bookAppointmentsViewModel.selectedAppointmentDate}".needTranslation,
labelText:
"${LocaleKeys.date.tr(context: context)}: ${bookAppointmentsViewModel.isWaitingAppointmentSelected ? DateUtil.formatDateToDate(DateTime.now(), false) : bookAppointmentsViewModel.selectedAppointmentDate}"
.needTranslation,
),
AppCustomChipWidget(
labelText: "${LocaleKeys.time.tr(context: context)}: ${bookAppointmentsViewModel.selectedAppointmentTime}".needTranslation,
labelText:
"${LocaleKeys.time.tr(context: context)}: ${bookAppointmentsViewModel.isWaitingAppointmentSelected ? "Waiting Appointment".needTranslation : bookAppointmentsViewModel.selectedAppointmentTime}"
.needTranslation,
),
],
),
@ -185,9 +194,13 @@ class _ReviewAppointmentPageState extends State<ReviewAppointmentPage> {
hasShadow: true,
),
child: CustomButton(
text: LocaleKeys.bookAppo.tr(context: context),
text: bookAppointmentsViewModel.isWaitingAppointmentSelected ? "Add to waiting list" : LocaleKeys.bookAppo.tr(context: context),
onPressed: () async {
initiateBookAppointment();
if (bookAppointmentsViewModel.isWaitingAppointmentSelected) {
getWalkInAppointmentPatientShare();
} else {
initiateBookAppointment();
}
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
@ -204,6 +217,27 @@ class _ReviewAppointmentPageState extends State<ReviewAppointmentPage> {
);
}
void getWalkInAppointmentPatientShare() async {
LoaderBottomSheet.showLoader(loadingText: "Fetching Appointment Share...".needTranslation);
await bookAppointmentsViewModel.getWalkInPatientShareAppointment(onSuccess: (val) {
LoaderBottomSheet.hideLoader();
Navigator.of(context).push(
CustomPageRoute(
page: WaitingAppointmentPaymentPage(),
),
);
}, onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
}
void initiateBookAppointment() async {
LoadingUtils.showFullScreenLoader(barrierDismissible: true, isSuccessDialog: false, loadingText: "Booking your appointment...".needTranslation);
myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true);

@ -5,16 +5,23 @@ import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/waiting_appointment/waiting_appointment_online_checkin_sheet.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
import 'package:provider/provider.dart';
class WaitingAppointmentInfo extends StatelessWidget {
const WaitingAppointmentInfo({super.key});
WaitingAppointmentInfo({super.key});
late BookAppointmentsViewModel bookAppointmentsViewModel;
@override
Widget build(BuildContext context) {
bookAppointmentsViewModel = Provider.of<BookAppointmentsViewModel>(context, listen: false);
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: Column(
@ -33,11 +40,40 @@ class WaitingAppointmentInfo extends StatelessWidget {
borderRadius: 24.h,
hasShadow: true,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Utils.buildSvgWithAssets(icon: AppAssets.waiting_appointment_icon, width: 48.h, height: 48.h, fit: BoxFit.contain)
],
child: Padding(
padding: EdgeInsets.all(16.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Utils.buildSvgWithAssets(icon: AppAssets.waiting_appointment_icon, width: 48.h, height: 48.h, fit: BoxFit.contain),
SizedBox(height: 16.h),
"What is Waiting Appointment?".needTranslation.toText16(isBold: true),
SizedBox(height: 16.h),
"The waiting appointments feature allows you to book an appointment while you are inside the hospital building, and in case there is no available slot in the doctors schedule."
.needTranslation
.toText14(isBold: false),
SizedBox(height: 16.h),
"The appointment with the doctor is confirmed, but the time of entry is uncertain.".needTranslation.toText14(isBold: false),
SizedBox(height: 24.h),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(
Icons.warning,
size: 20,
color: AppColors.warningColorYellow,
),
SizedBox(width: 10.w),
SizedBox(
width: MediaQuery.of(context).size.width * 0.7,
child: "Note: You must have to pay within 10 minutes of booking, otherwise your appointment will be cancelled automatically"
.needTranslation
.toText14(isBold: true, color: AppColors.warningColorYellow),
),
],
),
],
),
),
),
],
@ -53,7 +89,15 @@ class WaitingAppointmentInfo extends StatelessWidget {
),
child: CustomButton(
text: "Continue".needTranslation,
onPressed: () async {},
onPressed: () async {
showCommonBottomSheetWithoutHeight(context,
title: LocaleKeys.onlineCheckIn.tr(),
child: WaitingAppointmentOnlineCheckinSheet(
bookAppointmentsViewModel: bookAppointmentsViewModel,
),
callBackFunc: () {},
isFullScreen: false);
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
textColor: AppColors.whiteColor,

@ -0,0 +1,161 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_nfc_kit/flutter_nfc_kit.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/common_models/privilege/ProjectDetailListModel.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/location_util.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/review_appointment_page.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:barcode_scan2/barcode_scan2.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:hmg_patient_app_new/widgets/nfc/nfc_reader_sheet.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
class WaitingAppointmentOnlineCheckinSheet extends StatelessWidget {
WaitingAppointmentOnlineCheckinSheet({super.key, required this.bookAppointmentsViewModel});
BookAppointmentsViewModel bookAppointmentsViewModel;
bool _supportsNFC = false;
late LocationUtils locationUtils;
late AppState appState;
ProjectDetailListModel projectDetailListModel = ProjectDetailListModel();
@override
Widget build(BuildContext context) {
appState = getIt.get<AppState>();
locationUtils = getIt.get<LocationUtils>();
locationUtils.isShowConfirmDialog = true;
FlutterNfcKit.nfcAvailability.then((value) {
_supportsNFC = (value == NFCAvailability.available);
});
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
checkInOptionCard(
AppAssets.checkin_location_icon,
"Live Location".needTranslation,
"Verify your location to be at hospital to check in".needTranslation,
).onPress(() {
// locationUtils = LocationUtils(
// isShowConfirmDialog: false,
// navigationService: myAppointmentsViewModel.navigationService,
// appState: myAppointmentsViewModel.appState,
// );
locationUtils.getCurrentLocation(onSuccess: (value) {
projectDetailListModel = Utils.getProjectDetailObj(appState, bookAppointmentsViewModel.waitingAppointmentProjectID);
double dist = Utils.distance(value.latitude, value.longitude, double.parse(projectDetailListModel.latitude!), double.parse(projectDetailListModel.longitude!)).ceilToDouble() * 1000;
print(dist);
if (dist <= projectDetailListModel.geofenceRadius!) {
checkScannedNFCAndQRCode(projectDetailListModel.checkInQrCode!, context);
} else {
showCommonBottomSheetWithoutHeight(context,
title: "Error".needTranslation,
child: Utils.getErrorWidget(loadingText: "Please ensure you're within the hospital location to perform online check-in.".needTranslation), callBackFunc: () {
Navigator.of(context).pop();
}, isFullScreen: false);
}
});
}),
SizedBox(height: 16.h),
checkInOptionCard(
AppAssets.checkin_nfc_icon,
"NFC (Near Field Communication)".needTranslation,
"Scan your phone via NFC board to check in".needTranslation,
).onPress(() {
Future.delayed(const Duration(milliseconds: 500), () {
showNfcReader(context, onNcfScan: (String nfcId) {
Future.delayed(const Duration(milliseconds: 100), () {
checkScannedNFCAndQRCode(nfcId, context);
});
}, onCancel: () {});
});
}),
SizedBox(height: 16.h),
checkInOptionCard(
AppAssets.checkin_qr_icon,
"QR Code".needTranslation,
"Scan QR code with your camera to check in".needTranslation,
).onPress(() async {
String onlineCheckInQRCode = (await BarcodeScanner.scan().then((value) => value.rawContent));
if (onlineCheckInQRCode != "") {
checkScannedNFCAndQRCode(onlineCheckInQRCode, context);
} else {}
}),
],
);
}
Widget checkInOptionCard(String icon, String title, String subTitle) {
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: false,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Utils.buildSvgWithAssets(icon: icon, width: 40.h, height: 40.h, fit: BoxFit.fill),
SizedBox(height: 16.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
title.toText16(isBold: true, color: AppColors.textColor),
subTitle.toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor),
],
),
),
Transform.flip(
flipX: appState.isArabic(),
child: Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon_small,
iconColor: AppColors.blackColor,
width: 18.h,
height: 13.h,
fit: BoxFit.contain,
),
),
],
),
],
).paddingAll(16.h),
);
}
void checkScannedNFCAndQRCode(String scannedCode, BuildContext context) async {
LoaderBottomSheet.showLoader(loadingText: "Processing Check-In...".needTranslation);
bookAppointmentsViewModel.checkScannedNFCAndQRCode(
scannedCode,
bookAppointmentsViewModel.waitingAppointmentProjectID,
onSuccess: (value) {
LoaderBottomSheet.hideLoader();
bookAppointmentsViewModel.setIsWaitingAppointmentSelected(true);
Navigator.of(context).push(
CustomPageRoute(
page: ReviewAppointmentPage(),
),
);
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(context, title: "Error".needTranslation, child: Utils.getErrorWidget(loadingText: err), callBackFunc: () {
// Navigator.of(context).pop();
}, isFullScreen: false);
},
);
}
}

@ -0,0 +1,644 @@
import 'dart:async';
import 'dart:developer';
import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/cache_consts.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/core/utils/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/book_appointments/book_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/payfort/models/apple_pay_request_insert_model.dart';
import 'package:hmg_patient_app_new/features/payfort/payfort_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart';
import 'package:hmg_patient_app_new/presentation/insurance/insurance_home_page.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
import 'package:hmg_patient_app_new/widgets/in_app_browser/InAppBrowser.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:provider/provider.dart';
import 'package:smooth_corner/smooth_corner.dart';
class WaitingAppointmentPaymentPage extends StatefulWidget {
WaitingAppointmentPaymentPage({super.key});
// PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel;
@override
State<WaitingAppointmentPaymentPage> createState() => _WaitingAppointmentPaymentPageState();
}
class _WaitingAppointmentPaymentPageState extends State<WaitingAppointmentPaymentPage> {
late BookAppointmentsViewModel bookAppointmentsViewModel;
late MyAppointmentsViewModel myAppointmentsViewModel;
late PayfortViewModel payfortViewModel;
late AppState appState;
MyInAppBrowser? browser;
String selectedPaymentMethod = "";
String transID = "";
bool isShowTamara = false;
String tamaraPaymentStatus = "";
String tamaraOrderID = "";
@override
void initState() {
scheduleMicrotask(() {
payfortViewModel.initPayfortViewModel();
payfortViewModel.setIsApplePayConfigurationLoading(false);
// myAppointmentsViewModel.getPatientShareAppointment(
// widget.patientAppointmentHistoryResponseModel.projectID,
// widget.patientAppointmentHistoryResponseModel.clinicID,
// widget.patientAppointmentHistoryResponseModel.appointmentNo.toString(), widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false, onSuccess: (val) {
// myAppointmentsViewModel.getTamaraInstallmentsDetails().then((val) {
// if (myAppointmentsViewModel.patientAppointmentShareResponseModel!.patientShareWithTax! >= myAppointmentsViewModel.getTamaraInstallmentsDetailsResponseModel!.minLimit!.amount! &&
// myAppointmentsViewModel.patientAppointmentShareResponseModel!.patientShareWithTax! <= myAppointmentsViewModel.getTamaraInstallmentsDetailsResponseModel!.maxLimit!.amount!) {
// setState(() {
// isShowTamara = true;
// });
// }
// });
// }, onError: (err) {
// Navigator.of(context).pop();
// Navigator.of(context).pop();
// });
});
super.initState();
}
@override
Widget build(BuildContext context) {
appState = getIt.get<AppState>();
bookAppointmentsViewModel = Provider.of<BookAppointmentsViewModel>(context);
myAppointmentsViewModel = Provider.of<MyAppointmentsViewModel>(context);
payfortViewModel = Provider.of<PayfortViewModel>(context);
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: Consumer<BookAppointmentsViewModel>(builder: (context, bookAppointmentsVM, child) {
return Column(
children: [
Expanded(
child: CollapsingListView(
title: "Appointment Payment".needTranslation,
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 24.h),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: false,
),
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset(AppAssets.mada, width: 72.h, height: 25.h),
SizedBox(height: 16.h),
"Mada".needTranslation.toText16(isBold: true),
],
),
SizedBox(width: 8.h),
const Spacer(),
Transform.flip(
flipX: appState.isArabic(),
child: Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon_small,
iconColor: AppColors.blackColor,
width: 18.h,
height: 13.h,
fit: BoxFit.contain,
),
),
],
).paddingSymmetrical(16.h, 16.h),
).paddingSymmetrical(24.h, 0.h).onPress(() {
selectedPaymentMethod = "MADA";
openPaymentURL("mada");
}),
SizedBox(height: 16.h),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: false,
),
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Image.asset(AppAssets.visa, width: 50.h, height: 50.h),
SizedBox(width: 8.h),
Image.asset(AppAssets.Mastercard, width: 40.h, height: 40.h),
],
),
SizedBox(height: 16.h),
"Visa or Mastercard".needTranslation.toText16(isBold: true),
],
),
SizedBox(width: 8.h),
const Spacer(),
Transform.flip(
flipX: appState.isArabic(),
child: Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon_small,
iconColor: AppColors.blackColor,
width: 18.h,
height: 13.h,
fit: BoxFit.contain,
),
),
],
).paddingSymmetrical(16.h, 16.h),
).paddingSymmetrical(24.h, 0.h).onPress(() {
selectedPaymentMethod = "VISA";
openPaymentURL("visa");
}),
SizedBox(height: 16.h),
isShowTamara
? Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: false,
),
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset(AppAssets.tamara_en, width: 72.h, height: 25.h),
SizedBox(height: 16.h),
"Tamara".needTranslation.toText16(isBold: true),
],
),
SizedBox(width: 8.h),
const Spacer(),
Transform.flip(
flipX: appState.isArabic(),
child: Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon_small,
iconColor: AppColors.blackColor,
width: 18.h,
height: 13.h,
fit: BoxFit.contain,
),
),
],
).paddingSymmetrical(16.h, 16.h),
).paddingSymmetrical(24.h, 0.h).onPress(() {
selectedPaymentMethod = "TAMARA";
openPaymentURL("tamara");
})
: SizedBox.shrink(),
],
),
),
),
),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.h,
hasShadow: false,
),
child: Consumer<PayfortViewModel>(builder: (context, payfortVM, child) {
//TODO: Need to add loading state & animation for Apple Pay Configuration
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
(bookAppointmentsVM.patientWalkInAppointmentShareResponseModel!.isCash ?? true)
? Container(
height: 50.h,
decoration: ShapeDecoration(
color: AppColors.secondaryLightRedBorderColor,
shape: SmoothRectangleBorder(
borderRadius: BorderRadius.only(topLeft: Radius.circular(24), topRight: Radius.circular(24)),
smoothness: 1,
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"Insurance expired or inactive".needTranslation.toText14(color: AppColors.primaryRedColor, weight: FontWeight.w500).paddingSymmetrical(24.h, 0.h),
CustomButton(
text: LocaleKeys.updateInsurance.tr(context: context),
onPressed: () {
Navigator.of(context).push(
CustomPageRoute(
page: InsuranceHomePage(),
),
);
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.secondaryLightRedBorderColor,
textColor: AppColors.whiteColor,
fontSize: 10.f,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(15, 0, 15, 0),
height: 30.h,
).paddingSymmetrical(24.h, 0.h),
],
),
)
: const SizedBox(),
SizedBox(height: 24.h),
"Total amount to pay".needTranslation.toText18(isBold: true).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 17.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"Amount before tax".needTranslation.toText14(isBold: true),
Utils.getPaymentAmountWithSymbol(bookAppointmentsVM.patientWalkInAppointmentShareResponseModel!.patientShare!.toString().toText16(isBold: true), AppColors.blackColor, 13,
isSaudiCurrency: true),
],
).paddingSymmetrical(24.h, 0.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"VAT 15%".needTranslation.toText14(isBold: true, color: AppColors.greyTextColor),
Utils.getPaymentAmountWithSymbol(
bookAppointmentsVM.patientWalkInAppointmentShareResponseModel!.patientTaxAmount!.toString().toText14(isBold: true, color: AppColors.greyTextColor),
AppColors.greyTextColor,
13,
isSaudiCurrency: true),
],
).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 17.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"".needTranslation.toText14(isBold: true),
Utils.getPaymentAmountWithSymbol(
bookAppointmentsVM.patientWalkInAppointmentShareResponseModel!.patientShareWithTax!.toString().toText24(isBold: true), AppColors.blackColor, 17,
isSaudiCurrency: true),
],
).paddingSymmetrical(24.h, 0.h),
Platform.isIOS
? Utils.buildSvgWithAssets(
icon: AppAssets.apple_pay_button,
width: 200.h,
height: 80.h,
fit: BoxFit.contain,
).paddingSymmetrical(24.h, 0.h).onPress(() {
// payfortVM.setIsApplePayConfigurationLoading(true);
if (Utils.havePrivilege(103)) {
startApplePay();
} else {
openPaymentURL("ApplePay");
}
})
: SizedBox(height: 12.h),
SizedBox(height: 12.h),
],
);
}),
),
],
);
}),
);
}
onBrowserLoadStart(String url) {
print("onBrowserLoadStart");
print(url);
if (selectedPaymentMethod == "tamara") {
if (Platform.isAndroid) {
Uri uri = new Uri.dataFromString(url);
tamaraPaymentStatus = uri.queryParameters['status']!;
tamaraOrderID = uri.queryParameters['AuthorizePaymentId']!;
} else {
Uri uri = new Uri.dataFromString(url);
tamaraPaymentStatus = uri.queryParameters['paymentStatus']!;
tamaraOrderID = uri.queryParameters['orderId']!;
}
}
// if(selectedPaymentMethod != "TAMARA") {
MyInAppBrowser.successURLS.forEach((element) {
if (url.contains(element)) {
browser?.close();
MyInAppBrowser.isPaymentDone = true;
return;
}
});
// }
// if(selectedPaymentMethod != "TAMARA") {
MyInAppBrowser.errorURLS.forEach((element) {
if (url.contains(element)) {
browser?.close();
MyInAppBrowser.isPaymentDone = false;
return;
}
});
// }
}
onBrowserExit(bool isPaymentMade) async {
checkPaymentStatus();
}
void checkPaymentStatus() async {
LoaderBottomSheet.showLoader(loadingText: "Checking payment status, Please wait...".needTranslation);
if (selectedPaymentMethod == "TAMARA") {
await payfortViewModel.checkTamaraPaymentStatus(
transactionID: transID,
onSuccess: (apiResponse) async {
if (apiResponse.data["status"].toString().toLowerCase() == "success") {
tamaraOrderID = apiResponse.data["tamara_order_id"].toString();
await payfortViewModel.updateTamaraRequestStatus(responseMessage: "success", status: "14", clientRequestID: transID, tamaraOrderID: tamaraOrderID);
await payfortViewModel.markAppointmentAsTamaraPaid(projectID: bookAppointmentsViewModel.selectedDoctor.projectID!, appointmentNo: DateTime.now().millisecondsSinceEpoch);
// await myAppointmentsViewModel.addAdvanceNumberRequest(
// advanceNumber: "Tamara-Advance-0000",
// paymentReference: tamaraOrderID,
// appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo.toString(),
// onSuccess: (value) async {
// if (widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment!) {
// //TODO: Implement LiveCare Check-In API Call
// await myAppointmentsViewModel.insertLiveCareVIDARequest(
// clientRequestID: tamaraOrderID,
// patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel,
// onSuccess: (apiResponse) {
// Future.delayed(Duration(milliseconds: 500), () {
// 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), () {
// LoaderBottomSheet.hideLoader();
// Navigator.pushAndRemoveUntil(
// context,
// CustomPageRoute(
// page: LandingNavigation(),
// ),
// (r) => false);
// });
// });
// }
// });
} else {
await payfortViewModel.updateTamaraRequestStatus(responseMessage: "Failed", status: "00", clientRequestID: transID, tamaraOrderID: tamaraOrderID);
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: "Payment Failed! Please try again.".needTranslation),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
}
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
} else {
await payfortViewModel.checkPaymentStatus(
transactionID: transID,
onSuccess: (apiResponse) async {
print(apiResponse.data);
if (payfortViewModel.payfortCheckPaymentStatusResponseModel!.responseMessage!.toLowerCase() == "success") {
LoaderBottomSheet.hideLoader();
LoaderBottomSheet.showLoader(loadingText: "Booking Waiting Appointment, Please wait...".needTranslation);
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: payfortViewModel.payfortCheckPaymentStatusResponseModel!.amount!,
paymentReference: payfortViewModel.payfortCheckPaymentStatusResponseModel!.fortId!,
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: payfortViewModel.payfortCheckPaymentStatusResponseModel!.fortId!,
appointmentNo: appointmentNo,
onSuccess: (value) async {
LoaderBottomSheet.hideLoader();
sendCheckInRequest(bookAppointmentsViewModel.waitingAppointmentNFCCode, appointmentNo, context);
});
});
});
} else {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: "Payment Failed! Please try again.".needTranslation),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
}
});
}
}
openPaymentURL(String paymentMethod) {
browser = MyInAppBrowser(onExitCallback: onBrowserExit, onLoadStartCallback: onBrowserLoadStart, context: context);
transID = Utils.getAppointmentTransID(
bookAppointmentsViewModel.selectedDoctor.projectID!,
bookAppointmentsViewModel.selectedDoctor.clinicID!,
bookAppointmentsViewModel.selectedDoctor.doctorID!,
);
//TODO: Need to pass dynamic params to the payment request instead of static values
browser?.openPaymentBrowser(
bookAppointmentsViewModel.patientWalkInAppointmentShareResponseModel!.patientShareWithTax!,
"Appointment check in",
transID,
bookAppointmentsViewModel.selectedDoctor.projectID.toString(),
"CustID_${appState.getAuthenticatedUser()!.patientId.toString()}@HMG.com",
selectedPaymentMethod,
appState.getAuthenticatedUser()!.patientType.toString(),
"${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}",
appState.getAuthenticatedUser()!.patientId.toString(),
appState.getAuthenticatedUser()!,
browser!,
false,
"2",
"",
context,
"",
"",
"",
"",
"3");
}
startApplePay() async {
showCommonBottomSheet(context,
child: Utils.getLoadingWidget(), callBackFunc: (str) {}, title: "", height: ResponsiveExtension.screenHeight * 0.3, isCloseButtonVisible: false, isDismissible: false, isFullScreen: false);
transID = Utils.getAppointmentTransID(
bookAppointmentsViewModel.selectedDoctor.projectID!,
bookAppointmentsViewModel.selectedDoctor.clinicID!,
bookAppointmentsViewModel.selectedDoctor.doctorID!,
);
ApplePayInsertRequest applePayInsertRequest = ApplePayInsertRequest();
await payfortViewModel.getPayfortConfigurations(
serviceId: ServiceTypeEnum.appointmentPayment.getIdFromServiceEnum(), projectId: bookAppointmentsViewModel.selectedDoctor.projectID!, integrationId: 2);
applePayInsertRequest.clientRequestID = transID;
applePayInsertRequest.clinicID = bookAppointmentsViewModel.selectedDoctor.clinicID!;
applePayInsertRequest.currency = appState.getAuthenticatedUser()!.outSa! == 0 ? "SAR" : "AED";
applePayInsertRequest.customerEmail = "CustID_${appState.getAuthenticatedUser()!.patientId.toString()}@HMG.com";
applePayInsertRequest.customerID = appState.getAuthenticatedUser()!.patientId.toString();
applePayInsertRequest.customerName = "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}";
applePayInsertRequest.deviceToken = await Utils.getStringFromPrefs(CacheConst.pushToken);
applePayInsertRequest.voipToken = await Utils.getStringFromPrefs(CacheConst.voipToken);
applePayInsertRequest.doctorID = bookAppointmentsViewModel.selectedDoctor.doctorID;
applePayInsertRequest.projectID = bookAppointmentsViewModel.selectedDoctor.projectID.toString();
applePayInsertRequest.serviceID = ServiceTypeEnum.appointmentPayment.getIdFromServiceEnum().toString();
applePayInsertRequest.channelID = 3;
applePayInsertRequest.patientID = appState.getAuthenticatedUser()!.patientId.toString();
applePayInsertRequest.patientTypeID = appState.getAuthenticatedUser()!.patientType;
applePayInsertRequest.patientOutSA = appState.getAuthenticatedUser()!.outSa;
applePayInsertRequest.appointmentDate = DateUtil.convertDateToString(DateTime.now());
applePayInsertRequest.appointmentNo = DateTime.now().millisecondsSinceEpoch;
applePayInsertRequest.orderDescription = "Appointment Payment";
applePayInsertRequest.liveServiceID = "0";
applePayInsertRequest.latitude = "0.0";
applePayInsertRequest.longitude = "0.0";
applePayInsertRequest.amount = bookAppointmentsViewModel.patientWalkInAppointmentShareResponseModel!.patientShareWithTax!.toString();
applePayInsertRequest.isSchedule = "0";
applePayInsertRequest.language = appState.isArabic() ? 'ar' : 'en';
applePayInsertRequest.languageID = appState.isArabic() ? 1 : 2;
applePayInsertRequest.userName = appState.getAuthenticatedUser()!.patientId;
applePayInsertRequest.responseContinueURL = "http://hmg.com/Documents/success.html";
applePayInsertRequest.backClickUrl = "http://hmg.com/Documents/success.html";
applePayInsertRequest.paymentOption = "ApplePay";
applePayInsertRequest.isMobSDK = true;
applePayInsertRequest.merchantReference = transID;
applePayInsertRequest.merchantIdentifier = payfortViewModel.payfortProjectDetailsRespModel!.merchantIdentifier;
applePayInsertRequest.commandType = "PURCHASE";
applePayInsertRequest.signature = payfortViewModel.payfortProjectDetailsRespModel!.signature;
applePayInsertRequest.accessCode = payfortViewModel.payfortProjectDetailsRespModel!.accessCode;
applePayInsertRequest.shaRequestPhrase = payfortViewModel.payfortProjectDetailsRespModel!.shaRequest;
applePayInsertRequest.shaResponsePhrase = payfortViewModel.payfortProjectDetailsRespModel!.shaResponse;
applePayInsertRequest.returnURL = "";
//TODO: Need to pass dynamic params to the Apple Pay instead of static values
await payfortViewModel.applePayRequestInsert(applePayInsertRequest: applePayInsertRequest).then((value) {
payfortViewModel.paymentWithApplePay(
customerName: "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}",
// customerEmail: projectViewModel.authenticatedUserObject.user.emailAddress,
customerEmail: "CustID_${appState.getAuthenticatedUser()!.patientId.toString()}@HMG.com",
orderDescription: "Appointment Payment",
orderAmount: double.parse(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,
);
});
}
void sendCheckInRequest(String scannedCode, String appointmentNo, BuildContext context) async {
LoaderBottomSheet.showLoader(loadingText: "Processing Check-In...".needTranslation);
PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel = PatientAppointmentHistoryResponseModel(
appointmentNo: appointmentNo,
clinicID: bookAppointmentsViewModel.selectedDoctor.clinicID,
projectID: bookAppointmentsViewModel.selectedDoctor.projectID,
);
await myAppointmentsViewModel.sendCheckInNfcRequest(
patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel,
scannedCode: scannedCode,
checkInType: 2,
onSuccess: (apiResponse) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(context, title: "Success".needTranslation, child: Utils.getSuccessWidget(loadingText: apiResponse.data["SuccessMsg"]), callBackFunc: () {
Navigator.of(context).pop();
Navigator.pushAndRemoveUntil(
context,
CustomPageRoute(
page: LandingNavigation(),
),
(r) => false);
}, isFullScreen: false);
},
onError: (error) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(context, title: "Error".needTranslation, child: Utils.getErrorWidget(loadingText: error), callBackFunc: () {
Navigator.of(context).pop();
}, isFullScreen: false);
},
);
}
void insertWalkInAppointment() async {}
}

@ -177,6 +177,9 @@ class _AppointmentCalendarState extends State<AppointmentCalendar> {
onPressed: () async {
if (appState.isAuthenticated) {
if(selectedTime == "Waiting Appointment".needTranslation){
bookAppointmentsViewModel.setWaitingAppointmentProjectID(bookAppointmentsViewModel.selectedDoctor.projectID!);
bookAppointmentsViewModel.setWaitingAppointmentDoctor(bookAppointmentsViewModel.selectedDoctor);
Navigator.of(context).pop();
Navigator.of(context).push(
CustomPageRoute(

@ -623,7 +623,7 @@ class _LandingPageState extends State<LandingPage> {
isDone = true;
cacheService.saveBool(key: CacheConst.quickLoginEnabled, value: true);
setState(() {});
await Future.delayed(Duration(milliseconds: 3000)).then((value) {
await Future.delayed(Duration(milliseconds: 2000)).then((value) {
if (mounted) Navigator.pop(context);
});
});

Loading…
Cancel
Save