send feedback implementation done

pull/101/head
haroon amjad 2 weeks ago
parent a4e55cb6df
commit b13adde9d2

@ -847,7 +847,7 @@ class ApiConsts {
static final String addAdvanceNumberRequest = 'Services/PayFort_Serv.svc/REST/AddAdvancedNumberRequest';
// ************ static values for Api ****************
static final double appVersionID = 18.7;
static final double appVersionID = 50.0;
static final int appChannelId = 3;
static final String appIpAddress = "10.20.10.20";
static final String appGeneralId = "Cs2020@2016\$2958";

@ -3,14 +3,18 @@ import 'package:hmg_patient_app_new/core/api/api_client.dart';
import 'package:hmg_patient_app_new/core/api_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/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/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
abstract class ContactUsRepo {
Future<Either<Failure, GenericApiModel<List<GetHMGLocationsModel>>>> getHMGLocations();
Future<Either<Failure, GenericApiModel<List<GetPatientICProjectsModel>>>> getLiveChatProjectsList();
Future<Either<Failure, GenericApiModel<dynamic>>> insertCOCItem({required RequestInsertCOCItem requestInsertCOCItem, PatientAppointmentHistoryResponseModel? patientSelectedAppointment});
}
class ContactUsRepoImp implements ContactUsRepo {
@ -92,4 +96,48 @@ class ContactUsRepoImp implements ContactUsRepo {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<dynamic>>> insertCOCItem({required RequestInsertCOCItem requestInsertCOCItem, PatientAppointmentHistoryResponseModel? patientSelectedAppointment}) async {
final Map<String, dynamic> body = requestInsertCOCItem.toJson();
if (patientSelectedAppointment != null) {
body['AppoinmentNo'] = patientSelectedAppointment.appointmentNo;
body['AppointmentDate'] = patientSelectedAppointment.appointmentDate;
body['ClinicID'] = patientSelectedAppointment.clinicID;
body['ClinicName'] = patientSelectedAppointment.clinicName;
body['DoctorID'] = patientSelectedAppointment.doctorID;
body['DoctorName'] = patientSelectedAppointment.doctorNameObj;
body['ProjectName'] = patientSelectedAppointment.projectName;
}
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
SEND_FEEDBACK,
body: body,
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()));
}
}
}

