diff --git a/assets/images/svg/appointment_parking_icon.svg b/assets/images/svg/appointment_parking_icon.svg new file mode 100644 index 00000000..0a1c6daa --- /dev/null +++ b/assets/images/svg/appointment_parking_icon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 37530389..88d35279 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -1851,5 +1851,6 @@ "transactions": "المعاملات", "pharmacy": "الصيدلية", "visitsOrders": "الزيارات/الطلبات", - "earned": "حصل" + "earned": "حصل", + "getParkingQR": "الحصول على رمز الاستجابة السريعة لوقوف السيارات" } diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 257b2211..fccd6841 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -1841,7 +1841,8 @@ "transactions": "Transactions", "pharmacy": "Pharmacy", "visitsOrders": "Visits/Orders", - "earned": "Earned" + "earned": "Earned", + "getParkingQR": "Get Parking QR" } diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index fa64812f..7ad7f855 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -998,6 +998,8 @@ const DOWNLOAD_INVOICE_PDF = 'Services/Notifications.svc/REST/DownloadInvoiceRep const DOWNLOAD_PHARMACY_INVOICE_PDF = 'Services/Notifications.svc/REST/DownloadInvoiceReport'; +const GET_APPOINTMENT_PARKING_QR = 'Services/outps.svc/rest/pms_getParkingTicketByAppointmentNo'; + class ApiKeyConstants { static final String googleMapsApiKey = 'AIzaSyB6TERnxIr0yJ3qG4ULBZbu0sAD4tGqtng'; } diff --git a/lib/core/app_assets.dart b/lib/core/app_assets.dart index d6e041da..e4d23c08 100644 --- a/lib/core/app_assets.dart +++ b/lib/core/app_assets.dart @@ -256,6 +256,7 @@ class AppAssets { static const String back_top_nav_icon = '$svgBasePath/back_top_nav_icon.svg'; static const String bluetooth = '$svgBasePath/bluetooth.svg'; static const String calendar_filled_icon = '$svgBasePath/calendar_filled_icon.svg'; + static const String appointment_parking_icon = '$svgBasePath/appointment_parking_icon.svg'; //smartwatch static const String watchActivity = '$svgBasePath/watch_activity.svg'; diff --git a/lib/features/my_appointments/models/resp_models/appointment_parking_QR_response_model.dart b/lib/features/my_appointments/models/resp_models/appointment_parking_QR_response_model.dart new file mode 100644 index 00000000..a0a2c4d9 --- /dev/null +++ b/lib/features/my_appointments/models/resp_models/appointment_parking_QR_response_model.dart @@ -0,0 +1,84 @@ +class AppointmentParkingQRResponseModel { + String? admissionDate; + int? admissionNo; + String? appointmentDate; + int? appointmentNo; + int? createdBy; + String? createdOn; + String? gUID; + String? invoiceDate; + int? invoiceNo; + bool? isActive; + bool? isOutInPatient; + int? isPatient; + bool? isUsed; + int? patientID; + int? projectID; + dynamic ticketBase64; + int? ticketID; + String? ticketURL; + + AppointmentParkingQRResponseModel( + {this.admissionDate, + this.admissionNo, + this.appointmentDate, + this.appointmentNo, + this.createdBy, + this.createdOn, + this.gUID, + this.invoiceDate, + this.invoiceNo, + this.isActive, + this.isOutInPatient, + this.isPatient, + this.isUsed, + this.patientID, + this.projectID, + this.ticketBase64, + this.ticketID, + this.ticketURL}); + + AppointmentParkingQRResponseModel.fromJson(Map json) { + admissionDate = json['AdmissionDate']; + admissionNo = json['AdmissionNo']; + appointmentDate = json['AppointmentDate']; + appointmentNo = json['AppointmentNo']; + createdBy = json['CreatedBy']; + createdOn = json['CreatedOn']; + gUID = json['GUID']; + invoiceDate = json['InvoiceDate']; + invoiceNo = json['InvoiceNo']; + isActive = json['IsActive']; + isOutInPatient = json['IsOutInPatient']; + isPatient = json['IsPatient']; + isUsed = json['IsUsed']; + patientID = json['PatientID']; + projectID = json['ProjectID']; + ticketBase64 = json['TicketBase64'].cast(); + ticketID = json['TicketID']; + ticketURL = json['TicketURL']; + } + + Map toJson() { + final Map data = new Map(); + data['AdmissionDate'] = this.admissionDate; + data['AdmissionNo'] = this.admissionNo; + data['AppointmentDate'] = this.appointmentDate; + data['AppointmentNo'] = this.appointmentNo; + data['CreatedBy'] = this.createdBy; + data['CreatedOn'] = this.createdOn; + data['GUID'] = this.gUID; + data['InvoiceDate'] = this.invoiceDate; + data['InvoiceNo'] = this.invoiceNo; + data['IsActive'] = this.isActive; + data['IsOutInPatient'] = this.isOutInPatient; + data['IsPatient'] = this.isPatient; + data['IsUsed'] = this.isUsed; + data['PatientID'] = this.patientID; + data['ProjectID'] = this.projectID; + data['TicketBase64'] = this.ticketBase64; + data['TicketID'] = this.ticketID; + data['TicketURL'] = this.ticketURL; + return data; + } +} diff --git a/lib/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart b/lib/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart index 420c0482..d9a71d9f 100644 --- a/lib/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart +++ b/lib/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart @@ -76,6 +76,7 @@ class PatientAppointmentHistoryResponseModel { num? patientTaxAmount; String? doctorNationalityFlagURL; bool? isClinicReBookingAllowed; + bool? isParkingAvailable; PatientAppointmentHistoryResponseModel({ this.setupID, @@ -154,6 +155,7 @@ class PatientAppointmentHistoryResponseModel { this.patientTaxAmount, this.doctorNationalityFlagURL, this.isClinicReBookingAllowed, + this.isParkingAvailable, }); PatientAppointmentHistoryResponseModel.fromJson(Map json) { @@ -244,6 +246,7 @@ class PatientAppointmentHistoryResponseModel { patientTaxAmount = json['PatientTaxAmount']; doctorNationalityFlagURL = json['DoctorNationalityFlagURL']; isClinicReBookingAllowed = json['IsClinicReBookingAllowed']; + isParkingAvailable = json['IsParkingAvailable']; } Map toJson() { @@ -317,6 +320,7 @@ class PatientAppointmentHistoryResponseModel { data['SMSButtonVisable'] = this.sMSButtonVisable; data['ServiceID'] = this.serviceID; data['IsClinicReBookingAllowed'] = this.isClinicReBookingAllowed; + data['IsParkingAvailable'] = this.isParkingAvailable; return data; } } diff --git a/lib/features/my_appointments/my_appointments_repo.dart b/lib/features/my_appointments/my_appointments_repo.dart index 553491e1..d7a025fc 100644 --- a/lib/features/my_appointments/my_appointments_repo.dart +++ b/lib/features/my_appointments/my_appointments_repo.dart @@ -9,6 +9,7 @@ import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart'; import 'package:hmg_patient_app_new/core/utils/date_util.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/get_favorite_doctors_list.dart'; +import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/appointment_parking_QR_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/appointment_rated_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/rate_appointment_resp_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/ask_doctor_request_type_response_model.dart'; @@ -92,6 +93,8 @@ abstract class MyAppointmentsRepo { }); Future>>> getAppointmentInvoice(num appointmentNum); + + Future>> getParkingQR(num appointmentNum, int projectID); } class MyAppointmentsRepoImp implements MyAppointmentsRepo { @@ -1183,4 +1186,40 @@ class MyAppointmentsRepoImp implements MyAppointmentsRepo { return Left(UnknownFailure(e.toString())); } } + + @override + Future>> getParkingQR(num appointmentNum, int projectID) async { + Map mapDevice = {"AppointmentNo": appointmentNum, "ProjectID": projectID}; + + try { + GenericApiModel? apiResponse; + Failure? failure; + await apiClient.post( + GET_APPOINTMENT_PARKING_QR, + body: mapDevice, + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + try { + AppointmentParkingQRResponseModel appointmentParkingQRResponseModel = AppointmentParkingQRResponseModel.fromJson(response['ParkingTicketsForAppointment'][0]); + + apiResponse = GenericApiModel( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: null, + data: appointmentParkingQRResponseModel, + ); + } 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())); + } + } } diff --git a/lib/features/my_appointments/my_appointments_view_model.dart b/lib/features/my_appointments/my_appointments_view_model.dart index 0ad21586..5aae8211 100644 --- a/lib/features/my_appointments/my_appointments_view_model.dart +++ b/lib/features/my_appointments/my_appointments_view_model.dart @@ -10,6 +10,7 @@ import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/get_favorite_doctors_list.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/appointemnet_filters.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/reminder_type.dart'; +import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/appointment_parking_QR_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/appointment_rated_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/ask_doctor_request_type_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/get_tamara_installments_details_response_model.dart'; @@ -100,6 +101,8 @@ class MyAppointmentsViewModel extends ChangeNotifier { AppointmentRatedResponseModel? appointmentRatedResponseModel; bool isAppointmentRatedResponseLoading = false; + AppointmentParkingQRResponseModel? appointmentParkingQRResponseModel; + MyAppointmentsViewModel({required this.myAppointmentsRepo, required this.errorHandlerService, required this.appState}); void onTabChange(int index) { @@ -722,6 +725,25 @@ class MyAppointmentsViewModel extends ChangeNotifier { ); } + Future getParkingQR(num appointmentNum, int projectID, {Function(dynamic)? onSuccess, Function(String)? onError}) async { + final result = await myAppointmentsRepo.getParkingQR(appointmentNum, projectID); + + result.fold( + (failure) async { + if (onError != null) { + onError(failure.message); + } + }, + (apiResponse) { + appointmentParkingQRResponseModel = apiResponse.data!; + notifyListeners(); + if (onSuccess != null) { + onSuccess(apiResponse); + } + }, + ); + } + // Method to force refresh favorite doctors list void refreshFavouriteDoctors() { isFavouriteDoctorsDataFetched = false; diff --git a/lib/features/paytabs/paytabs_view_model.dart b/lib/features/paytabs/paytabs_view_model.dart index 0c610e6f..3243269a 100644 --- a/lib/features/paytabs/paytabs_view_model.dart +++ b/lib/features/paytabs/paytabs_view_model.dart @@ -23,7 +23,7 @@ class PayTabsViewModel extends ChangeNotifier { required this.appState, }); - setPaymentConfiguration(String paymentDescription, num amount) { + setPaymentConfiguration(String paymentDescription, num amount, {bool isAddCard = false}) { String cartID = DateTime.now().millisecondsSinceEpoch.toString(); paymentConfiguration = PaymentSdkConfigurationDetails( profileId: PaymentSdkDefaultConfig.profileID, @@ -76,7 +76,7 @@ class PayTabsViewModel extends ChangeNotifier { inputsCornerRadius: 12 // buttonFont: "Poppins", ); - paymentConfiguration.tokeniseType = PaymentSdkTokeniseType.MERCHANT_MANDATORY; + paymentConfiguration.tokeniseType = PaymentSdkTokeniseType.USER_OPTIONAL_DEFAULT_ON; paymentConfiguration.tokenFormat = PaymentSdkTokenFormat.Hex32Format; notifyListeners(); diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index e0dd8614..e1d21e12 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -1844,5 +1844,6 @@ abstract class LocaleKeys { static const pharmacy = 'pharmacy'; static const visitsOrders = 'visitsOrders'; static const earned = 'earned'; + static const getParkingQR = 'getParkingQR'; } diff --git a/lib/presentation/appointments/appointment_details_page.dart b/lib/presentation/appointments/appointment_details_page.dart index 2ec8f568..d28a3054 100644 --- a/lib/presentation/appointments/appointment_details_page.dart +++ b/lib/presentation/appointments/appointment_details_page.dart @@ -874,6 +874,35 @@ class _AppointmentDetailsPageState extends State { } }) : SizedBox.shrink(), + (widget.patientAppointmentHistoryResponseModel.isParkingAvailable ?? false) + ? MedicalFileCard( + label: LocaleKeys.getParkingQR.tr(context: context), + textColor: AppColors.blackColor, + backgroundColor: AppColors.whiteColor, + svgIcon: AppAssets.appointment_parking_icon, + isLargeText: true, + iconSize: 36.w, + ).onPress(() { + LoaderBottomSheet.showLoader(loadingText: LocaleKeys.loadingText.tr(context: context)); + myAppointmentsViewModel.getParkingQR( + widget.patientAppointmentHistoryResponseModel.appointmentNo, + widget.patientAppointmentHistoryResponseModel.projectID, + onSuccess: (val) { + LoaderBottomSheet.hideLoader(); + }, + onError: (err) { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight( + context, + child: Utils.getErrorWidget(loadingText: err), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + }, + ); + }) + : SizedBox.shrink(), ], ); }), diff --git a/lib/presentation/appointments/widgets/appointment_doctor_card.dart b/lib/presentation/appointments/widgets/appointment_doctor_card.dart index ecf164a4..299c3db9 100644 --- a/lib/presentation/appointments/widgets/appointment_doctor_card.dart +++ b/lib/presentation/appointments/widgets/appointment_doctor_card.dart @@ -216,7 +216,7 @@ class AppointmentDoctorCard extends StatelessWidget { AppointmentType.isArrived(patientAppointmentHistoryResponseModel), ), ), - if (timerWidget != null) timerWidget ?? SizedBox() + if (!AppointmentType.isArrived(patientAppointmentHistoryResponseModel) && timerWidget != null) timerWidget ?? SizedBox() ], ), ),