From 1575a8e308d55accfdc684fa767f92275b397589 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Wed, 11 Feb 2026 12:40:00 +0300 Subject: [PATCH] Feedback status implementation contd. --- lib/core/api/api_client.dart | 3 +- lib/features/contact_us/contact_us_repo.dart | 43 ++++++ .../contact_us/contact_us_view_model.dart | 42 ++++++ .../get_status_coc_response_model.dart | 124 ++++++++++++++++++ .../appointment_details_page.dart | 1 + lib/presentation/contact_us/contact_us.dart | 1 + .../contact_us/feedback_page.dart | 66 +++++++++- 7 files changed, 272 insertions(+), 8 deletions(-) create mode 100644 lib/features/contact_us/models/resp_models/get_status_coc_response_model.dart diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index 2166b51..0b27c58 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -221,7 +221,8 @@ class ApiClientImp implements ApiClient { // Handle body encoding based on isBodyPlainText flag final dynamic requestBody = isBodyPlainText ? body : json.encode(body); debugPrint("uri: ${Uri.parse(url.trim())}"); - debugPrint("body: ${json.encode(body)}", wrapWidth: 2048); + var requestBodyJSON = json.encode(body); + debugPrint("body: $requestBodyJSON", wrapWidth: 2048); final response = await http.post(Uri.parse(url.trim()), body: requestBody, headers: headers); final int statusCode = response.statusCode; // log("response.body: ${response.body}"); diff --git a/lib/features/contact_us/contact_us_repo.dart b/lib/features/contact_us/contact_us_repo.dart index 5b9057b..c758155 100644 --- a/lib/features/contact_us/contact_us_repo.dart +++ b/lib/features/contact_us/contact_us_repo.dart @@ -6,6 +6,7 @@ import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart'; import 'package:hmg_patient_app_new/features/contact_us/models/req_models/request_insert_coc_item.dart'; import 'package:hmg_patient_app_new/features/contact_us/models/resp_models/get_hmg_locations.dart'; import 'package:hmg_patient_app_new/features/contact_us/models/resp_models/get_patient_ic_projects.dart'; +import 'package:hmg_patient_app_new/features/contact_us/models/resp_models/get_status_coc_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/services/logger_service.dart'; @@ -17,6 +18,8 @@ abstract class ContactUsRepo { Future>> getChatRequestID({required String name, required String mobileNo, required String workGroup}); Future>> insertCOCItem({required RequestInsertCOCItem requestInsertCOCItem, PatientAppointmentHistoryResponseModel? patientSelectedAppointment}); + + Future>>> getStatusForCOC(String identificationNo, String mobileNo, {Function(dynamic)? onSuccess, Function(String)? onError}); } class ContactUsRepoImp implements ContactUsRepo { @@ -181,4 +184,44 @@ class ContactUsRepoImp implements ContactUsRepo { return Left(UnknownFailure(e.toString())); } } + + @override + Future>>> getStatusForCOC(String identificationNo, String mobileNo, {Function(dynamic)? onSuccess, Function(String)? onError}) async { + Map body = {}; + body['IdentificationNo'] = identificationNo; + body['MobileNo'] = mobileNo; + body['Searching_type'] = 1; + + try { + GenericApiModel>? apiResponse; + Failure? failure; + await apiClient.post( + GET_STATUS_FOR_COCO, + body: body, + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + try { + final list = response['ListCOCItems']; + final cocItemsList = list.map((item) => COCItem.fromJson(item as Map)).toList().cast(); + + apiResponse = GenericApiModel>( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: null, + data: cocItemsList, + ); + } 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/contact_us/contact_us_view_model.dart b/lib/features/contact_us/contact_us_view_model.dart index 1029802..5162aa0 100644 --- a/lib/features/contact_us/contact_us_view_model.dart +++ b/lib/features/contact_us/contact_us_view_model.dart @@ -9,6 +9,7 @@ import 'package:hmg_patient_app_new/features/contact_us/models/feedback_type.dar import 'package:hmg_patient_app_new/features/contact_us/models/req_models/request_insert_coc_item.dart'; import 'package:hmg_patient_app_new/features/contact_us/models/resp_models/get_hmg_locations.dart'; import 'package:hmg_patient_app_new/features/contact_us/models/resp_models/get_patient_ic_projects.dart'; +import 'package:hmg_patient_app_new/features/contact_us/models/resp_models/get_status_coc_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/services/error_handler_service.dart'; @@ -33,6 +34,9 @@ class ContactUsViewModel extends ChangeNotifier { List feedbackAttachmentList = []; + List cocItemsList = []; + bool isCOCItemsListLoading = false; + PatientAppointmentHistoryResponseModel? patientFeedbackSelectedAppointment; List feedbackTypeList = [ @@ -52,10 +56,12 @@ class ContactUsViewModel extends ChangeNotifier { isHMGLocationsListLoading = true; isHMGHospitalsListSelected = true; isLiveChatProjectsListLoading = true; + isCOCItemsListLoading = true; hmgHospitalsLocationsList.clear(); hmgPharmacyLocationsList.clear(); liveChatProjectsList.clear(); feedbackAttachmentList.clear(); + cocItemsList.clear(); selectedFeedbackType = FeedbackType(id: 5, nameEN: "Not classified", nameAR: 'غير محدد'); setPatientFeedbackSelectedAppointment(null); getHMGLocations(); @@ -74,6 +80,9 @@ class ContactUsViewModel extends ChangeNotifier { setIsSendFeedbackTabSelected(bool isSelected) { isSendFeedbackTabSelected = isSelected; + if (!isSelected) { + getStatusForCOC(identificationNo: appState.getAuthenticatedUser()!.patientIdentificationNo!, mobileNo: "966${Utils.getPhoneNumberWithoutZero(appState.getAuthenticatedUser()!.mobileNumber!)}"); + } notifyListeners(); } @@ -223,4 +232,37 @@ class ContactUsViewModel extends ChangeNotifier { }, ); } + + Future getStatusForCOC({required String identificationNo, required String mobileNo, Function(dynamic)? onSuccess, Function(String)? onError}) async { + isCOCItemsListLoading = true; + cocItemsList.clear(); + notifyListeners(); + + final result = await contactUsRepo.getStatusForCOC(identificationNo, mobileNo); + + result.fold( + (failure) async { + await errorHandlerService.handleError(failure: failure); + if (onError != null) { + isCOCItemsListLoading = false; + onError(failure.toString()); + } + }, + (apiResponse) { + if (apiResponse.messageStatus == 2) { + if (onError != null) { + isCOCItemsListLoading = false; + onError(apiResponse.errorMessage ?? 'Unknown error'); + } + } else if (apiResponse.messageStatus == 1) { + cocItemsList = apiResponse.data!; + isCOCItemsListLoading = false; + notifyListeners(); + if (onSuccess != null) { + onSuccess(apiResponse); + } + } + }, + ); + } } diff --git a/lib/features/contact_us/models/resp_models/get_status_coc_response_model.dart b/lib/features/contact_us/models/resp_models/get_status_coc_response_model.dart new file mode 100644 index 0000000..ed62d8b --- /dev/null +++ b/lib/features/contact_us/models/resp_models/get_status_coc_response_model.dart @@ -0,0 +1,124 @@ +class COCItem { + dynamic appointment; + String? appointmentClinicName; + String? appointmentDate; + String? appointmentProjectName; + String? cOCID; + String? cOCTitle; + String? channel; + dynamic clinic; + String? clinicID; + String? date; + dynamic detail; + dynamic doctor; + String? doctorID; + String? formType; + int? formTypeID; + dynamic identificationNo; + int? itemID; + dynamic mobileNo; + dynamic naturename; + dynamic patientID; + dynamic patientName; + dynamic project; + dynamic projectID; + String? solution; + String? status; + String? statusAr; + dynamic statusEn; + int? statusId; + + COCItem({ + this.appointment, + this.appointmentClinicName, + this.appointmentDate, + this.appointmentProjectName, + this.cOCID, + this.cOCTitle, + this.channel, + this.clinic, + this.clinicID, + this.date, + this.detail, + this.doctor, + this.doctorID, + this.formType, + this.formTypeID, + this.identificationNo, + this.itemID, + this.mobileNo, + this.naturename, + this.patientID, + this.patientName, + this.project, + this.projectID, + this.solution, + this.status, + this.statusAr, + this.statusEn, + this.statusId, + }); + + COCItem.fromJson(Map json) { + appointment = json['Appointment']; + appointmentClinicName = json['AppointmentClinicName']; + appointmentDate = json['AppointmentDate']; + appointmentProjectName = json['AppointmentProjectName']; + cOCID = json['COCID']; + cOCTitle = json['COCTitle']; + channel = json['Channel']; + clinic = json['Clinic']; + clinicID = json['ClinicID']; + date = json['Date']; + detail = json['Detail']; + doctor = json['Doctor']; + doctorID = json['DoctorID']; + formType = json['FormType']; + formTypeID = json['FormTypeID']; + identificationNo = json['IdentificationNo']; + itemID = json['ItemID']; + mobileNo = json['MobileNo']; + naturename = json['Naturename']; + patientID = json['PatientID']; + patientName = json['PatientName']; + project = json['Project']; + projectID = json['ProjectID']; + solution = json['Solution']; + status = json['Status']; + statusAr = json['StatusAr']; + statusEn = json['StatusEn']; + statusId = json['StatusId']; + } + + Map toJson() { + final Map data = new Map(); + data['Appointment'] = this.appointment; + data['AppointmentClinicName'] = this.appointmentClinicName; + data['AppointmentDate'] = this.appointmentDate; + data['AppointmentProjectName'] = this.appointmentProjectName; + data['COCID'] = this.cOCID; + data['COCTitle'] = this.cOCTitle; + data['Channel'] = this.channel; + data['Clinic'] = this.clinic; + data['ClinicID'] = this.clinicID; + data['Date'] = this.date; + data['Detail'] = this.detail; + data['Doctor'] = this.doctor; + data['DoctorID'] = this.doctorID; + data['FormType'] = this.formType; + data['FormTypeID'] = this.formTypeID; + data['IdentificationNo'] = this.identificationNo; + data['ItemID'] = this.itemID; + data['MobileNo'] = this.mobileNo; + data['Naturename'] = this.naturename; + data['PatientID'] = this.patientID; + data['PatientName'] = this.patientName; + data['Project'] = this.project; + data['ProjectID'] = this.projectID; + data['Solution'] = this.solution; + data['Status'] = this.status; + data['StatusAr'] = this.statusAr; + data['StatusEn'] = this.statusEn; + return data; + } +} diff --git a/lib/presentation/appointments/appointment_details_page.dart b/lib/presentation/appointments/appointment_details_page.dart index 0e0194b..833ad90 100644 --- a/lib/presentation/appointments/appointment_details_page.dart +++ b/lib/presentation/appointments/appointment_details_page.dart @@ -99,6 +99,7 @@ class _AppointmentDetailsPageState extends State { ? () { contactUsViewModel.setSelectedFeedbackType(FeedbackType(id: 1, nameEN: "Complaint for appointment", nameAR: 'شكوى على موعد')); contactUsViewModel.setPatientFeedbackSelectedAppointment(widget.patientAppointmentHistoryResponseModel); + contactUsViewModel.setIsSendFeedbackTabSelected(true); Navigator.of(context).push( CustomPageRoute( page: FeedbackPage(), diff --git a/lib/presentation/contact_us/contact_us.dart b/lib/presentation/contact_us/contact_us.dart index 40d42d5..2bcbc6c 100644 --- a/lib/presentation/contact_us/contact_us.dart +++ b/lib/presentation/contact_us/contact_us.dart @@ -57,6 +57,7 @@ class ContactUs extends StatelessWidget { contactUsViewModel.setSelectedFeedbackType( FeedbackType(id: 5, nameEN: "Not classified", nameAR: 'غير محدد'), ); + contactUsViewModel.setIsSendFeedbackTabSelected(true); Navigator.pop(context); Navigator.of(context).push( CustomPageRoute( diff --git a/lib/presentation/contact_us/feedback_page.dart b/lib/presentation/contact_us/feedback_page.dart index 8f10bc5..4944355 100644 --- a/lib/presentation/contact_us/feedback_page.dart +++ b/lib/presentation/contact_us/feedback_page.dart @@ -1,5 +1,6 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_staggered_animations/flutter_staggered_animations.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'; @@ -13,6 +14,7 @@ import 'package:hmg_patient_app_new/features/contact_us/models/feedback_type.dar import 'package:hmg_patient_app_new/features/medical_file/medical_file_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/contact_us/widgets/feedback_appointment_selection.dart'; +import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.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'; @@ -67,11 +69,12 @@ class FeedbackPage extends StatelessWidget { ), ), ), - Container( - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - customBorder: BorderRadius.only( - topLeft: Radius.circular(24.h), + contactUsViewModel.isSendFeedbackTabSelected + ? Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + customBorder: BorderRadius.only( + topLeft: Radius.circular(24.h), topRight: Radius.circular(24.h), ), hasShadow: true, @@ -126,7 +129,8 @@ class FeedbackPage extends StatelessWidget { iconColor: AppColors.whiteColor, iconSize: 20.h, ).paddingSymmetrical(24.h, 24.h), - ), + ) + : SizedBox.shrink(), ], ); }), @@ -389,7 +393,55 @@ class FeedbackPage extends StatelessWidget { ], ); } else { - return Container(); + return getIt.get().isAuthenticated + ? Column( + children: [ + SizedBox(height: 24.h), + ListView.builder( + itemCount: contactUsViewModel.isCOCItemsListLoading + ? 4 + : contactUsViewModel.cocItemsList.isEmpty + ? 1 + : contactUsViewModel.cocItemsList.length, + physics: NeverScrollableScrollPhysics(), + shrinkWrap: true, + padding: EdgeInsetsGeometry.zero, + itemBuilder: (context, index) { + return contactUsViewModel.isCOCItemsListLoading + ? LabResultItemView( + onTap: () {}, + labOrder: null, + index: index, + isLoading: true, + ) + : contactUsViewModel.cocItemsList.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: Container( + height: 200.h, + width: 300.w, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 20.h, + hasShadow: true, + ), + ).paddingOnly(bottom: 16.h), + ), + ), + ), + ) + : Utils.getNoDataWidget(context); + }), + ], + ) + : Utils.getNoDataWidget(context); } } }