@ -1,8 +1,15 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/api_consts.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/features/contact_us/contact_us_repo.dart';
import 'package:hmg_patient_app_new/features/contact_us/models/feedback_type.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/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
class ContactUsViewModel extends ChangeNotifier {
@ -24,6 +31,19 @@ class ContactUsViewModel extends ChangeNotifier {
List<String> feedbackAttachmentList = [];
PatientAppointmentHistoryResponseModel? patientFeedbackSelectedAppointment;
List<FeedbackType> feedbackTypeList = [
FeedbackType(id: 1, nameEN: "Complaint for appointment", nameAR: 'شكوى على موعد'),
FeedbackType(id: 2, nameEN: "Complaint without appointment", nameAR: 'شكوى بدون موعد'),
FeedbackType(id: 3, nameEN: "Question", nameAR: 'سؤال'),
FeedbackType(id: 4, nameEN: "Appreciation", nameAR: 'تقدير'),
FeedbackType(id: 6, nameEN: "Suggestion", nameAR: 'إقتراح'),
FeedbackType(id: 5, nameEN: "Not classified", nameAR: 'غير محدد'),
];
FeedbackType selectedFeedbackType = FeedbackType(id: 5, nameEN: "Not classified", nameAR: 'غير محدد');
ContactUsViewModel({required this.contactUsRepo, required this.errorHandlerService, required this.appState});
initContactUsViewModel() {
@ -34,6 +54,8 @@ class ContactUsViewModel extends ChangeNotifier {
hmgPharmacyLocationsList.clear();
liveChatProjectsList.clear();
feedbackAttachmentList.clear();
selectedFeedbackType = FeedbackType(id: 5, nameEN: "Not classified", nameAR: 'غير محدد');
setPatientFeedbackSelectedAppointment(null);
getHMGLocations();
notifyListeners();
}
@ -53,6 +75,26 @@ class ContactUsViewModel extends ChangeNotifier {
notifyListeners();
}
setSelectedFeedbackType(FeedbackType feedbackType) {
selectedFeedbackType = feedbackType;
notifyListeners();
}
addFeedbackAttachment(String attachmentPath) {
feedbackAttachmentList.add(attachmentPath);
notifyListeners();
}
removeFeedbackAttachment(String attachmentPath) {
feedbackAttachmentList.remove(attachmentPath);
notifyListeners();
}
setPatientFeedbackSelectedAppointment(PatientAppointmentHistoryResponseModel? appointment) {
patientFeedbackSelectedAppointment = appointment;
notifyListeners();
}
Future<void> getHMGLocations({Function(dynamic)? onSuccess, Function(String)? onError}) async {
isHMGLocationsListLoading = true;
hmgHospitalsLocationsList.clear();
@ -110,4 +152,47 @@ class ContactUsViewModel extends ChangeNotifier {
},
);
}
Future<void> insertCOCItem({required String subject, required String message, Function(dynamic)? onSuccess, Function(String)? onError}) async {
RequestInsertCOCItem requestInsertCOCItem = RequestInsertCOCItem();
requestInsertCOCItem.attachment = feedbackAttachmentList.isNotEmpty ? feedbackAttachmentList.first : "";
requestInsertCOCItem.title = subject;
requestInsertCOCItem.details = message;
requestInsertCOCItem.cOCTypeName = selectedFeedbackType.id.toString();
requestInsertCOCItem.formTypeID = selectedFeedbackType.id.toString();
requestInsertCOCItem.mobileNo = "966${Utils.getPhoneNumberWithoutZero(appState.getAuthenticatedUser()!.mobileNumber!)}";
requestInsertCOCItem.isUserLoggedIn = true;
requestInsertCOCItem.projectID = 0;
requestInsertCOCItem.patientName = "${appState.getAuthenticatedUser()!.firstName!} ${appState.getAuthenticatedUser()!.lastName!}";
requestInsertCOCItem.fileName = "";
requestInsertCOCItem.appVersion = ApiConsts.appVersionID;
requestInsertCOCItem.uILanguage = appState.isArabic() ? "ar" : "en"; //TODO Change it to be dynamic
requestInsertCOCItem.browserInfo = Platform.localHostname;
requestInsertCOCItem.deviceInfo = Platform.localHostname;
requestInsertCOCItem.resolution = "400x847";
requestInsertCOCItem.projectID = 0;
requestInsertCOCItem.tokenID = "C0c@@dm!n?T&A&A@Barcha202029582948";
requestInsertCOCItem.identificationNo = int.parse(appState.getAuthenticatedUser()!.patientIdentificationNo!);
if (BASE_URL.contains('uat')) {
requestInsertCOCItem.forDemo = true;
} else {
requestInsertCOCItem.forDemo = false;
}
final result = await contactUsRepo.insertCOCItem(requestInsertCOCItem: requestInsertCOCItem, patientSelectedAppointment: patientFeedbackSelectedAppointment);
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),
(apiResponse) {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
}

@ -0,0 +1,11 @@
class FeedbackType {
final int id;
final String nameEN;
final String nameAR;
FeedbackType({
required this.id,
required this.nameEN,
required this.nameAR,
});
}

@ -0,0 +1,137 @@
class RequestInsertCOCItem {
bool? isUserLoggedIn;
String? mobileNo;
int? identificationNo;
int? patientID;
int? patientOutSA;
int? patientTypeID;
String? tokenID;
String? patientName;
int? projectID;
String? fileName;
String? attachment;
String? uILanguage;
String? browserInfo;
String? cOCTypeName;
String? formTypeID;
String? details;
String? deviceInfo;
String? deviceType;
String? title;
String? resolution;
double? versionID;
int? channel;
int? languageID;
String? iPAdress;
String? generalid;
String? sessionID;
bool? isDentalAllowedBackend;
int? deviceTypeID;
int? patientType;
double? appVersion;
bool? forDemo;
RequestInsertCOCItem(
{this.isUserLoggedIn,
this.mobileNo,
this.identificationNo,
this.patientID,
this.patientOutSA,
this.patientTypeID,
this.tokenID,
this.patientName,
this.projectID,
this.fileName,
this.attachment,
this.uILanguage,
this.browserInfo,
this.cOCTypeName,
this.formTypeID,
this.details,
this.deviceInfo,
this.deviceType,
this.title,
this.resolution,
this.versionID,
this.channel,
this.languageID,
this.iPAdress,
this.generalid,
this.sessionID,
this.isDentalAllowedBackend,
this.deviceTypeID,
this.patientType,
this.appVersion,
this.forDemo});
RequestInsertCOCItem.fromJson(Map<String, dynamic> json) {
isUserLoggedIn = json['IsUserLoggedIn'];
mobileNo = json['MobileNo'];
identificationNo = json['IdentificationNo'];
patientID = json['PatientID'];
patientOutSA = json['PatientOutSA'];
patientTypeID = json['PatientTypeID'];
tokenID = json['TokenID'];
patientName = json['PatientName'];
projectID = json['ProjectID'];
fileName = json['FileName'];
attachment = json['Attachment'];
uILanguage = json['UILanguage'];
browserInfo = json['BrowserInfo'];
cOCTypeName = json['COCTypeName'];
formTypeID = json['FormTypeID'];
details = json['Details'];
deviceInfo = json['DeviceInfo'];
deviceType = json['DeviceType'];
title = json['Title'];
resolution = json['Resolution'];
versionID = json['VersionID'];
channel = json['Channel'];
languageID = json['LanguageID'];
iPAdress = json['IPAdress'];
generalid = json['generalid'];
sessionID = json['SessionID'];
isDentalAllowedBackend = json['isDentalAllowedBackend'];
deviceTypeID = json['DeviceTypeID'];
patientType = json['PatientType'];
appVersion = json['AppVersion'];
forDemo = json['ForDemo'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['IsUserLoggedIn'] = this.isUserLoggedIn;
data['MobileNo'] = this.mobileNo;
data['IdentificationNo'] = this.identificationNo;
data['PatientID'] = this.patientID;
data['PatientOutSA'] = this.patientOutSA;
data['PatientTypeID'] = this.patientTypeID;
data['TokenID'] = this.tokenID;
data['PatientName'] = this.patientName;
data['ProjectID'] = this.projectID;
data['FileName'] = this.fileName;
data['Attachment'] = this.attachment;
data['UILanguage'] = this.uILanguage;
data['BrowserInfo'] = this.browserInfo;
data['COCTypeName'] = this.cOCTypeName;
data['FormTypeID'] = this.formTypeID;
data['Details'] = this.details;
data['DeviceInfo'] = this.deviceInfo;
data['DeviceType'] = this.deviceType;
data['Title'] = this.title;
data['Resolution'] = this.resolution;
data['VersionID'] = this.versionID;
data['Channel'] = this.channel;
data['LanguageID'] = this.languageID;
data['IPAdress'] = this.iPAdress;
data['generalid'] = this.generalid;
data['SessionID'] = this.sessionID;
data['isDentalAllowedBackend'] = this.isDentalAllowedBackend;
data['DeviceTypeID'] = this.deviceTypeID;
data['PatientType'] = this.patientType;
data['AppVersion'] = this.appVersion;
data['ForDemo'] = this.forDemo;
return data;
}
}

@ -10,6 +10,7 @@ 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/book_appointments/models/resp_models/doctors_list_response_model.dart';
import 'package:hmg_patient_app_new/features/contact_us/contact_us_view_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/medical_file_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';
@ -33,7 +34,9 @@ class AppointmentCard extends StatelessWidget {
final bool isFromHomePage;
final bool isFromMedicalReport;
final bool isForEyeMeasurements;
final bool isForFeedback;
final MedicalFileViewModel? medicalFileViewModel;
final ContactUsViewModel? contactUsViewModel;
final BookAppointmentsViewModel bookAppointmentsViewModel;
const AppointmentCard({
@ -45,7 +48,9 @@ class AppointmentCard extends StatelessWidget {
this.isFromHomePage = false,
this.isFromMedicalReport = false,
this.isForEyeMeasurements = false,
this.isForFeedback = false,
this.medicalFileViewModel,
this.contactUsViewModel,
});
@override
@ -179,7 +184,11 @@ class AppointmentCard extends StatelessWidget {
return CustomButton(
text: 'Select appointment'.needTranslation,
onPressed: () {
medicalFileViewModel!.setSelectedMedicalReportAppointment(patientAppointmentHistoryResponseModel);
if (isForFeedback) {
contactUsViewModel!.setPatientFeedbackSelectedAppointment(patientAppointmentHistoryResponseModel);
} else {
medicalFileViewModel!.setSelectedMedicalReportAppointment(patientAppointmentHistoryResponseModel);
}
Navigator.pop(context, false);
},
backgroundColor: AppColors.secondaryLightRedColor,
@ -313,6 +322,7 @@ class AppointmentCard extends StatelessWidget {
}
void _goToDetails(BuildContext context) {
if (isFromMedicalReport) return;
if (isForEyeMeasurements) {
Navigator.of(context).push(
CustomPageRoute(

@ -9,6 +9,7 @@ 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/contact_us/contact_us_view_model.dart';
import 'package:hmg_patient_app_new/features/contact_us/models/feedback_type.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/contact_us/feedback_page.dart';
import 'package:hmg_patient_app_new/presentation/contact_us/find_us_page.dart';
@ -53,6 +54,9 @@ class ContactUs extends StatelessWidget {
LocaleKeys.feedback.tr(),
"Provide your feedback on our services".needTranslation,
).onPress(() {
contactUsViewModel.setSelectedFeedbackType(
FeedbackType(id: 5, nameEN: "Not classified", nameAR: 'غير محدد'),
);
Navigator.pop(context);
Navigator.of(context).push(
CustomPageRoute(

@ -1,29 +1,46 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/contact_us/contact_us_view_model.dart';
import 'package:hmg_patient_app_new/features/contact_us/models/feedback_type.dart';
import 'package:hmg_patient_app_new/features/medical_file/medical_file_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/appointments/widgets/appointment_card.dart';
import 'package:hmg_patient_app_new/presentation/contact_us/widgets/feedback_appointment_selection.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/chip/app_custom_chip_widget.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart';
import 'package:hmg_patient_app_new/widgets/image_picker.dart';
import 'package:hmg_patient_app_new/widgets/input_widget.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';
class FeedbackPage extends StatelessWidget {
FeedbackPage({super.key});
late ContactUsViewModel contactUsViewModel;
late MedicalFileViewModel medicalFileViewModel;
final TextEditingController subjectTextController = TextEditingController();
final TextEditingController messageTextController = TextEditingController();
@override
Widget build(BuildContext context) {
contactUsViewModel = Provider.of<ContactUsViewModel>(context);
contactUsViewModel = Provider.of<ContactUsViewModel>(context, listen: false);
medicalFileViewModel = Provider.of<MedicalFileViewModel>(context, listen: false);
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: Consumer<ContactUsViewModel>(builder: (context, contactUsVM, child) {
@ -64,7 +81,42 @@ class FeedbackPage extends StatelessWidget {
),
child: CustomButton(
text: LocaleKeys.submit.tr(context: context),
onPressed: () async {},
onPressed: () async {
if (subjectTextController.text.isEmpty) {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: LocaleKeys.emptySubject.tr(context: context)),
);
return;
}
if (messageTextController.text.isEmpty) {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: LocaleKeys.emptyMessage.tr(context: context)),
);
return;
}
LoaderBottomSheet.showLoader(loadingText: "Sending Feedback...".needTranslation);
contactUsViewModel.insertCOCItem(
subject: subjectTextController.text,
message: messageTextController.text,
onSuccess: (val) {
LoaderBottomSheet.hideLoader();
subjectTextController.clear();
messageTextController.clear();
contactUsViewModel.setPatientFeedbackSelectedAppointment(null);
showCommonBottomSheetWithoutHeight(context, child: Utils.getSuccessWidget(loadingText: LocaleKeys.success.tr(context: context)), callBackFunc: () {
Navigator.pop(context);
});
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getSuccessWidget(loadingText: err),
);
});
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
textColor: AppColors.whiteColor,
@ -113,26 +165,142 @@ class FeedbackPage extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.feedbackType.tr().toText16(color: AppColors.textColor, weight: FontWeight.w500),
LocaleKeys.select.tr().toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
],
),
],
(getIt.get<AppState>().isArabic() ? contactUsViewModel.selectedFeedbackType.nameAR : contactUsViewModel.selectedFeedbackType.nameEN)
.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
],
),
],
),
Utils.buildSvgWithAssets(icon: AppAssets.arrow_down, width: 25.h, height: 25.h),
],
).onPress(() {
showCommonBottomSheetWithoutHeight(context,
title: "Select Feedback Type".needTranslation,
child: Container(
width: double.infinity,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24),
child: ListView.builder(
itemCount: contactUsViewModel.feedbackTypeList.length,
physics: NeverScrollableScrollPhysics(),
padding: EdgeInsets.only(top: 8, bottom: 8),
shrinkWrap: true,
itemBuilder: (innerContext, index) {
return Theme(
data: Theme.of(context).copyWith(
listTileTheme: ListTileThemeData(horizontalTitleGap: 4),
),
child: RadioListTile<FeedbackType>(
title: Text(
getIt.get<AppState>().isArabic() ? contactUsViewModel.feedbackTypeList[index].nameAR : contactUsViewModel.feedbackTypeList[index].nameEN,
style: TextStyle(
fontSize: 16.h,
fontWeight: FontWeight.w500,
),
),
value: contactUsViewModel.feedbackTypeList[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: contactUsViewModel.selectedFeedbackType,
onChanged: (FeedbackType? newValue) async {
Navigator.pop(context);
contactUsViewModel.setSelectedFeedbackType(newValue!);
if (contactUsViewModel.selectedFeedbackType.id == 1) {
LoaderBottomSheet.showLoader(loadingText: "Loading appointments list...".needTranslation);
await medicalFileViewModel.getPatientMedicalReportAppointmentsList(onSuccess: (val) async {
LoaderBottomSheet.hideLoader();
bool? value = await Navigator.of(context).push(
CustomPageRoute(
page: FeedbackAppointmentSelection(),
fullScreenDialog: true,
direction: AxisDirection.down,
),
);
if (value != null) {
// showConfirmRequestMedicalReportBottomSheet();
}
}, onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: "You do not have any appointments to submit a feedback.".needTranslation),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
} else {
contactUsViewModel.setPatientFeedbackSelectedAppointment(null);
}
},
),
);
},
),
),
Utils.buildSvgWithAssets(icon: AppAssets.arrow_down, width: 25.h, height: 25.h),
],
).onPress(() {
showCommonBottomSheetWithoutHeight(context,
title: "Select Feedback Type".needTranslation, child: Container(), callBackFunc: () {}, isFullScreen: false, isCloseButtonVisible: true);
}),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true);
}),
]),
),
),
if (contactUsViewModel.patientFeedbackSelectedAppointment != null) ...[
SizedBox(height: 16.h),
"Selected Appointment:".needTranslation.toText16(isBold: true),
SizedBox(height: 8.h),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.r,
hasShadow: false,
),
padding: EdgeInsets.all(16.h),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
contactUsViewModel.patientFeedbackSelectedAppointment!.doctorImageURL!,
width: 63.h,
height: 63.h,
fit: BoxFit.cover,
).circle(100).toShimmer2(isShow: false),
SizedBox(width: 16.h),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
(contactUsViewModel.patientFeedbackSelectedAppointment!.doctorNameObj!).toText16(isBold: true, maxlines: 1).toShimmer2(isShow: false),
SizedBox(height: 8.h),
Wrap(
direction: Axis.horizontal,
spacing: 3.h,
runSpacing: 4.h,
children: [
AppCustomChipWidget(labelText: contactUsViewModel.patientFeedbackSelectedAppointment!.clinicName!).toShimmer2(isShow: false),
AppCustomChipWidget(labelText: contactUsViewModel.patientFeedbackSelectedAppointment!.projectName!).toShimmer2(isShow: false),
AppCustomChipWidget(
icon: AppAssets.appointment_calendar_icon,
labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(contactUsViewModel.patientFeedbackSelectedAppointment!.appointmentDate), false),
).toShimmer2(isShow: false),
],
),
],
),
),
],
),
),
),
],
SizedBox(height: 16.h),
TextInputWidget(
labelText: "Subject".needTranslation,
hintText: "Enter subject here".needTranslation,
// controller: searchEditingController,
controller: subjectTextController,
isEnable: true,
prefix: null,
autoFocus: false,
@ -147,7 +315,7 @@ class FeedbackPage extends StatelessWidget {
TextInputWidget(
labelText: "Message".needTranslation,
hintText: "Enter message here".needTranslation,
// controller: searchEditingController,
controller: messageTextController,
isEnable: true,
prefix: null,
autoFocus: false,
@ -170,10 +338,7 @@ class FeedbackPage extends StatelessWidget {
print(image);
print(file);
Navigator.pop(context);
// setState(() {
// EReferralAttachment eReferralAttachment = new EReferralAttachment(fileName: 'image ${medicalReportImages.length + 1}.png', base64String: image);
// medicalReportImages.add(eReferralAttachment);
// });
contactUsViewModel.addFeedbackAttachment(image);
},
);
},
@ -188,7 +353,44 @@ class FeedbackPage extends StatelessWidget {
icon: AppAssets.file_icon,
iconColor: AppColors.primaryRedColor,
iconSize: 16.h,
)
),
SizedBox(height: 16.h),
contactUsViewModel.feedbackAttachmentList.isNotEmpty
? Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 12.r,
hasShadow: false,
),
child: ListView.builder(
padding: EdgeInsets.all(16.h),
shrinkWrap: true,
itemCount: contactUsViewModel.feedbackAttachmentList.length,
itemBuilder: (BuildContext context, int index) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(
Icons.attach_file,
color: Color(0xff2B353E),
),
SizedBox(width: 8.w),
"Image ${index + 1}".toText14().paddingOnly(bottom: 8.h),
],
),
Utils.buildSvgWithAssets(icon: AppAssets.cancel_circle_icon).onPress(() {
contactUsViewModel.removeFeedbackAttachment(contactUsViewModel.feedbackAttachmentList[index]);
}),
],
);
},
),
)
: SizedBox.shrink(),
],
);
} else {

@ -0,0 +1,70 @@
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/utils/size_utils.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/contact_us/contact_us_view_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/medical_file_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/appointments/widgets/appointment_card.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:provider/provider.dart';
class FeedbackAppointmentSelection extends StatelessWidget {
FeedbackAppointmentSelection({super.key});
late MedicalFileViewModel medicalFileViewModel;
late ContactUsViewModel contactUsViewModel;
@override
Widget build(BuildContext context) {
medicalFileViewModel = Provider.of<MedicalFileViewModel>(context, listen: false);
contactUsViewModel = Provider.of<ContactUsViewModel>(context, listen: false);
return CollapsingListView(
title: LocaleKeys.feedback.tr(),
isClose: true,
child: Column(
children: [
ListView.separated(
padding: EdgeInsets.only(top: 24.h),
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: medicalFileViewModel.patientMedicalReportAppointmentHistoryList.length,
itemBuilder: (context, index) {
return 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,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true),
child: AppointmentCard(
patientAppointmentHistoryResponseModel: medicalFileViewModel.patientMedicalReportAppointmentHistoryList[index],
myAppointmentsViewModel: Provider.of<MyAppointmentsViewModel>(context, listen: false),
bookAppointmentsViewModel: Provider.of<BookAppointmentsViewModel>(context, listen: false),
medicalFileViewModel: medicalFileViewModel,
contactUsViewModel: contactUsViewModel,
isLoading: false,
isFromHomePage: false,
isFromMedicalReport: true,
isForFeedback: true,
),
).paddingSymmetrical(24.h, 0.h),
),
),
);
},
separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h),
),
SizedBox(height: 24.h),
],
),
);
}
}

