From 9b1c3fe920a577edb074d3bca6800122e683fda6 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Tue, 2 Sep 2025 15:22:42 +0300 Subject: [PATCH 1/6] medical file updates --- .../medical_file/medical_file_page.dart | 46 ++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/lib/presentation/medical_file/medical_file_page.dart b/lib/presentation/medical_file/medical_file_page.dart index 55ca84b..f4ba507 100644 --- a/lib/presentation/medical_file/medical_file_page.dart +++ b/lib/presentation/medical_file/medical_file_page.dart @@ -161,7 +161,51 @@ class MedicalFilePage extends StatelessWidget { ], ), ), - ) + ), + SizedBox(height: 16.h), + //Insurance Tab Data + Container( + height: 150.h, + width: double.infinity, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24, + ), + child: Padding( + padding: EdgeInsets.all(16.h), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Haroon Amjad".toText18(isBold: true), + "Policy: 223123345".toText12(isBold: true, color: AppColors.lightGrayColor), + ], + ), + CustomButton( + icon: AppAssets.cross_circle, + iconColor: AppColors.primaryRedColor, + iconSize: 13.h, + text: "Insurance Expired", + onPressed: () {}, + backgroundColor: AppColors.primaryRedColor.withOpacity(0.1), + borderColor: AppColors.primaryRedColor.withOpacity(0.0), + textColor: AppColors.primaryRedColor, + fontSize: 10, + fontWeight: FontWeight.w500, + borderRadius: 12, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 30.h, + ), + ], + ), + ], + ), + ), + ), ], ), ), From 22e9fb738b133c3ef8d7af07a9ff831637c96a34 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Tue, 2 Sep 2025 16:35:50 +0300 Subject: [PATCH 2/6] assets added --- assets/images/svg/Saudi_Riyal_Symbol.svg | 12 ++++++++++++ assets/images/svg/blood_icon.svg | 3 +++ assets/images/svg/checkmark_icon.svg | 3 +++ assets/images/svg/file_icon.svg | 3 +++ assets/images/svg/habib_logo_background.svg | 3 +++ assets/images/svg/insurance_active_icon.svg | 3 +++ assets/images/svg/recharge_icon.svg | 4 ++++ assets/images/svg/show_icon.svg | 4 ++++ 8 files changed, 35 insertions(+) create mode 100644 assets/images/svg/Saudi_Riyal_Symbol.svg create mode 100644 assets/images/svg/blood_icon.svg create mode 100644 assets/images/svg/checkmark_icon.svg create mode 100644 assets/images/svg/file_icon.svg create mode 100644 assets/images/svg/habib_logo_background.svg create mode 100644 assets/images/svg/insurance_active_icon.svg create mode 100644 assets/images/svg/recharge_icon.svg create mode 100644 assets/images/svg/show_icon.svg diff --git a/assets/images/svg/Saudi_Riyal_Symbol.svg b/assets/images/svg/Saudi_Riyal_Symbol.svg new file mode 100644 index 0000000..d57d83a --- /dev/null +++ b/assets/images/svg/Saudi_Riyal_Symbol.svg @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/assets/images/svg/blood_icon.svg b/assets/images/svg/blood_icon.svg new file mode 100644 index 0000000..c83b20c --- /dev/null +++ b/assets/images/svg/blood_icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/svg/checkmark_icon.svg b/assets/images/svg/checkmark_icon.svg new file mode 100644 index 0000000..e514106 --- /dev/null +++ b/assets/images/svg/checkmark_icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/svg/file_icon.svg b/assets/images/svg/file_icon.svg new file mode 100644 index 0000000..7bfc655 --- /dev/null +++ b/assets/images/svg/file_icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/svg/habib_logo_background.svg b/assets/images/svg/habib_logo_background.svg new file mode 100644 index 0000000..597c7b2 --- /dev/null +++ b/assets/images/svg/habib_logo_background.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/svg/insurance_active_icon.svg b/assets/images/svg/insurance_active_icon.svg new file mode 100644 index 0000000..33a25bb --- /dev/null +++ b/assets/images/svg/insurance_active_icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/svg/recharge_icon.svg b/assets/images/svg/recharge_icon.svg new file mode 100644 index 0000000..a6f26ce --- /dev/null +++ b/assets/images/svg/recharge_icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/images/svg/show_icon.svg b/assets/images/svg/show_icon.svg new file mode 100644 index 0000000..541fd55 --- /dev/null +++ b/assets/images/svg/show_icon.svg @@ -0,0 +1,4 @@ + + + + From 89456bc2aa76beaf080f906801d25ca49509bf67 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Tue, 2 Sep 2025 17:24:12 +0300 Subject: [PATCH 3/6] Medical File Insurance tab content done --- assets/images/svg/eye_results_icon.svg | 4 ++ lib/core/app_assets.dart | 1 + .../medical_file/medical_file_page.dart | 69 ++++++++++++++++++- .../widgets/medical_file_card.dart | 44 ++++++++++++ 4 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 assets/images/svg/eye_results_icon.svg create mode 100644 lib/presentation/medical_file/widgets/medical_file_card.dart diff --git a/assets/images/svg/eye_results_icon.svg b/assets/images/svg/eye_results_icon.svg new file mode 100644 index 0000000..fd9c754 --- /dev/null +++ b/assets/images/svg/eye_results_icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/lib/core/app_assets.dart b/lib/core/app_assets.dart index 0e7d944..cba90a1 100644 --- a/lib/core/app_assets.dart +++ b/lib/core/app_assets.dart @@ -59,6 +59,7 @@ class AppAssets { static const String habib_background_icon = '$svgBasePath/habib_logo_background.svg'; static const String show_icon = '$svgBasePath/show_icon.svg'; static const String recharge_icon = '$svgBasePath/recharge_icon.svg'; + static const String eye_result_icon = '$svgBasePath/eye_results_icon.svg'; // PNGS // static const String hmg_logo = '$pngBasePath/hmg_logo.png'; diff --git a/lib/presentation/medical_file/medical_file_page.dart b/lib/presentation/medical_file/medical_file_page.dart index f4ba507..6635ef5 100644 --- a/lib/presentation/medical_file/medical_file_page.dart +++ b/lib/presentation/medical_file/medical_file_page.dart @@ -5,6 +5,7 @@ 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/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/presentation/medical_file/widgets/medical_file_card.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/input_widget.dart'; @@ -165,7 +166,7 @@ class MedicalFilePage extends StatelessWidget { SizedBox(height: 16.h), //Insurance Tab Data Container( - height: 150.h, + // height: 150.h, width: double.infinity, decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.whiteColor, @@ -174,6 +175,7 @@ class MedicalFilePage extends StatelessWidget { child: Padding( padding: EdgeInsets.all(16.h), child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -202,10 +204,75 @@ class MedicalFilePage extends StatelessWidget { ), ], ), + SizedBox(height: 12.h), + "NCCI".toText12(isBold: true), + "NC_Dr Sulaiman Al Habib Medical Group".toText12(isBold: true), + SizedBox(height: 8.h), + Row( + children: [ + CustomButton( + icon: AppAssets.cross_circle, + iconColor: AppColors.primaryRedColor, + iconSize: 13.h, + text: "Expiry: 18 Mar, 2025", + onPressed: () {}, + backgroundColor: AppColors.primaryRedColor.withOpacity(0.1), + borderColor: AppColors.primaryRedColor.withOpacity(0.0), + textColor: AppColors.primaryRedColor, + fontSize: 10, + fontWeight: FontWeight.w500, + borderRadius: 12, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 30.h, + ), + SizedBox(width: 5.h), + CustomButton( + text: "Patient Card ID: 3628599", + onPressed: () {}, + backgroundColor: AppColors.greyColor, + borderColor: AppColors.greyColor, + textColor: AppColors.blackColor, + fontSize: 10, + fontWeight: FontWeight.normal, + borderRadius: 12, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 30.h, + ), + ], + ), + SizedBox(height: 10.h), + CustomButton( + icon: AppAssets.cross_circle, + iconColor: AppColors.primaryRedColor, + iconSize: 13.h, + text: "${LocaleKeys.updateInsurance.tr(context: context)} ${LocaleKeys.updateInsuranceSubtitle.tr(context: context)}", + onPressed: () {}, + backgroundColor: AppColors.bgGreenColor.withOpacity(0.20), + borderColor: AppColors.bgGreenColor.withOpacity(0.0), + textColor: AppColors.bgGreenColor, + fontSize: 14, + fontWeight: FontWeight.w500, + borderRadius: 12, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 40.h, + ), ], ), ), ), + 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", textColor: AppColors.blackColor, backgroundColor: AppColors.whiteColor, svgIcon: AppAssets.eye_result_icon), + MedicalFileCard(label: "Insurance Approvals", textColor: AppColors.blackColor, backgroundColor: AppColors.whiteColor, svgIcon: AppAssets.eye_result_icon), + MedicalFileCard(label: "My Invoices List", textColor: AppColors.blackColor, backgroundColor: AppColors.whiteColor, svgIcon: AppAssets.eye_result_icon), + MedicalFileCard(label: "Ancillary Orders List", textColor: AppColors.blackColor, backgroundColor: AppColors.whiteColor, svgIcon: AppAssets.eye_result_icon), + ], + ), ], ), ), diff --git a/lib/presentation/medical_file/widgets/medical_file_card.dart b/lib/presentation/medical_file/widgets/medical_file_card.dart new file mode 100644 index 0000000..92bb4ee --- /dev/null +++ b/lib/presentation/medical_file/widgets/medical_file_card.dart @@ -0,0 +1,44 @@ +import 'package:flutter/material.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'; + +class MedicalFileCard extends StatelessWidget { + final String label; + + // final Color svgColor; + final Color textColor; + final Color backgroundColor; + final String svgIcon; + + MedicalFileCard({ + required this.label, + // required this.svgColor, + required this.textColor, + required this.backgroundColor, + this.svgIcon = "", + }); + + @override + Widget build(BuildContext context) { + return Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: backgroundColor, + borderRadius: 20, + ), + child: Padding( + padding: EdgeInsets.all(8.h), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Utils.buildSvgWithAssets(icon: svgIcon, width: 30.h, height: 30.h, fit: BoxFit.contain), + SizedBox(height: 12.h), + label.toText11(color: textColor, isBold: true), + ], + ), + ), + ); + } +} From e044fc8c5e1746ccd3e88fac881de26112de3ebb Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Tue, 2 Sep 2025 19:13:15 +0300 Subject: [PATCH 4/6] lab implementation contd. --- assets/images/svg/search_icon.svg | 3 + lib/core/api/api_client.dart | 2 +- lib/core/app_assets.dart | 1 + lib/features/lab/lab_repo.dart | 9 + lib/features/lab/lab_view_model.dart | 13 ++ lib/main.dart | 4 + .../home/data/landing_page_data.dart | 22 +++ .../home/data/service_card_data.dart | 2 + lib/presentation/home/landing_page.dart | 1 + .../home/widgets/small_service_card.dart | 25 ++- lib/presentation/lab/lab_orders_page.dart | 173 ++++++++++++++++++ .../medical_file/medical_file_page.dart | 3 - lib/theme/colors.dart | 1 + 13 files changed, 254 insertions(+), 5 deletions(-) create mode 100644 assets/images/svg/search_icon.svg create mode 100644 lib/features/lab/lab_repo.dart create mode 100644 lib/features/lab/lab_view_model.dart create mode 100644 lib/presentation/lab/lab_orders_page.dart diff --git a/assets/images/svg/search_icon.svg b/assets/images/svg/search_icon.svg new file mode 100644 index 0000000..1a64ce5 --- /dev/null +++ b/assets/images/svg/search_icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index 92a7e6c..53bd522 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -179,7 +179,7 @@ class ApiClientImp implements ApiClient { // TODO : we will use all these from appState body['LanguageID'] = body['LanguageID'] ?? "2"; - body['VersionID'] = body['VersionID'] ?? "18.7"; + body['VersionID'] = body['VersionID'] ?? "50.0"; body['Channel'] = body['Channel'] ?? "3"; body['IPAdress'] = body['IPAdress'] ?? "10.20.10.20"; body['generalid'] = body['generalid'] ?? "Cs2020@2016\$2958"; diff --git a/lib/core/app_assets.dart b/lib/core/app_assets.dart index cba90a1..2032f56 100644 --- a/lib/core/app_assets.dart +++ b/lib/core/app_assets.dart @@ -60,6 +60,7 @@ class AppAssets { static const String show_icon = '$svgBasePath/show_icon.svg'; static const String recharge_icon = '$svgBasePath/recharge_icon.svg'; static const String eye_result_icon = '$svgBasePath/eye_results_icon.svg'; + static const String search_icon = '$svgBasePath/search_icon.svg'; // PNGS // static const String hmg_logo = '$pngBasePath/hmg_logo.png'; diff --git a/lib/features/lab/lab_repo.dart b/lib/features/lab/lab_repo.dart new file mode 100644 index 0000000..f651a71 --- /dev/null +++ b/lib/features/lab/lab_repo.dart @@ -0,0 +1,9 @@ +import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart'; +import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart'; +import 'package:dartz/dartz.dart'; + +abstract class AuthenticationRepo { + Future>> getPatientLabOrders({ + required String firebaseToken, + }); +} diff --git a/lib/features/lab/lab_view_model.dart b/lib/features/lab/lab_view_model.dart new file mode 100644 index 0000000..f0ebad3 --- /dev/null +++ b/lib/features/lab/lab_view_model.dart @@ -0,0 +1,13 @@ +import 'package:flutter/material.dart'; + +class LabViewModel extends ChangeNotifier { + + bool isLabOrdersLoading = false; + bool isLabResultsLoading = false; + + initLabProvider() { + isLabOrdersLoading = true; + isLabResultsLoading = true; + notifyListeners(); + } +} diff --git a/lib/main.dart b/lib/main.dart index bb4332b..1ea5d84 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -8,6 +8,7 @@ import 'package:flutter/services.dart'; import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart'; import 'package:hmg_patient_app_new/providers/bottom_navigation_provider.dart'; +import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart'; import 'package:hmg_patient_app_new/routes/app_routes.dart'; import 'package:hmg_patient_app_new/services/logger_service.dart'; import 'package:hmg_patient_app_new/services/navigation_service.dart'; @@ -54,6 +55,9 @@ void main() async { ChangeNotifierProvider( create: (_) => BottomNavigationProvider(), ), + ChangeNotifierProvider( + create: (_) => LabViewModel(), + ), ChangeNotifierProvider( create: (_) => AuthenticationViewModel( authenticationRepo: getIt(), diff --git a/lib/presentation/home/data/landing_page_data.dart b/lib/presentation/home/data/landing_page_data.dart index af43b9f..8474422 100644 --- a/lib/presentation/home/data/landing_page_data.dart +++ b/lib/presentation/home/data/landing_page_data.dart @@ -8,6 +8,7 @@ import 'package:hmg_patient_app_new/theme/colors.dart'; class LandingPageData { static List getNotLoggedInServiceCardsList = [ ServiceCardData( + serviceName: "emergency", icon: AppAssets.emergency_services_icon, title: "Emergency", subtitle: "Services", @@ -17,6 +18,7 @@ class LandingPageData { isBold: true, ), ServiceCardData( + serviceName: "indoor_navigation", icon: AppAssets.indoor_nav_icon, title: "Indoor", subtitle: "Navigation", @@ -26,6 +28,7 @@ class LandingPageData { isBold: false, ), ServiceCardData( + serviceName: "search_doctor", icon: AppAssets.search_doctor_icon, title: "Search", subtitle: "Doctor", @@ -35,6 +38,7 @@ class LandingPageData { isBold: false, ), ServiceCardData( + serviceName: "health_calculators", icon: AppAssets.health_calculators_icon, title: "Health", subtitle: "Calculators", @@ -44,6 +48,7 @@ class LandingPageData { isBold: false, ), ServiceCardData( + serviceName: "health_converters", icon: AppAssets.health_calculators_icon, title: "Health", subtitle: "Converters", @@ -53,6 +58,7 @@ class LandingPageData { isBold: false, ), ServiceCardData( + serviceName: "parking_guide", icon: AppAssets.health_calculators_icon, title: "Parking", subtitle: "Guide", @@ -65,6 +71,7 @@ class LandingPageData { static List getLoggedInServiceCardsList = [ ServiceCardData( + serviceName: "emergency", icon: AppAssets.emergency_services_icon, title: "Emergency", subtitle: "Services", @@ -74,6 +81,7 @@ class LandingPageData { isBold: true, ), ServiceCardData( + serviceName: "lab_results", icon: AppAssets.lab_result_icon, title: "My Lab", subtitle: "Results", @@ -83,6 +91,17 @@ class LandingPageData { isBold: false, ), ServiceCardData( + serviceName: "radiology_results", + icon: AppAssets.lab_result_icon, + title: "My Radiology", + subtitle: "Results", + backgroundColor: AppColors.whiteColor, + iconColor: AppColors.blackColor, + textColor: AppColors.blackColor, + isBold: false, + ), + ServiceCardData( + serviceName: "prescriptions", icon: AppAssets.my_prescription_icon, title: "My", subtitle: "Prescriptions", @@ -92,6 +111,7 @@ class LandingPageData { isBold: false, ), ServiceCardData( + serviceName: "insurance_update", icon: AppAssets.insurance_update_icon, title: "Insurance", subtitle: "Update", @@ -101,6 +121,7 @@ class LandingPageData { isBold: false, ), ServiceCardData( + serviceName: "my_doctors", icon: AppAssets.insurance_update_icon, title: "My", subtitle: "Doctors", @@ -110,6 +131,7 @@ class LandingPageData { isBold: false, ), ServiceCardData( + serviceName: "sick_leaves", icon: AppAssets.insurance_update_icon, title: "My Sick", subtitle: "Leaves", diff --git a/lib/presentation/home/data/service_card_data.dart b/lib/presentation/home/data/service_card_data.dart index 856a15e..49e7e3d 100644 --- a/lib/presentation/home/data/service_card_data.dart +++ b/lib/presentation/home/data/service_card_data.dart @@ -3,6 +3,7 @@ import 'dart:ui'; import 'package:hmg_patient_app_new/theme/colors.dart'; class ServiceCardData { + final String serviceName; final String icon; final String title; final String subtitle; @@ -13,6 +14,7 @@ class ServiceCardData { final String largeCardIcon; ServiceCardData({ + this.serviceName = "", this.icon = "", this.title = "", this.subtitle = "", diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index 8421856..a1707fa 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.dart @@ -155,6 +155,7 @@ class _LandingPageState extends State { horizontalOffset: 100.0, child: FadeInAnimation( child: SmallServiceCard( + serviceName: LandingPageData.getLoggedInServiceCardsList[index].serviceName, icon: LandingPageData.getLoggedInServiceCardsList[index].icon, title: LandingPageData.getLoggedInServiceCardsList[index].title, subtitle: LandingPageData.getLoggedInServiceCardsList[index].subtitle, diff --git a/lib/presentation/home/widgets/small_service_card.dart b/lib/presentation/home/widgets/small_service_card.dart index a138db6..0983a06 100644 --- a/lib/presentation/home/widgets/small_service_card.dart +++ b/lib/presentation/home/widgets/small_service_card.dart @@ -2,11 +2,14 @@ import 'package:flutter/material.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/presentation/lab/lab_orders_page.dart'; +import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart'; import '../../../core/utils/utils.dart'; import '../../../theme/colors.dart'; class SmallServiceCard extends StatelessWidget { + final String serviceName; final String icon; final String title; final String subtitle; @@ -18,6 +21,7 @@ class SmallServiceCard extends StatelessWidget { SmallServiceCard({ super.key, this.icon = "", + this.serviceName = "", this.title = "", this.subtitle = "", this.backgroundColor = AppColors.whiteColor, @@ -48,6 +52,25 @@ class SmallServiceCard extends StatelessWidget { ), ), ), - ); + ).onPress(() { + switch (serviceName) { + case "lab_results": + Navigator.of(context).push( + FadePage( + page: LabOrdersPage(), + ), + ); + break; + case "radiology_results": + break; + case "prescriptions": + break; + case "insurance_update": + break; + default: + // Handle unknown service + break; + } + }); } } diff --git a/lib/presentation/lab/lab_orders_page.dart b/lib/presentation/lab/lab_orders_page.dart new file mode 100644 index 0000000..bc7ff61 --- /dev/null +++ b/lib/presentation/lab/lab_orders_page.dart @@ -0,0 +1,173 @@ +import 'dart:async'; + +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/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/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/features/lab/lab_view_model.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/shimmer/movies_shimmer_widget.dart'; +import 'package:provider/provider.dart'; + +class LabOrdersPage extends StatefulWidget { + const LabOrdersPage({super.key}); + + @override + State createState() => _LabOrdersPageState(); +} + +class _LabOrdersPageState extends State { + late LabViewModel labProvider; + + int? expandedIndex; + + // Sample data for demonstration + final List labOrders = [ + 'Blood Test', + 'Urine Test', + 'X-Ray', + 'MRI', + ]; + + @override + void initState() { + scheduleMicrotask(() { + labProvider.initLabProvider(); + }); + super.initState(); + } + + @override + Widget build(BuildContext context) { + labProvider = Provider.of(context); + return Scaffold( + backgroundColor: AppColors.bgScaffoldColor, + appBar: AppBar( + title: const Text('Lab Results'), + backgroundColor: AppColors.bgScaffoldColor, + ), + body: Padding( + padding: EdgeInsets.all(24.h), + child: SingleChildScrollView( + child: Consumer( + builder: (context, model, child) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + LocaleKeys.labResults.tr(context: context).toText24(isBold: true), + Utils.buildSvgWithAssets(icon: AppAssets.search_icon), + ], + ), + SizedBox(height: 16.h), + // Build Tab Bar + SizedBox(height: 16.h), + // Expandable list + ListView.builder( + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemCount: model.isLabOrdersLoading ? 5 : labOrders.length, + itemBuilder: (context, index) { + final isExpanded = expandedIndex == index; + return model.isLabOrdersLoading + ? const MoviesShimmerWidget() + : 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, + margin: EdgeInsets.symmetric(vertical: 8.h), + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 20.h, + ), + child: InkWell( + onTap: () { + setState(() { + expandedIndex = isExpanded ? null : index; + }); + }, + child: Column( + children: [ + Padding( + padding: EdgeInsets.all(16.h), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + CustomButton( + text: LocaleKeys.pending.tr(context: context), + onPressed: () {}, + backgroundColor: getLabOrderStatusColor(44).withOpacity(0.15), + borderColor: getLabOrderStatusColor(44).withOpacity(0.01), + textColor: getLabOrderStatusColor(44), + fontSize: 10, + fontWeight: FontWeight.normal, + borderRadius: 8, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 30.h, + ), + Icon(isExpanded ? Icons.expand_less : Icons.expand_more), + ], + ), + SizedBox(height: 8.h), + Text(labOrders[index], style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), + ], + ), + ), + AnimatedCrossFade( + firstChild: SizedBox.shrink(), + secondChild: Padding( + padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 8.h), + child: Text('Details for ${labOrders[index]}'), + ), + crossFadeState: isExpanded ? CrossFadeState.showSecond : CrossFadeState.showFirst, + duration: Duration(milliseconds: 300), + ), + ], + ), + ), + ), + ), + ), + ); + }, + ), + ], + ); + }, + ), + ), + ), + ); + } + + Color getLabOrderStatusColor(num status) { + switch (status) { + case 44: + return AppColors.warningColorYellow; + case 45: + return AppColors.warningColorYellow; + case 16: + return AppColors.successColor; + case 17: + return AppColors.successColor; + default: + return AppColors.greyColor; + } + } +} diff --git a/lib/presentation/medical_file/medical_file_page.dart b/lib/presentation/medical_file/medical_file_page.dart index 6635ef5..7fa4fe9 100644 --- a/lib/presentation/medical_file/medical_file_page.dart +++ b/lib/presentation/medical_file/medical_file_page.dart @@ -87,9 +87,6 @@ class MedicalFilePage extends StatelessWidget { ), SizedBox(width: 4.h), CustomButton( - icon: AppAssets.checkmark_icon, - iconColor: AppColors.successColor, - iconSize: 13.h, text: LocaleKeys.verified.tr(context: context), onPressed: () {}, backgroundColor: AppColors.greyColor, diff --git a/lib/theme/colors.dart b/lib/theme/colors.dart index a6b3362..8b388f1 100644 --- a/lib/theme/colors.dart +++ b/lib/theme/colors.dart @@ -31,6 +31,7 @@ class AppColors { static const Color textColor = Color(0xFF2E3039); static const Color borderOnlyColor = Color(0xFF2E3039); static const Color dividerColor = Color(0xFFD2D2D2); + static const Color warningColorYellow = Color(0xFFF4A308); //Chips static const Color successColor = Color(0xff18C273); From a77fc49c68824cbb2c140409637c660319696af9 Mon Sep 17 00:00:00 2001 From: Haroon Amjad <> Date: Tue, 2 Sep 2025 22:45:47 +0300 Subject: [PATCH 5/6] lab result changes --- lib/core/api/api_client.dart | 7 +- lib/core/api_consts.dart | 4 +- lib/core/dependencies.dart | 14 +- lib/features/lab/lab_repo.dart | 58 ++- lib/features/lab/lab_view_model.dart | 38 +- .../patient_lab_orders_response_model.dart | 126 +++++ lib/main.dart | 9 +- lib/presentation/home/landing_page.dart | 441 +++++++++--------- lib/presentation/lab/lab_orders_page.dart | 53 ++- lib/providers/bottom_navigation_provider.dart | 12 - 10 files changed, 501 insertions(+), 261 deletions(-) create mode 100644 lib/features/lab/models/resp_models/patient_lab_orders_response_model.dart delete mode 100644 lib/providers/bottom_navigation_provider.dart diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index 53bd522..b3ea487 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -134,9 +134,7 @@ class ApiClientImp implements ApiClient { } if (body.containsKey('isDentalAllowedBackend')) { - body['isDentalAllowedBackend'] = body.containsKey('isDentalAllowedBackend') - ? body['isDentalAllowedBackend'] ?? IS_DENTAL_ALLOWED_BACKEND - : IS_DENTAL_ALLOWED_BACKEND; + body['isDentalAllowedBackend'] = body.containsKey('isDentalAllowedBackend') ? body['isDentalAllowedBackend'] ?? IS_DENTAL_ALLOWED_BACKEND : IS_DENTAL_ALLOWED_BACKEND; } //Todo: I have converted it to string @@ -229,8 +227,7 @@ class ApiClientImp implements ApiClient { } else if (parsed['Result'] == 'OK') { onSuccess(parsed, statusCode); } else { - onFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode, - failureType: ServerFailure("Error While Fetching data")); + 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) { diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index 6f82e26..6e1e92a 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -17,8 +17,8 @@ var PACKAGES_ORDERS = '/api/orders'; var PACKAGES_ORDER_HISTORY = '/api/orders/items'; var PACKAGES_TAMARA_OPT = '/api/orders/paymentoptions/tamara'; // var BASE_URL = 'http://10.50.100.198:2018/'; -var BASE_URL = 'https://uat.hmgwebservices.com/'; -// var BASE_URL = 'https://hmgwebservices.com/'; +// var BASE_URL = 'https://uat.hmgwebservices.com/'; +var BASE_URL = 'https://hmgwebservices.com/'; // var BASE_URL = 'http://10.201.204.103/'; // var BASE_URL = 'https://orash.cloudsolutions.com.sa/'; // var BASE_URL = 'https://vidauat.cloudsolutions.com.sa/'; diff --git a/lib/core/dependencies.dart b/lib/core/dependencies.dart index 549eeed..dca08fc 100644 --- a/lib/core/dependencies.dart +++ b/lib/core/dependencies.dart @@ -6,6 +6,8 @@ import 'package:hmg_patient_app_new/features/authentication/authentication_repo. import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart'; import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_repo.dart'; import 'package:hmg_patient_app_new/features/common/common_repo.dart'; +import 'package:hmg_patient_app_new/features/lab/lab_repo.dart'; +import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_repo.dart'; import 'package:hmg_patient_app_new/services/analytics/analytics_service.dart'; import 'package:hmg_patient_app_new/services/cache_service.dart'; @@ -54,12 +56,20 @@ class AppDependencies { // Repositories getIt.registerLazySingleton(() => CommonRepoImp(loggerService: getIt())); getIt.registerLazySingleton(() => AuthenticationRepoImp(loggerService: getIt(), apiClient: getIt())); - getIt.registerLazySingleton( - () => BookAppointmentsRepoImp(loggerService: getIt(), apiClient: getIt())); + getIt.registerLazySingleton(() => BookAppointmentsRepoImp(loggerService: getIt(), apiClient: getIt())); getIt.registerLazySingleton(() => MyAppointmentsRepoImp(loggerService: getIt(), apiClient: getIt())); + getIt.registerLazySingleton(() => LabRepoImp(loggerService: getIt(), apiClient: getIt())); // ViewModels // Global/shared VMs → LazySingleton + + getIt.registerLazySingleton( + () => LabViewModel( + labRepo: getIt(), + errorHandlerService: getIt(), + ), + ); + getIt.registerLazySingleton( () => AuthenticationViewModel( authenticationRepo: getIt(), diff --git a/lib/features/lab/lab_repo.dart b/lib/features/lab/lab_repo.dart index f651a71..061506a 100644 --- a/lib/features/lab/lab_repo.dart +++ b/lib/features/lab/lab_repo.dart @@ -1,9 +1,59 @@ +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/exceptions/api_failure.dart'; import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart'; import 'package:dartz/dartz.dart'; +import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_orders_response_model.dart'; +import 'package:hmg_patient_app_new/services/logger_service.dart'; -abstract class AuthenticationRepo { - Future>> getPatientLabOrders({ - required String firebaseToken, - }); +abstract class LabRepo { + Future>>> getPatientLabOrders({required num patientId}); +} + +class LabRepoImp implements LabRepo { + final ApiClient apiClient; + final LoggerService loggerService; + + LabRepoImp({required this.loggerService, required this.apiClient}); + + @override + Future>>> getPatientLabOrders({required num patientId}) async { + final mapDevice = {"PatientID": patientId}; + + try { + GenericApiModel>? apiResponse; + Failure? failure; + await apiClient.post( + GET_Patient_LAB_ORDERS, + body: mapDevice, + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, + onSuccess: (response, statusCode, {messageStatus}) { + try { + final list = response['ListPLO']; + if (list == null || list.isEmpty) { + throw Exception("lab list is empty"); + } + + final labOrders = list.map((item) => PatientLabOrdersResponseModel.fromJson(item as Map)).toList(); + + apiResponse = GenericApiModel>( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: null, + data: labOrders, + ); + } 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/lab/lab_view_model.dart b/lib/features/lab/lab_view_model.dart index f0ebad3..73f8b13 100644 --- a/lib/features/lab/lab_view_model.dart +++ b/lib/features/lab/lab_view_model.dart @@ -1,13 +1,45 @@ import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/features/lab/lab_repo.dart'; +import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_orders_response_model.dart'; +import 'package:hmg_patient_app_new/services/error_handler_service.dart'; class LabViewModel extends ChangeNotifier { - bool isLabOrdersLoading = false; bool isLabResultsLoading = false; + LabRepo labRepo; + ErrorHandlerService errorHandlerService; + + List patientLabOrders = []; + + LabViewModel({required this.labRepo, required this.errorHandlerService}); + initLabProvider() { - isLabOrdersLoading = true; - isLabResultsLoading = true; + patientLabOrders.clear(); + // isLabOrdersLoading = true; + // isLabResultsLoading = true; + // getPatientLabOrders(); notifyListeners(); } + + Future getPatientLabOrders({Function(dynamic)? onSuccess, Function(String)? onError}) async { + final result = await labRepo.getPatientLabOrders(patientId: 1231755); + + 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) { + patientLabOrders = apiResponse.data!; + isLabOrdersLoading = false; + isLabResultsLoading = false; + notifyListeners(); + if (onSuccess != null) { + onSuccess(apiResponse); + } + } + }, + ); + } } 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 new file mode 100644 index 0000000..5cd8fbd --- /dev/null +++ b/lib/features/lab/models/resp_models/patient_lab_orders_response_model.dart @@ -0,0 +1,126 @@ +class PatientLabOrdersResponseModel { + String? description; + dynamic femaleInterpretativeData; + int? gender; + bool? isCertificateAllowed; + int? lineItemNo; + dynamic maleInterpretativeData; + dynamic notes; + int? orderLineItemNo; + int? orderNo; + String? packageID; + int? patientID; + String? projectID; + String? referanceRange; + String? resultValue; + int? resultValueBasedLineItemNo; + String? resultValueFlag; + String? sampleCollectedOn; + String? sampleReceivedOn; + String? setupID; + dynamic superVerifiedOn; + String? testCode; + String? uOM; + String? verifiedOn; + String? packageShortDescription; + String? testShortDescription; + dynamic verifiedOnDateTime; + num? percentage; + num? width; + num? resultTypeID; + + PatientLabOrdersResponseModel( + {this.description, + this.femaleInterpretativeData, + this.gender, + this.isCertificateAllowed, + this.lineItemNo, + this.maleInterpretativeData, + this.notes, + this.orderLineItemNo, + this.orderNo, + this.packageID, + this.patientID, + this.projectID, + this.referanceRange, + this.resultValue, + this.resultValueBasedLineItemNo, + this.resultValueFlag, + this.sampleCollectedOn, + this.sampleReceivedOn, + this.setupID, + this.superVerifiedOn, + this.testCode, + this.uOM, + this.verifiedOn, + this.verifiedOnDateTime}); + + PatientLabOrdersResponseModel.fromJson(Map json, {String? flag}) { + description = json['Description']; + femaleInterpretativeData = json['FemaleInterpretativeData']; + gender = json['Gender']; + isCertificateAllowed = json['IsCertificateAllowed']; + lineItemNo = json['LineItemNo']; + maleInterpretativeData = json['MaleInterpretativeData']; + notes = json['Notes']; + orderLineItemNo = json['OrderLineItemNo']; + orderNo = json['OrderNo']; + packageID = json['PackageID']; + patientID = json['PatientID']; + projectID = json['ProjectID']; + referanceRange = json['ReferanceRange']; + resultValue = json['ResultValue']; + resultValueBasedLineItemNo = json['ResultValueBasedLineItemNo']; + resultValueFlag = json['ResultValueFlag']; + sampleCollectedOn = json['SampleCollectedOn']; + sampleReceivedOn = json['SampleReceivedOn']; + 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']; + } + + Map toJson() { + final Map data = new Map(); + data['Description'] = this.description; + data['FemaleInterpretativeData'] = this.femaleInterpretativeData; + 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['OrderNo'] = this.orderNo; + data['PackageID'] = this.packageID; + 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['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; + + return data; + } + + bool shouldShowResultBarAndGraph() { + if (resultTypeID == null) return false; + if (resultTypeID == 6) return false; + + return true; + } +} diff --git a/lib/main.dart b/lib/main.dart index 1ea5d84..3f09649 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -7,7 +7,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart'; -import 'package:hmg_patient_app_new/providers/bottom_navigation_provider.dart'; import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart'; import 'package:hmg_patient_app_new/routes/app_routes.dart'; import 'package:hmg_patient_app_new/services/logger_service.dart'; @@ -52,11 +51,11 @@ void main() async { path: 'assets/langs', fallbackLocale: Locale('en', 'US'), child: MultiProvider(providers: [ - ChangeNotifierProvider( - create: (_) => BottomNavigationProvider(), - ), ChangeNotifierProvider( - create: (_) => LabViewModel(), + create: (_) => LabViewModel( + labRepo: getIt(), + errorHandlerService: getIt(), + ), ), ChangeNotifierProvider( create: (_) => AuthenticationViewModel( diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index a1707fa..f930dca 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.dart @@ -16,7 +16,6 @@ import 'package:hmg_patient_app_new/presentation/home/widgets/habib_wallet_card. import 'package:hmg_patient_app_new/presentation/home/widgets/large_service_card.dart'; import 'package:hmg_patient_app_new/presentation/home/widgets/small_service_card.dart'; import 'package:hmg_patient_app_new/presentation/medical_file/medical_file_page.dart'; -import 'package:hmg_patient_app_new/providers/bottom_navigation_provider.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/transitions/fade_page.dart'; @@ -34,247 +33,245 @@ class _LandingPageState extends State { Widget build(BuildContext context) { AppState appState = getIt.get(); final AuthenticationViewModel authenticationViewModel = context.read(); - return Consumer(builder: (context, navigationProvider, child) { - return Scaffold( - backgroundColor: AppColors.bgScaffoldColor, - body: Padding( - padding: EdgeInsets.all(24.h), - child: SingleChildScrollView( - child: Column( - children: [ - Padding( - padding: EdgeInsets.only(top: 50.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - CustomButton( - text: LocaleKeys.loginOrRegister.tr(context: context), - onPressed: () async { - await authenticationViewModel.selectDeviceImei(); - }, - backgroundColor: Color(0xffFEE9EA), - borderColor: Color(0xffFEE9EA), - textColor: Color(0xffED1C2B), - fontSize: 16, - fontWeight: FontWeight.w500, - borderRadius: 12, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 50, - ), - Utils.buildSvgWithAssets( - icon: AppAssets.contact_icon, - width: 24, - height: 24, - ).onPress(() { - Navigator.of(context).push( - FadePage( - page: MedicalFilePage(), - // page: LoginScreen(), - ), - ); - }), - ], - ), + return Scaffold( + backgroundColor: AppColors.bgScaffoldColor, + body: Padding( + padding: EdgeInsets.all(24.h), + child: SingleChildScrollView( + child: Column( + children: [ + Padding( + padding: EdgeInsets.only(top: 50.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + CustomButton( + text: LocaleKeys.loginOrRegister.tr(context: context), + onPressed: () async { + await authenticationViewModel.selectDeviceImei(); + }, + backgroundColor: Color(0xffFEE9EA), + borderColor: Color(0xffFEE9EA), + textColor: Color(0xffED1C2B), + fontSize: 16, + fontWeight: FontWeight.w500, + borderRadius: 12, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 50, + ), + Utils.buildSvgWithAssets( + icon: AppAssets.contact_icon, + width: 24, + height: 24, + ).onPress(() { + Navigator.of(context).push( + FadePage( + page: MedicalFilePage(), + // page: LoginScreen(), + ), + ); + }), + ], ), - SizedBox(height: 16.h), - appState.isAuthenticated - ? Column( - children: [ - Container( - width: double.infinity, - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 24, - ), - child: Padding( - padding: EdgeInsets.all(12.h), - child: Column( - children: [ - Utils.buildSvgWithAssets(icon: AppAssets.home_calendar_icon, width: 32.h, height: 32.h), - SizedBox(height: 12.h), - "You do not have any upcoming appointment. Please book an appointment".toText12(isCenter: true), - SizedBox(height: 12.h), - CustomButton( - text: LocaleKeys.bookAppo.tr(context: context), - onPressed: () { - Navigator.of(context).pushReplacement( - MaterialPageRoute(builder: (BuildContext context) => LandingPage()), - ); - }, - backgroundColor: Color(0xffFEE9EA), - borderColor: Color(0xffFEE9EA), - textColor: Color(0xffED1C2B), - fontSize: 14, - fontWeight: FontWeight.w500, - borderRadius: 12, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 40, - icon: AppAssets.add_icon, - iconColor: AppColors.primaryRedColor, - ), - ], - ), - ), + ), + SizedBox(height: 16.h), + appState.isAuthenticated + ? Column( + children: [ + Container( + width: double.infinity, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24, ), - SizedBox(height: 12.h), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - "Quick Links".toText16(isBold: true), - Row( - children: [ - "View medical file".toText12(color: AppColors.primaryRedColor), - SizedBox(width: 2.h), - Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 10.h), - ], - ), - ], + child: Padding( + padding: EdgeInsets.all(12.h), + child: Column( + children: [ + Utils.buildSvgWithAssets(icon: AppAssets.home_calendar_icon, width: 32.h, height: 32.h), + SizedBox(height: 12.h), + "You do not have any upcoming appointment. Please book an appointment".toText12(isCenter: true), + SizedBox(height: 12.h), + CustomButton( + text: LocaleKeys.bookAppo.tr(context: context), + onPressed: () { + Navigator.of(context).pushReplacement( + MaterialPageRoute(builder: (BuildContext context) => LandingPage()), + ); + }, + backgroundColor: Color(0xffFEE9EA), + borderColor: Color(0xffFEE9EA), + textColor: Color(0xffED1C2B), + fontSize: 14, + fontWeight: FontWeight.w500, + borderRadius: 12, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 40, + icon: AppAssets.add_icon, + iconColor: AppColors.primaryRedColor, + ), + ], + ), ), - SizedBox(height: 12.h), - Container( - height: 127.h, - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 24, + ), + SizedBox(height: 12.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + "Quick Links".toText16(isBold: true), + Row( + children: [ + "View medical file".toText12(color: AppColors.primaryRedColor), + SizedBox(width: 2.h), + Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 10.h), + ], ), - child: Padding( - padding: EdgeInsets.all(16.h), - child: Column( - children: [ - Expanded( - child: ListView.separated( - scrollDirection: Axis.horizontal, - itemCount: LandingPageData.getLoggedInServiceCardsList.length, - shrinkWrap: true, - padding: const EdgeInsets.only(left: 0, right: 8), - itemBuilder: (context, index) { - return AnimationConfiguration.staggeredList( - position: index, - duration: const Duration(milliseconds: 1000), - child: SlideAnimation( - horizontalOffset: 100.0, - child: FadeInAnimation( - child: SmallServiceCard( - serviceName: LandingPageData.getLoggedInServiceCardsList[index].serviceName, - icon: LandingPageData.getLoggedInServiceCardsList[index].icon, - title: LandingPageData.getLoggedInServiceCardsList[index].title, - subtitle: LandingPageData.getLoggedInServiceCardsList[index].subtitle, - iconColor: LandingPageData.getLoggedInServiceCardsList[index].iconColor, - textColor: LandingPageData.getLoggedInServiceCardsList[index].textColor, - backgroundColor: LandingPageData.getLoggedInServiceCardsList[index].backgroundColor, - isBold: LandingPageData.getLoggedInServiceCardsList[index].isBold, - ), + ], + ), + SizedBox(height: 12.h), + Container( + height: 127.h, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24, + ), + child: Padding( + padding: EdgeInsets.all(16.h), + child: Column( + children: [ + Expanded( + child: ListView.separated( + scrollDirection: Axis.horizontal, + itemCount: LandingPageData.getLoggedInServiceCardsList.length, + shrinkWrap: true, + padding: const EdgeInsets.only(left: 0, right: 8), + itemBuilder: (context, index) { + return AnimationConfiguration.staggeredList( + position: index, + duration: const Duration(milliseconds: 1000), + child: SlideAnimation( + horizontalOffset: 100.0, + child: FadeInAnimation( + child: SmallServiceCard( + serviceName: LandingPageData.getLoggedInServiceCardsList[index].serviceName, + icon: LandingPageData.getLoggedInServiceCardsList[index].icon, + title: LandingPageData.getLoggedInServiceCardsList[index].title, + subtitle: LandingPageData.getLoggedInServiceCardsList[index].subtitle, + iconColor: LandingPageData.getLoggedInServiceCardsList[index].iconColor, + textColor: LandingPageData.getLoggedInServiceCardsList[index].textColor, + backgroundColor: LandingPageData.getLoggedInServiceCardsList[index].backgroundColor, + isBold: LandingPageData.getLoggedInServiceCardsList[index].isBold, ), ), - ); - }, - separatorBuilder: (BuildContext cxt, int index) => 0.width, - ), + ), + ); + }, + separatorBuilder: (BuildContext cxt, int index) => 0.width, ), - ], - ), + ), + ], ), - ) - ], - ) - : Container( - height: 127.h, - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 24, - ), - child: Padding( - padding: EdgeInsets.all(16.h), - child: Column( - children: [ - Expanded( - child: ListView.separated( - scrollDirection: Axis.horizontal, - itemCount: LandingPageData.getNotLoggedInServiceCardsList.length, - shrinkWrap: true, - padding: const EdgeInsets.only(left: 0, right: 8), - itemBuilder: (context, index) { - return AnimationConfiguration.staggeredList( - position: index, - duration: const Duration(milliseconds: 1000), - child: SlideAnimation( - horizontalOffset: 100.0, - child: FadeInAnimation( - child: SmallServiceCard( - icon: LandingPageData.getNotLoggedInServiceCardsList[index].icon, - title: LandingPageData.getNotLoggedInServiceCardsList[index].title, - subtitle: LandingPageData.getNotLoggedInServiceCardsList[index].subtitle, - iconColor: LandingPageData.getNotLoggedInServiceCardsList[index].iconColor, - textColor: LandingPageData.getNotLoggedInServiceCardsList[index].textColor, - backgroundColor: LandingPageData.getNotLoggedInServiceCardsList[index].backgroundColor, - isBold: LandingPageData.getNotLoggedInServiceCardsList[index].isBold, - ), + ), + ) + ], + ) + : Container( + height: 127.h, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24, + ), + child: Padding( + padding: EdgeInsets.all(16.h), + child: Column( + children: [ + Expanded( + child: ListView.separated( + scrollDirection: Axis.horizontal, + itemCount: LandingPageData.getNotLoggedInServiceCardsList.length, + shrinkWrap: true, + padding: const EdgeInsets.only(left: 0, right: 8), + itemBuilder: (context, index) { + return AnimationConfiguration.staggeredList( + position: index, + duration: const Duration(milliseconds: 1000), + child: SlideAnimation( + horizontalOffset: 100.0, + child: FadeInAnimation( + child: SmallServiceCard( + icon: LandingPageData.getNotLoggedInServiceCardsList[index].icon, + title: LandingPageData.getNotLoggedInServiceCardsList[index].title, + subtitle: LandingPageData.getNotLoggedInServiceCardsList[index].subtitle, + iconColor: LandingPageData.getNotLoggedInServiceCardsList[index].iconColor, + textColor: LandingPageData.getNotLoggedInServiceCardsList[index].textColor, + backgroundColor: LandingPageData.getNotLoggedInServiceCardsList[index].backgroundColor, + isBold: LandingPageData.getNotLoggedInServiceCardsList[index].isBold, ), ), - ); - }, - separatorBuilder: (BuildContext cxt, int index) => 0.width, - ), + ), + ); + }, + separatorBuilder: (BuildContext cxt, int index) => 0.width, ), - ], - ), + ), + ], ), ), - SizedBox(height: 16.h), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - "Services".toText16(isBold: true), - Row( - children: [ - "View all services".toText12(color: AppColors.primaryRedColor), - SizedBox(width: 2.h), - Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 10.h), - ], ), - ], - ), - SizedBox(height: 16.h), - SizedBox( - height: 325.h, - child: Column( + SizedBox(height: 16.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + "Services".toText16(isBold: true), + Row( children: [ - Expanded( - child: ListView.separated( - scrollDirection: Axis.horizontal, - itemCount: LandingPageData.getServiceCardsList.length, - shrinkWrap: true, - padding: const EdgeInsets.only(left: 0, right: 8), - itemBuilder: (context, index) { - return AnimationConfiguration.staggeredList( - position: index, - duration: const Duration(milliseconds: 1000), - child: SlideAnimation( - horizontalOffset: 100.0, - child: FadeInAnimation( - child: LargeServiceCard( - image: LandingPageData.getServiceCardsList[index].icon, - title: LandingPageData.getServiceCardsList[index].title, - subtitle: LandingPageData.getServiceCardsList[index].subtitle, - icon: LandingPageData.getServiceCardsList[index].largeCardIcon, - ), + "View all services".toText12(color: AppColors.primaryRedColor), + SizedBox(width: 2.h), + Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 10.h), + ], + ), + ], + ), + SizedBox(height: 16.h), + SizedBox( + height: 325.h, + child: Column( + children: [ + Expanded( + child: ListView.separated( + scrollDirection: Axis.horizontal, + itemCount: LandingPageData.getServiceCardsList.length, + shrinkWrap: true, + padding: const EdgeInsets.only(left: 0, right: 8), + itemBuilder: (context, index) { + return AnimationConfiguration.staggeredList( + position: index, + duration: const Duration(milliseconds: 1000), + child: SlideAnimation( + horizontalOffset: 100.0, + child: FadeInAnimation( + child: LargeServiceCard( + image: LandingPageData.getServiceCardsList[index].icon, + title: LandingPageData.getServiceCardsList[index].title, + subtitle: LandingPageData.getServiceCardsList[index].subtitle, + icon: LandingPageData.getServiceCardsList[index].largeCardIcon, ), ), - ); - }, - separatorBuilder: (BuildContext cxt, int index) => 0.width, - ), + ), + ); + }, + separatorBuilder: (BuildContext cxt, int index) => 0.width, ), - ], - ), + ), + ], ), - SizedBox(height: 16.h), - appState.isAuthenticated ? HabibWalletCard() : SizedBox(), - ], - ), + ), + SizedBox(height: 16.h), + appState.isAuthenticated ? HabibWalletCard() : SizedBox(), + ], ), ), - ); - }); + ), + ); } } diff --git a/lib/presentation/lab/lab_orders_page.dart b/lib/presentation/lab/lab_orders_page.dart index bc7ff61..e0143ca 100644 --- a/lib/presentation/lab/lab_orders_page.dart +++ b/lib/presentation/lab/lab_orders_page.dart @@ -29,10 +29,10 @@ class _LabOrdersPageState extends State { // Sample data for demonstration final List labOrders = [ - 'Blood Test', - 'Urine Test', - 'X-Ray', - 'MRI', + 'Mohammad Al Harbi', + 'Mohammad Al Harbi', + 'Mohammad Al Harbi', + 'Mohammad Al Harbi', ]; @override @@ -116,7 +116,7 @@ class _LabOrdersPageState extends State { borderColor: getLabOrderStatusColor(44).withOpacity(0.01), textColor: getLabOrderStatusColor(44), fontSize: 10, - fontWeight: FontWeight.normal, + fontWeight: FontWeight.w500, borderRadius: 8, padding: EdgeInsets.fromLTRB(10, 0, 10, 0), height: 30.h, @@ -125,7 +125,48 @@ class _LabOrdersPageState extends State { ], ), SizedBox(height: 8.h), - Text(labOrders[index], style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), + Row( + children: [ + Image.network( + "https://hmgwebservices.com/Images/MobileImages/SUWAIDI/152305.png", + 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)), + ], + ), + SizedBox(height: 8.h), + Row( + children: [ + CustomButton( + text: "12th June, 2025", + onPressed: () {}, + backgroundColor: AppColors.greyColor, + borderColor: AppColors.greyColor, + textColor: AppColors.blackColor, + fontSize: 12, + fontWeight: FontWeight.w500, + borderRadius: 8, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 24.h, + ), + SizedBox(width: 8.h), + CustomButton( + text: "Clinic: Cardiology", + onPressed: () {}, + backgroundColor: AppColors.greyColor, + borderColor: AppColors.greyColor, + textColor: AppColors.blackColor, + fontSize: 12, + fontWeight: FontWeight.w500, + borderRadius: 8, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 24.h, + ), + ], + ), ], ), ), diff --git a/lib/providers/bottom_navigation_provider.dart b/lib/providers/bottom_navigation_provider.dart deleted file mode 100644 index 58a0d4e..0000000 --- a/lib/providers/bottom_navigation_provider.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:flutter/material.dart'; - -class BottomNavigationProvider extends ChangeNotifier { - int _currentIndex = 0; - - int get currentIndex => _currentIndex; - - void setIndex(int index) { - _currentIndex = index; - notifyListeners(); - } -} \ No newline at end of file From f5e655fd35df6b230385e9110c2e819c1bce9f67 Mon Sep 17 00:00:00 2001 From: Haroon Amjad <> Date: Tue, 2 Sep 2025 23:25:45 +0300 Subject: [PATCH 6/6] 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),