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 AddMemberDialog extends StatefulWidget { final ChitGroup group; const AddMemberDialog({ super.key, required this.group, }); @override State createState() => _AddMemberDialogState(); } class _AddMemberDialogState extends State { final _formKey = GlobalKey(); final _mobileNumberController = TextEditingController(); final _fullNameController = TextEditingController(); final _emailController = TextEditingController(); final _addressController = TextEditingController(); final _emergencyContactController = TextEditingController(); bool _isLoading = false; bool _isSearching = false; User? _existingUser; String _searchStatus = ''; @override void dispose() { _mobileNumberController.dispose(); _fullNameController.dispose(); _emailController.dispose(); _addressController.dispose(); _emergencyContactController.dispose(); super.dispose(); } Future _searchExistingUser() async { final mobileNumber = _mobileNumberController.text.trim(); if (mobileNumber.isEmpty) return; setState(() { _isSearching = true; _searchStatus = 'Searching...'; _existingUser = null; }); try { // This would typically call an API to search for existing users // For now, we'll simulate the search await Future.delayed(const Duration(seconds: 1)); // Simulate finding an existing user (you would replace this with actual API call) if (mobileNumber == '9876543211') { setState(() { _existingUser = User( id: 'user-2', mobileNumber: mobileNumber, fullName: 'John Doe', role: 'member', isActive: true, createdAt: DateTime.now(), updatedAt: DateTime.now(), ); _searchStatus = 'User found!'; _fullNameController.text = _existingUser!.fullName; }); } else { setState(() { _existingUser = null; _searchStatus = 'No existing user found. Creating new member.'; _fullNameController.clear(); }); } } catch (e) { setState(() { _searchStatus = 'Search failed. Please try again.'; }); } finally { setState(() { _isSearching = false; }); } } Future _addMember() async { if (!_formKey.currentState!.validate()) return; setState(() => _isLoading = true); try { final memberData = { 'group_id': widget.group.id, 'mobile_number': _mobileNumberController.text.trim(), 'full_name': _fullNameController.text.trim(), 'email': _emailController.text.trim().isEmpty ? null : _emailController.text.trim(), 'address': _addressController.text.trim().isEmpty ? null : _addressController.text.trim(), 'emergency_contact': _emergencyContactController.text.trim().isEmpty ? null : _emergencyContactController.text.trim(), }; final success = await ChitGroupService.to.addMemberToGroup(widget.group.id, memberData); if (success) { Get.back(); // Close dialog Get.snackbar( 'Success', 'Member added successfully!', backgroundColor: Colors.green.shade100, colorText: Colors.green.shade800, snackPosition: SnackPosition.TOP, ); } } catch (e) { Get.snackbar( 'Error', 'Failed to add member. Please try again.', backgroundColor: Colors.red.shade100, colorText: Colors.red.shade800, snackPosition: SnackPosition.TOP, ); } finally { setState(() => _isLoading = false); } } @override Widget build(BuildContext context) { return Dialog( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16.r)), child: Container( width: 500.w, constraints: BoxConstraints(maxHeight: 0.8.sh), child: Column( mainAxisSize: MainAxisSize.min, children: [ // Header Container( padding: EdgeInsets.all(20.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.person_add, color: Colors.white, size: 24.w, ), SizedBox(width: 12.w), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Add Member', style: TextStyle( color: Colors.white, fontSize: 18.sp, fontWeight: FontWeight.w600, ), ), Text( 'Chitfund: ${widget.group.name}', style: TextStyle( color: Colors.white.withOpacity(0.8), fontSize: 14.sp, ), ), ], ), ), IconButton( onPressed: () => Get.back(), icon: const Icon(Icons.close, color: Colors.white), padding: EdgeInsets.zero, constraints: const BoxConstraints(), ), ], ), ), // Form Content Flexible( child: SingleChildScrollView( padding: EdgeInsets.all(20.w), child: Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Chitfund Info Container( padding: EdgeInsets.all(16.w), decoration: BoxDecoration( color: Colors.blue.shade50, borderRadius: BorderRadius.circular(8.r), border: Border.all(color: Colors.blue.shade200), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Chitfund Information', style: TextStyle( fontSize: 14.sp, fontWeight: FontWeight.w600, color: Colors.blue.shade800, ), ), SizedBox(height: 8.h), Row( children: [ Expanded( child: _buildInfoItem('Monthly Installment', '₹${widget.group.monthlyInstallment.toStringAsFixed(0)}'), ), Expanded( child: _buildInfoItem('Current Members', '${widget.group.currentMemberCount}/${widget.group.maxMembers}'), ), ], ), ], ), ), SizedBox(height: 24.h), // Member Information Section _buildSectionTitle('Member Information'), SizedBox(height: 16.h), // Mobile Number with Search TextFormField( controller: _mobileNumberController, decoration: InputDecoration( labelText: 'Mobile Number *', hintText: 'Enter 10-digit mobile number', prefixIcon: const Icon(Icons.phone), suffixIcon: _isSearching ? SizedBox( width: 20.w, height: 20.w, child: const CircularProgressIndicator(strokeWidth: 2), ) : IconButton( icon: const Icon(Icons.search), onPressed: _searchExistingUser, ), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8.r), ), ), keyboardType: TextInputType.phone, maxLength: 10, validator: (value) { if (value == null || value.trim().isEmpty) { return 'Mobile number is required'; } if (value.length != 10) { return 'Mobile number must be 10 digits'; } if (!RegExp(r'^[0-9]+$').hasMatch(value)) { return 'Mobile number must contain only digits'; } return null; }, onChanged: (_) { setState(() { _existingUser = null; _searchStatus = ''; }); }, ), SizedBox(height: 8.h), // Search Status if (_searchStatus.isNotEmpty) Container( padding: EdgeInsets.all(8.w), decoration: BoxDecoration( color: _existingUser != null ? Colors.green.shade50 : Colors.orange.shade50, borderRadius: BorderRadius.circular(4.r), border: Border.all( color: _existingUser != null ? Colors.green.shade200 : Colors.orange.shade200, ), ), child: Row( children: [ Icon( _existingUser != null ? Icons.check_circle : Icons.info, size: 16.w, color: _existingUser != null ? Colors.green.shade600 : Colors.orange.shade600, ), SizedBox(width: 8.w), Expanded( child: Text( _searchStatus, style: TextStyle( fontSize: 12.sp, color: _existingUser != null ? Colors.green.shade700 : Colors.orange.shade700, ), ), ), ], ), ), SizedBox(height: 16.h), // Full Name TextFormField( controller: _fullNameController, decoration: InputDecoration( labelText: 'Full Name *', hintText: 'Enter full name', prefixIcon: const Icon(Icons.person), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8.r), ), ), validator: (value) { if (value == null || value.trim().isEmpty) { return 'Full name is required'; } if (value.trim().length < 2) { return 'Name must be at least 2 characters'; } return null; }, ), SizedBox(height: 16.h), // Email (Optional) TextFormField( controller: _emailController, decoration: InputDecoration( labelText: 'Email (Optional)', hintText: 'Enter email address', prefixIcon: const Icon(Icons.email), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8.r), ), ), keyboardType: TextInputType.emailAddress, validator: (value) { if (value != null && value.trim().isNotEmpty) { if (!RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(value)) { return 'Please enter a valid email address'; } } return null; }, ), SizedBox(height: 16.h), // Address (Optional) TextFormField( controller: _addressController, decoration: InputDecoration( labelText: 'Address (Optional)', hintText: 'Enter address', prefixIcon: const Icon(Icons.location_on), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8.r), ), ), maxLines: 2, ), SizedBox(height: 16.h), // Emergency Contact (Optional) TextFormField( controller: _emergencyContactController, decoration: InputDecoration( labelText: 'Emergency Contact (Optional)', hintText: 'Enter emergency contact number', prefixIcon: const Icon(Icons.emergency), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8.r), ), ), keyboardType: TextInputType.phone, maxLength: 10, validator: (value) { if (value != null && value.trim().isNotEmpty) { if (value.length != 10) { return 'Emergency contact must be 10 digits'; } if (!RegExp(r'^[0-9]+$').hasMatch(value)) { return 'Emergency contact must contain only digits'; } } return null; }, ), SizedBox(height: 24.h), // Terms and Conditions Container( padding: EdgeInsets.all(16.w), decoration: BoxDecoration( color: Colors.grey.shade50, borderRadius: BorderRadius.circular(8.r), border: Border.all(color: Colors.grey.shade300), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Terms & Conditions', style: TextStyle( fontSize: 14.sp, fontWeight: FontWeight.w600, color: Colors.grey.shade800, ), ), SizedBox(height: 8.h), Text( '• Member agrees to pay monthly installment of ₹${widget.group.monthlyInstallment.toStringAsFixed(0)}\n' '• Member must attend monthly draws on ${widget.group.drawDate}th of each month\n' '• Member can win the lottery only once per group\n' '• Foreman commission of ₹${widget.group.foremanCommissionAmount} applies', style: TextStyle( fontSize: 12.sp, color: Colors.grey.shade600, height: 1.4, ), ), ], ), ), SizedBox(height: 24.h), // Action Buttons Row( children: [ Expanded( child: OutlinedButton( onPressed: _isLoading ? null : () => Get.back(), style: OutlinedButton.styleFrom( padding: EdgeInsets.symmetric(vertical: 16.h), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.r), ), ), child: Text( 'Cancel', style: TextStyle(fontSize: 16.sp), ), ), ), SizedBox(width: 16.w), Expanded( child: ElevatedButton( onPressed: _isLoading ? null : _addMember, style: ElevatedButton.styleFrom( backgroundColor: Colors.blue.shade600, foregroundColor: Colors.white, padding: EdgeInsets.symmetric(vertical: 16.h), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.r), ), ), child: _isLoading ? SizedBox( height: 20.h, width: 20.w, child: const CircularProgressIndicator( strokeWidth: 2, valueColor: AlwaysStoppedAnimation(Colors.white), ), ) : Text( 'Add Member', style: TextStyle(fontSize: 16.sp), ), ), ), ], ), ], ), ), ), ), ], ), ), ); } Widget _buildSectionTitle(String title) { return Text( title, style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w600, color: Colors.grey.shade800, ), ); } Widget _buildInfoItem(String label, String value) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( label, style: TextStyle( fontSize: 12.sp, color: Colors.blue.shade600, ), ), SizedBox(height: 4.h), Text( value, style: TextStyle( fontSize: 14.sp, fontWeight: FontWeight.w600, color: Colors.blue.shade800, ), ), ], ); } }