@ -90,7 +90,7 @@ class _WalletPaymentConfirmPageState extends State<WalletPaymentConfirmPage> {
Transform.flip(
flipX: appState.isArabic(),
child: Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon,
icon: AppAssets.forward_arrow_icon_small,
iconColor: AppColors.blackColor,
width: 18.h,
height: 13.h,
@ -132,7 +132,7 @@ class _WalletPaymentConfirmPageState extends State<WalletPaymentConfirmPage> {
Transform.flip(
flipX: appState.isArabic(),
child: Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon,
icon: AppAssets.forward_arrow_icon_small,
iconColor: AppColors.blackColor,
width: 18.h,
height: 13.h,

@ -10,7 +10,7 @@ class ServicesPage extends StatelessWidget {
Widget build(BuildContext context) {
return CollapsingListView(
title: "Explore Services".needTranslation,
isLeading: false,
isLeading: Navigator.canPop(context),
child: Padding(
padding: EdgeInsets.all(24.h),
child: Column(

@ -31,6 +31,7 @@ import 'package:hmg_patient_app_new/presentation/book_appointment/book_appointme
import 'package:hmg_patient_app_new/presentation/book_appointment/livecare/immediate_livecare_pending_request_page.dart';
import 'package:hmg_patient_app_new/presentation/contact_us/contact_us.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/er_online_checkin/er_online_checkin_home.dart';
import 'package:hmg_patient_app_new/presentation/hmg_services/services_page.dart';
import 'package:hmg_patient_app_new/presentation/home/data/landing_page_data.dart';
import 'package:hmg_patient_app_new/presentation/home/widgets/habib_wallet_card.dart';
import 'package:hmg_patient_app_new/presentation/home/widgets/large_service_card.dart';
@ -526,7 +527,9 @@ class _LandingPageState extends State<LandingPage> {
SizedBox(width: 2.h),
Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 10.h),
],
),
).onPress(() {
Navigator.of(context).push(CustomPageRoute(page: ServicesPage()));
}),
],
).paddingSymmetrical(24.h, 0.h),
SizedBox(

Loading…
Cancel
Save