From 14725616c60b7bf3ede96be893f0a0f1be786ff0 Mon Sep 17 00:00:00 2001 From: Haroon Amjad <> Date: Sat, 13 Sep 2025 00:48:22 +0300 Subject: [PATCH] medical report implementation contd. --- .../medical_file/medical_file_repo.dart | 48 +++++ .../medical_file/medical_file_view_model.dart | 65 +++++- .../patient_medical_response_model.dart | 192 ++++++++++++++++++ .../medical_file/medical_file_page.dart | 112 +++++++--- .../medical_file/medical_reports_page.dart | 91 +++++++++ .../widgets/patient_medical_report_card.dart | 120 +++++++++++ 6 files changed, 599 insertions(+), 29 deletions(-) create mode 100644 lib/features/medical_file/models/patient_medical_response_model.dart create mode 100644 lib/presentation/medical_file/medical_reports_page.dart create mode 100644 lib/presentation/medical_file/widgets/patient_medical_report_card.dart diff --git a/lib/features/medical_file/medical_file_repo.dart b/lib/features/medical_file/medical_file_repo.dart index 14be4ae..6d30adc 100644 --- a/lib/features/medical_file/medical_file_repo.dart +++ b/lib/features/medical_file/medical_file_repo.dart @@ -3,6 +3,7 @@ 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/medical_file/models/patient_medical_response_model.dart'; import 'package:hmg_patient_app_new/features/medical_file/models/patient_sickleave_response_model.dart'; import 'package:hmg_patient_app_new/features/medical_file/models/patient_vaccine_response_model.dart'; import 'package:hmg_patient_app_new/services/logger_service.dart'; @@ -15,6 +16,8 @@ abstract class MedicalFileRepo { Future>>> getPatientSickLeavesList(); Future>> getPatientSickLeavePDF(PatientSickLeavesResponseModel patientSickLeavesResponseModel, AuthenticatedUser authenticatedUser); + + Future>>> getPatientMedicalReportsList(); } class MedicalFileRepoImp implements MedicalFileRepo { @@ -157,4 +160,49 @@ class MedicalFileRepoImp implements MedicalFileRepo { return Left(UnknownFailure(e.toString())); } } + + @override + Future>>> getPatientMedicalReportsList() async { + Map mapDevice = { + "IsReport": true, + "EncounterType": 1, + "RequestType": 1, + }; + + try { + GenericApiModel>? apiResponse; + Failure? failure; + await apiClient.post( + REPORTS, + body: mapDevice, + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + try { + final list = response['GetPatientMedicalStatus']; + // if (list == null || list.isEmpty) { + // throw Exception("lab list is empty"); + // } + + final vaccinesList = list.map((item) => PatientMedicalReportResponseModel.fromJson(item as Map)).toList().cast(); + + apiResponse = GenericApiModel>( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: null, + data: vaccinesList, + ); + } 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/medical_file/medical_file_view_model.dart b/lib/features/medical_file/medical_file_view_model.dart index 7140e0c..bcc7ed2 100644 --- a/lib/features/medical_file/medical_file_view_model.dart +++ b/lib/features/medical_file/medical_file_view_model.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/features/authentication/models/resp_models/authenticated_user_resp_model.dart'; import 'package:hmg_patient_app_new/features/medical_file/medical_file_repo.dart'; +import 'package:hmg_patient_app_new/features/medical_file/models/patient_medical_response_model.dart'; import 'package:hmg_patient_app_new/features/medical_file/models/patient_sickleave_response_model.dart'; import 'package:hmg_patient_app_new/features/medical_file/models/patient_vaccine_response_model.dart'; import 'package:hmg_patient_app_new/services/error_handler_service.dart'; @@ -10,6 +11,7 @@ class MedicalFileViewModel extends ChangeNotifier { bool isPatientVaccineListLoading = false; bool isPatientSickLeaveListLoading = false; bool isPatientSickLeavePDFLoading = false; + bool isPatientMedicalReportsListLoading = false; MedicalFileRepo medicalFileRepo; ErrorHandlerService errorHandlerService; @@ -17,12 +19,33 @@ class MedicalFileViewModel extends ChangeNotifier { List patientVaccineList = []; List patientSickLeaveList = []; + List patientMedicalReportList = []; + + List patientMedicalReportRequestedList = []; + List patientMedicalReportReadyList = []; + List patientMedicalReportCancelledList = []; + String patientSickLeavePDFBase64 = ""; + int selectedMedicalReportsTabIndex = 0; + MedicalFileViewModel({required this.medicalFileRepo, required this.errorHandlerService}); initMedicalFileProvider() { isPatientVaccineListLoading = true; + isPatientMedicalReportsListLoading = true; + notifyListeners(); + } + + void onMedicalReportTabChange(int index) { + selectedMedicalReportsTabIndex = index; + if (index == 0) { + patientMedicalReportList = patientMedicalReportRequestedList; + } else if (index == 1) { + patientMedicalReportList = patientMedicalReportReadyList; + } else if (index == 2) { + patientMedicalReportList = patientMedicalReportCancelledList; + } notifyListeners(); } @@ -44,6 +67,14 @@ class MedicalFileViewModel extends ChangeNotifier { notifyListeners(); } + setIsPatientMedicalReportsLoading(bool val) { + if (val) { + patientMedicalReportList.clear(); + } + isPatientMedicalReportsListLoading = val; + notifyListeners(); + } + void onTabChanged(int index) { selectedTabIndex = index; notifyListeners(); @@ -101,7 +132,8 @@ class MedicalFileViewModel extends ChangeNotifier { ); } - Future getPatientSickLeavePDF(PatientSickLeavesResponseModel patientSickLeavesResponseModel, AuthenticatedUser authenticatedUser,{Function(dynamic)? onSuccess, Function(String)? onError}) async { + Future getPatientSickLeavePDF(PatientSickLeavesResponseModel patientSickLeavesResponseModel, AuthenticatedUser authenticatedUser, + {Function(dynamic)? onSuccess, Function(String)? onError}) async { final result = await medicalFileRepo.getPatientSickLeavePDF(patientSickLeavesResponseModel, authenticatedUser); result.fold( @@ -125,4 +157,35 @@ class MedicalFileViewModel extends ChangeNotifier { }, ); } + + Future getPatientMedicalReportList({Function(dynamic)? onSuccess, Function(String)? onError}) async { + patientMedicalReportList.clear(); + final result = await medicalFileRepo.getPatientMedicalReportsList(); + + result.fold( + (failure) async => await errorHandlerService.handleError( + failure: failure, + onOkPressed: () { + onError!(failure.message); + }, + ), + (apiResponse) { + if (apiResponse.messageStatus == 2) { + // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); + } else if (apiResponse.messageStatus == 1) { + patientMedicalReportList = apiResponse.data!; + if (patientMedicalReportList.isNotEmpty) { + patientMedicalReportRequestedList = patientMedicalReportList.where((element) => element.status == 1).toList(); + patientMedicalReportReadyList = patientMedicalReportList.where((element) => element.status == 2).toList(); + patientMedicalReportCancelledList = patientMedicalReportList.where((element) => element.status == 4).toList(); + } + isPatientMedicalReportsListLoading = false; + notifyListeners(); + if (onSuccess != null) { + onSuccess(apiResponse); + } + } + }, + ); + } } diff --git a/lib/features/medical_file/models/patient_medical_response_model.dart b/lib/features/medical_file/models/patient_medical_response_model.dart new file mode 100644 index 0000000..52785af --- /dev/null +++ b/lib/features/medical_file/models/patient_medical_response_model.dart @@ -0,0 +1,192 @@ +class PatientMedicalReportResponseModel { + int? status; + String? encounterDate; + int? projectID; + int? invoiceNo; + int? encounterNo; + String? procedureId; + int? requestType; + String? setupId; + int? patientID; + int? doctorID; + int? clinicID; + String? requestDate; + bool? isRead; + dynamic isReadOn; + num? actualDoctorRate; + String? admissionDate; + int? admissionNumber; + String? appointmentDate; + int? appointmentNO; + String? appointmentTime; + String? clinicDescription; + dynamic clinicDescriptionN; + num? decimalDoctorRate; + String? docName; + dynamic docNameN; + String? doctorImageURL; + String? doctorName; + dynamic doctorNameN; + num? doctorRate; + num? doctorStarsRate; + int? invoiceNoVP; + dynamic invoiceType; + bool? isDoctorAllowVedioCall; + bool? isExecludeDoctor; + bool? isInOutPatient; + String? isInOutPatientDescription; + String? isInOutPatientDescriptionN; + int? noOfPatientsRate; + String? projectName; + dynamic projectNameN; + int? sourceID; + dynamic sourceName; + dynamic sourceNameN; + String? statusDesc; + dynamic strAppointmentDate; + + PatientMedicalReportResponseModel( + {this.status, + this.encounterDate, + this.projectID, + this.invoiceNo, + this.encounterNo, + this.procedureId, + this.requestType, + this.setupId, + this.patientID, + this.doctorID, + this.clinicID, + this.requestDate, + this.isRead, + this.isReadOn, + this.actualDoctorRate, + this.admissionDate, + this.admissionNumber, + this.appointmentDate, + this.appointmentNO, + this.appointmentTime, + this.clinicDescription, + this.clinicDescriptionN, + this.decimalDoctorRate, + this.docName, + this.docNameN, + this.doctorImageURL, + this.doctorName, + this.doctorNameN, + this.doctorRate, + this.doctorStarsRate, + this.invoiceNoVP, + this.invoiceType, + this.isDoctorAllowVedioCall, + this.isExecludeDoctor, + this.isInOutPatient, + this.isInOutPatientDescription, + this.isInOutPatientDescriptionN, + this.noOfPatientsRate, + this.projectName, + this.projectNameN, + this.sourceID, + this.sourceName, + this.sourceNameN, + this.statusDesc, + this.strAppointmentDate}); + + PatientMedicalReportResponseModel.fromJson(Map json) { + status = json['Status']; + encounterDate = json['EncounterDate']; + projectID = json['ProjectID']; + invoiceNo = json['InvoiceNo']; + encounterNo = json['EncounterNo']; + procedureId = json['ProcedureId']; + requestType = json['RequestType']; + setupId = json['SetupId']; + patientID = json['PatientID']; + doctorID = json['DoctorID']; + clinicID = json['ClinicID']; + requestDate = json['RequestDate']; + isRead = json['IsRead']; + isReadOn = json['IsReadOn']; + actualDoctorRate = json['ActualDoctorRate']; + admissionDate = json['AdmissionDate']; + admissionNumber = json['AdmissionNumber']; + appointmentDate = json['AppointmentDate']; + appointmentNO = json['AppointmentNO']; + appointmentTime = json['AppointmentTime']; + clinicDescription = json['ClinicDescription']; + clinicDescriptionN = json['ClinicDescriptionN']; + decimalDoctorRate = json['DecimalDoctorRate']; + docName = json['DocName']; + docNameN = json['DocNameN']; + doctorImageURL = json['DoctorImageURL']; + doctorName = json['DoctorName']; + doctorNameN = json['DoctorNameN']; + doctorRate = json['DoctorRate']; + doctorStarsRate = json['DoctorStarsRate']; + invoiceNoVP = json['InvoiceNo_VP']; + invoiceType = json['InvoiceType']; + isDoctorAllowVedioCall = json['IsDoctorAllowVedioCall']; + isExecludeDoctor = json['IsExecludeDoctor']; + isInOutPatient = json['IsInOutPatient']; + isInOutPatientDescription = json['IsInOutPatientDescription']; + isInOutPatientDescriptionN = json['IsInOutPatientDescriptionN']; + noOfPatientsRate = json['NoOfPatientsRate']; + projectName = json['ProjectName']; + projectNameN = json['ProjectNameN']; + sourceID = json['SourceID']; + sourceName = json['SourceName']; + sourceNameN = json['SourceNameN']; + statusDesc = json['StatusDesc']; + strAppointmentDate = json['StrAppointmentDate']; + } + + Map toJson() { + final Map data = new Map(); + data['Status'] = this.status; + data['EncounterDate'] = this.encounterDate; + data['ProjectID'] = this.projectID; + data['InvoiceNo'] = this.invoiceNo; + data['EncounterNo'] = this.encounterNo; + data['ProcedureId'] = this.procedureId; + data['RequestType'] = this.requestType; + data['SetupId'] = this.setupId; + data['PatientID'] = this.patientID; + data['DoctorID'] = this.doctorID; + data['ClinicID'] = this.clinicID; + data['RequestDate'] = this.requestDate; + data['IsRead'] = this.isRead; + data['IsReadOn'] = this.isReadOn; + data['ActualDoctorRate'] = this.actualDoctorRate; + data['AdmissionDate'] = this.admissionDate; + data['AdmissionNumber'] = this.admissionNumber; + data['AppointmentDate'] = this.appointmentDate; + data['AppointmentNO'] = this.appointmentNO; + data['AppointmentTime'] = this.appointmentTime; + data['ClinicDescription'] = this.clinicDescription; + data['ClinicDescriptionN'] = this.clinicDescriptionN; + data['DecimalDoctorRate'] = this.decimalDoctorRate; + data['DocName'] = this.docName; + data['DocNameN'] = this.docNameN; + data['DoctorImageURL'] = this.doctorImageURL; + data['DoctorName'] = this.doctorName; + data['DoctorNameN'] = this.doctorNameN; + data['DoctorRate'] = this.doctorRate; + data['DoctorStarsRate'] = this.doctorStarsRate; + data['InvoiceNo_VP'] = this.invoiceNoVP; + data['InvoiceType'] = this.invoiceType; + data['IsDoctorAllowVedioCall'] = this.isDoctorAllowVedioCall; + data['IsExecludeDoctor'] = this.isExecludeDoctor; + data['IsInOutPatient'] = this.isInOutPatient; + data['IsInOutPatientDescription'] = this.isInOutPatientDescription; + data['IsInOutPatientDescriptionN'] = this.isInOutPatientDescriptionN; + data['NoOfPatientsRate'] = this.noOfPatientsRate; + data['ProjectName'] = this.projectName; + data['ProjectNameN'] = this.projectNameN; + data['SourceID'] = this.sourceID; + data['SourceName'] = this.sourceName; + data['SourceNameN'] = this.sourceNameN; + data['StatusDesc'] = this.statusDesc; + data['StrAppointmentDate'] = this.strAppointmentDate; + return data; + } +} diff --git a/lib/presentation/medical_file/medical_file_page.dart b/lib/presentation/medical_file/medical_file_page.dart index 02af055..22aff4d 100644 --- a/lib/presentation/medical_file/medical_file_page.dart +++ b/lib/presentation/medical_file/medical_file_page.dart @@ -23,6 +23,7 @@ import 'package:hmg_patient_app_new/presentation/appointments/my_doctors_page.da import 'package:hmg_patient_app_new/presentation/insurance/insurance_home_page.dart'; import 'package:hmg_patient_app_new/presentation/insurance/widgets/patient_insurance_card.dart'; import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart'; +import 'package:hmg_patient_app_new/presentation/medical_file/medical_reports_page.dart'; import 'package:hmg_patient_app_new/presentation/medical_file/vaccine_list_page.dart'; import 'package:hmg_patient_app_new/presentation/medical_file/widgets/lab_rad_card.dart'; import 'package:hmg_patient_app_new/presentation/medical_file/widgets/medical_file_card.dart'; @@ -601,16 +602,41 @@ class _MedicalFilePageState extends State { padding: EdgeInsets.only(top: 12), shrinkWrap: true, children: [ - MedicalFileCard(label: "Update Insurance".needTranslation, textColor: AppColors.blackColor, backgroundColor: AppColors.whiteColor, svgIcon: AppAssets.eye_result_icon).onPress(() { + MedicalFileCard( + label: "Update Insurance".needTranslation, + textColor: AppColors.blackColor, + backgroundColor: AppColors.whiteColor, + svgIcon: AppAssets.eye_result_icon, + isLargeText: false, + iconSize: 36.h) + .onPress(() { Navigator.of(context).push( FadePage( page: InsuranceHomePage(), ), ); }), - MedicalFileCard(label: "Insurance Approvals".needTranslation, textColor: AppColors.blackColor, backgroundColor: AppColors.whiteColor, svgIcon: AppAssets.eye_result_icon), - MedicalFileCard(label: "My Invoices List".needTranslation, textColor: AppColors.blackColor, backgroundColor: AppColors.whiteColor, svgIcon: AppAssets.eye_result_icon), - MedicalFileCard(label: "Ancillary Orders List".needTranslation, textColor: AppColors.blackColor, backgroundColor: AppColors.whiteColor, svgIcon: AppAssets.eye_result_icon), + MedicalFileCard( + label: "Insurance Approvals".needTranslation, + textColor: AppColors.blackColor, + backgroundColor: AppColors.whiteColor, + svgIcon: AppAssets.eye_result_icon, + isLargeText: false, + iconSize: 36.h), + MedicalFileCard( + label: "My Invoices List".needTranslation, + textColor: AppColors.blackColor, + backgroundColor: AppColors.whiteColor, + svgIcon: AppAssets.eye_result_icon, + isLargeText: false, + iconSize: 36.h), + MedicalFileCard( + label: "Ancillary Orders List".needTranslation, + textColor: AppColors.blackColor, + backgroundColor: AppColors.whiteColor, + svgIcon: AppAssets.eye_result_icon, + isLargeText: false, + iconSize: 36.h), ], ).paddingSymmetrical(24.h, 0.0), SizedBox(height: 16.h), @@ -626,31 +652,61 @@ class _MedicalFilePageState extends State { patientSickLeavesResponseModel: PatientSickLeavesResponseModel(), isLoading: true, ).paddingSymmetrical(24.h, 0.0) - : medicalFileVM.patientSickLeaveList.isNotEmpty ? PatientSickLeaveCard( - patientSickLeavesResponseModel: medicalFileVM.patientSickLeaveList.first, - isLoading: false, - ).paddingSymmetrical(24.h, 0.0) : SizedBox.shrink(); + : medicalFileVM.patientSickLeaveList.isNotEmpty + ? PatientSickLeaveCard( + patientSickLeavesResponseModel: medicalFileVM.patientSickLeaveList.first, + isLoading: false, + ).paddingSymmetrical(24.h, 0.0) + : SizedBox.shrink(); }), - SizedBox(height: 10.h), - // GridView( - // gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, crossAxisSpacing: 13, mainAxisSpacing: 13), - // physics: NeverScrollableScrollPhysics(), - // padding: EdgeInsets.only(top: 12), - // shrinkWrap: true, - // children: [ - // MedicalFileCard(label: "Update Insurance".needTranslation, textColor: AppColors.blackColor, backgroundColor: AppColors.whiteColor, svgIcon: AppAssets.eye_result_icon).onPress(() { - // Navigator.of(context).push( - // FadePage( - // page: InsuranceHomePage(), - // ), - // ); - // }), - // MedicalFileCard(label: "Insurance Approvals".needTranslation, textColor: AppColors.blackColor, backgroundColor: AppColors.whiteColor, svgIcon: AppAssets.eye_result_icon), - // MedicalFileCard(label: "My Invoices List".needTranslation, textColor: AppColors.blackColor, backgroundColor: AppColors.whiteColor, svgIcon: AppAssets.eye_result_icon), - // MedicalFileCard(label: "Ancillary Orders List".needTranslation, textColor: AppColors.blackColor, backgroundColor: AppColors.whiteColor, svgIcon: AppAssets.eye_result_icon), - // ], - // ).paddingSymmetrical(24.h, 0.0), - // SizedBox(height: 16.h), + SizedBox(height: 16.h), + GridView( + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, crossAxisSpacing: 13, mainAxisSpacing: 13), + physics: NeverScrollableScrollPhysics(), + padding: EdgeInsets.zero, + shrinkWrap: true, + children: [ + MedicalFileCard( + label: LocaleKeys.monthlyReports.tr(context: context), + textColor: AppColors.blackColor, + backgroundColor: AppColors.whiteColor, + svgIcon: AppAssets.eye_result_icon, + isLargeText: false, + iconSize: 40.h, + ), + MedicalFileCard( + label: "Medical Reports".needTranslation, + textColor: AppColors.blackColor, + backgroundColor: AppColors.whiteColor, + svgIcon: AppAssets.allergy_info_icon, + isLargeText: false, + iconSize: 40.h, + ).onPress(() { + medicalFileViewModel.setIsPatientMedicalReportsLoading(true); + medicalFileViewModel.getPatientMedicalReportList(); + Navigator.of(context).push( + FadePage( + page: MedicalReportsPage(), + ), + ); + }), + MedicalFileCard( + label: "Sick Leave Report".needTranslation, + textColor: AppColors.blackColor, + backgroundColor: AppColors.whiteColor, + svgIcon: AppAssets.vaccine_info_icon, + isLargeText: false, + iconSize: 40.h, + ).onPress(() { + Navigator.of(context).push( + FadePage( + page: VaccineListPage(), + ), + ); + }), + ], + ).paddingSymmetrical(24.h, 0.0), + SizedBox(height: 24.h), ], ); case 3: diff --git a/lib/presentation/medical_file/medical_reports_page.dart b/lib/presentation/medical_file/medical_reports_page.dart new file mode 100644 index 0000000..c30f9af --- /dev/null +++ b/lib/presentation/medical_file/medical_reports_page.dart @@ -0,0 +1,91 @@ +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/string_extensions.dart'; +import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; +import 'package:hmg_patient_app_new/features/medical_file/medical_file_view_model.dart'; +import 'package:hmg_patient_app_new/features/medical_file/models/patient_medical_response_model.dart'; +import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart'; +import 'package:hmg_patient_app_new/presentation/medical_file/widgets/patient_medical_report_card.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart'; +import 'package:provider/provider.dart'; + +class MedicalReportsPage extends StatefulWidget { + const MedicalReportsPage({super.key}); + + @override + State createState() => _MedicalReportsPageState(); +} + +class _MedicalReportsPageState extends State { + late MedicalFileViewModel medicalFileViewModel; + + @override + Widget build(BuildContext context) { + medicalFileViewModel = Provider.of(context, listen: false); + return Scaffold( + backgroundColor: AppColors.bgScaffoldColor, + body: CollapsingListView( + title: "Medical Reports".needTranslation, + child: SingleChildScrollView( + child: Column( + children: [ + SizedBox(height: 16.h), + CustomTabBar( + activeTextColor: Color(0xffED1C2B), + activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1), + tabs: [ + CustomTabBarModel(null, "Requested".needTranslation), + CustomTabBarModel(null, "Ready".needTranslation), + CustomTabBarModel(null, "Cancelled".needTranslation), + ], + onTabChange: (index) { + medicalFileViewModel.onMedicalReportTabChange(index); + }, + ).paddingSymmetrical(24.h, 0.h), + Consumer(builder: (context, medicalFileVM, child) { + return ListView.separated( + padding: EdgeInsets.only(top: 24.h), + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemCount: medicalFileViewModel.isPatientMedicalReportsListLoading ? 3 : medicalFileViewModel.patientMedicalReportList.length, + // medicalFileViewModel.patientMedicalReportList.isNotEmpty + // ? medicalFileViewModel.patientMedicalReportList.length + // : 1, + itemBuilder: (context, index) { + return medicalFileViewModel.isPatientMedicalReportsListLoading + ? PatientMedicalReportCard( + patientMedicalReportResponseModel: PatientMedicalReportResponseModel(), + isLoading: true, + ).paddingSymmetrical(24.h, 0.h) + : 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: PatientMedicalReportCard( + patientMedicalReportResponseModel: medicalFileVM.patientMedicalReportList[index], + isLoading: false, + ), + ).paddingSymmetrical(24.h, 0.h), + ), + ), + ); + }, + separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h), + ); + }), + SizedBox(height: 24.h), + ], + ), + ), + ), + ); + } +} diff --git a/lib/presentation/medical_file/widgets/patient_medical_report_card.dart b/lib/presentation/medical_file/widgets/patient_medical_report_card.dart new file mode 100644 index 0000000..3f890e6 --- /dev/null +++ b/lib/presentation/medical_file/widgets/patient_medical_report_card.dart @@ -0,0 +1,120 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:hmg_patient_app_new/core/app_assets.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/extensions/string_extensions.dart'; +import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; +import 'package:hmg_patient_app_new/features/medical_file/models/patient_medical_response_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/chip/app_custom_chip_widget.dart'; + +class PatientMedicalReportCard extends StatelessWidget { + PatientMedicalReportCard({super.key, required this.patientMedicalReportResponseModel, this.isLoading = false}); + + PatientMedicalReportResponseModel patientMedicalReportResponseModel; + + bool isLoading = true; + + @override + Widget build(BuildContext context) { + return Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 20.h, + hasShadow: true, + ), + child: Padding( + padding: EdgeInsets.all(16.h), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Image.network( + isLoading ? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png" : patientMedicalReportResponseModel.doctorImageURL!, + width: 63.h, + height: 63.h, + fit: BoxFit.fill, + ).circle(100).toShimmer2(isShow: isLoading), + SizedBox(width: 16.h), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + (isLoading ? "" : patientMedicalReportResponseModel.doctorName!).toText16(isBold: true).toShimmer2(isShow: isLoading), + SizedBox(height: 4.h), + Wrap( + direction: Axis.horizontal, + spacing: 3.h, + runSpacing: 4.h, + children: [ + AppCustomChipWidget(labelText: isLoading ? "" : patientMedicalReportResponseModel.clinicDescription!).toShimmer2(isShow: isLoading), + AppCustomChipWidget(labelText: isLoading ? "" : patientMedicalReportResponseModel.projectName!).toShimmer2(isShow: isLoading), + AppCustomChipWidget( + icon: AppAssets.doctor_calendar_icon, + labelText: isLoading + ? "" + : "${DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientMedicalReportResponseModel.requestDate), false)}, ${DateUtil.formatDateToTimeLang(DateUtil.convertStringToDate(patientMedicalReportResponseModel.requestDate), false)}") + .toShimmer2(isShow: isLoading), + AppCustomChipWidget( + icon: AppAssets.rating_icon, iconColor: AppColors.ratingColorYellow, labelText: isLoading ? "" : "Rating: ${patientMedicalReportResponseModel.decimalDoctorRate}") + .toShimmer2(isShow: isLoading), + ], + ), + ], + ), + ), + ], + ), + patientMedicalReportResponseModel.status == 2 + ? Padding( + padding: EdgeInsets.only(top: 16.h), + child: Row( + children: [ + Expanded( + child: CustomButton( + text: "Share", + onPressed: () {}, + backgroundColor: AppColors.secondaryLightRedColor, + borderColor: AppColors.secondaryLightRedColor, + textColor: AppColors.primaryRedColor, + fontSize: 14, + fontWeight: FontWeight.w500, + borderRadius: 12.h, + height: 40.h, + icon: AppAssets.download_1, + iconColor: AppColors.primaryRedColor, + iconSize: 16.h, + ).toShimmer2(isShow: isLoading), + ), + SizedBox(width: 16.h), + Expanded( + child: CustomButton( + text: "Download", + onPressed: () {}, + backgroundColor: AppColors.secondaryLightRedColor, + borderColor: AppColors.secondaryLightRedColor, + textColor: AppColors.primaryRedColor, + fontSize: 14, + fontWeight: FontWeight.w500, + borderRadius: 12.h, + height: 40.h, + icon: AppAssets.download_1, + iconColor: AppColors.primaryRedColor, + iconSize: 16.h, + ).toShimmer2(isShow: isLoading), + ), + ], + ), + ) + : SizedBox.shrink() + ], + ), + ), + ); + } +}