import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import '../../core/services/auth_service.dart'; import '../../core/services/notification_service.dart'; import '../../core/services/chit_group_service.dart'; import '../../core/utils/snackbar_util.dart'; import '../../shared/widgets/interactive_card.dart'; import '../../shared/widgets/notification_badge.dart'; import '../../features/notifications/notification_center_page.dart'; import 'member_group_details_page.dart'; import 'member_payment_dialog.dart'; class MemberDashboard extends StatefulWidget { const MemberDashboard({super.key}); @override State createState() => _MemberDashboardState(); } class _MemberDashboardState extends State { final _chitGroupService = Get.find(); @override void initState() { super.initState(); // Initialize notification service if (!Get.isRegistered()) { Get.put(NotificationService()); } // Load member's chit groups _loadData(); } Future _loadData() async { await _chitGroupService.loadMemberChitGroups(status: 'active'); } @override Widget build(BuildContext context) { final scheme = Theme.of(context).colorScheme; return Scaffold( backgroundColor: scheme.surface, appBar: AppBar( title: Text( 'My Chitfunds', style: TextStyle( fontSize: 18.sp, fontWeight: FontWeight.w600, color: scheme.onPrimary, ), ), backgroundColor: scheme.primary, foregroundColor: scheme.onPrimary, elevation: 0, actions: [ // Notifications with badge Obx(() { final unreadCount = NotificationService.to.unreadCount.value; return IconButton( icon: NotificationBadge( count: unreadCount, child: Icon(Icons.notifications_rounded, size: 24.w), ), onPressed: () => Get.to(() => const NotificationCenterPage()), tooltip: 'Notifications', ); }), IconButton( icon: Icon(Icons.logout, size: 24.w), onPressed: () => _showLogoutDialog(context), ), ], ), body: Obx(() { final groups = _chitGroupService.chitGroups; final isLoading = _chitGroupService.isLoading.value; return RefreshIndicator( onRefresh: _loadData, child: ListView( padding: EdgeInsets.all(12.w), children: [ Container( padding: EdgeInsets.all(20.w), decoration: BoxDecoration( gradient: LinearGradient( colors: [ scheme.primaryContainer, Color.lerp(scheme.primaryContainer, scheme.tertiaryContainer, 0.35)!, ], ), borderRadius: BorderRadius.circular(16.r), boxShadow: [ BoxShadow( color: scheme.primary.withOpacity(0.12), blurRadius: 8, offset: const Offset(0, 2), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ CircleAvatar( radius: 24.r, backgroundColor: scheme.primary, child: Icon( Icons.person, size: 24.w, color: scheme.onPrimary, ), ), SizedBox(width: 12.w), Expanded( child: Text( 'Welcome, ${AuthService.to.currentUser.value?.fullName ?? 'Member'}!', style: TextStyle( fontSize: 20.sp, fontWeight: FontWeight.bold, color: scheme.onPrimaryContainer, ), ), ), ], ), SizedBox(height: 12.h), Text( groups.isEmpty ? 'Join a chit fund to start managing your investments.' : 'Manage your chit fund investments and track your payments.', style: TextStyle( fontSize: 16.sp, color: scheme.onPrimaryContainer.withOpacity(0.92), ), ), ], ), ), SizedBox(height: 16.h), // Loading indicator if (isLoading) Center( child: Padding( padding: EdgeInsets.all(32.h), child: CircularProgressIndicator( color: scheme.primary, ), ), ), if (!isLoading && groups.isEmpty) _buildEmptyState(context), if (!isLoading && groups.isNotEmpty) ...[ Text( 'My Chitfunds', style: TextStyle( fontSize: 20.sp, fontWeight: FontWeight.bold, color: scheme.onSurface, ), ), SizedBox(height: 12.h), ...groups.map((group) => Padding( padding: EdgeInsets.only(bottom: 12.h), child: _buildGroupCard(context, group), )), ], SizedBox(height: 16.h), ], ), ); }), bottomNavigationBar: Obx(() { final unreadCount = NotificationService.to.unreadCount.value; return BottomNavigationBar( type: BottomNavigationBarType.fixed, selectedItemColor: scheme.primary, unselectedItemColor: scheme.onSurfaceVariant, selectedLabelStyle: TextStyle(fontSize: 12.sp, fontWeight: FontWeight.w600), unselectedLabelStyle: TextStyle(fontSize: 12.sp), iconSize: 24.w, items: [ const BottomNavigationBarItem( icon: Icon(Icons.home), label: 'Home', ), const BottomNavigationBarItem( icon: Icon(Icons.payment), label: 'Payments', ), BottomNavigationBarItem( icon: NotificationBadge( count: unreadCount, child: const Icon(Icons.notifications), ), label: 'Notifications', ), const BottomNavigationBarItem( icon: Icon(Icons.person), label: 'Profile', ), ], onTap: (index) { if (index == 2) { Get.to(() => const NotificationCenterPage()); } else { SnackbarUtil.showInfo('Feature coming soon'); } }, ); }), ); } Widget _buildEmptyState(BuildContext context) { final scheme = Theme.of(context).colorScheme; return Center( child: Padding( padding: EdgeInsets.all(32.w), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.account_balance_wallet_outlined, size: 80.w, color: scheme.outlineVariant, ), SizedBox(height: 24.h), Text( 'No Chit Funds Yet', style: TextStyle( fontSize: 22.sp, fontWeight: FontWeight.bold, color: scheme.onSurface, ), ), SizedBox(height: 12.h), Text( 'You haven\'t joined any chit funds yet.\nContact your manager to get started!', textAlign: TextAlign.center, style: TextStyle( fontSize: 16.sp, color: scheme.onSurfaceVariant, ), ), SizedBox(height: 32.h), Container( padding: EdgeInsets.all(16.w), decoration: BoxDecoration( color: scheme.secondaryContainer.withOpacity(0.5), borderRadius: BorderRadius.circular(12.r), border: Border.all(color: scheme.outlineVariant), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon( Icons.info_outline, color: scheme.secondary, size: 20.w, ), SizedBox(width: 8.w), Text( 'How to get started?', style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.bold, color: scheme.onSecondaryContainer, ), ), ], ), SizedBox(height: 12.h), Text( '1. Your manager will add you to a chit group\n' '2. You\'ll receive a notification\n' '3. Start managing your payments here!', style: TextStyle( fontSize: 14.sp, color: scheme.onSurfaceVariant, height: 1.5, ), ), ], ), ), ], ), ), ); } Widget _buildGroupCard(BuildContext context, dynamic group) { final scheme = Theme.of(context).colorScheme; final color = scheme.primary; final groupName = group.name ?? 'Unnamed Group'; final totalValue = group.totalValue ?? 0.0; final monthlyInstallment = group.monthlyInstallment ?? 0.0; final durationMonths = group.durationMonths ?? 0; final status = group.status ?? 'pending'; // Format currency final totalValueFormatted = '₹${_formatCurrency(totalValue)}'; final installmentValueFormatted = '₹${_formatCurrency(monthlyInstallment)}'; return InteractiveCard( onTap: () { Get.to(() => MemberGroupDetailsPage(group: group)); }, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: Text( groupName, style: TextStyle( fontSize: 20.sp, fontWeight: FontWeight.bold, color: color, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), ), SizedBox(width: 8.w), Container( padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 6.h), decoration: BoxDecoration( color: _getStatusColor(context, status).withOpacity(0.12), borderRadius: BorderRadius.circular(16.r), border: Border.all(color: _getStatusColor(context, status), width: 1.5), ), child: Text( _getStatusText(status), style: TextStyle( fontSize: 14.sp, color: _getStatusColor(context, status), fontWeight: FontWeight.w600, ), ), ), ], ), SizedBox(height: 16.h), Column( children: [ Row( children: [ Expanded( child: _buildGroupInfo(context, 'Total Value', totalValueFormatted), ), SizedBox(width: 8.w), Expanded( child: _buildGroupInfo(context, 'Duration', '$durationMonths months'), ), ], ), SizedBox(height: 12.h), Row( children: [ Expanded( child: _buildGroupInfo(context, 'Installment', installmentValueFormatted), ), SizedBox(width: 8.w), Expanded( child: _buildGroupInfo(context, 'Status', _getStatusText(status)), ), ], ), ], ), // Pay Now Button (only for active groups) if (status.toLowerCase() == 'active') ...[ SizedBox(height: 16.h), Row( children: [ Expanded( flex: 2, child: ElevatedButton.icon( onPressed: () => _showPaymentDialog(group), icon: Icon(Icons.payment, size: 20.w), label: Text( 'Pay Now', style: TextStyle( fontSize: 15.sp, fontWeight: FontWeight.w600, ), ), style: ElevatedButton.styleFrom( backgroundColor: scheme.primary, foregroundColor: scheme.onPrimary, padding: EdgeInsets.symmetric(vertical: 12.h), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.r), ), elevation: 2, ), ), ), SizedBox(width: 8.w), Expanded( child: OutlinedButton( onPressed: () { Get.to(() => MemberGroupDetailsPage(group: group)); }, style: OutlinedButton.styleFrom( padding: EdgeInsets.symmetric(vertical: 12.h), side: BorderSide(color: scheme.primary), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.r), ), ), child: Text( 'Details', style: TextStyle( fontSize: 15.sp, fontWeight: FontWeight.w600, color: scheme.primary, ), ), ), ), ], ), ], ], ), ); } void _showPaymentDialog(dynamic group) { // Find member for this group final myMember = group.members?.firstWhere( (m) => m.userId == AuthService.to.currentUser.value?.id, orElse: () => null, ); if (myMember == null) { SnackbarUtil.showError('Member information not found'); return; } showDialog( context: context, builder: (context) => MemberPaymentDialog( group: group, member: myMember, ), ).then((result) { if (result == true) { // Payment successful, reload data _loadData(); } }); } Color _getStatusColor(BuildContext context, String status) { final scheme = Theme.of(context).colorScheme; switch (status.toLowerCase()) { case 'active': return scheme.primary; case 'pending': return scheme.tertiary; case 'completed': return scheme.secondary; default: return scheme.onSurfaceVariant; } } String _getStatusText(String status) { return status[0].toUpperCase() + status.substring(1).toLowerCase(); } String _formatCurrency(double amount) { // Format number with Indian comma notation final amountStr = amount.toStringAsFixed(0); return amountStr.replaceAllMapped( RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'), (Match m) => '${m[1]},' ); } Widget _buildGroupInfo(BuildContext context, String label, String value) { final scheme = Theme.of(context).colorScheme; return Container( padding: EdgeInsets.all(12.w), decoration: BoxDecoration( color: scheme.surfaceContainerHighest, borderRadius: BorderRadius.circular(12.r), border: Border.all(color: scheme.outlineVariant), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( label, style: TextStyle( fontSize: 14.sp, color: scheme.onSurfaceVariant, fontWeight: FontWeight.w500, ), ), SizedBox(height: 6.h), Text( value, style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w600, color: scheme.onSurface, ), ), ], ), ); } void _showLogoutDialog(BuildContext context) { showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Logout'), content: const Text('Are you sure you want to logout?'), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('Cancel'), ), ElevatedButton( onPressed: () { Navigator.of(context).pop(); AuthService.to.logout(); }, style: ElevatedButton.styleFrom( backgroundColor: Theme.of(context).colorScheme.error, foregroundColor: Theme.of(context).colorScheme.onError, ), child: const Text('Logout'), ), ], ), ); } }