diff --git a/lib/features/my_appointments/models/resp_models/ask_doctor_request_type_response_model.dart b/lib/features/my_appointments/models/resp_models/ask_doctor_request_type_response_model.dart new file mode 100644 index 0000000..3b53214 --- /dev/null +++ b/lib/features/my_appointments/models/resp_models/ask_doctor_request_type_response_model.dart @@ -0,0 +1,92 @@ +class AskDocRequestType { + String? setupID; + int? parameterGroup; + int? parameterType; + int? parameterCode; + String? description; + String? descriptionN; + String? alias; + String? aliasN; + String? prefix; + String? suffix; + String? isColorCodingRequired; + String? backColor; + String? foreColor; + bool? isBuiltIn; + bool? isActive; + int? createdBy; + String? createdOn; + String? editedBy; + String? editedOn; + String? rowVer; + + AskDocRequestType( + {this.setupID, + this.parameterGroup, + this.parameterType, + this.parameterCode, + this.description, + this.descriptionN, + this.alias, + this.aliasN, + this.prefix, + this.suffix, + this.isColorCodingRequired, + this.backColor, + this.foreColor, + this.isBuiltIn, + this.isActive, + this.createdBy, + this.createdOn, + this.editedBy, + this.editedOn, + this.rowVer}); + + AskDocRequestType.fromJson(Map json) { + setupID = json['SetupID']; + parameterGroup = json['ParameterGroup']; + parameterType = json['ParameterType']; + parameterCode = json['ParameterCode']; + description = json['Description']; + descriptionN = json['DescriptionN']; + alias = json['Alias']; + aliasN = json['AliasN']; + prefix = json['Prefix']; + suffix = json['Suffix']; + isColorCodingRequired = json['IsColorCodingRequired']; + backColor = json['BackColor']; + foreColor = json['ForeColor']; + isBuiltIn = json['IsBuiltIn']; + isActive = json['IsActive']; + createdBy = json['CreatedBy']; + createdOn = json['CreatedOn']; + editedBy = json['EditedBy']; + editedOn = json['EditedOn']; + rowVer = json['RowVer']; + } + + Map toJson() { + final Map data = new Map(); + data['SetupID'] = this.setupID; + data['ParameterGroup'] = this.parameterGroup; + data['ParameterType'] = this.parameterType; + data['ParameterCode'] = this.parameterCode; + data['Description'] = this.description; + data['DescriptionN'] = this.descriptionN; + data['Alias'] = this.alias; + data['AliasN'] = this.aliasN; + data['Prefix'] = this.prefix; + data['Suffix'] = this.suffix; + data['IsColorCodingRequired'] = this.isColorCodingRequired; + data['BackColor'] = this.backColor; + data['ForeColor'] = this.foreColor; + data['IsBuiltIn'] = this.isBuiltIn; + data['IsActive'] = this.isActive; + data['CreatedBy'] = this.createdBy; + data['CreatedOn'] = this.createdOn; + data['EditedBy'] = this.editedBy; + data['EditedOn'] = this.editedOn; + data['RowVer'] = this.rowVer; + return data; + } +} diff --git a/lib/features/my_appointments/my_appointments_repo.dart b/lib/features/my_appointments/my_appointments_repo.dart index 32ce829..5fd7c12 100644 --- a/lib/features/my_appointments/my_appointments_repo.dart +++ b/lib/features/my_appointments/my_appointments_repo.dart @@ -6,7 +6,9 @@ import 'package:hmg_patient_app_new/core/api_consts.dart'; import 'package:hmg_patient_app_new/core/cache_consts.dart'; import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart'; import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart'; +import 'package:hmg_patient_app_new/core/utils/date_util.dart'; import 'package:hmg_patient_app_new/core/utils/utils.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'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart' show HospitalsModel; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart'; @@ -50,7 +52,12 @@ abstract class MyAppointmentsRepo { Future>> getActiveAppointmentsCount(); + Future>>> getAskDoctorRequestTypes(); + Future>> isDoctorAvailable({required int projectID, required int clinicID, required int doctorID}); + + Future>> sendAskDocCallRequest( + {required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, required String requestType, required String remarks, required String userMobileNumber}); } class MyAppointmentsRepoImp implements MyAppointmentsRepo { @@ -656,4 +663,86 @@ class MyAppointmentsRepoImp implements MyAppointmentsRepo { return Left(UnknownFailure(e.toString())); } } + + @override + Future>>> getAskDoctorRequestTypes() async { + Map mapDevice = {}; + try { + GenericApiModel>? apiResponse; + Failure? failure; + await apiClient.post(GET_CALL_REQUEST_TYPE, onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + try { + final list = response['ListReqTypes']; + + final askDoctorRequestTypesList = list.map((item) => AskDocRequestType.fromJson(item as Map)).toList().cast(); + + apiResponse = GenericApiModel>( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: null, + data: askDoctorRequestTypesList, + ); + } catch (e) { + failure = DataParsingFailure(e.toString()); + } + }, body: mapDevice); + 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> sendAskDocCallRequest( + {required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, required String requestType, required String remarks, required String userMobileNumber}) async { + Map body = {}; + + body['ProjectID'] = patientAppointmentHistoryResponseModel.projectID; + body['SetupID'] = patientAppointmentHistoryResponseModel.setupID; + body['DoctorID'] = patientAppointmentHistoryResponseModel.doctorID; + body['PatientMobileNumber'] = userMobileNumber; + body['IsMessageSent'] = false; + body['RequestDate'] = DateUtil.convertDateToString(DateTime.now()); + body['RequestTime'] = DateUtil.convertDateToString(DateTime.now()); + body['Remarks'] = remarks; + body['Status'] = 2; // 4 for testing only.."cancelled status insert" else should be changed to 1 in live version + body['CreatedBy'] = 102; + body['CreatedOn'] = DateUtil.convertDateToString(DateTime.now()); + body['EditedBy'] = 102; + body['EditedOn'] = DateUtil.convertDateToString(DateTime.now()); + body['isDentalAllowedBackend'] = false; + body['AppointmentNo'] = patientAppointmentHistoryResponseModel.appointmentNo; + body['ClinicID'] = patientAppointmentHistoryResponseModel.clinicID; + body['QuestionType'] = num.parse(requestType); + body['RequestType'] = num.parse(requestType); + body['RequestTypeID'] = num.parse(requestType); + + try { + GenericApiModel? apiResponse; + Failure? failure; + await apiClient.post(INSERT_CALL_INFO, onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + try { + apiResponse = GenericApiModel( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: null, + data: true, + ); + } catch (e) { + failure = DataParsingFailure(e.toString()); + } + }, body: body); + 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 e8a5720..371f838 100644 --- a/lib/features/my_appointments/my_appointments_view_model.dart +++ b/lib/features/my_appointments/my_appointments_view_model.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/utils/date_util.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/appointemnet_filters.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'; 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'; @@ -42,6 +43,8 @@ class MyAppointmentsViewModel extends ChangeNotifier { List patientMyDoctorsList = []; + List askDoctorRequestTypeList = []; + PatientAppointmentShareResponseModel? patientAppointmentShareResponseModel; GetTamaraInstallmentsDetailsResponseModel? getTamaraInstallmentsDetailsResponseModel; @@ -586,4 +589,53 @@ class MyAppointmentsViewModel extends ChangeNotifier { }, ); } + + Future getAskDoctorRequestTypes({Function(dynamic)? onSuccess, Function(String)? onError}) async { + final result = await myAppointmentsRepo.getAskDoctorRequestTypes(); + + result.fold( + (failure) async => await errorHandlerService.handleError(failure: failure), + (apiResponse) { + if (apiResponse.messageStatus == 2) { + onError!(apiResponse.errorMessage!); + } else if (apiResponse.messageStatus == 1) { + askDoctorRequestTypeList = apiResponse.data!; + notifyListeners(); + if (onSuccess != null) { + onSuccess(apiResponse.data); + } + } + }, + ); + } + + Future sendAskDocCallRequest({ + required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, + required String requestType, + required String remarks, + required String userMobileNumber, + Function(dynamic)? onSuccess, + Function(String)? onError, + }) async { + final result = await myAppointmentsRepo.sendAskDocCallRequest( + patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel, requestType: requestType, remarks: remarks, userMobileNumber: userMobileNumber); + + result.fold( + // (failure) async => await errorHandlerService.handleError(failure: failure), + (failure) async { + await errorHandlerService.handleError(failure: failure); + if (onError != null) onError(failure.message); + }, + (apiResponse) { + if (apiResponse.messageStatus == 2) { + onError!(apiResponse.errorMessage!); + } else if (apiResponse.messageStatus == 1) { + notifyListeners(); + if (onSuccess != null) { + onSuccess(apiResponse.data); + } + } + }, + ); + } } diff --git a/lib/presentation/appointments/appointment_details_page.dart b/lib/presentation/appointments/appointment_details_page.dart index 7350fe4..79084c9 100644 --- a/lib/presentation/appointments/appointment_details_page.dart +++ b/lib/presentation/appointments/appointment_details_page.dart @@ -20,6 +20,7 @@ import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/appointments/appointment_payment_page.dart'; import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_checkin_bottom_sheet.dart'; import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_doctor_card.dart'; +import 'package:hmg_patient_app_new/presentation/appointments/widgets/ask_doctor_request_type_select.dart'; import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/appointment_calendar.dart'; import 'package:hmg_patient_app_new/presentation/prescriptions/prescription_detail_page.dart'; import 'package:hmg_patient_app_new/presentation/prescriptions/prescriptions_list_page.dart'; @@ -81,8 +82,34 @@ class _AppointmentDetailsPageState extends State { children: [ AppointmentDoctorCard( patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel, - onAskDoctorTap: () { - print("Ask Doctor"); + onAskDoctorTap: () async { + LoaderBottomSheet.showLoader(loadingText: "Checking doctor availability...".needTranslation); + await myAppointmentsViewModel.isDoctorAvailable( + projectID: widget.patientAppointmentHistoryResponseModel.projectID, + doctorId: widget.patientAppointmentHistoryResponseModel.doctorID, + clinicId: widget.patientAppointmentHistoryResponseModel.clinicID, + onSuccess: (value) async { + if (value) { + print("Doctor is available"); + await myAppointmentsViewModel.getAskDoctorRequestTypes(onSuccess: (val) { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight( + context, + title: LocaleKeys.askDoctor.tr(context: context), + child: AskDoctorRequestTypeSelect( + askDoctorRequestTypeList: myAppointmentsViewModel.askDoctorRequestTypeList, + myAppointmentsViewModel: myAppointmentsViewModel, + patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel, + ), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + }); + } else { + print("Doctor is not available"); + } + }); }, onCancelTap: () async { myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true); diff --git a/lib/presentation/appointments/widgets/appointment_card.dart b/lib/presentation/appointments/widgets/appointment_card.dart index 25ecb4f..f20d0b6 100644 --- a/lib/presentation/appointments/widgets/appointment_card.dart +++ b/lib/presentation/appointments/widgets/appointment_card.dart @@ -16,6 +16,7 @@ import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_vie import 'package:hmg_patient_app_new/features/my_appointments/utils/appointment_type.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/appointments/appointment_details_page.dart'; +import 'package:hmg_patient_app_new/presentation/appointments/widgets/ask_doctor_request_type_select.dart'; import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/appointment_calendar.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; @@ -245,12 +246,32 @@ class AppointmentCard extends StatelessWidget { return CustomButton( text: LocaleKeys.askDoctor.tr(context: context), onPressed: () async { + LoaderBottomSheet.showLoader(loadingText: "Checking doctor availability...".needTranslation); await myAppointmentsViewModel.isDoctorAvailable( projectID: patientAppointmentHistoryResponseModel.projectID, doctorId: patientAppointmentHistoryResponseModel.doctorID, clinicId: patientAppointmentHistoryResponseModel.clinicID, - onSuccess: (value) { - if (value) {} + onSuccess: (value) async { + if (value) { + print("Doctor is available"); + await myAppointmentsViewModel.getAskDoctorRequestTypes(onSuccess: (val) { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight( + context, + title: LocaleKeys.askDoctor.tr(context: context), + child: AskDoctorRequestTypeSelect( + askDoctorRequestTypeList: myAppointmentsViewModel.askDoctorRequestTypeList, + myAppointmentsViewModel: myAppointmentsViewModel, + patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel, + ), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + }); + } else { + print("Doctor is not available"); + } }); }, backgroundColor: AppColors.secondaryLightRedColor, diff --git a/lib/presentation/appointments/widgets/ask_doctor_request_type_select.dart b/lib/presentation/appointments/widgets/ask_doctor_request_type_select.dart new file mode 100644 index 0000000..9f06a4d --- /dev/null +++ b/lib/presentation/appointments/widgets/ask_doctor_request_type_select.dart @@ -0,0 +1,138 @@ +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/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/ask_doctor_request_type_response_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/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/common_bottom_sheet.dart'; +import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; + +class AskDoctorRequestTypeSelect extends StatelessWidget { + AskDoctorRequestTypeSelect({super.key, required this.askDoctorRequestTypeList, required this.myAppointmentsViewModel, required this.patientAppointmentHistoryResponseModel}); + + final MyAppointmentsViewModel myAppointmentsViewModel; + final PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel; + List askDoctorRequestTypeList = []; + int selectedParameterCodeValue = 2; + int selectedParameterCode = 0; + + final ValueNotifier requestTypeSelectNotifier = ValueNotifier(0); + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Container( + width: double.infinity, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24), + child: ListView.builder( + itemCount: askDoctorRequestTypeList.length, + physics: NeverScrollableScrollPhysics(), + padding: EdgeInsets.only(top: 8, bottom: 8), + shrinkWrap: true, + itemBuilder: (context, index) { + return ValueListenableBuilder( + valueListenable: requestTypeSelectNotifier, + builder: (context, duration, child) { + return Theme( + data: Theme.of(context).copyWith( + listTileTheme: ListTileThemeData(horizontalTitleGap: 4), + ), + child: RadioListTile( + title: (askDoctorRequestTypeList[index].description ?? '').toText14(weight: FontWeight.w500), + value: index, + fillColor: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.selected)) { + return AppColors.primaryRedColor; + } + return Color(0xffEEEEEE); + }), + contentPadding: EdgeInsets.only(left: 12.h, right: 12.h), + groupValue: selectedParameterCode, + onChanged: (int? newValue) { + selectedParameterCode = newValue!; + selectedParameterCodeValue = askDoctorRequestTypeList[index].parameterCode!; + requestTypeSelectNotifier.value = selectedParameterCode; + debugPrint(selectedParameterCodeValue.toString()); + }, + ), + ); + }, + ); + }, + ), + ), + SizedBox(height: 16.h), + Row( + children: [ + Expanded( + child: CustomButton( + text: LocaleKeys.cancel.tr(), + onPressed: () { + Navigator.pop(context); + }, + backgroundColor: AppColors.primaryRedColor, + borderColor: AppColors.primaryRedColor, + textColor: AppColors.whiteColor, + icon: AppAssets.cancel, + iconColor: AppColors.whiteColor, + borderRadius: 12.r, + iconSize: 14.h, + fontSize: 14.f, + height: 40.h, + ), + ), + SizedBox(width: 8.h), + Expanded( + child: CustomButton( + text: LocaleKeys.confirm.tr(), + onPressed: () async { + Navigator.pop(context); + LoaderBottomSheet.showLoader(loadingText: "Sending Request..."); + await myAppointmentsViewModel.sendAskDocCallRequest( + patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel, + requestType: selectedParameterCodeValue.toString(), + remarks: "", + userMobileNumber: myAppointmentsViewModel.appState.getAuthenticatedUser()!.mobileNumber!, + onSuccess: (val) { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight( + context, + child: Utils.getSuccessWidget(loadingText: "Request has been sent successfully, you will be contacted soon.".needTranslation), + callBackFunc: () { + Navigator.of(context).pop(); + }, + title: "", + isCloseButtonVisible: true, + isDismissible: false, + isFullScreen: false, + ); + }, + onError: (errMessage) { + LoaderBottomSheet.hideLoader(); + }); + }, + backgroundColor: AppColors.bgGreenColor, + borderColor: AppColors.bgGreenColor, + textColor: Colors.white, + icon: AppAssets.confirm, + iconSize: 14.h, + borderRadius: 12.r, + fontSize: 14.f, + height: 40.h, + ), + ), + ], + ) + ], + ); + } +}