HHC in Progress
parent
95bd2a2a7e
commit
fe00447483
@ -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<HhcOrderDetailPage> createState() => _HhcOrderDetailPageState();
|
||||
}
|
||||
|
||||
class _HhcOrderDetailPageState extends State<HhcOrderDetailPage> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
final hmgServicesViewModel = context.read<HmgServicesViewModel>();
|
||||
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<HmgServicesViewModel>(
|
||||
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),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -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<HhcProceduresPage> createState() => _HhcProceduresPageState();
|
||||
}
|
||||
|
||||
class _HhcProceduresPageState extends State<HhcProceduresPage> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
final HmgServicesViewModel hmgServicesViewModel = context.read<HmgServicesViewModel>();
|
||||
final AppState appState = getIt.get<AppState>();
|
||||
|
||||
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<GetCMCAllOrdersResponseModel> 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<GetCMCServicesResponseModel> 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<HmgServicesViewModel>(
|
||||
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<AppState>().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<HmgServicesViewModel>();
|
||||
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<HmgServicesViewModel>(
|
||||
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<HmgServicesViewModel>(
|
||||
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);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -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<GetCMCServicesResponseModel> selectedServices;
|
||||
|
||||
const HhcSelectionReviewPage({super.key, required this.selectedServices});
|
||||
|
||||
@override
|
||||
State<HhcSelectionReviewPage> createState() => _HhcSelectionReviewPageState();
|
||||
}
|
||||
|
||||
class _HhcSelectionReviewPageState extends State<HhcSelectionReviewPage> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
// Initialize ViewModel state with selected services
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
final hmgServicesViewModel = context.read<HmgServicesViewModel>();
|
||||
if (widget.selectedServices.isNotEmpty) {
|
||||
hmgServicesViewModel.setSelectedServiceForHhcOrder(widget.selectedServices.first);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final appState = getIt.get<AppState>();
|
||||
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<HmgServicesViewModel>();
|
||||
final appState = getIt.get<AppState>();
|
||||
|
||||
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,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -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<HmgServicesViewModel>();
|
||||
|
||||
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,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -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),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue