chitfund/luckychit/lib/interfaces/member/member_group_details_page.dart

1131 lines
34 KiB
Dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import '../../core/services/chit_group_service.dart';
import '../../core/services/payment_service.dart';
import '../../core/services/auth_service.dart';
import '../../core/models/chit_group.dart';
import '../../core/models/payment.dart';
import '../../core/models/monthly_draw.dart';
import 'member_payment_dialog.dart';
class MemberGroupDetailsPage extends StatefulWidget {
final ChitGroup group;
const MemberGroupDetailsPage({
super.key,
required this.group,
});
@override
State<MemberGroupDetailsPage> createState() => _MemberGroupDetailsPageState();
}
class _MemberGroupDetailsPageState extends State<MemberGroupDetailsPage>
with SingleTickerProviderStateMixin {
late TabController _tabController;
final _chitGroupService = Get.find<ChitGroupService>();
final _paymentService = Get.find<PaymentService>();
final _authService = Get.find<AuthService>();
@override
void initState() {
super.initState();
_tabController = TabController(length: 3, vsync: this);
// Load data
WidgetsBinding.instance.addPostFrameCallback((_) {
_loadData();
});
}
Future<void> _loadData() async {
final groupId = widget.group.id;
await Future.wait([
_chitGroupService.loadChitGroupDetails(groupId),
_chitGroupService.loadGroupMembers(groupId),
_chitGroupService.loadGroupMonthlyDraws(groupId),
_paymentService.loadGroupPayments(groupId),
]);
}
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey.shade50,
appBar: AppBar(
leading: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () => Navigator.pop(context),
tooltip: 'Back',
),
title: Text(
widget.group.name,
style: TextStyle(fontSize: 20.sp, fontWeight: FontWeight.w600),
),
backgroundColor: Colors.green.shade600,
foregroundColor: Colors.white,
elevation: 2,
bottom: TabBar(
controller: _tabController,
indicatorColor: Colors.white,
indicatorWeight: 3,
labelStyle: TextStyle(fontSize: 14.sp, fontWeight: FontWeight.w600),
unselectedLabelStyle: TextStyle(fontSize: 14.sp),
tabs: const [
Tab(text: 'Overview'),
Tab(text: 'Payments'),
Tab(text: 'Draws'),
],
),
),
body: TabBarView(
controller: _tabController,
children: [
_buildOverviewTab(),
_buildPaymentsTab(),
_buildDrawsTab(),
],
),
floatingActionButton: widget.group.status.toLowerCase() == 'active'
? FloatingActionButton.extended(
onPressed: _showPaymentDialog,
backgroundColor: Colors.green.shade600,
foregroundColor: Colors.white,
icon: Icon(Icons.payment, size: 24.w),
label: Text(
'Pay Now',
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
),
),
elevation: 4,
)
: null,
);
}
void _showPaymentDialog() {
final myUserId = _authService.currentUser.value?.id;
if (myUserId == null) {
Get.snackbar(
'Error',
'User not found',
backgroundColor: Colors.red.shade100,
colorText: Colors.red.shade800,
);
return;
}
final myMember = widget.group.members?.cast<dynamic>().firstWhere(
(m) => m.userId == myUserId,
orElse: () => null,
);
if (myMember == null) {
Get.snackbar(
'Error',
'Member information not found',
backgroundColor: Colors.red.shade100,
colorText: Colors.red.shade800,
);
return;
}
showDialog(
context: context,
builder: (context) => MemberPaymentDialog(
group: widget.group,
member: myMember,
),
).then((result) {
if (result == true) {
// Payment successful, reload data
_loadData();
}
});
}
Widget _buildOverviewTab() {
return Obx(() {
final group = _chitGroupService.selectedGroup.value ?? widget.group;
final members = _chitGroupService.groupMembers;
final myMember = members.firstWhereOrNull(
(m) => m.userId == _authService.currentUser.value?.id,
);
return RefreshIndicator(
onRefresh: _loadData,
child: ListView(
padding: EdgeInsets.all(16.w),
children: [
// Last Draw Winner Card (if exists)
if (_chitGroupService.monthlyDraws.isNotEmpty)
_buildLastDrawWinnerCard(_chitGroupService.monthlyDraws.first),
if (_chitGroupService.monthlyDraws.isNotEmpty)
SizedBox(height: 16.h),
// Group Info Card (Compact)
_buildCompactGroupInfoCard(group),
SizedBox(height: 16.h),
// My Status Card
if (myMember != null) _buildMyStatusCard(myMember),
if (myMember != null) SizedBox(height: 16.h),
// Quick Stats
_buildQuickStats(group, myMember),
SizedBox(height: 16.h),
// Members Card
_buildMembersCard(members),
],
),
);
});
}
Widget _buildPaymentsTab() {
final myUserId = _authService.currentUser.value?.id;
return Obx(() {
final payments = _paymentService.payments;
final isLoading = _paymentService.isLoading;
// Filter to show only my payments
final myPayments = payments.where((p) => p.userId == myUserId).toList();
if (isLoading) {
return Center(
child: CircularProgressIndicator(color: Colors.green.shade600),
);
}
return RefreshIndicator(
onRefresh: () => _paymentService.loadGroupPayments(widget.group.id),
child: myPayments.isEmpty
? _buildEmptyPayments()
: ListView.builder(
padding: EdgeInsets.all(16.w),
itemCount: myPayments.length,
itemBuilder: (context, index) {
return _buildPaymentCard(myPayments[index]);
},
),
);
});
}
Widget _buildDrawsTab() {
return Obx(() {
final draws = _chitGroupService.monthlyDraws;
if (_chitGroupService.isLoading.value) {
return Center(
child: CircularProgressIndicator(color: Colors.green.shade600),
);
}
return RefreshIndicator(
onRefresh: () => _chitGroupService.loadGroupMonthlyDraws(widget.group.id),
child: draws.isEmpty
? _buildEmptyDraws()
: ListView.builder(
padding: EdgeInsets.all(16.w),
itemCount: draws.length,
itemBuilder: (context, index) {
return _buildDrawCard(draws[index]);
},
),
);
});
}
Widget _buildLastDrawWinnerCard(MonthlyDraw lastDraw) {
final isWinner = lastDraw.winnerId == _authService.currentUser.value?.id;
return Card(
elevation: 3,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16.r)),
child: Container(
padding: EdgeInsets.all(16.w),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: isWinner
? [Colors.amber.shade400, Colors.amber.shade600]
: [Colors.purple.shade400, Colors.purple.shade600],
),
borderRadius: BorderRadius.circular(16.r),
),
child: Column(
children: [
Row(
children: [
Container(
padding: EdgeInsets.all(8.w),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.3),
borderRadius: BorderRadius.circular(12.r),
),
child: Icon(
isWinner ? Icons.emoji_events : Icons.casino,
color: Colors.white,
size: 24.w,
),
),
SizedBox(width: 12.w),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
isWinner ? '🎉 You Won!' : 'Latest Draw Winner',
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
Text(
'Month ${lastDraw.month}, ${lastDraw.year}',
style: TextStyle(
fontSize: 14.sp,
color: Colors.white.withOpacity(0.9),
),
),
],
),
),
],
),
SizedBox(height: 16.h),
Container(
padding: EdgeInsets.all(16.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12.r),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Column(
children: [
Text(
lastDraw.winner?.fullName ?? 'Unknown',
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.bold,
color: Colors.grey.shade800,
),
),
SizedBox(height: 4.h),
Text(
'Winner',
style: TextStyle(
fontSize: 14.sp,
color: Colors.grey.shade600,
),
),
],
),
Container(
width: 1,
height: 40.h,
color: Colors.grey.shade300,
),
Column(
children: [
Text(
'${_formatCurrency(lastDraw.prizeAmount)}',
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.bold,
color: Colors.green.shade700,
),
),
SizedBox(height: 4.h),
Text(
'Prize',
style: TextStyle(
fontSize: 14.sp,
color: Colors.grey.shade600,
),
),
],
),
],
),
),
],
),
),
);
}
Widget _buildCompactGroupInfoCard(ChitGroup group) {
return Card(
elevation: 2,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16.r)),
child: Padding(
padding: EdgeInsets.all(16.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Group Info',
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.bold,
color: Colors.grey.shade800,
),
),
_buildStatusBadge(group.status),
],
),
SizedBox(height: 16.h),
Row(
children: [
Expanded(child: _buildCompactInfo('Total Value', '${_formatCurrency(group.totalValue)}', Icons.account_balance_wallet)),
SizedBox(width: 12.w),
Expanded(child: _buildCompactInfo('Installment', '${_formatCurrency(group.monthlyInstallment)}', Icons.payment)),
],
),
SizedBox(height: 12.h),
Row(
children: [
Expanded(child: _buildCompactInfo('Duration', '${group.durationMonths} months', Icons.calendar_today)),
SizedBox(width: 12.w),
Expanded(child: _buildCompactInfo('Draw Date', '${group.drawDate}th', Icons.event)),
],
),
if (group.startDate != null) ...[
SizedBox(height: 12.h),
_buildCompactInfo('Started On', _formatDate(group.startDate!), Icons.play_circle),
],
],
),
),
);
}
Widget _buildCompactInfo(String label, String value, IconData icon) {
return Row(
children: [
Icon(icon, size: 18.w, color: Colors.green.shade600),
SizedBox(width: 8.w),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: TextStyle(
fontSize: 12.sp,
color: Colors.grey.shade600,
),
),
SizedBox(height: 2.h),
Text(
value,
style: TextStyle(
fontSize: 14.sp,
fontWeight: FontWeight.w600,
color: Colors.grey.shade800,
),
),
],
),
),
],
);
}
Widget _buildMyStatusCard(dynamic member) {
return Card(
elevation: 2,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16.r)),
child: Container(
padding: EdgeInsets.all(20.w),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.blue.shade50, Colors.blue.shade100],
),
borderRadius: BorderRadius.circular(16.r),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(Icons.person, color: Colors.blue.shade700, size: 24.w),
SizedBox(width: 12.w),
Text(
'My Status',
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.bold,
color: Colors.blue.shade800,
),
),
],
),
SizedBox(height: 16.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
_buildStatItem('Total Paid', '${_formatCurrency(member.totalPaid)}', Colors.green),
Container(width: 1, height: 40.h, color: Colors.blue.shade300),
_buildStatItem('Total Won', '${_formatCurrency(member.totalWon)}', Colors.orange),
],
),
SizedBox(height: 12.h),
Container(
padding: EdgeInsets.all(12.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12.r),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Joined',
style: TextStyle(
fontSize: 14.sp,
color: Colors.grey.shade600,
),
),
Text(
_formatDate(member.joinedDate),
style: TextStyle(
fontSize: 14.sp,
fontWeight: FontWeight.w600,
color: Colors.grey.shade800,
),
),
],
),
),
],
),
),
);
}
Widget _buildMembersCard(List<dynamic> members) {
return Card(
elevation: 2,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16.r)),
child: Padding(
padding: EdgeInsets.all(20.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Members',
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.bold,
color: Colors.grey.shade800,
),
),
Text(
'${members.length} members',
style: TextStyle(
fontSize: 14.sp,
color: Colors.grey.shade600,
),
),
],
),
SizedBox(height: 16.h),
...members.map((member) => _buildMemberItem(member)),
],
),
),
);
}
Widget _buildMemberItem(dynamic member) {
final user = member.user;
final isMe = member.userId == _authService.currentUser.value?.id;
return Container(
margin: EdgeInsets.only(bottom: 12.h),
padding: EdgeInsets.all(12.w),
decoration: BoxDecoration(
color: isMe ? Colors.green.shade50 : Colors.grey.shade50,
borderRadius: BorderRadius.circular(12.r),
border: Border.all(
color: isMe ? Colors.green.shade300 : Colors.grey.shade200,
),
),
child: Row(
children: [
CircleAvatar(
radius: 20.r,
backgroundColor: isMe ? Colors.green.shade600 : Colors.grey.shade400,
child: Text(
user?.fullName?.substring(0, 1).toUpperCase() ?? 'M',
style: TextStyle(
color: Colors.white,
fontSize: 16.sp,
fontWeight: FontWeight.bold,
),
),
),
SizedBox(width: 12.w),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Text(
user?.fullName ?? 'Unknown',
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
color: Colors.grey.shade800,
),
),
),
if (isMe)
Container(
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h),
decoration: BoxDecoration(
color: Colors.green.shade600,
borderRadius: BorderRadius.circular(8.r),
),
child: Text(
'You',
style: TextStyle(
fontSize: 12.sp,
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
],
),
SizedBox(height: 4.h),
Text(
user?.mobileNumber ?? '',
style: TextStyle(
fontSize: 14.sp,
color: Colors.grey.shade600,
),
),
],
),
),
],
),
);
}
Widget _buildQuickStats(ChitGroup group, dynamic myMember) {
return Row(
children: [
Expanded(
child: _buildQuickStatCard(
'Total Members',
'${group.currentMemberCount}',
Icons.people,
Colors.blue.shade600,
),
),
SizedBox(width: 12.w),
Expanded(
child: _buildQuickStatCard(
'Duration',
'${group.durationMonths}M',
Icons.calendar_month,
Colors.orange.shade600,
),
),
],
);
}
Widget _buildQuickStatCard(String label, String value, IconData icon, Color color) {
return Card(
elevation: 2,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.r)),
child: Container(
padding: EdgeInsets.all(16.w),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [color.withOpacity(0.1), color.withOpacity(0.05)],
),
borderRadius: BorderRadius.circular(12.r),
),
child: Column(
children: [
Icon(icon, color: color, size: 28.w),
SizedBox(height: 8.h),
Text(
value,
style: TextStyle(
fontSize: 24.sp,
fontWeight: FontWeight.bold,
color: color,
),
),
SizedBox(height: 4.h),
Text(
label,
style: TextStyle(
fontSize: 12.sp,
color: Colors.grey.shade600,
),
textAlign: TextAlign.center,
),
],
),
),
);
}
Widget _buildPaymentCard(Payment payment) {
return Card(
margin: EdgeInsets.only(bottom: 12.h),
elevation: 2,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.r)),
child: Padding(
padding: EdgeInsets.all(16.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Month ${payment.month}, ${payment.year}',
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
color: Colors.grey.shade800,
),
),
_buildPaymentStatusBadge(payment.status),
],
),
SizedBox(height: 12.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Amount',
style: TextStyle(
fontSize: 14.sp,
color: Colors.grey.shade600,
),
),
SizedBox(height: 4.h),
Text(
'${_formatCurrency(payment.amount)}',
style: TextStyle(
fontSize: 20.sp,
fontWeight: FontWeight.bold,
color: Colors.green.shade700,
),
),
],
),
if (payment.paidAt != null)
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
'Paid On',
style: TextStyle(
fontSize: 14.sp,
color: Colors.grey.shade600,
),
),
SizedBox(height: 4.h),
Text(
_formatDate(payment.paidAt!),
style: TextStyle(
fontSize: 14.sp,
fontWeight: FontWeight.w600,
color: Colors.grey.shade800,
),
),
],
),
],
),
if (payment.notes != null && payment.notes!.isNotEmpty) ...[
SizedBox(height: 12.h),
Container(
padding: EdgeInsets.all(12.w),
decoration: BoxDecoration(
color: Colors.grey.shade100,
borderRadius: BorderRadius.circular(8.r),
),
child: Row(
children: [
Icon(Icons.note, size: 16.w, color: Colors.grey.shade600),
SizedBox(width: 8.w),
Expanded(
child: Text(
payment.notes!,
style: TextStyle(
fontSize: 14.sp,
color: Colors.grey.shade700,
),
),
),
],
),
),
],
],
),
),
);
}
Widget _buildDrawCard(MonthlyDraw draw) {
final isWinner = draw.winnerId == _authService.currentUser.value?.id;
return Card(
margin: EdgeInsets.only(bottom: 12.h),
elevation: 2,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.r)),
child: Container(
padding: EdgeInsets.all(16.w),
decoration: BoxDecoration(
gradient: isWinner
? LinearGradient(
colors: [Colors.amber.shade50, Colors.amber.shade100],
)
: null,
borderRadius: BorderRadius.circular(12.r),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Month ${draw.month}',
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.bold,
color: isWinner ? Colors.amber.shade900 : Colors.grey.shade800,
),
),
if (isWinner)
Container(
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 6.h),
decoration: BoxDecoration(
color: Colors.amber.shade600,
borderRadius: BorderRadius.circular(12.r),
),
child: Row(
children: [
Icon(Icons.emoji_events, color: Colors.white, size: 16.w),
SizedBox(width: 4.w),
Text(
'Winner!',
style: TextStyle(
fontSize: 14.sp,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
],
),
),
],
),
SizedBox(height: 16.h),
_buildDrawInfo('Prize Amount', '${_formatCurrency(draw.prizeAmount)}'),
SizedBox(height: 12.h),
Container(
padding: EdgeInsets.all(12.w),
decoration: BoxDecoration(
color: isWinner ? Colors.amber.shade100 : Colors.grey.shade100,
borderRadius: BorderRadius.circular(8.r),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Winner',
style: TextStyle(
fontSize: 12.sp,
color: Colors.grey.shade600,
),
),
SizedBox(height: 4.h),
Text(
draw.winner?.fullName ?? 'Unknown',
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
color: isWinner ? Colors.amber.shade900 : Colors.grey.shade800,
),
),
],
),
),
SizedBox(height: 12.h),
Row(
children: [
Icon(Icons.event, size: 16.w, color: Colors.grey.shade600),
SizedBox(width: 8.w),
Text(
'Drawn on ${_formatDate(draw.drawDate)}',
style: TextStyle(
fontSize: 14.sp,
color: Colors.grey.shade600,
),
),
],
),
],
),
),
);
}
Widget _buildDrawInfo(String label, String value) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: TextStyle(
fontSize: 12.sp,
color: Colors.grey.shade600,
),
),
SizedBox(height: 4.h),
Text(
value,
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.bold,
color: Colors.grey.shade800,
),
),
],
);
}
Widget _buildEmptyPayments() {
return Center(
child: Padding(
padding: EdgeInsets.all(32.w),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.payment_outlined,
size: 64.w,
color: Colors.grey.shade300,
),
SizedBox(height: 16.h),
Text(
'No Payments Yet',
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.bold,
color: Colors.grey.shade700,
),
),
SizedBox(height: 8.h),
Text(
'Your payment history will appear here',
style: TextStyle(
fontSize: 14.sp,
color: Colors.grey.shade600,
),
),
],
),
),
);
}
Widget _buildEmptyDraws() {
return Center(
child: Padding(
padding: EdgeInsets.all(32.w),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.casino_outlined,
size: 64.w,
color: Colors.grey.shade300,
),
SizedBox(height: 16.h),
Text(
'No Draws Yet',
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.bold,
color: Colors.grey.shade700,
),
),
SizedBox(height: 8.h),
Text(
widget.group.status == 'forming'
? 'Group needs to start before draws can happen'
: 'Draw results will appear here',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 14.sp,
color: Colors.grey.shade600,
),
),
],
),
),
);
}
Widget _buildStatItem(String label, String value, Color color) {
return Column(
children: [
Text(
value,
style: TextStyle(
fontSize: 20.sp,
fontWeight: FontWeight.bold,
color: color,
),
),
SizedBox(height: 4.h),
Text(
label,
style: TextStyle(
fontSize: 14.sp,
color: Colors.grey.shade600,
),
),
],
);
}
Widget _buildStatusBadge(String status) {
Color color;
String text;
switch (status.toLowerCase()) {
case 'active':
color = Colors.green.shade600;
text = 'Active';
break;
case 'forming':
color = Colors.orange.shade600;
text = 'Forming';
break;
case 'completed':
color = Colors.blue.shade600;
text = 'Completed';
break;
default:
color = Colors.grey.shade600;
text = status;
}
return Container(
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 6.h),
decoration: BoxDecoration(
color: color.withOpacity(0.1),
borderRadius: BorderRadius.circular(12.r),
border: Border.all(color: color, width: 1.5),
),
child: Text(
text,
style: TextStyle(
fontSize: 14.sp,
color: color,
fontWeight: FontWeight.w600,
),
),
);
}
Widget _buildPaymentStatusBadge(String status) {
Color color;
String text;
switch (status.toLowerCase()) {
case 'success':
color = Colors.green.shade600;
text = 'Paid';
break;
case 'pending':
color = Colors.orange.shade600;
text = 'Pending';
break;
case 'failed':
color = Colors.red.shade600;
text = 'Failed';
break;
case 'cancelled':
color = Colors.grey.shade600;
text = 'Cancelled';
break;
default:
color = Colors.grey.shade600;
text = status;
}
return Container(
padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 4.h),
decoration: BoxDecoration(
color: color.withOpacity(0.1),
borderRadius: BorderRadius.circular(8.r),
border: Border.all(color: color, width: 1.5),
),
child: Text(
text,
style: TextStyle(
fontSize: 12.sp,
color: color,
fontWeight: FontWeight.w600,
),
),
);
}
String _formatCurrency(double amount) {
final amountStr = amount.toStringAsFixed(0);
return amountStr.replaceAllMapped(
RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'),
(Match m) => '${m[1]},',
);
}
String _formatDate(DateTime date) {
return '${date.day}/${date.month}/${date.year}';
}
}