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/models/chit_group.dart'; import '../../core/models/user.dart'; class MemberSelectionDialog extends StatefulWidget { final ChitGroup group; const MemberSelectionDialog({ super.key, required this.group, }); @override State createState() => _MemberSelectionDialogState(); } class _MemberSelectionDialogState extends State { final ChitGroupService _service = ChitGroupService.to; final TextEditingController _searchController = TextEditingController(); List _allUsers = []; List _filteredUsers = []; List _selectedUsers = []; bool _isLoading = false; bool _isAdding = false; String _searchQuery = ''; @override void initState() { super.initState(); // Load available users directly (no need to load existing members separately) _loadAllUsers(); } @override void dispose() { _searchController.dispose(); super.dispose(); } Future _loadAllUsers() async { try { // Use the enhanced API that filters by group ID final users = await _service.getAvailableUsersForGroup(widget.group.id); print('Total available users for group ${widget.group.id}: ${users.length}'); print('User IDs: ${users.map((u) => u.id).toList()}'); setState(() { _allUsers = users; _filteredUsers = users; }); } catch (e) { print('Error loading available users: $e'); setState(() { _allUsers = []; _filteredUsers = []; }); // Show error message instead of sample data Get.snackbar( 'Error', 'Failed to load available users. Please try again.', backgroundColor: Colors.red.shade100, colorText: Colors.red.shade800, snackPosition: SnackPosition.TOP, ); } finally { setState(() => _isLoading = false); } } void _filterUsers(String query) { setState(() { _searchQuery = query; if (query.isEmpty) { _filteredUsers = _allUsers; } else { _filteredUsers = _allUsers.where((user) { return user.fullName.toLowerCase().contains(query.toLowerCase()) || user.mobileNumber.contains(query); }).toList(); } }); } void _toggleUserSelection(User user) { setState(() { if (_selectedUsers.contains(user)) { _selectedUsers.remove(user); } else { _selectedUsers.add(user); } }); } Future _addSelectedUsersToGroup() async { if (_selectedUsers.isEmpty) { Get.snackbar( 'Error', 'Please select at least one user', backgroundColor: Colors.orange.shade100, colorText: Colors.orange.shade800, snackPosition: SnackPosition.TOP, ); return; } setState(() => _isAdding = true); try { int successCount = 0; int errorCount = 0; for (final user in _selectedUsers) { final success = await _service.addMemberToGroup(widget.group.id, { 'mobile_number': user.mobileNumber, }); if (success) { successCount++; } else { errorCount++; } } Navigator.of(context).pop(); // Close dialog if (successCount > 0) { Get.snackbar( 'Success', '$successCount user(s) added to chitfund successfully!', backgroundColor: Colors.green.shade100, colorText: Colors.green.shade800, snackPosition: SnackPosition.TOP, ); } if (errorCount > 0) { Get.snackbar( 'Warning', '$errorCount user(s) could not be added (may already be members)', backgroundColor: Colors.orange.shade100, colorText: Colors.orange.shade800, snackPosition: SnackPosition.TOP, ); } } catch (e) { Get.snackbar( 'Error', 'Failed to add members. Please try again.', backgroundColor: Colors.red.shade100, colorText: Colors.red.shade800, snackPosition: SnackPosition.TOP, ); } finally { setState(() => _isAdding = false); } } @override Widget build(BuildContext context) { return Dialog( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16.r)), child: Container( width: 0.85.sw, height: 0.8.sh, child: Column( children: [ // Header Container( padding: EdgeInsets.all(12.w), decoration: BoxDecoration( color: Colors.blue.shade600, borderRadius: BorderRadius.only( topLeft: Radius.circular(16.r), topRight: Radius.circular(16.r), ), ), child: Row( children: [ Icon( Icons.people_alt, color: Colors.white, size: 24.w, ), SizedBox(width: 12.w), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Select Members', style: TextStyle( color: Colors.white, fontSize: 16.sp, fontWeight: FontWeight.w600, ), ), Text( widget.group.name, style: TextStyle( color: Colors.white.withOpacity(0.8), fontSize: 12.sp, ), ), ], ), ), IconButton( onPressed: () => Navigator.of(context).pop(), icon: const Icon(Icons.close, color: Colors.white), padding: EdgeInsets.zero, constraints: const BoxConstraints(), ), ], ), ), // Chitfund Info Container( padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 6.h), color: Colors.blue.shade50, child: Row( children: [ Expanded( child: _buildInfoItem('Monthly', '₹${widget.group.monthlyInstallment.toStringAsFixed(0)}'), ), Expanded( child: _buildInfoItem('Members', '${widget.group.currentMemberCount}/${widget.group.maxMembers}'), ), Expanded( child: _buildInfoItem('Available', '${widget.group.maxMembers - widget.group.currentMemberCount}'), ), ], ), ), // Search and Selection Controls Container( padding: EdgeInsets.all(8.w), child: Column( children: [ // Search Bar TextField( controller: _searchController, decoration: InputDecoration( hintText: 'Search users...', prefixIcon: const Icon(Icons.search), suffixIcon: _isLoading ? SizedBox( width: 20.w, height: 20.w, child: const CircularProgressIndicator(strokeWidth: 2), ) : IconButton( icon: const Icon(Icons.refresh), onPressed: () { print('Manual refresh triggered'); _loadAllUsers(); }, tooltip: 'Refresh members', ), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8.r), ), contentPadding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 12.h), ), onChanged: _filterUsers, ), SizedBox(height: 6.h), // Selection Summary Row( children: [ Expanded( child: Text( '${_filteredUsers.length} users available', style: TextStyle( fontSize: 14.sp, color: Colors.grey.shade600, ), ), ), if (_selectedUsers.isNotEmpty) Container( padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 4.h), decoration: BoxDecoration( color: Colors.blue.shade100, borderRadius: BorderRadius.circular(12.r), ), child: Text( '${_selectedUsers.length} selected', style: TextStyle( fontSize: 12.sp, fontWeight: FontWeight.w600, color: Colors.blue.shade700, ), ), ), ], ), ], ), ), // Users List Flexible( child: _isLoading && _allUsers.isEmpty ? const Center(child: CircularProgressIndicator()) : _filteredUsers.isEmpty ? Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.people_outline, size: 64.w, color: Colors.grey.shade400, ), SizedBox(height: 16.h), Text( _searchQuery.isEmpty ? 'No users found' : 'No users match your search', style: TextStyle( fontSize: 16.sp, color: Colors.grey.shade600, ), ), if (_searchQuery.isNotEmpty) ...[ SizedBox(height: 8.h), TextButton( onPressed: () { _searchController.clear(); _filterUsers(''); }, child: const Text('Clear search'), ), ], ], ), ) : ListView.builder( padding: EdgeInsets.symmetric(horizontal: 12.w), itemCount: _filteredUsers.length, itemBuilder: (context, index) { final user = _filteredUsers[index]; final isSelected = _selectedUsers.contains(user); return _buildUserCard(user, isSelected); }, ), ), // Footer Container( padding: EdgeInsets.all(8.w), decoration: BoxDecoration( color: Colors.grey.shade50, borderRadius: BorderRadius.only( bottomLeft: Radius.circular(16.r), bottomRight: Radius.circular(16.r), ), ), child: Column( mainAxisSize: MainAxisSize.min, children: [ // Status text Text( _selectedUsers.isEmpty ? 'Select users to add' : 'Ready to add ${_selectedUsers.length} user(s)', style: TextStyle( fontSize: 12.sp, color: Colors.grey.shade600, ), textAlign: TextAlign.center, ), SizedBox(height: 8.h), // Action buttons Row( children: [ Expanded( child: OutlinedButton( onPressed: () => Navigator.of(context).pop(), style: OutlinedButton.styleFrom( padding: EdgeInsets.symmetric(vertical: 12.h), ), child: const Text('Cancel'), ), ), SizedBox(width: 8.w), Expanded( child: ElevatedButton( onPressed: _isAdding || _selectedUsers.isEmpty ? null : _addSelectedUsersToGroup, style: ElevatedButton.styleFrom( backgroundColor: Colors.blue.shade600, foregroundColor: Colors.white, padding: EdgeInsets.symmetric(vertical: 12.h), ), child: _isAdding ? SizedBox( width: 16.w, height: 16.w, child: const CircularProgressIndicator( strokeWidth: 2, valueColor: AlwaysStoppedAnimation(Colors.white), ), ) : Text('Add ${_selectedUsers.length} Member(s)'), ), ), ], ), ], ), ), ], ), ), ); } Widget _buildInfoItem(String label, String value) { return Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( label, style: TextStyle( fontSize: 10.sp, color: Colors.blue.shade600, fontWeight: FontWeight.w500, ), textAlign: TextAlign.center, ), SizedBox(height: 2.h), Text( value, style: TextStyle( fontSize: 12.sp, fontWeight: FontWeight.w600, color: Colors.blue.shade800, ), textAlign: TextAlign.center, ), ], ); } Widget _buildUserCard(User user, bool isSelected) { return Card( margin: EdgeInsets.only(bottom: 4.h), elevation: isSelected ? 4 : 1, color: isSelected ? Colors.blue.shade50 : Colors.white, child: ListTile( dense: true, contentPadding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 4.h), leading: CircleAvatar( radius: 16.r, backgroundColor: isSelected ? Colors.blue.shade600 : Colors.blue.shade100, child: Text( user.fullName.isNotEmpty ? user.fullName[0].toUpperCase() : '?', style: TextStyle( color: isSelected ? Colors.white : Colors.blue.shade700, fontWeight: FontWeight.w600, fontSize: 12.sp, ), ), ), title: Text( user.fullName, style: TextStyle( fontSize: 14.sp, fontWeight: FontWeight.w600, color: isSelected ? Colors.blue.shade800 : Colors.grey.shade800, ), ), subtitle: Text( user.mobileNumber, style: TextStyle( fontSize: 12.sp, color: isSelected ? Colors.blue.shade600 : Colors.grey.shade600, ), ), trailing: Checkbox( value: isSelected, onChanged: (bool? value) => _toggleUserSelection(user), activeColor: Colors.blue.shade600, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, ), onTap: () => _toggleUserSelection(user), ), ); } String _formatDate(DateTime date) { return '${date.day}/${date.month}/${date.year}'; } }