apskel-owner-flutter/lib/presentation/pages/sales/widgets/sales_payment_method_card.dart
Efril 8d801e52d9
Some checks are pending
Build & Deploy iOS to TestFlight / build-and-deploy (push) Waiting to run
feat: update sales ui
2026-06-23 23:18:22 +07:00

266 lines
8.1 KiB
Dart

import 'package:flutter/material.dart';
import 'package:shimmer/shimmer.dart';
import '../../../../common/extension/extension.dart';
import '../../../../common/theme/theme.dart';
import '../../../../domain/analytic/analytic.dart';
import '../../../components/spacer/spacer.dart';
class SalesPaymentMethodCard extends StatelessWidget {
final PaymentMethodAnalytic paymentMethodAnalytic;
final bool isFetching;
const SalesPaymentMethodCard({
super.key,
required this.paymentMethodAnalytic,
required this.isFetching,
});
@override
Widget build(BuildContext context) {
if (isFetching) return _buildShimmer();
final data = paymentMethodAnalytic.data;
final totalTransactions = paymentMethodAnalytic.summary.totalOrders;
return Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: AppColor.surface,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.04),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Title row
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
context.lang.payment_methods,
style: AppStyle.xl.copyWith(
fontWeight: FontWeight.bold,
color: AppColor.textPrimary,
fontSize: 18,
),
),
Text(
'$totalTransactions ${context.lang.transactions.toLowerCase()}',
style: AppStyle.sm.copyWith(
color: AppColor.textSecondary,
fontWeight: FontWeight.w500,
fontSize: 13,
),
),
],
),
const SpaceHeight(16),
// Payment method items
if (data.isEmpty)
Center(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 20),
child: Text(
context.lang.no_data_available,
style: AppStyle.md.copyWith(color: AppColor.textSecondary),
),
),
)
else
...data.asMap().entries.map((entry) {
final index = entry.key;
final item = entry.value;
return Column(
children: [
_buildPaymentMethodItem(item, index),
if (index < data.length - 1) const SpaceHeight(16),
],
);
}),
],
),
);
}
Widget _buildPaymentMethodItem(PaymentMethodItem item, int index) {
final colors = [
AppColor.primary,
const Color(0xFF00BCD4),
const Color(0xFFFF9800),
AppColor.success,
AppColor.info,
];
final color = colors[index % colors.length];
return Column(
children: [
// Name + count + amount + percentage
Row(
children: [
// Name
Expanded(
child: Row(
children: [
Text(
item.paymentMethodName,
style: AppStyle.md.copyWith(
color: AppColor.textPrimary,
fontWeight: FontWeight.w600,
fontSize: 14,
),
),
const SpaceWidth(8),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 2,
),
decoration: BoxDecoration(
color: AppColor.textSecondary.withOpacity(0.1),
borderRadius: BorderRadius.circular(10),
),
child: Text(
'${item.paymentCount}x',
style: AppStyle.xs.copyWith(
color: AppColor.textSecondary,
fontWeight: FontWeight.w600,
fontSize: 12,
),
),
),
],
),
),
// Amount
Text(
item.totalAmount.toInt().currencyFormatRp,
style: AppStyle.md.copyWith(
color: AppColor.textPrimary,
fontWeight: FontWeight.w600,
fontSize: 14,
),
),
const SpaceWidth(6),
// Percentage
Text(
'${item.percentage.toStringAsFixed(1)}%',
style: AppStyle.xs.copyWith(
color: AppColor.textSecondary,
fontWeight: FontWeight.w500,
fontSize: 12,
),
),
],
),
const SpaceHeight(8),
// Progress bar
ClipRRect(
borderRadius: BorderRadius.circular(4),
child: LinearProgressIndicator(
value: item.percentage / 100,
minHeight: 6,
backgroundColor: AppColor.border.withOpacity(0.3),
valueColor: AlwaysStoppedAnimation<Color>(color),
),
),
],
);
}
Widget _buildShimmer() {
return Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: AppColor.surface,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.04),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: Shimmer.fromColors(
baseColor: Colors.grey[300]!,
highlightColor: Colors.grey[100]!,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
width: 150,
height: 20,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(4),
),
),
Container(
width: 80,
height: 14,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(4),
),
),
],
),
const SpaceHeight(20),
...List.generate(
3,
(index) => Padding(
padding: const EdgeInsets.only(bottom: 16),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
width: 120,
height: 14,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(4),
),
),
Container(
width: 90,
height: 14,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(4),
),
),
],
),
const SpaceHeight(8),
Container(
width: double.infinity,
height: 6,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(4),
),
),
],
),
),
),
],
),
),
);
}
}