diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index 30f06cf..64d9d28 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -838,13 +838,19 @@ class ApiConsts { static final String createAdvancePayments = 'Services/Patients.svc/REST/HIS_CreateAdvancePayment'; static final String addAdvanceNumberRequest = 'Services/PayFort_Serv.svc/REST/AddAdvancedNumberRequest'; - // RC CMC ServIces + // RC COMPREHENSIVE MEDICAL CHECKUP ServIces static final String allCMCOrdersRc = 'api/cmc/list'; static final String allCMCServicesRc = 'api/cmc/getallcmc'; static final String updateCMCOrder = 'api/cmc/update'; static final String addCMCOrder = 'api/cmc/add'; static final String getHospitalsList = 'Services/Lists.svc/REST/GetProject'; + // RC HOME HEALTHCARE ServIces + static final String allHHCOrdersRc = 'api/hhc/list'; + static final String allHHCServicesRc = 'api/HHC/getallhhc'; + static final String updateHHCOrder = 'api/hhc/update'; + static final String addHHCOrder = 'api/HHC/add'; + // ************ static values for Api **************** static final double appVersionID = 20.0; static final int appChannelId = 3; diff --git a/lib/extensions/widget_extensions.dart b/lib/extensions/widget_extensions.dart index 424aa88..70f10bb 100644 --- a/lib/extensions/widget_extensions.dart +++ b/lib/extensions/widget_extensions.dart @@ -1,9 +1,8 @@ -import 'package:hmg_patient_app_new/core/enums.dart'; -import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; +import 'package:hmg_patient_app_new/core/enums.dart'; import 'package:hmg_patient_app_new/extensions/int_extensions.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:shimmer/shimmer.dart'; import 'package:sizer/sizer.dart'; import 'package:smooth_corner/smooth_corner.dart'; @@ -19,7 +18,8 @@ extension WidgetExtensions on Widget { Widget paddingAll(double _value) => Padding(padding: EdgeInsets.all(_value), child: this); - Widget paddingSymmetrical(double horizontal, double vertical) => Padding(padding: EdgeInsets.symmetric(horizontal: horizontal, vertical: vertical), child: this); + Widget paddingSymmetrical(double horizontal, double vertical) => + Padding(padding: EdgeInsets.symmetric(horizontal: horizontal, vertical: vertical), child: this); Widget paddingOnly({double left = 0.0, double right = 0.0, double top = 0.0, double bottom = 0.0}) => Padding(padding: EdgeInsetsDirectional.only(start: left, end: right, top: top, bottom: bottom), child: this); @@ -99,7 +99,7 @@ extension WidgetExtensions on Widget { bool disablePadding = false, double radius = 20, Color? color, - Color borderColor = AppColors.buttonColor, + Color? borderColor, bool disableWidth = false, bool isAlignment = false}) { return Container( @@ -110,7 +110,7 @@ extension WidgetExtensions on Widget { ), color: color, border: Border.all( - color: borderColor, + color: borderColor ?? Colors.transparent, width: disableWidth ? 2 : 1, ), ), diff --git a/lib/features/hmg_services/hmg_services_repo.dart b/lib/features/hmg_services/hmg_services_repo.dart index b9ad0a4..254d309 100644 --- a/lib/features/hmg_services/hmg_services_repo.dart +++ b/lib/features/hmg_services/hmg_services_repo.dart @@ -13,12 +13,18 @@ import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/ import 'package:hmg_patient_app_new/services/logger_service.dart'; abstract class HmgServicesRepo { - Future>>> getAllCmcOrders(); + Future>>> getAllComprehensiveCheckupOrders(); + + Future>>> getAllHomeHealthCareCheckupOrders(); Future>> updateCmcPresOrder(OrderUpdateRequestModel requestModel); + Future>> updateHhcPresOrder(OrderUpdateRequestModel requestModel); + Future>>> getAllCmcServices({required int patientID}); + Future>>> getAllHhcServices({required int patientID}); + Future>>> getHospitalsList(); Future>> addCmcOrder({ @@ -26,6 +32,12 @@ abstract class HmgServicesRepo { required int orderServiceID, required List services, }); + + Future>> addHhcOrder({ + required int projectID, + required int orderServiceID, + required List services, + }); } class HmgServicesRepoImp implements HmgServicesRepo { @@ -35,7 +47,7 @@ class HmgServicesRepoImp implements HmgServicesRepo { HmgServicesRepoImp({required this.apiClient, required this.loggerService}); @override - Future>>> getAllCmcOrders() async { + Future>>> getAllComprehensiveCheckupOrders() async { Map requestBody = {}; try { @@ -93,6 +105,65 @@ class HmgServicesRepoImp implements HmgServicesRepo { } } + @override + Future>>> getAllHomeHealthCareCheckupOrders() async { + Map requestBody = {}; + + try { + GenericApiModel>? apiResponse; + Failure? failure; + + await apiClient.post( + ApiConsts.allHHCOrdersRc, + isRCService: true, + body: requestBody, + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + loggerService.logError("HHC Orders API Failed: $error, Status: $statusCode"); + }, + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + try { + List cmcOrdersList = []; + // Log the full response for debugging + // Extract MessageStatus and ErrorEndUserMessage from root level + final apiErrorMessage = response['ErrorEndUserMessage'] as String?; + // Parse the response array + if (response['response'] != null && response['response'] is List) { + final ordersList = response['response'] as List; + + for (var orderJson in ordersList) { + if (orderJson is Map) { + try { + cmcOrdersList.add(GetCMCAllOrdersResponseModel.fromJson(orderJson)); + } catch (e) { + loggerService.logError("Error parsing individual order: ${e.toString()}"); + } + } + } + } + + apiResponse = GenericApiModel>( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: apiErrorMessage ?? errorMessage, + data: cmcOrdersList, + ); + } catch (e) { + loggerService.logError("Error parsing HHC orders: ${e.toString()}"); + failure = DataParsingFailure(e.toString()); + } + }, + ); + + if (failure != null) return Left(failure!); + if (apiResponse == null) return Left(ServerFailure("Unknown error")); + return Right(apiResponse!); + } catch (e) { + loggerService.logError("Unknown error in getAllHHCOrders: ${e.toString()}"); + return Left(UnknownFailure(e.toString())); + } + } + @override Future>>> getAllCmcServices({required int patientID}) async { Map requestBody = {}; @@ -146,6 +217,59 @@ class HmgServicesRepoImp implements HmgServicesRepo { } } + @override + Future>>> getAllHhcServices({required int patientID}) async { + Map requestBody = {}; + + try { + GenericApiModel>? apiResponse; + Failure? failure; + + await apiClient.post( + '${ApiConsts.allHHCServicesRc}?patientID=$patientID', + isRCService: true, + isAllowAny: true, + body: requestBody, + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + loggerService.logError("HHC Services API Failed: $error, Status: $statusCode"); + }, + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + try { + List hhcServicesList = []; + + if (response['response'] != null && response['response'] is List) { + final servicesList = response['response'] as List; + + for (var serviceJson in servicesList) { + if (serviceJson is Map) { + hhcServicesList.add(GetCMCServicesResponseModel.fromJson(serviceJson)); + } + } + } + + apiResponse = GenericApiModel>( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: errorMessage, + data: hhcServicesList, + ); + } catch (e) { + loggerService.logError("Error parsing HHC services: ${e.toString()}"); + failure = DataParsingFailure(e.toString()); + } + }, + ); + + if (failure != null) return Left(failure!); + if (apiResponse == null) return Left(ServerFailure("Unknown error")); + return Right(apiResponse!); + } catch (e) { + log("Unknown error in getAllHhcServices: ${e.toString()}"); + return Left(UnknownFailure(e.toString())); + } + } + @override Future>> updateCmcPresOrder(OrderUpdateRequestModel requestModel) async { try { @@ -186,6 +310,46 @@ class HmgServicesRepoImp implements HmgServicesRepo { } } + @override + Future>> updateHhcPresOrder(OrderUpdateRequestModel requestModel) async { + try { + GenericApiModel? apiResponse; + Failure? failure; + + await apiClient.post( + ApiConsts.updateHHCOrder, + isRCService: true, + body: requestModel.toJson(), + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + loggerService.logError("Update HHC Order API Failed: $error, Status: $statusCode"); + }, + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + try { + apiResponse = GenericApiModel( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: errorMessage, + data: true, + ); + + loggerService.logInfo("HHC Order updated successfully: PresOrderID=${requestModel.presOrderID}"); + } catch (e) { + loggerService.logError("Error processing update HHC order response: ${e.toString()}"); + failure = DataParsingFailure(e.toString()); + } + }, + ); + + if (failure != null) return Left(failure!); + if (apiResponse == null) return Left(ServerFailure("Unknown error")); + return Right(apiResponse!); + } catch (e) { + loggerService.logError("Unknown error in updateHhcPresOrder: ${e.toString()}"); + return Left(UnknownFailure(e.toString())); + } + } + @override Future>>> getHospitalsList() async { Map requestBody = {}; @@ -301,4 +465,58 @@ class HmgServicesRepoImp implements HmgServicesRepo { return Left(UnknownFailure(e.toString())); } } + + @override + Future>> addHhcOrder({ + required int projectID, + required int orderServiceID, + required List services, + }) async { + try { + GenericApiModel? apiResponse; + Failure? failure; + + final requestBody = { + 'ProjectID': projectID, + 'OrderServiceID': orderServiceID, + 'procedures': services.map((service) => service.toJson()).toList(), + }; + + await apiClient.post( + ApiConsts.addHHCOrder, + isRCService: true, + body: requestBody, + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + loggerService.logError("Add HHC Order API Failed: $error, Status: $statusCode"); + }, + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + int requestId = 0; + if (response is Map) { + requestId = response['response']; + } + try { + apiResponse = GenericApiModel( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: errorMessage, + data: requestId, + ); + + loggerService.logInfo("HHC Order added successfully: ProjectID=$projectID, OrderServiceID=$orderServiceID"); + } catch (e) { + loggerService.logError("Error processing add HHC order response: ${e.toString()}"); + failure = DataParsingFailure(e.toString()); + } + }, + ); + + if (failure != null) return Left(failure!); + if (apiResponse == null) return Left(ServerFailure("Unknown error")); + return Right(apiResponse!); + } catch (e) { + loggerService.logError("Unknown error in addHhcOrder: ${e.toString()}"); + return Left(UnknownFailure(e.toString())); + } + } } diff --git a/lib/features/hmg_services/hmg_services_view_model.dart b/lib/features/hmg_services/hmg_services_view_model.dart index 5c0f3e5..24b7fff 100644 --- a/lib/features/hmg_services/hmg_services_view_model.dart +++ b/lib/features/hmg_services/hmg_services_view_model.dart @@ -20,17 +20,31 @@ class HmgServicesViewModel extends ChangeNotifier { bool isUpdatingOrder = false; bool isHospitalListLoading = false; + // HHC specific loading states + bool isHhcOrdersLoading = false; + bool isHhcServicesLoading = false; + List cmcOrdersList = []; List cmcServicesList = []; List hospitalsList = []; List filteredHospitalsList = []; HospitalsModel? selectedHospital; + // HHC specific lists + List hhcOrdersList = []; + List hhcServicesList = []; + // CMC order creation state HospitalsModel? selectedHospitalForOrder; GetCMCServicesResponseModel? selectedServiceForOrder; - Future getOrdersList() async { + // HHC order creation state (no hospital selection needed for home healthcare) + GetCMCServicesResponseModel? selectedServiceForHhcOrder; + + // HHC multiple services selection + List selectedHhcServices = []; + + Future getCmcOrdersList() async { cmcOrdersList.clear(); isCmcOrdersLoading = true; notifyListeners(); @@ -60,7 +74,7 @@ class HmgServicesViewModel extends ChangeNotifier { isCmcOrdersLoading = true; notifyListeners(); - final result = await hmgServicesRepo.getAllCmcOrders(); + final result = await hmgServicesRepo.getAllComprehensiveCheckupOrders(); result.fold( (failure) async { @@ -290,4 +304,212 @@ class HmgServicesViewModel extends ChangeNotifier { return requestId; } + +// ******************* HOME HEALTHCARE APIs ******************** + + Future getHhcOrdersList() async { + hhcOrdersList.clear(); + isHhcOrdersLoading = true; + notifyListeners(); + await getAllHhcOrders(); + } + + Future getAllHhcOrders({ + Function(dynamic)? onSuccess, + Function(String)? onError, + }) async { + isHhcOrdersLoading = true; + notifyListeners(); + + final result = await hmgServicesRepo.getAllHomeHealthCareCheckupOrders(); + + result.fold( + (failure) async { + isHhcOrdersLoading = false; + notifyListeners(); + await errorHandlerService.handleError(failure: failure); + if (onError != null) { + onError(failure.toString()); + } + }, + (apiResponse) { + isHhcOrdersLoading = false; + if (apiResponse.messageStatus == 1) { + hhcOrdersList = apiResponse.data ?? []; + notifyListeners(); + if (onSuccess != null) { + onSuccess(apiResponse); + } + } else { + notifyListeners(); + if (onError != null) { + onError(apiResponse.errorMessage ?? 'Unknown error'); + } + } + }, + ); + } + + Future getAllHhcServices({required int patientID, Function(dynamic)? onSuccess, Function(String)? onError}) async { + isHhcServicesLoading = true; + notifyListeners(); + + final result = await hmgServicesRepo.getAllHhcServices(patientID: patientID); + + result.fold( + (failure) async { + isHhcServicesLoading = false; + notifyListeners(); + await errorHandlerService.handleError(failure: failure); + if (onError != null) { + onError(failure.toString()); + } + }, + (apiResponse) { + isHhcServicesLoading = false; + if (apiResponse.messageStatus == 1) { + hhcServicesList = apiResponse.data ?? []; + notifyListeners(); + if (onSuccess != null) { + onSuccess(apiResponse); + } + } else { + notifyListeners(); + if (onError != null) { + onError(apiResponse.errorMessage ?? 'Unknown error'); + } + } + }, + ); + } + + Future updateHhcPresOrder({ + required OrderUpdateRequestModel requestModel, + Function(dynamic)? onSuccess, + Function(String)? onError, + }) async { + isUpdatingOrder = true; + notifyListeners(); + + final result = await hmgServicesRepo.updateHhcPresOrder(requestModel); + + bool success = false; + + result.fold( + (failure) async { + isUpdatingOrder = false; + notifyListeners(); + await errorHandlerService.handleError(failure: failure); + if (onError != null) { + onError(failure.toString()); + } + }, + (apiResponse) { + isUpdatingOrder = false; + if (apiResponse.messageStatus == 1) { + success = true; + notifyListeners(); + if (onSuccess != null) { + onSuccess(apiResponse); + } + } else { + notifyListeners(); + if (onError != null) { + onError(apiResponse.errorMessage ?? 'Unknown error'); + } + } + }, + ); + + return success; + } + + Future addHhcOrder({ + required int projectID, + required int orderServiceID, + required List services, + Function(int)? onSuccess, + Function(String)? onError, + }) async { + isUpdatingOrder = true; + notifyListeners(); + + final result = await hmgServicesRepo.addHhcOrder( + projectID: projectID, + orderServiceID: orderServiceID, + services: services, + ); + + int requestId = 0; + + result.fold( + (failure) async { + isUpdatingOrder = false; + notifyListeners(); + await errorHandlerService.handleError(failure: failure); + if (onError != null) { + onError(failure.toString()); + } + }, + (apiResponse) { + isUpdatingOrder = false; + if (apiResponse.messageStatus == 1) { + requestId = apiResponse.data ?? 0; + notifyListeners(); + if (onSuccess != null) { + onSuccess(requestId); + } + } else { + notifyListeners(); + if (onError != null) { + onError(apiResponse.errorMessage ?? 'Unknown error'); + } + } + }, + ); + + return requestId; + } + + // HHC Order management methods (no hospital selection for home healthcare) + void setSelectedServiceForHhcOrder(GetCMCServicesResponseModel? service) { + selectedServiceForHhcOrder = service; + notifyListeners(); + } + + void clearHhcOrderSelection() { + selectedServiceForHhcOrder = null; + selectedHhcServices.clear(); + notifyListeners(); + } + + bool get isHhcOrderReadyToConfirm => selectedServiceForHhcOrder != null; + + // Multiple HHC services selection methods + void toggleHhcServiceSelection(GetCMCServicesResponseModel service) { + final index = selectedHhcServices.indexWhere((s) => s.iD == service.iD); + if (index != -1) { + selectedHhcServices.removeAt(index); + } else { + selectedHhcServices.add(service); + } + notifyListeners(); + } + + bool isHhcServiceSelected(GetCMCServicesResponseModel service) { + return selectedHhcServices.any((s) => s.iD == service.iD); + } + + double getHhcSelectedServicesTotal() { + double total = 0.0; + for (var service in selectedHhcServices) { + total += (service.priceTotal ?? 0); + } + return total; + } + + void clearHhcServicesSelection() { + selectedHhcServices.clear(); + notifyListeners(); + } } diff --git a/lib/presentation/comprehensive_checkup/cmc_order_detail_page.dart b/lib/presentation/comprehensive_checkup/cmc_order_detail_page.dart index c02f9f1..7547fd0 100644 --- a/lib/presentation/comprehensive_checkup/cmc_order_detail_page.dart +++ b/lib/presentation/comprehensive_checkup/cmc_order_detail_page.dart @@ -30,7 +30,7 @@ class _CmcOrderDetailPageState extends State { super.initState(); final hmgServicesViewModel = context.read(); scheduleMicrotask(() async { - await hmgServicesViewModel.getOrdersList(); + await hmgServicesViewModel.getCmcOrdersList(); }); } diff --git a/lib/presentation/hmg_services/services_page.dart b/lib/presentation/hmg_services/services_page.dart index 2242441..65bed10 100644 --- a/lib/presentation/hmg_services/services_page.dart +++ b/lib/presentation/hmg_services/services_page.dart @@ -31,6 +31,16 @@ class ServicesPage extends StatelessWidget { textColor: AppColors.blackColor, route: AppRoutes.comprehensiveCheckupPage, ), + HmgServicesComponentModel( + 12, + "Home Health Care".needTranslation, + "".needTranslation, + AppAssets.emergency_services_icon, + true, + bgColor: AppColors.bgGreenColor, + textColor: AppColors.blackColor, + route: AppRoutes.homeHealthCarePage, + ), ]; @override diff --git a/lib/presentation/home_health_care/hhc_order_detail_page.dart b/lib/presentation/home_health_care/hhc_order_detail_page.dart new file mode 100644 index 0000000..21b0def --- /dev/null +++ b/lib/presentation/home_health_care/hhc_order_detail_page.dart @@ -0,0 +1,248 @@ +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/features/hmg_services/hmg_services_view_model.dart'; +import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get_cmc_all_orders_resp_model.dart'; +import 'package:hmg_patient_app_new/presentation/home_health_care/widgets/hhc_ui_selection_helper.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; +import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; +import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; +import 'package:provider/provider.dart'; + +class HhcOrderDetailPage extends StatefulWidget { + const HhcOrderDetailPage({super.key}); + + @override + State createState() => _HhcOrderDetailPageState(); +} + +class _HhcOrderDetailPageState extends State { + @override + void initState() { + super.initState(); + final hmgServicesViewModel = context.read(); + scheduleMicrotask(() async { + await hmgServicesViewModel.getAllHhcOrders(); + }); + } + + Color _getStatusColor(int? statusId) { + switch (statusId) { + case 1: // Pending + return const Color(0xffCC9B14); + case 2: // Processing + return const Color(0xff2E303A); + case 3: // Completed + return const Color(0xff359846); + case 4: // Cancelled + case 6: // Rejected + case 7: // Rejected + return const Color(0xffD02127); + default: + return AppColors.greyColor; + } + } + + String _formatDate(String? dateString) { + if (dateString == null) return ''; + try { + final date = DateTime.parse(dateString); + return DateFormat('MMM dd, yyyy').format(date); + } catch (e) { + return dateString; + } + } + + Widget _buildLoadingShimmer() { + return ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: 3, + separatorBuilder: (_, __) => SizedBox(height: 12.h), + itemBuilder: (context, index) { + return _buildOrderCard(GetCMCAllOrdersResponseModel(), isLoading: true); + }, + ); + } + + Widget _buildOrderCard(GetCMCAllOrdersResponseModel order, {bool isLoading = false}) { + final statusColor = _getStatusColor(order.statusId); + final canCancel = order.statusId == 1 || order.statusId == 2; + + return AnimatedContainer( + duration: Duration(milliseconds: 300), + curve: Curves.easeInOut, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24.h, + hasShadow: true, + ), + child: Padding( + padding: EdgeInsets.all(16.w), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Status and Date Row + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 6.h), + decoration: BoxDecoration( + color: statusColor.withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(8.r), + ), + child: (isLoading ? "Processing" : order.statusText ?? '') + .toText12( + color: statusColor, + fontWeight: FontWeight.w600, + ) + .toShimmer2(isShow: isLoading), + ), + SizedBox(width: 8.w), + (isLoading ? "Jan 15, 2024" : _formatDate(order.created)) + .toText12( + color: AppColors.textColorLight, + fontWeight: FontWeight.w500, + ) + .toShimmer2(isShow: isLoading), + ], + ), + + SizedBox(height: 16.h), + + // Request ID + Row( + children: [ + if (!isLoading) ...[ + "Request ID:".needTranslation.toText14( + color: AppColors.textColorLight, + weight: FontWeight.w500, + ), + SizedBox(width: 4.w), + ], + (isLoading ? "12345" : "${order.iD ?? '-'}").toText16(isBold: true).toShimmer2(isShow: isLoading), + ], + ), + + SizedBox(height: 12.h), + + // Chips for Hospital, Service, and Amount + Wrap( + spacing: 6.w, + runSpacing: 6.h, + children: [ + // Service + if (order.serviceText != null || isLoading) + AppCustomChipWidget( + icon: AppAssets.servicesBottom, + labelText: isLoading ? "Service Name" : order.serviceText ?? '-', + ).toShimmer2(isShow: isLoading), + ], + ), + + // Cancel Button + if (canCancel || isLoading) ...[ + SizedBox(height: 16.h), + Row( + children: [ + Expanded( + child: CustomButton( + text: "Cancel Order".needTranslation, + onPressed: isLoading ? () {} : () => HhcUiSelectionHelper.showCancelConfirmationDialog(context: context, order: order), + backgroundColor: AppColors.primaryRedColor, + borderColor: AppColors.primaryRedColor, + textColor: AppColors.whiteColor, + fontSize: 14.f, + fontWeight: FontWeight.w600, + borderRadius: 10.r, + height: 44.h, + ).toShimmer2(isShow: isLoading), + ), + ], + ), + ] + ], + ), + ), + ); + } + + Widget _buildEmptyState() { + return Center( + child: Padding( + padding: EdgeInsets.symmetric(vertical: 40.h), + child: Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 12.r, + hasShadow: false, + ), + child: Utils.getNoDataWidget( + context, + noDataText: "You don't have any Home Health Care orders yet.".needTranslation, + isSmallWidget: true, + width: 62.w, + height: 62.h, + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return CollapsingListView( + title: "HHC Orders".needTranslation, + isLeading: true, + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Consumer( + builder: (context, viewModel, child) { + if (viewModel.isHhcOrdersLoading) { + return _buildLoadingShimmer(); + } + + if (viewModel.hhcOrdersList.isEmpty) { + return _buildEmptyState(); + } + + return ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: viewModel.hhcOrdersList.length, + separatorBuilder: (_, __) => SizedBox(height: 12.h), + itemBuilder: (context, index) { + final order = viewModel.hhcOrdersList.reversed.toList()[index]; + + return AnimationConfiguration.staggeredList( + position: index, + duration: const Duration(milliseconds: 500), + child: SlideAnimation( + verticalOffset: 100.0, + child: FadeInAnimation( + child: _buildOrderCard(order), + ), + ), + ); + }, + ); + }, + ), + ], + ).paddingSymmetrical(24.w, 0), + ), + ); + } +} diff --git a/lib/presentation/home_health_care/hhc_procedures_page.dart b/lib/presentation/home_health_care/hhc_procedures_page.dart new file mode 100644 index 0000000..0cf57ce --- /dev/null +++ b/lib/presentation/home_health_care/hhc_procedures_page.dart @@ -0,0 +1,414 @@ +import 'dart:async'; + +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/app_state.dart'; +import 'package:hmg_patient_app_new/core/dependencies.dart'; +import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; +import 'package:hmg_patient_app_new/core/utils/utils.dart'; +import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; +import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; +import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_view_model.dart'; +import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get_cmc_all_orders_resp_model.dart'; +import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get_cmc_services_resp_model.dart'; +import 'package:hmg_patient_app_new/presentation/home_health_care/hhc_order_detail_page.dart'; +import 'package:hmg_patient_app_new/presentation/home_health_care/hhc_selection_review_page.dart'; +import 'package:hmg_patient_app_new/presentation/home_health_care/widgets/hhc_ui_selection_helper.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; +import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; +import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; +import 'package:provider/provider.dart'; +import 'package:shimmer/shimmer.dart'; + +class HhcProceduresPage extends StatefulWidget { + const HhcProceduresPage({super.key}); + + @override + State createState() => _HhcProceduresPageState(); +} + +class _HhcProceduresPageState extends State { + @override + void initState() { + super.initState(); + final HmgServicesViewModel hmgServicesViewModel = context.read(); + final AppState appState = getIt.get(); + + scheduleMicrotask(() async { + final user = appState.getAuthenticatedUser(); + if (user != null) { + // Clear previous selections when entering the page + hmgServicesViewModel.clearHhcServicesSelection(); + await hmgServicesViewModel.getAllHhcOrders(); + await hmgServicesViewModel.getAllHhcServices(patientID: user.patientId ?? 0); + } + }); + } + + GetCMCAllOrdersResponseModel? _getPendingOrder(List orders) { + if (orders.isEmpty) return null; + + // Find pending or processing orders (status 1 or 2) + for (var order in orders) { + if (order.statusId == 1 || order.statusId == 2) { + return order; + } + } + + return null; + } + + Widget _buildPendingOrderCard(GetCMCAllOrdersResponseModel order) { + int status = order.statusId ?? 0; + String statusDisp = order.statusText ?? ""; + Color statusColor; + + if (status == 1) { + // pending + statusColor = AppColors.statusPendingColor; + } else if (status == 2) { + // processing + statusColor = AppColors.statusProcessingColor; + } else if (status == 3) { + // completed + statusColor = AppColors.statusCompletedColor; + } else { + // cancel / rejected + statusColor = AppColors.statusRejectedColor; + } + + final canCancel = order.statusId == 1 || order.statusId == 2; + + return Container( + width: double.infinity, + margin: EdgeInsets.all(16.w), + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24.h, + hasShadow: true, + ), + child: Padding( + padding: EdgeInsets.all(16.w), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Status and Date Row + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 6.h), + decoration: BoxDecoration( + color: statusColor.withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(8.r), + ), + child: statusDisp.toText12( + color: statusColor, + fontWeight: FontWeight.w600, + ), + ), + SizedBox(width: 8.w), + if (order.created != null) + DateFormat('MMM dd, yyyy').format(DateTime.parse(order.created!)).toText12( + color: AppColors.textColorLight, + fontWeight: FontWeight.w500, + ), + ], + ), + + SizedBox(height: 16.h), + + // Request ID + Row( + children: [ + "Request ID:".needTranslation.toText14(color: AppColors.textColorLight, weight: FontWeight.w500), + SizedBox(width: 4.w), + "${order.iD ?? '-'}".toText16(isBold: true), + ], + ), + + SizedBox(height: 12.h), + + // Info message + Container( + padding: EdgeInsets.all(12.w), + decoration: BoxDecoration( + color: AppColors.infoBannerBgColor, + borderRadius: BorderRadius.circular(10.r), + border: Border.all( + color: AppColors.infoBannerBorderColor, + width: 1, + ), + ), + child: Row( + children: [ + Icon( + Icons.info_outline, + size: 20.w, + color: AppColors.infoBannerIconColor, + ), + SizedBox(width: 8.w), + Expanded( + child: "You have a pending order. Please wait for it to be processed.".needTranslation.toText12( + color: AppColors.infoBannerTextColor, + fontWeight: FontWeight.w500, + ), + ), + ], + ), + ), + if (canCancel) ...[ + SizedBox(height: 16.h), + Row( + children: [ + Expanded( + child: CustomButton( + text: "Cancel Order".needTranslation, + onPressed: () => HhcUiSelectionHelper.showCancelConfirmationDialog(context: context, order: order), + backgroundColor: AppColors.primaryRedColor, + borderColor: AppColors.primaryRedColor, + textColor: AppColors.whiteColor, + fontSize: 14.f, + fontWeight: FontWeight.w600, + borderRadius: 10.r, + height: 44.h, + ), + ), + ], + ), + ] + ], + ), + ), + ); + } + + Widget _buildServiceSelectionList(List services) { + if (services.isEmpty) { + return Center( + child: Padding( + padding: EdgeInsets.all(24.h), + child: Text( + 'No services available'.needTranslation, + style: TextStyle( + fontSize: 16.h, + color: AppColors.greyTextColor, + ), + ), + ), + ); + } + + return Consumer( + builder: (context, viewModel, child) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 8.h), + if (viewModel.selectedHhcServices.isNotEmpty) ...[ + SizedBox(height: 16.h), + Container( + margin: EdgeInsets.symmetric(horizontal: 16.w), + padding: EdgeInsets.all(16.w), + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.primaryRedColor.withValues(alpha: 0.1), + borderRadius: 16.r, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Selected Services".needTranslation.toText12( + color: AppColors.textColorLight, + fontWeight: FontWeight.w600, + ), + "${viewModel.selectedHhcServices.length} service(s) selected".toText14( + isBold: true, + weight: FontWeight.bold, + ), + ], + ), + Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + "Total Amount".needTranslation.toText12( + color: AppColors.textColorLight, + fontWeight: FontWeight.w600, + ), + Utils.getPaymentAmountWithSymbol( + viewModel.getHhcSelectedServicesTotal().toStringAsFixed(2).toText16( + isBold: true, + weight: FontWeight.bold, + color: AppColors.primaryRedColor, + ), + AppColors.primaryRedColor, + 14, + isSaudiCurrency: true, + ), + ], + ), + ], + ), + ), + ], + + SizedBox(height: 16.h), + Text( + 'Select Services'.needTranslation, + style: TextStyle( + fontSize: 20.h, + fontWeight: FontWeight.w700, + color: AppColors.blackColor, + letterSpacing: -0.8, + ), + ).paddingOnly(left: 16.w, right: 16.w), + SizedBox(height: 12.h), + ListView.builder( + padding: EdgeInsets.symmetric(horizontal: 16.w), + itemCount: services.length, + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemBuilder: (context, index) { + final service = services[index]; + final isSelected = viewModel.isHhcServiceSelected(service); + final isArabic = getIt.get().isArabic(); + final serviceName = isArabic ? (service.textN ?? service.text ?? '') : (service.text ?? ''); + + return AnimatedContainer( + duration: Duration(milliseconds: 300), + curve: Curves.easeInOut, + margin: EdgeInsets.only(bottom: 12.h), + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 16.r, + hasShadow: true, + ), + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: () => viewModel.toggleHhcServiceSelection(service), + borderRadius: BorderRadius.circular(16.r), + child: Container( + padding: EdgeInsets.all(16.w), + child: Row( + children: [ + Checkbox( + value: isSelected, + onChanged: (v) => viewModel.toggleHhcServiceSelection(service), + activeColor: AppColors.primaryRedColor, + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + visualDensity: VisualDensity.compact, + ), + SizedBox(width: 12.w), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + serviceName.toText16( + weight: FontWeight.w400, + color: AppColors.blackColor, + maxlines: 2, + ), + ], + ), + ), + ], + ), + ), + ), + ), + ); + }, + ), + // Summary Section + ], + ); + }, + ); + } + + void _proceedWithSelectedService() { + final hmgServicesViewModel = context.read(); + if (hmgServicesViewModel.selectedHhcServices.isNotEmpty) { + hmgServicesViewModel.setSelectedServiceForHhcOrder(hmgServicesViewModel.selectedHhcServices.first); + Navigator.of(context).pushReplacement( + CustomPageRoute( + page: HhcSelectionReviewPage(selectedServices: hmgServicesViewModel.selectedHhcServices), + direction: AxisDirection.left, + ), + ); + } + } + + Widget _buildLoadingShimmer() { + return ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + padding: EdgeInsets.all(16.w), + itemCount: 10, + separatorBuilder: (_, __) => SizedBox(height: 12.h), + itemBuilder: (context, index) { + return Shimmer.fromColors( + baseColor: Colors.grey[300]!, + highlightColor: Colors.grey[100]!, + child: Container( + height: 80.h, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10.r), + ), + ), + ); + }, + ); + } + + @override + Widget build(BuildContext context) { + return CollapsingListView( + title: "Home Health Care".needTranslation, + history: () => Navigator.of(context).push(CustomPageRoute(page: HhcOrderDetailPage(), direction: AxisDirection.up)), + bottomChild: Consumer( + builder: (context, hmgServicesViewModel, child) { + if (hmgServicesViewModel.isHhcOrdersLoading || hmgServicesViewModel.isHhcServicesLoading) return SizedBox.shrink(); + final pendingOrder = _getPendingOrder(hmgServicesViewModel.hhcOrdersList); + if (pendingOrder == null && hmgServicesViewModel.selectedHhcServices.isNotEmpty) { + return SafeArea( + top: false, + child: Padding( + padding: EdgeInsets.only(left: 16.w, right: 16.w, top: 12.h), + child: CustomButton( + borderWidth: 0, + text: "Next".needTranslation, + onPressed: _proceedWithSelectedService, + textColor: AppColors.whiteColor, + borderRadius: 12.r, + borderColor: Colors.transparent, + padding: EdgeInsets.symmetric(vertical: 14.h), + ), + ), + ); + } + return SizedBox.shrink(); + }, + ), + child: Consumer( + builder: (context, hmgServicesViewModel, child) { + if (hmgServicesViewModel.isHhcOrdersLoading || hmgServicesViewModel.isHhcServicesLoading) { + return _buildLoadingShimmer(); + } + final pendingOrder = _getPendingOrder(hmgServicesViewModel.hhcOrdersList); + if (pendingOrder != null) { + return _buildPendingOrderCard(pendingOrder); + } else { + return _buildServiceSelectionList(hmgServicesViewModel.hhcServicesList); + } + }, + ), + ); + } +} diff --git a/lib/presentation/home_health_care/hhc_selection_review_page.dart b/lib/presentation/home_health_care/hhc_selection_review_page.dart new file mode 100644 index 0000000..7baeec0 --- /dev/null +++ b/lib/presentation/home_health_care/hhc_selection_review_page.dart @@ -0,0 +1,244 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/app_state.dart'; +import 'package:hmg_patient_app_new/core/dependencies.dart'; +import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; +import 'package:hmg_patient_app_new/core/utils/utils.dart'; +import 'package:hmg_patient_app_new/extensions/route_extensions.dart'; +import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; +import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; +import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_view_model.dart'; +import 'package:hmg_patient_app_new/features/hmg_services/models/req_models/cmc_create_new_order_req_model.dart'; +import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get_cmc_services_resp_model.dart'; +import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart'; +import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; +import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; +import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; +import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; +import 'package:maps_launcher/maps_launcher.dart'; +import 'package:provider/provider.dart'; + +class HhcSelectionReviewPage extends StatefulWidget { + final List selectedServices; + + const HhcSelectionReviewPage({super.key, required this.selectedServices}); + + @override + State createState() => _HhcSelectionReviewPageState(); +} + +class _HhcSelectionReviewPageState extends State { + @override + void initState() { + super.initState(); + // Initialize ViewModel state with selected services + WidgetsBinding.instance.addPostFrameCallback((_) { + final hmgServicesViewModel = context.read(); + if (widget.selectedServices.isNotEmpty) { + hmgServicesViewModel.setSelectedServiceForHhcOrder(widget.selectedServices.first); + } + }); + } + + @override + Widget build(BuildContext context) { + final appState = getIt.get(); + final isArabic = appState.isArabic(); + + return CollapsingListView( + title: "Summary".needTranslation, + bottomChild: _buildBottomButton(), + child: SingleChildScrollView( + padding: EdgeInsets.all(16.w), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildSelectedServicesCard(isArabic), + SizedBox(height: 16.h), + ], + ), + ), + ); + } + + Widget _buildSelectedServicesCard(bool isArabic) { + return Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 16.r, + ), + padding: EdgeInsets.all(16.w), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Selected Services".needTranslation.toText14( + weight: FontWeight.w600, + color: AppColors.greyTextColor, + letterSpacing: -0.4, + ), + SizedBox(height: 12.h), + ...widget.selectedServices.map((service) { + final serviceName = isArabic ? (service.textN ?? service.text ?? '') : (service.text ?? ''); + final price = service.priceTotal ?? 0.0; + return Padding( + padding: EdgeInsets.only(bottom: 4.h), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: serviceName.toText14( + weight: FontWeight.w600, + color: AppColors.blackColor, + letterSpacing: -0.5, + maxlines: 2, + ), + ), + ], + ), + ); + }), + ], + ), + ); + } + + Widget _buildBottomButton() { + return SafeArea( + top: false, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 12.h), + decoration: BoxDecoration( + color: AppColors.whiteColor, + boxShadow: [ + BoxShadow( + color: Color.fromARGB(13, 0, 0, 0), + blurRadius: 8, + offset: Offset(0, -2), + ), + ], + ), + child: CustomButton( + text: "Confirm".needTranslation, + onPressed: _handleConfirm, + textColor: AppColors.whiteColor, + backgroundColor: AppColors.successColor, + borderRadius: 12.r, + borderColor: Colors.transparent, + borderWidth: 0, + padding: EdgeInsets.symmetric(vertical: 14.h), + ), + ), + ); + } + + void _launchDirections(HospitalsModel selectedHospital) { + final double lat = double.parse(selectedHospital.latitude ?? "0.0"); + final double lng = double.parse(selectedHospital.longitude ?? "0.0"); + + if (lat != 0.0 && lng != 0.0) { + MapsLauncher.launchCoordinates( + lat, + lng, + selectedHospital.name ?? "Hospital", + ); + } + } + + showSuccessBottomSheet(int requestId, HmgServicesViewModel hmgServicesViewModel) { + return showCommonBottomSheetWithoutHeight( + context, + child: Padding( + padding: EdgeInsets.all(16.w), + child: Column( + children: [ + Utils.getSuccessWidget(loadingText: "Your request has been successfully submitted.".needTranslation), + Row( + children: [ + "Here is your request #: ".needTranslation.toText14( + color: AppColors.textColorLight, + weight: FontWeight.w500, + ), + SizedBox(width: 4.w), + ("$requestId").toText16(isBold: true), + ], + ), + SizedBox(height: 24.h), + Row( + children: [ + Expanded( + child: CustomButton( + height: 56.h, + text: LocaleKeys.ok.tr(), + onPressed: () { + context.pop(); + context.pop(); + hmgServicesViewModel.getAllHhcOrders(); + }, + textColor: AppColors.whiteColor, + ), + ), + ], + ), + ], + ), + ), + isCloseButtonVisible: false, + isDismissible: false, + isFullScreen: false, + ); + } + + void _handleConfirm() { + final hmgServicesViewModel = context.read(); + final appState = getIt.get(); + + return showCommonBottomSheetWithoutHeight( + title: LocaleKeys.notice.tr(context: context), + context, + child: Utils.getWarningWidget( + loadingText: "Are you sure you want to submit this request?".needTranslation, + isShowActionButtons: true, + onCancelTap: () { + Navigator.pop(context); + }, + onConfirmTap: () async { + Navigator.pop(context); + LoaderBottomSheet.showLoader(); + + // Create the services list from all selected services + final servicesList = widget.selectedServices.map((selectedService) { + return PatientERCMCInsertServicesList( + recordID: selectedService.iD, + serviceID: selectedService.serviceID, + selectedServiceName: selectedService.text, + selectedServiceNameAR: selectedService.textN, + price: selectedService.price, + vAT: selectedService.priceVAT, + totalPrice: selectedService.priceTotal, + ); + }).toList(); + + // For HHC, we don't need hospital selection, use a default projectID or 0 + await hmgServicesViewModel.addHhcOrder( + projectID: 0, + // HHC doesn't require hospital/project selection + orderServiceID: widget.selectedServices.first.orderServiceID ?? 4, + // HHC service ID + services: servicesList, + onSuccess: (requestId) { + LoaderBottomSheet.hideLoader(); + showSuccessBottomSheet(requestId, hmgServicesViewModel); + }, + onError: (err) { + LoaderBottomSheet.hideLoader(); + }, + ); + }), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + } +} diff --git a/lib/presentation/home_health_care/widgets/hhc_ui_selection_helper.dart b/lib/presentation/home_health_care/widgets/hhc_ui_selection_helper.dart new file mode 100644 index 0000000..688612c --- /dev/null +++ b/lib/presentation/home_health_care/widgets/hhc_ui_selection_helper.dart @@ -0,0 +1,90 @@ +import 'package:easy_localization/easy_localization.dart'; +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/route_extensions.dart'; +import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; +import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_view_model.dart'; +import 'package:hmg_patient_app_new/features/hmg_services/models/req_models/order_update_req_model.dart'; +import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get_cmc_all_orders_resp_model.dart'; +import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; +import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; +import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; +import 'package:provider/provider.dart'; + +class HhcUiSelectionHelper { + static void showCancelConfirmationDialog({ + required BuildContext context, + required GetCMCAllOrdersResponseModel order, + }) { + final HmgServicesViewModel hmgServicesViewModel = context.read(); + + return showCommonBottomSheetWithoutHeight( + title: LocaleKeys.notice.tr(context: context), + context, + child: Utils.getWarningWidget( + loadingText: "Are you sure you want to cancel this order?".needTranslation, + isShowActionButtons: true, + onCancelTap: () { + Navigator.pop(context); + }, + onConfirmTap: () async { + Navigator.pop(context); + LoaderBottomSheet.showLoader(); + + final requestModel = OrderUpdateRequestModel( + presOrderID: order.iD, + rejectionReason: "Cancelled by user", + presOrderStatus: 4, // Cancelled status + editedBy: 3, + ); + + await hmgServicesViewModel.updateHhcPresOrder( + requestModel: requestModel, + onSuccess: (_) async { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight( + context, + child: Padding( + padding: EdgeInsets.all(16.w), + child: Column( + children: [ + Utils.getSuccessWidget(loadingText: "Order has been cancelled successfully".needTranslation), + SizedBox(height: 24.h), + Row( + children: [ + Expanded( + child: CustomButton( + height: 56.h, + text: LocaleKeys.ok.tr(), + onPressed: () { + context.pop(); + hmgServicesViewModel.getAllHhcOrders(); + }, + textColor: AppColors.whiteColor, + ), + ), + ], + ), + ], + ), + ), + isCloseButtonVisible: false, + isDismissible: false, + isFullScreen: false, + ); + }, + onError: (error) { + LoaderBottomSheet.hideLoader(); + }, + ); + }, + ), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + } +} diff --git a/lib/presentation/services/services_page.dart b/lib/presentation/services/services_page.dart deleted file mode 100644 index 24a259b..0000000 --- a/lib/presentation/services/services_page.dart +++ /dev/null @@ -1,23 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:hmg_patient_app_new/theme/colors.dart'; - -class ServicesPage extends StatelessWidget { - const ServicesPage({super.key}); - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: AppColors.bgScaffoldColor, - appBar: AppBar( - title: const Text('Appointments'), - backgroundColor: AppColors.bgScaffoldColor, - ), - body: const Center( - child: Text( - 'Appointments Page', - style: TextStyle(fontSize: 24), - ), - ), - ); - } -} \ No newline at end of file diff --git a/lib/routes/app_routes.dart b/lib/routes/app_routes.dart index 842710d..a0ee1e5 100644 --- a/lib/routes/app_routes.dart +++ b/lib/routes/app_routes.dart @@ -5,6 +5,7 @@ import 'package:hmg_patient_app_new/presentation/authentication/register_step2.d import 'package:hmg_patient_app_new/presentation/comprehensive_checkup/comprehensive_checkup_page.dart'; import 'package:hmg_patient_app_new/presentation/e_referral/e_referral_page_home.dart'; import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart'; +import 'package:hmg_patient_app_new/presentation/home_health_care/hhc_procedures_page.dart'; import 'package:hmg_patient_app_new/presentation/medical_file/medical_file_page.dart'; import 'package:hmg_patient_app_new/splashPage.dart'; @@ -17,6 +18,7 @@ class AppRoutes { static const String medicalFilePage = '/medicalFilePage'; static const String eReferralPage = '/erReferralPage'; static const String comprehensiveCheckupPage = '/comprehensiveCheckupPage'; + static const String homeHealthCarePage = '/homeHealthCarePage'; static Map get routes => { initialRoute: (context) => SplashPage(), @@ -26,6 +28,7 @@ class AppRoutes { registerStepTwo: (context) => RegisterNewStep2(), medicalFilePage: (context) => MedicalFilePage(), eReferralPage: (context) => EReferralPage(), - comprehensiveCheckupPage: (context) => ComprehensiveCheckupPage() + comprehensiveCheckupPage: (context) => ComprehensiveCheckupPage(), + homeHealthCarePage: (context) => HhcProceduresPage() }; } diff --git a/lib/theme/colors.dart b/lib/theme/colors.dart index 469704a..b3abe6a 100644 --- a/lib/theme/colors.dart +++ b/lib/theme/colors.dart @@ -3,21 +3,12 @@ import 'package:flutter/material.dart'; class AppColors { static const transparent = Colors.transparent; static const mainPurple = Color(0xFF7954F7); - static const purpleBg = Color(0xFFAEA4FC); - static const deepPurple = Color(0xFF7C65E7); - static const logoColor = Color(0xFF7C65E7); - static const buttonColor = Color(0xFF6A46F5); - static const splashBgColor = Color(0xFF3C355D); - static const lightGray = Color(0xFFF4F5F7); - static const lightPurple = Color(0xFFB7A3E6); static const scaffoldBgColor = Color(0xFFF8F8F8); static const bottomSheetBgColor = Color(0xFFF8F8FA); static const lightGreyEFColor = Color(0xffeaeaff); static const greyF7Color = Color(0xffF7F7F7); static const lightGrayColor = Color(0xff808080); - static const buttonGrayColor = Color(0xffF1F1F1); - static const lightPurpleAlpha = Color(0x5AB7A3E6); // New UI Colors static const whiteColor = Color(0xFFffffff); diff --git a/lib/widgets/buttons/default_button.dart b/lib/widgets/buttons/default_button.dart index eb02c38..d8d8cac 100644 --- a/lib/widgets/buttons/default_button.dart +++ b/lib/widgets/buttons/default_button.dart @@ -1,7 +1,6 @@ -import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; -import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; extension WithContainer on Widget { Widget get insideContainer => Container( @@ -26,20 +25,22 @@ class DefaultButton extends StatelessWidget { final double height; final double borderRadius; - const DefaultButton(this.text, this.onPress, - {Key? key, - this.color, - this.isTextExpanded = true, - this.svgIcon, - this.disabledColor, - this.count = 0, - this.textColor = Colors.white, - this.iconData, - this.fontSize, - this.colors, - this.height = 50, - this.borderRadius = 100}) - : super(key: key); + const DefaultButton( + this.text, + this.onPress, { + super.key, + this.color, + this.isTextExpanded = true, + this.svgIcon, + this.disabledColor, + this.count = 0, + this.textColor = Colors.white, + this.iconData, + this.fontSize, + this.colors, + this.height = 50, + this.borderRadius = 100, + }); @override Widget build(BuildContext context) { @@ -48,30 +49,20 @@ class DefaultButton extends StatelessWidget { child: Container( height: height, decoration: BoxDecoration( - borderRadius: BorderRadius.circular(borderRadius), - gradient: onPress == null - ? LinearGradient( - colors: [ - disabledColor ?? const Color(0xffEAEAEA), - disabledColor ?? const Color(0xffEAEAEA), - ], - ) - : LinearGradient( - transform: const GradientRotation(.83), - begin: Alignment.topRight, - end: Alignment.bottomLeft, - colors: colors ?? - [ - AppColors.buttonColor, - AppColors.buttonColor, - ], - ), - ), + borderRadius: BorderRadius.circular(borderRadius), + gradient: onPress == null + ? LinearGradient( + colors: [ + disabledColor ?? const Color(0xffEAEAEA), + disabledColor ?? const Color(0xffEAEAEA), + ], + ) + : null), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ if (iconData != null) Icon(iconData, color: textColor), - if (svgIcon != null) SvgPicture.asset(svgIcon ?? "", color: textColor), + if (svgIcon != null) SvgPicture.asset(svgIcon ?? ""), if (!isTextExpanded) Padding( padding: EdgeInsets.only( diff --git a/lib/widgets/dialogs/confirm_dialog.dart b/lib/widgets/dialogs/confirm_dialog.dart index f753681..ce597c2 100644 --- a/lib/widgets/dialogs/confirm_dialog.dart +++ b/lib/widgets/dialogs/confirm_dialog.dart @@ -15,7 +15,7 @@ class ConfirmDialog extends StatelessWidget { final VoidCallback? onTap; final VoidCallback? onCloseTap; - const ConfirmDialog({Key? key, this.title, required this.message, this.okTitle, this.onTap, this.onCloseTap}) : super(key: key); + const ConfirmDialog({super.key, this.title, required this.message, this.okTitle, this.onTap, this.onCloseTap}); @override Widget build(BuildContext context) {