|
|
|
@ -2,20 +2,27 @@ import 'dart:async';
|
|
|
|
|
|
|
|
|
|
|
|
import 'package:easy_localization/easy_localization.dart';
|
|
|
|
import 'package:easy_localization/easy_localization.dart';
|
|
|
|
import 'package:flutter/material.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/app_state.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/dependencies.dart';
|
|
|
|
import 'package:hmg_patient_app_new/core/utils/size_utils.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/string_extensions.dart';
|
|
|
|
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
|
|
|
|
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
|
|
|
|
import 'package:hmg_patient_app_new/features/offers_and_discounts/offers_and_discounts_view_model.dart';
|
|
|
|
import 'package:hmg_patient_app_new/features/offers_and_discounts/offers_and_discounts_view_model.dart';
|
|
|
|
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
|
|
|
|
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
|
|
|
|
import 'package:hmg_patient_app_new/presentation/offers_and_discounts/offer_and_discounts_success_payment_qr_page.dart';
|
|
|
|
import 'package:hmg_patient_app_new/presentation/offers_and_discounts/offer_and_discounts_success_payment_qr_page.dart';
|
|
|
|
|
|
|
|
import 'package:hmg_patient_app_new/presentation/offers_and_discounts/offers_and_discounts_detailed_page.dart';
|
|
|
|
import 'package:hmg_patient_app_new/theme/colors.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/appbar/collapsing_list_view.dart';
|
|
|
|
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.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:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
|
|
|
|
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
|
|
|
|
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
|
|
|
|
import 'package:provider/provider.dart';
|
|
|
|
import 'package:provider/provider.dart';
|
|
|
|
|
|
|
|
import 'package:shimmer/shimmer.dart';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import '../../features/offers_and_discounts/models/offers_purchases_history_response_model.dart';
|
|
|
|
|
|
|
|
|
|
|
|
class OffersAndDiscountsHistoryPage extends StatefulWidget {
|
|
|
|
class OffersAndDiscountsHistoryPage extends StatefulWidget {
|
|
|
|
const OffersAndDiscountsHistoryPage({super.key});
|
|
|
|
const OffersAndDiscountsHistoryPage({super.key});
|
|
|
|
@ -25,70 +32,102 @@ class OffersAndDiscountsHistoryPage extends StatefulWidget {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class _OffersAndDiscountsHistoryPageState extends State<OffersAndDiscountsHistoryPage> {
|
|
|
|
class _OffersAndDiscountsHistoryPageState extends State<OffersAndDiscountsHistoryPage> {
|
|
|
|
late OffersAndDiscountsViewModel offersAndDiscountsViewModel;
|
|
|
|
|
|
|
|
late AppState appState;
|
|
|
|
late AppState appState;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Track which history items have expanded hospitals list
|
|
|
|
|
|
|
|
Set<String> expandedHospitals = {};
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
@override
|
|
|
|
void initState() {
|
|
|
|
void initState() {
|
|
|
|
|
|
|
|
super.initState();
|
|
|
|
scheduleMicrotask(() {
|
|
|
|
scheduleMicrotask(() {
|
|
|
|
offersAndDiscountsViewModel.getOffersAndDiscountsHistory();
|
|
|
|
final offersAndDiscountsViewModel = Provider.of<OffersAndDiscountsViewModel>(context, listen: false);
|
|
|
|
|
|
|
|
offersAndDiscountsViewModel.initializeHistory();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
super.initState();
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
appState = getIt.get<AppState>();
|
|
|
|
appState = getIt.get<AppState>();
|
|
|
|
offersAndDiscountsViewModel = Provider.of<OffersAndDiscountsViewModel>(context, listen: false);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return CollapsingListView(
|
|
|
|
return CollapsingListView(
|
|
|
|
title: LocaleKeys.order.tr(context: context),
|
|
|
|
title: LocaleKeys.order.tr(context: context),
|
|
|
|
|
|
|
|
isLeading: true,
|
|
|
|
child: SingleChildScrollView(
|
|
|
|
child: SingleChildScrollView(
|
|
|
|
child: Consumer<OffersAndDiscountsViewModel>(builder: (context, offersAndDiscountVM, child) {
|
|
|
|
child: Consumer<OffersAndDiscountsViewModel>(builder: (context, offersAndDiscountVM, child) {
|
|
|
|
|
|
|
|
// Show loading state
|
|
|
|
if (offersAndDiscountVM.isHistoryLoading) {
|
|
|
|
if (offersAndDiscountVM.isHistoryLoading) {
|
|
|
|
return Container(
|
|
|
|
return _buildLoadingState();
|
|
|
|
padding: EdgeInsets.all(24.h),
|
|
|
|
|
|
|
|
child: Center(
|
|
|
|
|
|
|
|
child: CircularProgressIndicator(
|
|
|
|
|
|
|
|
color: AppColors.primaryRedColor,
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
final historyList = offersAndDiscountVM.filteredHistory;
|
|
|
|
List<Datum> historyList = offersAndDiscountVM.filteredHistory;
|
|
|
|
|
|
|
|
|
|
|
|
if (historyList.isEmpty) {
|
|
|
|
if (historyList.isEmpty) {
|
|
|
|
return Container(
|
|
|
|
return Utils.getNoDataWidget(context);
|
|
|
|
padding: EdgeInsets.all(24.h),
|
|
|
|
|
|
|
|
child: Column(
|
|
|
|
|
|
|
|
children: [
|
|
|
|
|
|
|
|
Icon(
|
|
|
|
|
|
|
|
Icons.history,
|
|
|
|
|
|
|
|
size: 64.h,
|
|
|
|
|
|
|
|
color: AppColors.greyTextColor,
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
SizedBox(height: 16.h),
|
|
|
|
|
|
|
|
LocaleKeys.noDataAvailable.tr(context: context).toText18(isBold: true),
|
|
|
|
|
|
|
|
SizedBox(height: 8.h),
|
|
|
|
|
|
|
|
"You haven't purchased any offers yet.".toText14(color: AppColors.greyTextColor),
|
|
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return Column(
|
|
|
|
return Column(
|
|
|
|
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
children: [
|
|
|
|
children: [
|
|
|
|
SizedBox(height: 24.h),
|
|
|
|
|
|
|
|
ListView.separated(
|
|
|
|
ListView.separated(
|
|
|
|
shrinkWrap: true,
|
|
|
|
shrinkWrap: true,
|
|
|
|
physics: NeverScrollableScrollPhysics(),
|
|
|
|
physics: NeverScrollableScrollPhysics(),
|
|
|
|
itemCount: historyList.length,
|
|
|
|
itemCount: historyList.length,
|
|
|
|
|
|
|
|
padding: EdgeInsets.only(bottom: 50),
|
|
|
|
separatorBuilder: (context, index) => SizedBox(height: 16.h),
|
|
|
|
separatorBuilder: (context, index) => SizedBox(height: 16.h),
|
|
|
|
itemBuilder: (context, index) {
|
|
|
|
itemBuilder: (context, index) {
|
|
|
|
final history = historyList[index];
|
|
|
|
Datum history = historyList[index];
|
|
|
|
|
|
|
|
return AnimationConfiguration.staggeredList(
|
|
|
|
|
|
|
|
position: index,
|
|
|
|
|
|
|
|
duration: const Duration(milliseconds: 500),
|
|
|
|
|
|
|
|
child: SlideAnimation(
|
|
|
|
|
|
|
|
verticalOffset: 100.0,
|
|
|
|
|
|
|
|
child: FadeInAnimation(
|
|
|
|
|
|
|
|
child: _buildHistoryCard(history),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Widget _buildLoadingState() {
|
|
|
|
return Container(
|
|
|
|
return Container(
|
|
|
|
|
|
|
|
padding: EdgeInsets.symmetric(horizontal: 24.w, vertical: 40.h),
|
|
|
|
|
|
|
|
child: Column(
|
|
|
|
|
|
|
|
children: List.generate(
|
|
|
|
|
|
|
|
3,
|
|
|
|
|
|
|
|
(index) => Container(
|
|
|
|
|
|
|
|
margin: EdgeInsets.only(bottom: 16.h),
|
|
|
|
|
|
|
|
child: Shimmer.fromColors(
|
|
|
|
|
|
|
|
baseColor: AppColors.shimmerBaseColor,
|
|
|
|
|
|
|
|
highlightColor: AppColors.shimmerHighlightColor,
|
|
|
|
|
|
|
|
child: Container(
|
|
|
|
|
|
|
|
height: 200.h,
|
|
|
|
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
|
|
|
|
color: AppColors.whiteColor,
|
|
|
|
|
|
|
|
borderRadius: BorderRadius.circular(20.r),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Widget _buildHistoryCard(Datum history) {
|
|
|
|
|
|
|
|
return AnimatedContainer(
|
|
|
|
|
|
|
|
duration: Duration(milliseconds: 300),
|
|
|
|
|
|
|
|
curve: Curves.easeInOut,
|
|
|
|
|
|
|
|
margin: EdgeInsets.symmetric(vertical: 0.h),
|
|
|
|
|
|
|
|
child: Container(
|
|
|
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: false),
|
|
|
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: false),
|
|
|
|
child: Column(
|
|
|
|
child: Column(
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
@ -103,9 +142,7 @@ class _OffersAndDiscountsHistoryPageState extends State<OffersAndDiscountsHistor
|
|
|
|
Row(
|
|
|
|
Row(
|
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
|
|
children: [
|
|
|
|
children: [
|
|
|
|
Expanded(
|
|
|
|
(appState.getLanguageID() == 1 ? history.offer!.nameAr ?? '' : history.offer!.name ?? '').toText16(isBold: true),
|
|
|
|
child: (appState.getLanguageID() == 1 ? history.offer.nameAr : history.offer.name).toText16(isBold: true),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
],
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
SizedBox(height: 12.h),
|
|
|
|
SizedBox(height: 12.h),
|
|
|
|
@ -114,35 +151,31 @@ class _OffersAndDiscountsHistoryPageState extends State<OffersAndDiscountsHistor
|
|
|
|
runSpacing: 8.h,
|
|
|
|
runSpacing: 8.h,
|
|
|
|
children: [
|
|
|
|
children: [
|
|
|
|
AppCustomChipWidget(
|
|
|
|
AppCustomChipWidget(
|
|
|
|
labelText: "Order: ${history.voucherCode}",
|
|
|
|
labelText: "${LocaleKeys.orderLabel.tr(context: context)}: ${history.voucherCode}",
|
|
|
|
backgroundColor: AppColors.chipBgColor,
|
|
|
|
backgroundColor: AppColors.chipBgColor,
|
|
|
|
textColor: AppColors.greyTextColor,
|
|
|
|
textColor: AppColors.textColor,
|
|
|
|
icon: "",
|
|
|
|
icon: AppAssets.my_sick_leave_icon,
|
|
|
|
labelPadding: EdgeInsetsDirectional.only(start: 8.w, end: 8.w),
|
|
|
|
labelPadding: EdgeInsetsDirectional.only(start: 0.w, end: 8.w),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
AppCustomChipWidget(
|
|
|
|
AppCustomChipWidget(
|
|
|
|
labelText: "Purchased: ${_formatDateChipFromDateTime(history.purchaseDate)}",
|
|
|
|
labelText: "${LocaleKeys.purchased.tr(context: context)}: ${_formatDateChipFromDateTime(history.purchaseDate!)}",
|
|
|
|
backgroundColor: AppColors.chipBgColor,
|
|
|
|
backgroundColor: AppColors.chipBgColor,
|
|
|
|
textColor: AppColors.greyTextColor,
|
|
|
|
textColor: AppColors.textColor,
|
|
|
|
icon: "",
|
|
|
|
icon: AppAssets.calendar,
|
|
|
|
labelPadding: EdgeInsetsDirectional.only(start: 8.w, end: 8.w),
|
|
|
|
labelPadding: EdgeInsetsDirectional.only(start: 0.w, end: 8.w),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
AppCustomChipWidget(
|
|
|
|
history.offer!.validTo != null
|
|
|
|
labelText: "Valid until: ${_formatDateChipFromDateTime(history.validTo)}",
|
|
|
|
? AppCustomChipWidget(
|
|
|
|
|
|
|
|
labelText: "${LocaleKeys.validUntil.tr(context: context)}: ${_formatDateChipFromDateTime(history.offer!.validTo!)}",
|
|
|
|
backgroundColor: AppColors.chipBgColor,
|
|
|
|
backgroundColor: AppColors.chipBgColor,
|
|
|
|
textColor: AppColors.greyTextColor,
|
|
|
|
textColor: AppColors.textColor,
|
|
|
|
icon: "",
|
|
|
|
icon: AppAssets.calendar,
|
|
|
|
labelPadding: EdgeInsetsDirectional.only(start: 8.w, end: 8.w),
|
|
|
|
labelPadding: EdgeInsetsDirectional.only(start: 0.w, end: 8.w),
|
|
|
|
isEnglishOnly: true,
|
|
|
|
isEnglishOnly: true,
|
|
|
|
),
|
|
|
|
)
|
|
|
|
AppCustomChipWidget(
|
|
|
|
: SizedBox(),
|
|
|
|
labelText:
|
|
|
|
// Hospital chips - show multiple chips when expanded
|
|
|
|
"Hospital: ${appState.getLanguageID() == 1 ? history.branches.first.nameAr : history.branches.first.name} ${history.branches.length > 1 ? '(+${history.branches.length - 1} more)' : ''}",
|
|
|
|
...(_buildHospitalChips(history)),
|
|
|
|
backgroundColor: AppColors.chipBgColor,
|
|
|
|
|
|
|
|
textColor: AppColors.greyTextColor,
|
|
|
|
|
|
|
|
icon: "",
|
|
|
|
|
|
|
|
labelPadding: EdgeInsetsDirectional.only(start: 8.w, end: 8.w),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
],
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
SizedBox(height: 12.h),
|
|
|
|
SizedBox(height: 12.h),
|
|
|
|
@ -150,129 +183,248 @@ class _OffersAndDiscountsHistoryPageState extends State<OffersAndDiscountsHistor
|
|
|
|
children: [
|
|
|
|
children: [
|
|
|
|
Expanded(
|
|
|
|
Expanded(
|
|
|
|
child: CustomButton(
|
|
|
|
child: CustomButton(
|
|
|
|
text: "View Offer Details",
|
|
|
|
text: LocaleKeys.viewOfferDetails.tr(),
|
|
|
|
onPressed: () {},
|
|
|
|
onPressed: () {
|
|
|
|
|
|
|
|
Navigator.of(context).push(
|
|
|
|
|
|
|
|
CustomPageRoute(
|
|
|
|
|
|
|
|
page: OffersAndDiscountsDetailedPage(offerId: history.offer!.id!),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
},
|
|
|
|
backgroundColor: AppColors.lightRedButtonColor,
|
|
|
|
backgroundColor: AppColors.lightRedButtonColor,
|
|
|
|
borderColor: AppColors.lightRedButtonColor,
|
|
|
|
borderColor: AppColors.lightRedButtonColor,
|
|
|
|
textColor: AppColors.primaryRedColor,
|
|
|
|
textColor: AppColors.primaryRedColor,
|
|
|
|
borderWidth: 0.w,
|
|
|
|
borderWidth: 0.w,
|
|
|
|
|
|
|
|
fontWeight: FontWeight.w500,
|
|
|
|
|
|
|
|
fontSize: 14.f,
|
|
|
|
|
|
|
|
height: 40.h,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
SizedBox(
|
|
|
|
SizedBox(width: 9.w),
|
|
|
|
width: 9.w,
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
Expanded(
|
|
|
|
Expanded(
|
|
|
|
child: CustomButton(
|
|
|
|
child: CustomButton(
|
|
|
|
text: "View Order Details",
|
|
|
|
text: LocaleKeys.viewOrderDetails.tr(),
|
|
|
|
onPressed: () {
|
|
|
|
onPressed: () {
|
|
|
|
Navigator.of(context).push(CustomPageRoute(page: OffersAndDiscountsSuccessQrPage(purchaseData: history)));
|
|
|
|
Navigator.of(context).push(CustomPageRoute(
|
|
|
|
|
|
|
|
page: OffersAndDiscountsSuccessQrPage(
|
|
|
|
|
|
|
|
purchaseData: history,
|
|
|
|
|
|
|
|
isFromPaymentScreen: false,
|
|
|
|
|
|
|
|
)));
|
|
|
|
},
|
|
|
|
},
|
|
|
|
backgroundColor: AppColors.whiteColor,
|
|
|
|
backgroundColor: AppColors.whiteColor,
|
|
|
|
borderColor: AppColors.textColor,
|
|
|
|
borderColor: AppColors.textColor,
|
|
|
|
textColor: AppColors.textColor,
|
|
|
|
textColor: AppColors.textColor,
|
|
|
|
|
|
|
|
fontWeight: FontWeight.w500,
|
|
|
|
|
|
|
|
fontSize: 14.f,
|
|
|
|
|
|
|
|
height: 40.h,
|
|
|
|
|
|
|
|
borderWidth: 1.w,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
],
|
|
|
|
).paddingSymmetrical(16.h, 16.h),
|
|
|
|
|
|
|
|
).paddingSymmetrical(24.h, 0.h);
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
),
|
|
|
|
),
|
|
|
|
SizedBox(height: 24.h),
|
|
|
|
|
|
|
|
],
|
|
|
|
],
|
|
|
|
);
|
|
|
|
).paddingSymmetrical(16.h, 16.h),
|
|
|
|
}),
|
|
|
|
).paddingSymmetrical(24.h, 0.h),
|
|
|
|
),
|
|
|
|
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Color _getStatusColor(String status) {
|
|
|
|
String _formatDateChipFromDateTime(DateTime date) {
|
|
|
|
switch (status.toLowerCase()) {
|
|
|
|
try {
|
|
|
|
case 'completed':
|
|
|
|
return DateFormat('d MMM yyyy').format(date);
|
|
|
|
case 'success':
|
|
|
|
} catch (e) {
|
|
|
|
case 'paid':
|
|
|
|
return date.toString();
|
|
|
|
return AppColors.lightGreenColor;
|
|
|
|
|
|
|
|
case 'pending':
|
|
|
|
|
|
|
|
return AppColors.alertColor;
|
|
|
|
|
|
|
|
case 'cancelled':
|
|
|
|
|
|
|
|
case 'failed':
|
|
|
|
|
|
|
|
return AppColors.errorColor;
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
return AppColors.greyTextColor;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
String _getStatusText(String status) {
|
|
|
|
List<Widget> _buildHospitalChips(dynamic history) {
|
|
|
|
switch (status.toLowerCase()) {
|
|
|
|
final isExpanded = expandedHospitals.contains(history.voucherCode);
|
|
|
|
case 'active':
|
|
|
|
final isArabic = appState.getLanguageID() == 1;
|
|
|
|
case 'valid':
|
|
|
|
|
|
|
|
return LocaleKeys.active.tr(context: context);
|
|
|
|
if (history.branches == null || history.branches!.isEmpty) {
|
|
|
|
case 'redeemed':
|
|
|
|
return [
|
|
|
|
case 'used':
|
|
|
|
AppCustomChipWidget(
|
|
|
|
return "Redeemed";
|
|
|
|
labelText: "Hospital: N/A",
|
|
|
|
case 'expired':
|
|
|
|
backgroundColor: AppColors.chipBgColor,
|
|
|
|
return LocaleKeys.expired.tr(context: context);
|
|
|
|
textColor: AppColors.textColor,
|
|
|
|
case 'pending':
|
|
|
|
icon: AppAssets.hospital,
|
|
|
|
return LocaleKeys.pending.tr(context: context);
|
|
|
|
labelPadding: EdgeInsetsDirectional.only(start: 0.w, end: 8.w),
|
|
|
|
case 'cancelled':
|
|
|
|
),
|
|
|
|
return LocaleKeys.cancelled.tr(context: context);
|
|
|
|
];
|
|
|
|
default:
|
|
|
|
|
|
|
|
return status.toUpperCase();
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If only one hospital, just show it
|
|
|
|
|
|
|
|
if (history.branches!.length == 1) {
|
|
|
|
|
|
|
|
final hospitalName = isArabic ? history.branches!.first.nameAr : history.branches!.first.name;
|
|
|
|
|
|
|
|
return [
|
|
|
|
|
|
|
|
AppCustomChipWidget(
|
|
|
|
|
|
|
|
labelText: "Hospital: $hospitalName",
|
|
|
|
|
|
|
|
backgroundColor: AppColors.chipBgColor,
|
|
|
|
|
|
|
|
textColor: AppColors.textColor,
|
|
|
|
|
|
|
|
icon: AppAssets.hospital,
|
|
|
|
|
|
|
|
labelPadding: EdgeInsetsDirectional.only(start: 0.w, end: 8.w),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
String _formatDateChipFromDateTime(DateTime date) {
|
|
|
|
// Multiple hospitals
|
|
|
|
try {
|
|
|
|
if (isExpanded) {
|
|
|
|
return DateFormat('d MMM yyyy').format(date);
|
|
|
|
// Show each hospital as a separate chip
|
|
|
|
} catch (e) {
|
|
|
|
List<Widget> chips = history.branches!.map<Widget>((branch) {
|
|
|
|
return date.toString();
|
|
|
|
final hospitalName = isArabic ? branch.nameAr : branch.name;
|
|
|
|
|
|
|
|
return AppCustomChipWidget(
|
|
|
|
|
|
|
|
labelText: "Hospital: $hospitalName",
|
|
|
|
|
|
|
|
backgroundColor: AppColors.chipBgColor,
|
|
|
|
|
|
|
|
textColor: AppColors.textColor,
|
|
|
|
|
|
|
|
icon: AppAssets.hospital,
|
|
|
|
|
|
|
|
labelPadding: EdgeInsetsDirectional.only(start: 0.w, end: 8.w),
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}).toList();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Add a "Show less" chip at the end
|
|
|
|
|
|
|
|
chips.add(
|
|
|
|
|
|
|
|
AppCustomChipWidget(
|
|
|
|
|
|
|
|
labelText: "Show less",
|
|
|
|
|
|
|
|
backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.1),
|
|
|
|
|
|
|
|
textColor: AppColors.primaryRedColor,
|
|
|
|
|
|
|
|
icon: "",
|
|
|
|
|
|
|
|
labelPadding: EdgeInsetsDirectional.only(start: 8.w, end: 8.w),
|
|
|
|
|
|
|
|
onChipTap: () {
|
|
|
|
|
|
|
|
setState(() {
|
|
|
|
|
|
|
|
expandedHospitals.remove(history.voucherCode);
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return chips;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// Show collapsed view with count
|
|
|
|
|
|
|
|
final firstHospital = isArabic ? history.branches!.first.nameAr : history.branches!.first.name;
|
|
|
|
|
|
|
|
final remainingCount = history.branches!.length - 1;
|
|
|
|
|
|
|
|
return [
|
|
|
|
|
|
|
|
AppCustomChipWidget(
|
|
|
|
|
|
|
|
labelText: "Hospital: $firstHospital (+$remainingCount more)",
|
|
|
|
|
|
|
|
backgroundColor: AppColors.chipBgColor,
|
|
|
|
|
|
|
|
textColor: AppColors.textColor,
|
|
|
|
|
|
|
|
icon: AppAssets.hospital,
|
|
|
|
|
|
|
|
labelPadding: EdgeInsetsDirectional.only(start: 0.w, end: 8.w),
|
|
|
|
|
|
|
|
onChipTap: () {
|
|
|
|
|
|
|
|
setState(() {
|
|
|
|
|
|
|
|
expandedHospitals.add(history.voucherCode!);
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
String _getOfferStatus(dynamic history) {
|
|
|
|
String _getOfferStatus(dynamic history) {
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
final now = DateTime.now();
|
|
|
|
final now = DateTime.now();
|
|
|
|
|
|
|
|
final state = history.state?.toLowerCase() ?? '';
|
|
|
|
|
|
|
|
|
|
|
|
// Check if the offer has expired based on validTo date
|
|
|
|
// Check state first
|
|
|
|
if (now.isAfter(history.validTo)) {
|
|
|
|
switch (state) {
|
|
|
|
|
|
|
|
case 'purchased':
|
|
|
|
|
|
|
|
// Check if expired by date
|
|
|
|
|
|
|
|
if (history.validTo != null && now.isAfter(history.validTo)) {
|
|
|
|
return LocaleKeys.expired.tr(context: context);
|
|
|
|
return LocaleKeys.expired.tr(context: context);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return LocaleKeys.purchased.tr(context: context);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case 'redeemed':
|
|
|
|
|
|
|
|
return LocaleKeys.redeemed.tr(context: context);
|
|
|
|
|
|
|
|
|
|
|
|
// Check state for active/available status
|
|
|
|
case 'partially_redeemed':
|
|
|
|
if (history.state.toLowerCase() == 'redeemed' || history.state.toLowerCase() == 'used') {
|
|
|
|
// Check if expired by date
|
|
|
|
|
|
|
|
if (history.validTo != null && now.isAfter(history.validTo)) {
|
|
|
|
return LocaleKeys.expired.tr(context: context);
|
|
|
|
return LocaleKeys.expired.tr(context: context);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return LocaleKeys.partiallyRedeemed.tr(context: context);
|
|
|
|
|
|
|
|
|
|
|
|
if (history.state.toLowerCase() == 'active' || history.state.toLowerCase() == 'valid') {
|
|
|
|
case 'expired':
|
|
|
|
return LocaleKeys.active.tr(context: context);
|
|
|
|
return LocaleKeys.expired.tr(context: context);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case 'active':
|
|
|
|
|
|
|
|
case 'valid':
|
|
|
|
|
|
|
|
// Check if expired by date
|
|
|
|
|
|
|
|
if (history.validTo != null && now.isAfter(history.validTo)) {
|
|
|
|
|
|
|
|
return LocaleKeys.expired.tr(context: context);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return LocaleKeys.active.tr(context: context);
|
|
|
|
|
|
|
|
|
|
|
|
// For pending or other states, show as available
|
|
|
|
default:
|
|
|
|
return "Available";
|
|
|
|
// Check if expired by date for unknown states
|
|
|
|
|
|
|
|
if (history.validTo != null && now.isAfter(history.validTo)) {
|
|
|
|
|
|
|
|
return LocaleKeys.expired.tr(context: context);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return LocaleKeys.available.tr(context: context);
|
|
|
|
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
} catch (e) {
|
|
|
|
return LocaleKeys.active.tr(context: context);
|
|
|
|
return LocaleKeys.active.tr(context: context);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Color _getOfferStatusBgColor(dynamic history) {
|
|
|
|
Color _getOfferStatusBgColor(dynamic history) {
|
|
|
|
final status = _getOfferStatus(history);
|
|
|
|
final state = history.state?.toLowerCase() ?? '';
|
|
|
|
if (status == LocaleKeys.active.tr(context: context)) {
|
|
|
|
final now = DateTime.now();
|
|
|
|
|
|
|
|
final isExpired = history.validTo != null && now.isAfter(history.validTo);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If expired by date, show error color
|
|
|
|
|
|
|
|
if (isExpired && state != 'redeemed') {
|
|
|
|
|
|
|
|
return AppColors.errorColor.withValues(alpha: 0.1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
switch (state) {
|
|
|
|
|
|
|
|
case 'purchased':
|
|
|
|
return AppColors.successColor.withValues(alpha: 0.1);
|
|
|
|
return AppColors.successColor.withValues(alpha: 0.1);
|
|
|
|
} else if (status == LocaleKeys.expired.tr(context: context)) {
|
|
|
|
|
|
|
|
|
|
|
|
case 'redeemed':
|
|
|
|
|
|
|
|
return AppColors.greyTextColor.withValues(alpha: 0.1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case 'partially_redeemed':
|
|
|
|
|
|
|
|
return AppColors.alertColor.withValues(alpha: 0.1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case 'expired':
|
|
|
|
return AppColors.errorColor.withValues(alpha: 0.1);
|
|
|
|
return AppColors.errorColor.withValues(alpha: 0.1);
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
|
|
case 'active':
|
|
|
|
|
|
|
|
case 'valid':
|
|
|
|
|
|
|
|
return AppColors.successColor.withValues(alpha: 0.1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
return AppColors.alertColor.withValues(alpha: 0.1);
|
|
|
|
return AppColors.alertColor.withValues(alpha: 0.1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Color _getOfferStatusTextColor(dynamic history) {
|
|
|
|
Color _getOfferStatusTextColor(dynamic history) {
|
|
|
|
final status = _getOfferStatus(history);
|
|
|
|
final state = history.state?.toLowerCase() ?? '';
|
|
|
|
if (status == LocaleKeys.active.tr(context: context)) {
|
|
|
|
final now = DateTime.now();
|
|
|
|
|
|
|
|
final isExpired = history.validTo != null && now.isAfter(history.validTo);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If expired by date, show error color
|
|
|
|
|
|
|
|
if (isExpired && state != 'redeemed') {
|
|
|
|
|
|
|
|
return AppColors.errorColor;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
switch (state) {
|
|
|
|
|
|
|
|
case 'purchased':
|
|
|
|
return AppColors.successColor;
|
|
|
|
return AppColors.successColor;
|
|
|
|
} else if (status == LocaleKeys.expired.tr(context: context)) {
|
|
|
|
|
|
|
|
|
|
|
|
case 'redeemed':
|
|
|
|
|
|
|
|
return AppColors.greyTextColor;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case 'partially_redeemed':
|
|
|
|
|
|
|
|
return AppColors.alertColor;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case 'expired':
|
|
|
|
return AppColors.errorColor;
|
|
|
|
return AppColors.errorColor;
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
|
|
case 'active':
|
|
|
|
|
|
|
|
case 'valid':
|
|
|
|
|
|
|
|
return AppColors.successColor;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
return AppColors.alertColor;
|
|
|
|
return AppColors.alertColor;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|