From f5e655fd35df6b230385e9110c2e819c1bce9f67 Mon Sep 17 00:00:00 2001 From: Haroon Amjad <> Date: Tue, 2 Sep 2025 23:25:45 +0300 Subject: [PATCH] Lab order API implemented --- lib/core/api/api_client.dart | 11 +- lib/extensions/widget_extensions.dart | 28 +- lib/features/lab/lab_repo.dart | 28 +- lib/features/lab/lab_view_model.dart | 8 +- .../patient_lab_orders_response_model.dart | 307 ++++++++++++------ lib/presentation/lab/lab_orders_page.dart | 24 +- 6 files changed, 277 insertions(+), 129 deletions(-) diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index b3ea487..d43ca93 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -189,6 +189,7 @@ class ApiClientImp implements ApiClient { : await Utils.isGoogleServicesAvailable() ? "2" : "3"); + body['TokenID'] = "@dm!n"; body.removeWhere((key, value) => value == null); log("body: ${json.encode(body)}"); log("uri: ${Uri.parse(url.trim())}"); @@ -223,18 +224,18 @@ class ApiClientImp implements ApiClient { if (parsed['isSMSSent'] == true) { onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus']); } else if (parsed['MessageStatus'] == 1) { - onSuccess(parsed, statusCode); + onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus']); } else if (parsed['Result'] == 'OK') { - onSuccess(parsed, statusCode); + onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus']); } else { onFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode, failureType: ServerFailure("Error While Fetching data")); logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); } } else if (parsed['MessageStatus'] == 1 || parsed['SMSLoginRequired'] == true) { - onSuccess(parsed, statusCode); + onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus']); } else if (parsed['MessageStatus'] == 2 && parsed['IsAuthenticated']) { if (parsed['SameClinicApptList'] != null) { - onSuccess(parsed, statusCode); + onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus']); } else { if (parsed['message'] == null && parsed['ErrorEndUserMessage'] == null) { if (parsed['ErrorSearchMsg'] == null) { @@ -263,7 +264,7 @@ class ApiClientImp implements ApiClient { } } else { if (parsed['SameClinicApptList'] != null) { - onSuccess(parsed, statusCode); + onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus']); } else { if (parsed['message'] != null) { onFailure( diff --git a/lib/extensions/widget_extensions.dart b/lib/extensions/widget_extensions.dart index e6913d2..d1a3db4 100644 --- a/lib/extensions/widget_extensions.dart +++ b/lib/extensions/widget_extensions.dart @@ -78,7 +78,14 @@ extension WidgetExtensions on Widget { } Widget objectContainerBorderView( - {String title = "", String note = "", bool disablePadding = false, double radius = 20, Color? color, Color borderColor = AppColors.buttonColor, bool disableWidth = false, bool isAlignment = false}) { + {String title = "", + String note = "", + bool disablePadding = false, + double radius = 20, + Color? color, + Color borderColor = AppColors.buttonColor, + bool disableWidth = false, + bool isAlignment = false}) { return Container( padding: disablePadding ? EdgeInsets.zero : const EdgeInsets.only(top: 15, bottom: 15, left: 14, right: 14), decoration: BoxDecoration( @@ -127,6 +134,7 @@ extension SmoothContainerExtension on ShapeBorder { bool isDisabled = false, Color? backgroundColor, BorderSide? side, + bool hasShadow = false, }) { final bgColor = backgroundColor ?? color; return ShapeDecoration( @@ -136,15 +144,19 @@ extension SmoothContainerExtension on ShapeBorder { smoothness: 1, side: side ?? BorderSide.none, ), + shadows: hasShadow + ? [ + BoxShadow( + color: const Color(0xff000000).withOpacity(.05), + blurRadius: 32, + offset: const Offset(0, 0), + ) + ] + : [], ); } } - - - - - //Height Spacers in percentages Widget heightSpacer02per() => SizedBox(height: 0.2.h); @@ -191,8 +203,6 @@ Widget widthSpacer4per() => SizedBox(height: 4.w); Widget widthSpacer5per() => SizedBox(height: 5.w); - - extension ChipTypeEnumExtension on ChipTypeEnum { Color get color { switch (this) { @@ -223,4 +233,4 @@ extension ChipTypeEnumExtension on ChipTypeEnum { return AppColors.warningLightColor; // Replace with your actual color } } -} \ No newline at end of file +} diff --git a/lib/features/lab/lab_repo.dart b/lib/features/lab/lab_repo.dart index 061506a..6d2711c 100644 --- a/lib/features/lab/lab_repo.dart +++ b/lib/features/lab/lab_repo.dart @@ -7,7 +7,7 @@ import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_ import 'package:hmg_patient_app_new/services/logger_service.dart'; abstract class LabRepo { - Future>>> getPatientLabOrders({required num patientId}); + Future>>> getPatientLabOrders({required String patientId}); } class LabRepoImp implements LabRepo { @@ -17,8 +17,24 @@ class LabRepoImp implements LabRepo { LabRepoImp({required this.loggerService, required this.apiClient}); @override - Future>>> getPatientLabOrders({required num patientId}) async { - final mapDevice = {"PatientID": patientId}; + Future>>> getPatientLabOrders({required String patientId}) async { + final mapDevice = { + "isDentalAllowedBackend": false, + "VersionID": 50.0, + "Channel": 3, + "LanguageID": 2, + "IPAdress": "10.20.10.20", + "generalid": "Cs2020@2016\$2958", + "Latitude": 0.0, + "Longitude": 0.0, + "DeviceTypeID": 1, + "PatientType": 1, + "PatientTypeID": 1, + "TokenID": "@dm!n", + "PatientID": "2663907", + "PatientOutSA": "0", + "SessionID": "03478TYC02N80874CTYN04883475!?" + }; try { GenericApiModel>? apiResponse; @@ -36,7 +52,11 @@ class LabRepoImp implements LabRepo { throw Exception("lab list is empty"); } - final labOrders = list.map((item) => PatientLabOrdersResponseModel.fromJson(item as Map)).toList(); + // final labOrders = list.map((item) => PatientLabOrdersResponseModel.fromJson(item as Map)).toList(); + final labOrders = list + .map((item) => PatientLabOrdersResponseModel.fromJson(item as Map)) + .toList() + .cast(); apiResponse = GenericApiModel>( messageStatus: messageStatus, diff --git a/lib/features/lab/lab_view_model.dart b/lib/features/lab/lab_view_model.dart index 73f8b13..acd87eb 100644 --- a/lib/features/lab/lab_view_model.dart +++ b/lib/features/lab/lab_view_model.dart @@ -16,14 +16,14 @@ class LabViewModel extends ChangeNotifier { initLabProvider() { patientLabOrders.clear(); - // isLabOrdersLoading = true; - // isLabResultsLoading = true; - // getPatientLabOrders(); + isLabOrdersLoading = true; + isLabResultsLoading = true; + getPatientLabOrders(); notifyListeners(); } Future getPatientLabOrders({Function(dynamic)? onSuccess, Function(String)? onError}) async { - final result = await labRepo.getPatientLabOrders(patientId: 1231755); + final result = await labRepo.getPatientLabOrders(patientId: "1231755"); result.fold( (failure) async => await errorHandlerService.handleError(failure: failure), diff --git a/lib/features/lab/models/resp_models/patient_lab_orders_response_model.dart b/lib/features/lab/models/resp_models/patient_lab_orders_response_model.dart index 5cd8fbd..8f6dc4f 100644 --- a/lib/features/lab/models/resp_models/patient_lab_orders_response_model.dart +++ b/lib/features/lab/models/resp_models/patient_lab_orders_response_model.dart @@ -1,126 +1,245 @@ class PatientLabOrdersResponseModel { - String? description; - dynamic femaleInterpretativeData; + int? actualDoctorRate; + dynamic? admissionDate; + dynamic? admissionNumber; + dynamic? appointmentDate; + dynamic? appointmentNo; + dynamic? appointmentTime; + String? clinicDescription; + String? clinicDescriptionEnglish; + dynamic? clinicDescriptionN; + int? clinicID; + String? createdOn; + num? decimalDoctorRate; + int? doctorID; + String? doctorImageURL; + String? doctorName; + String? doctorNameEnglish; + dynamic? doctorNameN; + int? doctorRate; + num? doctorStarsRate; + String? doctorTitle; int? gender; - bool? isCertificateAllowed; - int? lineItemNo; - dynamic maleInterpretativeData; - dynamic notes; - int? orderLineItemNo; - int? orderNo; - String? packageID; - int? patientID; + String? genderDescription; + String? invoiceNo; + dynamic? invoiceNoVP; + String? invoiceType; + bool? isActiveDoctorProfile; + bool? isDoctorAllowVedioCall; + bool? isDrReviewReq; + bool? isExecludeDoctor; + bool? isInOutPatient; + String? isInOutPatientDescription; + String? isInOutPatientDescriptionN; + bool? isLiveCareAppointment; + bool? isRead; + bool? isSendEmail; + String? nationalityFlagURL; + int? noOfPatientsRate; + String? orderDate; + String? orderNo; + dynamic? orderProjectID; + String? patientID; String? projectID; - String? referanceRange; - String? resultValue; - int? resultValueBasedLineItemNo; - String? resultValueFlag; - String? sampleCollectedOn; - String? sampleReceivedOn; + String? projectName; + dynamic? projectNameN; + String? qR; String? setupID; - dynamic superVerifiedOn; - String? testCode; - String? uOM; - String? verifiedOn; - String? packageShortDescription; - String? testShortDescription; - dynamic verifiedOnDateTime; - num? percentage; - num? width; - num? resultTypeID; + List? speciality; + int? status; + String? statusDesc; + String? strOrderDate; + List? testDetails; PatientLabOrdersResponseModel( - {this.description, - this.femaleInterpretativeData, + {this.actualDoctorRate, + this.admissionDate, + this.admissionNumber, + this.appointmentDate, + this.appointmentNo, + this.appointmentTime, + this.clinicDescription, + this.clinicDescriptionEnglish, + this.clinicDescriptionN, + this.clinicID, + this.createdOn, + this.decimalDoctorRate, + this.doctorID, + this.doctorImageURL, + this.doctorName, + this.doctorNameEnglish, + this.doctorNameN, + this.doctorRate, + this.doctorStarsRate, + this.doctorTitle, this.gender, - this.isCertificateAllowed, - this.lineItemNo, - this.maleInterpretativeData, - this.notes, - this.orderLineItemNo, + this.genderDescription, + this.invoiceNo, + this.invoiceNoVP, + this.invoiceType, + this.isActiveDoctorProfile, + this.isDoctorAllowVedioCall, + this.isDrReviewReq, + this.isExecludeDoctor, + this.isInOutPatient, + this.isInOutPatientDescription, + this.isInOutPatientDescriptionN, + this.isLiveCareAppointment, + this.isRead, + this.isSendEmail, + this.nationalityFlagURL, + this.noOfPatientsRate, + this.orderDate, this.orderNo, - this.packageID, + this.orderProjectID, this.patientID, this.projectID, - this.referanceRange, - this.resultValue, - this.resultValueBasedLineItemNo, - this.resultValueFlag, - this.sampleCollectedOn, - this.sampleReceivedOn, + this.projectName, + this.projectNameN, + this.qR, this.setupID, - this.superVerifiedOn, - this.testCode, - this.uOM, - this.verifiedOn, - this.verifiedOnDateTime}); + this.speciality, + this.status, + this.statusDesc, + this.strOrderDate, + this.testDetails}); - PatientLabOrdersResponseModel.fromJson(Map json, {String? flag}) { - description = json['Description']; - femaleInterpretativeData = json['FemaleInterpretativeData']; + PatientLabOrdersResponseModel.fromJson(Map json) { + actualDoctorRate = json['ActualDoctorRate']; + admissionDate = json['AdmissionDate']; + admissionNumber = json['AdmissionNumber']; + appointmentDate = json['AppointmentDate']; + appointmentNo = json['AppointmentNo']; + appointmentTime = json['AppointmentTime']; + clinicDescription = json['ClinicDescription']; + clinicDescriptionEnglish = json['ClinicDescriptionEnglish']; + clinicDescriptionN = json['ClinicDescriptionN']; + clinicID = json['ClinicID']; + createdOn = json['CreatedOn']; + decimalDoctorRate = json['DecimalDoctorRate']; + doctorID = json['DoctorID']; + doctorImageURL = json['DoctorImageURL']; + doctorName = json['DoctorName']; + doctorNameEnglish = json['DoctorNameEnglish']; + doctorNameN = json['DoctorNameN']; + doctorRate = json['DoctorRate']; + doctorStarsRate = json['DoctorStarsRate']; + doctorTitle = json['DoctorTitle']; gender = json['Gender']; - isCertificateAllowed = json['IsCertificateAllowed']; - lineItemNo = json['LineItemNo']; - maleInterpretativeData = json['MaleInterpretativeData']; - notes = json['Notes']; - orderLineItemNo = json['OrderLineItemNo']; + genderDescription = json['GenderDescription']; + invoiceNo = json['InvoiceNo']; + invoiceNoVP = json['InvoiceNo_VP']; + invoiceType = json['InvoiceType']; + isActiveDoctorProfile = json['IsActiveDoctorProfile']; + isDoctorAllowVedioCall = json['IsDoctorAllowVedioCall']; + isDrReviewReq = json['IsDrReviewReq']; + isExecludeDoctor = json['IsExecludeDoctor']; + isInOutPatient = json['IsInOutPatient']; + isInOutPatientDescription = json['IsInOutPatientDescription']; + isInOutPatientDescriptionN = json['IsInOutPatientDescriptionN']; + isLiveCareAppointment = json['IsLiveCareAppointment']; + isRead = json['IsRead']; + isSendEmail = json['IsSendEmail']; + nationalityFlagURL = json['NationalityFlagURL']; + noOfPatientsRate = json['NoOfPatientsRate']; + orderDate = json['OrderDate']; orderNo = json['OrderNo']; - packageID = json['PackageID']; + orderProjectID = json['OrderProjectID']; patientID = json['PatientID']; projectID = json['ProjectID']; - referanceRange = json['ReferanceRange']; - resultValue = json['ResultValue']; - resultValueBasedLineItemNo = json['ResultValueBasedLineItemNo']; - resultValueFlag = json['ResultValueFlag']; - sampleCollectedOn = json['SampleCollectedOn']; - sampleReceivedOn = json['SampleReceivedOn']; + projectName = json['ProjectName']; + projectNameN = json['ProjectNameN']; + qR = json['QR']; setupID = json['SetupID']; - superVerifiedOn = json['SuperVerifiedOn']; - testCode = json['TestCode']; - uOM = json['UOM']; - verifiedOn = json['VerifiedOn']; - verifiedOnDateTime = json['VerifiedOnDateTime']; - packageShortDescription = json['PackageShortDescription']; - testShortDescription = json['TestShortDescription']; - resultTypeID = json['ResultTypeID']; + speciality = json['Speciality'].cast(); + status = json['Status']; + statusDesc = json['StatusDesc']; + strOrderDate = json['StrOrderDate']; + if (json['TestDetails'] != dynamic) { + testDetails = []; + json['TestDetails'].forEach((v) { + testDetails!.add(new TestDetails.fromJson(v)); + }); + } } Map toJson() { final Map data = new Map(); - data['Description'] = this.description; - data['FemaleInterpretativeData'] = this.femaleInterpretativeData; + 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['ClinicDescriptionEnglish'] = this.clinicDescriptionEnglish; + data['ClinicDescriptionN'] = this.clinicDescriptionN; + data['ClinicID'] = this.clinicID; + data['CreatedOn'] = this.createdOn; + data['DecimalDoctorRate'] = this.decimalDoctorRate; + data['DoctorID'] = this.doctorID; + data['DoctorImageURL'] = this.doctorImageURL; + data['DoctorName'] = this.doctorName; + data['DoctorNameEnglish'] = this.doctorNameEnglish; + data['DoctorNameN'] = this.doctorNameN; + data['DoctorRate'] = this.doctorRate; + data['DoctorStarsRate'] = this.doctorStarsRate; + data['DoctorTitle'] = this.doctorTitle; data['Gender'] = this.gender; - data['IsCertificateAllowed'] = this.isCertificateAllowed; - data['LineItemNo'] = this.lineItemNo; - data['MaleInterpretativeData'] = this.maleInterpretativeData; - data['Notes'] = this.notes; - data['OrderLineItemNo'] = this.orderLineItemNo; + data['GenderDescription'] = this.genderDescription; + data['InvoiceNo'] = this.invoiceNo; + data['InvoiceNo_VP'] = this.invoiceNoVP; + data['InvoiceType'] = this.invoiceType; + data['IsActiveDoctorProfile'] = this.isActiveDoctorProfile; + data['IsDoctorAllowVedioCall'] = this.isDoctorAllowVedioCall; + data['IsDrReviewReq'] = this.isDrReviewReq; + data['IsExecludeDoctor'] = this.isExecludeDoctor; + data['IsInOutPatient'] = this.isInOutPatient; + data['IsInOutPatientDescription'] = this.isInOutPatientDescription; + data['IsInOutPatientDescriptionN'] = this.isInOutPatientDescriptionN; + data['IsLiveCareAppointment'] = this.isLiveCareAppointment; + data['IsRead'] = this.isRead; + data['IsSendEmail'] = this.isSendEmail; + data['NationalityFlagURL'] = this.nationalityFlagURL; + data['NoOfPatientsRate'] = this.noOfPatientsRate; + data['OrderDate'] = this.orderDate; data['OrderNo'] = this.orderNo; - data['PackageID'] = this.packageID; + data['OrderProjectID'] = this.orderProjectID; data['PatientID'] = this.patientID; data['ProjectID'] = this.projectID; - data['ReferanceRange'] = this.referanceRange; - data['ResultValue'] = this.resultValue; - data['ResultValueBasedLineItemNo'] = this.resultValueBasedLineItemNo; - data['ResultValueFlag'] = this.resultValueFlag; - data['SampleCollectedOn'] = this.sampleCollectedOn; - data['SampleReceivedOn'] = this.sampleReceivedOn; + data['ProjectName'] = this.projectName; + data['ProjectNameN'] = this.projectNameN; + data['QR'] = this.qR; data['SetupID'] = this.setupID; - data['SuperVerifiedOn'] = this.superVerifiedOn; - data['TestCode'] = this.testCode; - data['UOM'] = this.uOM; - data['VerifiedOn'] = this.verifiedOn; - data['VerifiedOnDateTime'] = this.verifiedOnDateTime; - data['PackageShortDescription'] = this.packageShortDescription; - data['TestShortDescription'] = this.testShortDescription; - + data['Speciality'] = this.speciality; + data['Status'] = this.status; + data['StatusDesc'] = this.statusDesc; + data['StrOrderDate'] = this.strOrderDate; + if (this.testDetails != dynamic) { + data['TestDetails'] = this.testDetails!.map((v) => v.toJson()).toList(); + } return data; } +} + +class TestDetails { + String? description; + String? testCode; + String? testID; + + TestDetails({this.description, this.testCode, this.testID}); - bool shouldShowResultBarAndGraph() { - if (resultTypeID == null) return false; - if (resultTypeID == 6) return false; + TestDetails.fromJson(Map json) { + description = json['Description']; + testCode = json['TestCode']; + testID = json['TestID']; + } - return true; + Map toJson() { + final Map data = new Map(); + data['Description'] = this.description; + data['TestCode'] = this.testCode; + data['TestID'] = this.testID; + return data; } } diff --git a/lib/presentation/lab/lab_orders_page.dart b/lib/presentation/lab/lab_orders_page.dart index e0143ca..7854ee8 100644 --- a/lib/presentation/lab/lab_orders_page.dart +++ b/lib/presentation/lab/lab_orders_page.dart @@ -4,6 +4,7 @@ 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/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'; @@ -74,7 +75,7 @@ class _LabOrdersPageState extends State { ListView.builder( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), - itemCount: model.isLabOrdersLoading ? 5 : labOrders.length, + itemCount: model.isLabOrdersLoading ? 5 : model.patientLabOrders.length, itemBuilder: (context, index) { final isExpanded = expandedIndex == index; return model.isLabOrdersLoading @@ -89,10 +90,7 @@ class _LabOrdersPageState extends State { duration: Duration(milliseconds: 300), curve: Curves.easeInOut, margin: EdgeInsets.symmetric(vertical: 8.h), - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 20.h, - ), + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true), child: InkWell( onTap: () { setState(() { @@ -112,9 +110,9 @@ class _LabOrdersPageState extends State { CustomButton( text: LocaleKeys.pending.tr(context: context), onPressed: () {}, - backgroundColor: getLabOrderStatusColor(44).withOpacity(0.15), - borderColor: getLabOrderStatusColor(44).withOpacity(0.01), - textColor: getLabOrderStatusColor(44), + backgroundColor: getLabOrderStatusColor(model.patientLabOrders[index].status!).withOpacity(0.15), + borderColor: getLabOrderStatusColor(model.patientLabOrders[index].status!).withOpacity(0.01), + textColor: getLabOrderStatusColor(model.patientLabOrders[index].status!), fontSize: 10, fontWeight: FontWeight.w500, borderRadius: 8, @@ -128,20 +126,20 @@ class _LabOrdersPageState extends State { Row( children: [ Image.network( - "https://hmgwebservices.com/Images/MobileImages/SUWAIDI/152305.png", + model.patientLabOrders[index].doctorImageURL!, width: 24.h, height: 24.h, fit: BoxFit.fill, ).circle(100), SizedBox(width: 4.h), - Text(labOrders[index], style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), + model.patientLabOrders[index].doctorName!.toText16(isBold: true) ], ), SizedBox(height: 8.h), Row( children: [ CustomButton( - text: "12th June, 2025", + text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(model.patientLabOrders[index].createdOn), false), onPressed: () {}, backgroundColor: AppColors.greyColor, borderColor: AppColors.greyColor, @@ -154,7 +152,7 @@ class _LabOrdersPageState extends State { ), SizedBox(width: 8.h), CustomButton( - text: "Clinic: Cardiology", + text: model.patientLabOrders[index].clinicDescription!, onPressed: () {}, backgroundColor: AppColors.greyColor, borderColor: AppColors.greyColor, @@ -174,7 +172,7 @@ class _LabOrdersPageState extends State { firstChild: SizedBox.shrink(), secondChild: Padding( padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 8.h), - child: Text('Details for ${labOrders[index]}'), + child: Text('Details for ${model.patientLabOrders[index].clinicDescription}'), ), crossFadeState: isExpanded ? CrossFadeState.showSecond : CrossFadeState.showFirst, duration: Duration(milliseconds: 300),