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/home/lakum_wallet_details.dart

431 lines
14 KiB
Dart

import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/api_consts.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/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_view_model.dart';
import 'package:hmg_patient_app_new/features/habib_wallet/models/lakum_inquiry_information_response_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:provider/provider.dart';
import 'package:url_launcher/url_launcher.dart';
class LakumWalletDetails extends StatelessWidget {
const LakumWalletDetails({super.key});
@override
Widget build(BuildContext context) {
AppState appState = getIt.get<AppState>();
return CollapsingListView(
title: LocaleKeys.lakumPoints.tr(context: context),
child: Consumer<HabibWalletViewModel>(
builder: (context, viewModel, child) {
// Check if loading
if (viewModel.isLakumAccountInfoLoading) {
return Center(
child: Padding(
padding: EdgeInsets.all(32.w),
child: CircularProgressIndicator(
color: AppColors.primaryRedColor,
),
),
);
}
// Check if account number is not available
if (viewModel.yahalaAccountNumber == "0" || viewModel.yahalaAccountNumber.isEmpty) {
return Center(
child: Padding(
padding: EdgeInsets.all(32.w),
child: LocaleKeys.lakumMsg.tr().toText14(
color: AppColors.greyTextColor,
),
),
);
}
// Get all transactions
List<PointsDetails> transactions = viewModel.getAllLakumTransactions();
// Display main UI
return SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(16.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Main Lakum Card with gradient and user info
_buildLakumMainCard(viewModel.lakumAccountInfo, appState),
SizedBox(height: 24.h),
// Redeem Button
_buildRedeemButton(context),
SizedBox(height: 24.h),
// Transaction List Header
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.transactions.tr(context: context).toText16(isBold: true),
if (transactions.isNotEmpty) "${transactions.length} Records".toText12(color: AppColors.greyTextColor),
],
),
SizedBox(height: 12.h),
// Transaction List Container
if (transactions.isEmpty) _buildEmptyTransactions() else _buildTransactionsList(transactions),
SizedBox(height: 24.h),
],
),
),
);
},
),
);
}
Widget _buildLakumMainCard(LakumInquiryInformationResponseModel accountInfo, AppState appState) {
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
AppColors.habibPharmacyColor,
AppColors.habibPharmacyColor.withAlpha(220),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(24.r),
boxShadow: [
BoxShadow(
color: AppColors.habibPharmacyColor.withAlpha(76),
blurRadius: 16,
offset: Offset(0, 8),
),
],
),
child: Padding(
padding: EdgeInsets.all(20.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Top Row: User Info and Grid Icon
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"${appState.getAuthenticatedUser()?.firstName ?? ''} ${appState.getAuthenticatedUser()?.lastName ?? ''}".toText18(
isBold: true,
color: Colors.white,
),
SizedBox(height: 4.h),
(accountInfo.accountNumber ?? 0).toString().toText14(
color: Colors.white.withAlpha(230),
),
],
),
),
Utils.buildImgWithAssets(
icon: AppAssets.lakumLogoWhite,
width: 80.h,
height: 80.h,
),
],
),
// SizedBox(height: 24.h),
LocaleKeys.lakumPoints.tr().toText18(color: Colors.white.withAlpha(230), isBold: true),
SizedBox(height: 8.h),
// Points Balance
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
(accountInfo.pointsBalance?.toString() ?? "0").toText44(
isBold: true,
color: Colors.white,
),
SizedBox(width: 8.w),
LocaleKeys.points
.tr()
.toText18(
color: Colors.white.withAlpha(230),
isBold: true,
)
.paddingOnly(bottom: 8.h),
],
),
SizedBox(height: 4.h),
// Balance Amount in SAR
"${accountInfo.pointsBalanceAmount?.toStringAsFixed(2) ?? "0.00"} SAR".toText18(
color: Colors.white.withAlpha(204),
),
SizedBox(height: 20.h),
// Stats Row
Row(
children: [
Expanded(
child: _buildStatChip(
LocaleKeys.gained.tr(),
accountInfo.gainedPoints?.toString() ?? "0",
Icons.arrow_circle_up,
),
),
SizedBox(width: 8.w),
Expanded(
child: _buildStatChip(
LocaleKeys.consumed.tr(),
accountInfo.consumedPoints?.toString() ?? "0",
Icons.arrow_circle_down,
),
),
],
),
],
),
),
);
}
Widget _buildStatChip(String label, String value, IconData icon) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 10.h),
decoration: BoxDecoration(
color: Colors.white.withAlpha(51),
borderRadius: BorderRadius.circular(12.r),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, color: Colors.white, size: 16.f),
SizedBox(width: 6.w),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
value.toText14(color: Colors.white, isBold: true),
label.toText10(color: Colors.white.withAlpha(204)),
],
),
],
),
);
}
Widget _buildRedeemButton(BuildContext context) {
return CustomButton(
height: 46.h,
icon: AppAssets.redeem_icon,
iconColor: AppColors.whiteColor,
iconSize: 24.h,
backgroundColor: AppColors.habibPharmacyColor,
textColor: AppColors.whiteColor,
text: LocaleKeys.redeem.tr(context: context),
borderWidth: 0.w,
fontWeight: FontWeight.w600,
borderColor: AppColors.habibPharmacyColor.withAlpha(15),
padding: EdgeInsets.fromLTRB(4, 0, 12, 0),
fontSize: 14.f,
onPressed: () {
Uri uri = Uri.parse(PHARMACY_REDIRECT_URL);
launchUrl(uri, mode: LaunchMode.externalApplication);
},
);
}
Widget _buildEmptyTransactions() {
return Container(
padding: EdgeInsets.all(32.w),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 16.r,
hasShadow: false,
),
child: Center(
child: Column(
children: [
Icon(Icons.receipt_long_outlined, size: 48.f, color: AppColors.greyTextColor),
SizedBox(height: 12.h),
"No transactions found".toText14(
color: AppColors.greyTextColor,
isCenter: true,
),
],
),
),
);
}
Widget _buildTransactionsList(List<PointsDetails> transactions) {
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 16.r,
hasShadow: false,
),
child: ListView.separated(
padding: EdgeInsets.all(16.w),
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: transactions.length,
separatorBuilder: (context, index) => Divider(
color: AppColors.dividerColor,
height: 24.h,
),
itemBuilder: (context, index) {
return _buildTransactionItem(transactions[index]);
},
),
);
}
Widget _buildTransactionItem(PointsDetails transaction) {
// Determine if points were gained or used
bool isGained = transaction.operationType?.toLowerCase() == 'gain' || transaction.operationType?.toLowerCase() == 'credit' || (transaction.points ?? 0) > 0;
Color transactionColor = isGained ? AppColors.habibPharmacyColor : AppColors.primaryRedColor;
String pointsText = "${isGained ? '+' : '-'}${transaction.points?.abs() ?? 0}";
// Format date
String formattedDate = "";
if (transaction.transactionDate != null) {
try {
formattedDate = DateUtil.formatDateToDate(
DateUtil.convertStringToDate(transaction.transactionDate!),
false,
);
} catch (e) {
formattedDate = transaction.transactionDate ?? "";
}
}
return Row(
children: [
// Transaction Icon
Container(
width: 44.w,
height: 44.h,
decoration: BoxDecoration(
color: transactionColor.withAlpha(25),
borderRadius: BorderRadius.circular(12.r),
),
child: Icon(
isGained ? Icons.add_rounded : Icons.remove_rounded,
color: transactionColor,
size: 24.f,
),
),
SizedBox(width: 12.w),
// Transaction Details
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
(transaction.subTransactionTypeDescription ?? transaction.operationType ?? "Transaction").toText14(
isBold: true,
maxlines: 2,
),
SizedBox(height: 2.h),
formattedDate.toText12(color: AppColors.greyTextColor),
],
),
),
// Points Value
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
pointsText.toText18(
isBold: true,
color: transactionColor,
),
if (transaction.amount != null && transaction.amount! > 0)
"${transaction.amount?.toStringAsFixed(2) ?? "0.00"} SAR".toText11(
color: AppColors.greyTextColor,
),
],
),
],
);
}
}
// Custom painter for wavy background pattern
class _WavyBackgroundPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
// Base color from AppColors
final baseColor = AppColors.habibPharmacyColor;
final paint = Paint()
..color = Colors.white.withAlpha(25)
..style = PaintingStyle.fill;
// Draw multiple wave patterns
final path1 = Path();
path1.moveTo(0, size.height * 0.3);
path1.quadraticBezierTo(
size.width * 0.25,
size.height * 0.2,
size.width * 0.5,
size.height * 0.3,
);
path1.quadraticBezierTo(
size.width * 0.75,
size.height * 0.4,
size.width,
size.height * 0.3,
);
path1.lineTo(size.width, 0);
path1.lineTo(0, 0);
path1.close();
canvas.drawPath(path1, paint);
// Second wave with darker shade
paint.color = Colors.black.withAlpha(15);
final path2 = Path();
path2.moveTo(0, size.height * 0.6);
path2.quadraticBezierTo(
size.width * 0.3,
size.height * 0.5,
size.width * 0.6,
size.height * 0.6,
);
path2.quadraticBezierTo(
size.width * 0.8,
size.height * 0.7,
size.width,
size.height * 0.6,
);
path2.lineTo(size.width, size.height);
path2.lineTo(0, size.height);
path2.close();
canvas.drawPath(path2, paint);
// Decorative circles with white overlay
paint.color = Colors.white.withAlpha(20);
canvas.drawCircle(Offset(size.width * 0.85, size.height * 0.15), 30, paint);
paint.color = Colors.white.withAlpha(10);
canvas.drawCircle(Offset(size.width * 0.15, size.height * 0.75), 40, paint);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}