From f985c00545b4eacfffc3ac93fc0460fdafc2bc8a Mon Sep 17 00:00:00 2001 From: Deep Koluguri Date: Wed, 5 Nov 2025 21:06:44 -0500 Subject: [PATCH] member dashboard update --- .../interfaces/member/member_dashboard.dart | 473 ++++++++---------- 1 file changed, 221 insertions(+), 252 deletions(-) diff --git a/luckychit/lib/interfaces/member/member_dashboard.dart b/luckychit/lib/interfaces/member/member_dashboard.dart index a4c2902..856a2e0 100644 --- a/luckychit/lib/interfaces/member/member_dashboard.dart +++ b/luckychit/lib/interfaces/member/member_dashboard.dart @@ -3,21 +3,39 @@ 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'; -class MemberDashboard extends StatelessWidget { +class MemberDashboard extends StatefulWidget { const MemberDashboard({super.key}); @override - Widget build(BuildContext context) { + 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) { return Scaffold( backgroundColor: Colors.grey.shade50, appBar: AppBar( @@ -50,140 +68,110 @@ class MemberDashboard extends StatelessWidget { ), ], ), - body: RefreshIndicator( - onRefresh: () async { - // TODO: Implement refresh logic - await Future.delayed(const Duration(seconds: 1)); - }, - child: ListView( - padding: EdgeInsets.all(12.w), - children: [ - // Welcome Section - Container( - padding: EdgeInsets.all(20.w), - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [Colors.green.shade50, Colors.green.shade100], + body: Obx(() { + final groups = _chitGroupService.chitGroups; + final isLoading = _chitGroupService.isLoading.value; + + return RefreshIndicator( + onRefresh: _loadData, + child: ListView( + padding: EdgeInsets.all(12.w), + children: [ + // Welcome Section + Container( + padding: EdgeInsets.all(20.w), + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [Colors.green.shade50, Colors.green.shade100], + ), + borderRadius: BorderRadius.circular(16.r), + boxShadow: [ + BoxShadow( + color: Colors.green.shade200.withOpacity(0.3), + blurRadius: 8, + offset: const Offset(0, 2), + ), + ], ), - borderRadius: BorderRadius.circular(16.r), - boxShadow: [ - BoxShadow( - color: Colors.green.shade200.withOpacity(0.3), - blurRadius: 8, - offset: const Offset(0, 2), - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - CircleAvatar( - radius: 24.r, - backgroundColor: Colors.green.shade600, - child: Icon( - Icons.person, - size: 24.w, - color: Colors.white, - ), - ), - SizedBox(width: 12.w), - Expanded( - child: Obx(() => Text( - 'Welcome, ${AuthService.to.currentUser.value?.fullName ?? 'Member'}!', - style: TextStyle( - fontSize: 20.sp, - fontWeight: FontWeight.bold, - color: Colors.green.shade800, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + CircleAvatar( + radius: 24.r, + backgroundColor: Colors.green.shade600, + child: Icon( + Icons.person, + size: 24.w, + color: Colors.white, ), - )), + ), + SizedBox(width: 12.w), + Expanded( + child: Text( + 'Welcome, ${AuthService.to.currentUser.value?.fullName ?? 'Member'}!', + style: TextStyle( + fontSize: 20.sp, + fontWeight: FontWeight.bold, + color: Colors.green.shade800, + ), + ), + ), + ], + ), + 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: Colors.green.shade700, ), - ], - ), - SizedBox(height: 12.h), - Text( - 'Manage your chit fund investments and track your payments.', - style: TextStyle( - fontSize: 16.sp, - color: Colors.green.shade700, + ), + ], + ), + ), + SizedBox(height: 16.h), + + // Loading indicator + if (isLoading) + Center( + child: Padding( + padding: EdgeInsets.all(32.h), + child: CircularProgressIndicator( + color: Colors.green.shade600, ), ), - ], - ), - ), - SizedBox(height: 16.h), + ), - // Payment Due Card - _buildPaymentDueCard(), - SizedBox(height: 16.h), + // Empty state + if (!isLoading && groups.isEmpty) + _buildEmptyState(), - // My Chitfunds Section - Text( - 'My Chitfunds', - style: TextStyle( - fontSize: 20.sp, - fontWeight: FontWeight.bold, - color: Colors.grey.shade800, - ), - ), - SizedBox(height: 12.h), - _buildGroupCard( - 'Group A', - '₹1,00,000', - '20 months', - '15/20 members', - '₹5,000', - 'Due: 25th Jan', - Colors.blue, - ), - SizedBox(height: 12.h), - _buildGroupCard( - 'Group B', - '₹50,000', - '10 months', - '8/10 members', - '₹5,000', - 'Due: 28th Jan', - Colors.green, - ), - SizedBox(height: 16.h), + // My Chitfunds Section (only if groups exist) + if (!isLoading && groups.isNotEmpty) ...[ + Text( + 'My Chitfunds', + style: TextStyle( + fontSize: 20.sp, + fontWeight: FontWeight.bold, + color: Colors.grey.shade800, + ), + ), + SizedBox(height: 12.h), + ...groups.map((group) => Padding( + padding: EdgeInsets.only(bottom: 12.h), + child: _buildGroupCard(group), + )), + ], - // Recent Activity Section - Text( - 'Recent Activity', - style: TextStyle( - fontSize: 20.sp, - fontWeight: FontWeight.bold, - color: Colors.grey.shade800, - ), - ), - SizedBox(height: 12.h), - ActivityCard( - title: 'Payment Successful', - description: '₹5,000 paid for Group A', - time: '2h ago', - icon: Icons.payment, - color: Colors.green.shade600, - ), - ActivityCard( - title: 'Lottery Draw', - description: 'Draw completed for Group B', - time: '1d ago', - icon: Icons.casino, - color: Colors.orange.shade600, - ), - ActivityCard( - title: 'New Member', - description: 'John Doe joined Group A', - time: '3d ago', - icon: Icons.person_add, - color: Colors.blue.shade600, - ), - SizedBox(height: 16.h), - ], - ), - ), + SizedBox(height: 16.h), + ], + ), + ); + }), bottomNavigationBar: Obx(() { final unreadCount = NotificationService.to.unreadCount.value; @@ -227,93 +215,77 @@ class MemberDashboard extends StatelessWidget { ); } - Widget _buildPaymentDueCard() { - return Card( - elevation: 3, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16.r), - ), - child: Container( - padding: EdgeInsets.all(20.w), - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [Colors.orange.shade50, Colors.orange.shade100], - ), - borderRadius: BorderRadius.circular(16.r), - ), + Widget _buildEmptyState() { + return Center( + child: Padding( + padding: EdgeInsets.all(32.w), child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, children: [ - Row( - children: [ - Container( - padding: EdgeInsets.all(8.w), - decoration: BoxDecoration( - color: Colors.orange.shade600.withOpacity(0.1), - borderRadius: BorderRadius.circular(12.r), - ), - child: Icon( - Icons.payment, - color: Colors.orange.shade700, - size: 28.w, - ), - ), - SizedBox(width: 12.w), - Text( - 'Payment Due', - style: TextStyle( - fontSize: 18.sp, - fontWeight: FontWeight.bold, - color: Colors.orange.shade700, - ), - ), - ], + Icon( + Icons.account_balance_wallet_outlined, + size: 80.w, + color: Colors.grey.shade300, ), - SizedBox(height: 16.h), + SizedBox(height: 24.h), Text( - '₹5,000', + 'No Chit Funds Yet', style: TextStyle( - fontSize: 28.sp, + fontSize: 22.sp, fontWeight: FontWeight.bold, - color: Colors.orange.shade800, + color: Colors.grey.shade700, ), ), - SizedBox(height: 6.h), + SizedBox(height: 12.h), Text( - 'Due by 25th January 2024', + 'You haven\'t joined any chit funds yet.\nContact your manager to get started!', + textAlign: TextAlign.center, style: TextStyle( fontSize: 16.sp, - color: Colors.orange.shade700, - fontWeight: FontWeight.w500, + color: Colors.grey.shade600, ), ), - SizedBox(height: 20.h), - SizedBox( - width: double.infinity, - height: 48.h, - child: ElevatedButton( - onPressed: () { - // TODO: Implement payment - SnackbarUtil.showInfo( - 'Payment feature coming soon!', - title: 'Coming Soon', - ); - }, - style: ElevatedButton.styleFrom( - backgroundColor: Colors.orange.shade600, - foregroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12.r), + SizedBox(height: 32.h), + Container( + padding: EdgeInsets.all(16.w), + decoration: BoxDecoration( + color: Colors.blue.shade50, + borderRadius: BorderRadius.circular(12.r), + border: Border.all(color: Colors.blue.shade200), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Icon( + Icons.info_outline, + color: Colors.blue.shade700, + size: 20.w, + ), + SizedBox(width: 8.w), + Text( + 'How to get started?', + style: TextStyle( + fontSize: 16.sp, + fontWeight: FontWeight.bold, + color: Colors.blue.shade700, + ), + ), + ], ), - elevation: 2, - ), - child: Text( - 'Pay Now', - style: TextStyle( - fontSize: 16.sp, - fontWeight: FontWeight.w600, + 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: Colors.blue.shade900, + height: 1.5, + ), ), - ), + ], ), ), ], @@ -322,15 +294,18 @@ class MemberDashboard extends StatelessWidget { ); } - Widget _buildGroupCard( - String name, - String value, - String duration, - String members, - String installment, - String dueDate, - Color color, - ) { + Widget _buildGroupCard(dynamic group) { + final color = Colors.green.shade600; + final groupName = group.name ?? 'Unnamed Group'; + final totalAmount = group.totalAmount ?? 0; + final monthlyInstallment = group.monthlyInstallment ?? 0; + final durationMonths = group.durationMonths ?? 0; + final status = group.status ?? 'pending'; + + // Format currency + final totalValue = '₹${totalAmount.toString().replaceAllMapped(RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'), (Match m) => '${m[1]},')}'; + final installmentValue = '₹${monthlyInstallment.toString().replaceAllMapped(RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'), (Match m) => '${m[1]},')}'; + return InteractiveCard( onTap: () { SnackbarUtil.showInfo('Group details page coming soon!'); @@ -341,26 +316,31 @@ class MemberDashboard extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text( - name, - style: TextStyle( - fontSize: 20.sp, - fontWeight: FontWeight.bold, - color: color, + 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: color.withOpacity(0.1), + color: _getStatusColor(status).withOpacity(0.1), borderRadius: BorderRadius.circular(16.r), - border: Border.all(color: color, width: 1.5), + border: Border.all(color: _getStatusColor(status), width: 1.5), ), child: Text( - 'Active', + _getStatusText(status), style: TextStyle( fontSize: 14.sp, - color: color, + color: _getStatusColor(status), fontWeight: FontWeight.w600, ), ), @@ -373,11 +353,11 @@ class MemberDashboard extends StatelessWidget { Row( children: [ Expanded( - child: _buildGroupInfo('Total Value', value), + child: _buildGroupInfo('Total Value', totalValue), ), SizedBox(width: 8.w), Expanded( - child: _buildGroupInfo('Duration', duration), + child: _buildGroupInfo('Duration', '$durationMonths months'), ), ], ), @@ -385,49 +365,38 @@ class MemberDashboard extends StatelessWidget { Row( children: [ Expanded( - child: _buildGroupInfo('Members', members), + child: _buildGroupInfo('Installment', installmentValue), ), SizedBox(width: 8.w), Expanded( - child: _buildGroupInfo('Installment', installment), + child: _buildGroupInfo('Status', _getStatusText(status)), ), ], ), ], ), - SizedBox(height: 16.h), - Container( - width: double.infinity, - padding: EdgeInsets.all(12.w), - decoration: BoxDecoration( - color: color.withOpacity(0.05), - borderRadius: BorderRadius.circular(12.r), - border: Border.all(color: color.withOpacity(0.3)), - ), - child: Row( - children: [ - Icon( - Icons.schedule, - size: 20.w, - color: color, - ), - SizedBox(width: 8.w), - Text( - dueDate, - style: TextStyle( - fontSize: 16.sp, - color: color, - fontWeight: FontWeight.w600, - ), - ), - ], - ), - ), ], ), ); } + Color _getStatusColor(String status) { + switch (status.toLowerCase()) { + case 'active': + return Colors.green.shade600; + case 'pending': + return Colors.orange.shade600; + case 'completed': + return Colors.blue.shade600; + default: + return Colors.grey.shade600; + } + } + + String _getStatusText(String status) { + return status[0].toUpperCase() + status.substring(1).toLowerCase(); + } + Widget _buildGroupInfo(String label, String value) { return Container( padding: EdgeInsets.all(12.w),