You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
HMG_Patient_App_New/lib/presentation/covid19test/covid_review_screen.dart

442 lines
20 KiB
Dart

import 'dart:async';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.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/covid_get_test_proceedure_resp.dart';
import 'package:hmg_patient_app_new/features/hmg_services/models/ui_models/covid_questionnare_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:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:provider/provider.dart';
import 'package:hmg_patient_app_new/presentation/covid19test/covid_payment_screen.dart';
class CovidReviewScreen extends StatefulWidget {
final HospitalsModel selectedHospital;
final List<CovidQuestionnaireModel> qaList;
const CovidReviewScreen({super.key, required this.selectedHospital, required this.qaList});
@override
State<CovidReviewScreen> createState() => _CovidReviewScreenState();
}
class _CovidReviewScreenState extends State<CovidReviewScreen> {
late HmgServicesViewModel hmgServicesViewModel;
bool _acceptedTerms =false;
Covid19GetTestProceduresResp? _selectedProcedure;
@override
void initState() {
super.initState();
hmgServicesViewModel = Provider.of<HmgServicesViewModel>(context, listen: false);
scheduleMicrotask(() {
});
}
@override
Widget build(BuildContext context) {
return CollapsingListView(
title: "COVID-19",
bottomChild: Consumer<HmgServicesViewModel>(builder: (context, vm, _) {
final info = vm.covidPaymentInfo;
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.r,
hasShadow: true,
),
child: SizedBox(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (info == null) ...[
// show a placeholder/loading while payment info is null
SizedBox(height: 24.h),
Center(child: CircularProgressIndicator()),
SizedBox(height: 24.h),
] else ...[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"Amount before tax".needTranslation.toText18(isBold: true),
Utils.getPaymentAmountWithSymbol(
(info.patientShareField ?? 0).toString().toText16(isBold: true),
AppColors.blackColor,
13,
isSaudiCurrency: true),
],
),
SizedBox(height: 4.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"Tax Amount".needTranslation.toText14(isBold: true),
Utils.getPaymentAmountWithSymbol(
(info.patientTaxAmountField ?? 0).toString().toText16(isBold: true),
AppColors.blackColor,
13,
isSaudiCurrency: true)
],
),
SizedBox(height: 18.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
width: 150.h,
child: Utils.getPaymentMethods(),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Utils.getPaymentAmountWithSymbol(
(info.patientShareWithTaxField ?? 0).toString().toText24(isBold: true),
AppColors.blackColor,
17,
isSaudiCurrency: true),
],
),
],
)
],
).paddingOnly(left: 16.h, top: 24.h, right: 16.h, bottom: 0.h),
GestureDetector(
onTap: () {
setState(() {
_acceptedTerms = !_acceptedTerms;
});
},
child: Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 12.r,
hasShadow: false,
),
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 12.h),
child: Row(
children: [
Container(
width: 20.w,
height: 20.h,
decoration: BoxDecoration(
color: _acceptedTerms
? AppColors.primaryRedColor
: AppColors.whiteColor,
border: Border.all(
color: _acceptedTerms
? AppColors.primaryRedColor
: AppColors.greyTextColor.withValues(alpha: 0.3),
width: 2,
),
borderRadius: BorderRadius.circular(4.r),
),
child: _acceptedTerms
? Icon(
Icons.check,
size: 14.h,
color: AppColors.whiteColor,
)
: null,
),
SizedBox(width: 12.w),
Expanded(
child: RichText(
text: TextSpan(
style: TextStyle(
fontSize: 14.f,
color: AppColors.textColor,
fontWeight: FontWeight.w400,
),
children: [
const TextSpan(text: "I agree to the "),
TextSpan(
text: "terms and conditions",
style: TextStyle(
color: AppColors.primaryRedColor,
fontWeight: FontWeight.w600,
decoration: TextDecoration.underline,
decorationColor: AppColors.primaryRedColor,
),
),
],
),
),
),
],
),
),
),
// Two-button layout: Cancel (left) and Next (right)
Padding(
padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 24.h),
child: Row(
children: [
Expanded(
child: CustomButton(
height: 56.h,
text: LocaleKeys.cancel.tr(),
onPressed: () {
Navigator.of(context).pop();
},
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
// icon: AppAssets.cancel,
// iconColor: AppColors.primaryRedColor,
borderRadius: 12.r,
),
),
SizedBox(width: 8.h),
Expanded(
child: CustomButton(
height: 56.h,
text: "Next".needTranslation,
onPressed: () async {
// Validate selection and payment info
if (_selectedProcedure == null) {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: "Please select a procedure".needTranslation),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
return;
}
if (info == null) {
// If payment info missing, attempt to fetch
LoaderBottomSheet.showLoader();
try {
await hmgServicesViewModel.getPaymentInfo(procedureID: _selectedProcedure!.procedureId!);
} catch (e) {
debugPrint('getPaymentInfo error: $e');
} finally {
LoaderBottomSheet.hideLoader();
}
if (hmgServicesViewModel.covidPaymentInfo == null) {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: "Payment information not available".needTranslation),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
return;
}
}
// Compute amount and project/clinic IDs defensively
final paymentInfo = hmgServicesViewModel.covidPaymentInfo ?? info!;
final double amount = paymentInfo.patientShareWithTaxField ?? (paymentInfo.patientShareField?.toDouble() ?? 0.0);
// projectID may be int or string; parse defensively
int projectID = 0;
try {
final p = widget.selectedHospital.mainProjectID;
if (p is int) projectID = p;
else if (p is String) projectID = int.tryParse(p) ?? 0;
} catch (_) {}
int clinicID = 0;
try {
clinicID = int.tryParse(widget.selectedHospital.setupID ?? '') ?? int.tryParse(widget.selectedHospital.iD?.toString() ?? '') ?? 0;
} catch (_) {}
// Navigate to payment screen
Navigator.of(context).push(
CustomPageRoute(
page: CovidPaymentScreen(
amount: amount,
projectID: projectID,
clinicID: clinicID,
procedureId: _selectedProcedure!.procedureId ?? '',
taxAmount: paymentInfo.patientTaxAmountField?.toDouble() ?? 0.0,
),
),
);
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
textColor: AppColors.whiteColor,
fontSize: 16.f,
fontWeight: FontWeight.w500,
borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w),
// icon: AppAssets.add_icon,
// iconColor: AppColors.whiteColor,
iconSize: 18.h,
),
),
],
),
)
]
],
),
),
);
}),
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(24.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Please select the procedure:".toText14(
color: AppColors.textColor,
weight: FontWeight.w500,
),
SizedBox(height: 16.h),
Consumer<HmgServicesViewModel>(
builder: (context, vm, _) {
final procedures = vm.covidTestProcedureList;
// ensure default selection is first item (once available)
if (_selectedProcedure == null && procedures.isNotEmpty) {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) {
setState(() {
_selectedProcedure = procedures[0];
});
// also fetch payment info for default selection and show loader while loading
if (procedures[0].procedureId != null) {
LoaderBottomSheet.showLoader();
hmgServicesViewModel
.getPaymentInfo(procedureID: procedures[0].procedureId!)
.whenComplete(() {
LoaderBottomSheet.hideLoader();
});
}
}
});
}
// Use a shrink-wrapped ListView.separated and match prescription styling
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: false,
),
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 16.h),
child: ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: procedures.length,
separatorBuilder: (context, index) => Divider(
height: 1.h,
thickness: 1.h,
color: AppColors.borderOnlyColor.withValues(alpha: 0.05),
).paddingOnly(top:8,bottom:16.h),
itemBuilder: (context, index) {
final item = procedures[index];
// Let the radio option widget manage its own padding to avoid doubled spacing
return _buildRadioOption(value: item, title: item.procedureName ?? '');
},
).paddingOnly(bottom:16.h)
),
);
},
),
],
),
),
),
);
}
Widget _buildRadioOption({
required Covid19GetTestProceduresResp value,
required String title,
}) {
final bool isSelected = _selectedProcedure?.procedureId == value.procedureId;
return GestureDetector(
onTap: () async {
setState(() {
_selectedProcedure = value;
});
// show bottomsheet loader while fetching payment info
if (value.procedureId != null) {
LoaderBottomSheet.showLoader();
try {
await hmgServicesViewModel.getPaymentInfo(procedureID: value.procedureId!, projectID: widget.selectedHospital.mainProjectID);
} catch (e) {
debugPrint('getPaymentInfo error: $e');
} finally {
LoaderBottomSheet.hideLoader();
}
}
},
child: Row(
children: [
Container(
width: 20.h,
height: 20.h,
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: isSelected
? AppColors.primaryRedColor
: AppColors.greyTextColor.withValues(alpha: 0.3),
width: 2,
),
),
child: isSelected
? Center(
child: Container(
width: 10.h,
height: 10.h,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColors.primaryRedColor,
),
),
)
: null,
),
SizedBox(width: 12.h),
Expanded(
child: title.toText14(
color: AppColors.textColor,
weight: FontWeight.w400,
),
),
],
)
// Keep only bottom padding here and rely on the surrounding container's left/right inset
.paddingOnly(left: 0.h, right: 0.h, top: 0.h, bottom: 12.h),
);
}
}