import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter/services.dart'; import '../../core/services/api_service.dart'; import '../../core/models/group_member.dart'; import '../../core/utils/snackbar_util.dart'; class EditMemberDialog extends StatefulWidget { final GroupMember member; const EditMemberDialog({ super.key, required this.member, }); @override State createState() => _EditMemberDialogState(); } class _EditMemberDialogState extends State { final _formKey = GlobalKey(); final _nameController = TextEditingController(); final _phoneController = TextEditingController(); final _emailController = TextEditingController(); final _addressController = TextEditingController(); final _emergencyContactController = TextEditingController(); final _apiService = ApiService(); bool _isLoading = false; bool _showMemberId = false; @override void initState() { super.initState(); _nameController.text = widget.member.user?.fullName ?? ''; _phoneController.text = widget.member.user?.mobileNumber ?? ''; _emailController.text = widget.member.user?.email ?? ''; _addressController.text = widget.member.user?.address ?? ''; _emergencyContactController.text = widget.member.user?.emergencyContact ?? ''; } @override void dispose() { _nameController.dispose(); _phoneController.dispose(); _emailController.dispose(); _addressController.dispose(); _emergencyContactController.dispose(); super.dispose(); } Future _handleSubmit() async { if (_formKey.currentState!.validate()) { setState(() => _isLoading = true); try { final updates = {}; // Only include changed fields if (_nameController.text != (widget.member.user?.fullName ?? '')) { updates['full_name'] = _nameController.text; } if (_phoneController.text != (widget.member.user?.mobileNumber ?? '')) { updates['mobile_number'] = _phoneController.text; } if (_emailController.text != (widget.member.user?.email ?? '')) { updates['email'] = _emailController.text.isEmpty ? null : _emailController.text; } if (_addressController.text != (widget.member.user?.address ?? '')) { updates['address'] = _addressController.text.isEmpty ? null : _addressController.text; } if (_emergencyContactController.text != (widget.member.user?.emergencyContact ?? '')) { updates['emergency_contact'] = _emergencyContactController.text.isEmpty ? null : _emergencyContactController.text; } if (updates.isEmpty) { SnackbarUtil.showWarning('No changes made'); Get.back(); return; } final response = await _apiService.updateMemberDetails( widget.member.userId, updates, ); if (response['success']) { SnackbarUtil.showSuccess( 'Member details updated successfully', title: 'Success', ); Get.back(result: true); } else { SnackbarUtil.showError( response['message'] ?? 'Failed to update member', title: 'Error', ); } } catch (e) { SnackbarUtil.showError('Error: ${e.toString()}'); } finally { setState(() => _isLoading = false); } } } void _copyMemberId() { Clipboard.setData(ClipboardData(text: widget.member.userId)); SnackbarUtil.showSuccess( 'Member ID copied to clipboard', duration: const Duration(seconds: 2), ); } @override Widget build(BuildContext context) { return Dialog( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.r)), child: Container( width: 500.w, constraints: BoxConstraints( maxHeight: MediaQuery.of(context).size.height * 0.85, ), child: Column( mainAxisSize: MainAxisSize.min, children: [ // Fixed Header Container( padding: EdgeInsets.all(24.w), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.only( topLeft: Radius.circular(20.r), topRight: Radius.circular(20.r), ), border: Border( bottom: BorderSide(color: Colors.grey.shade200), ), ), child: Row( children: [ // Member Number Badge Container( width: 40.w, height: 40.w, decoration: BoxDecoration( color: Colors.purple.shade600, shape: BoxShape.circle, ), child: Center( child: Text( '#${widget.member.memberNumber}', style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 16.sp, ), ), ), ), SizedBox(width: 12.w), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Edit Member #${widget.member.memberNumber}', style: TextStyle( fontSize: 20.sp, fontWeight: FontWeight.bold, ), ), Text( widget.member.user?.fullName ?? 'Unknown', style: TextStyle( fontSize: 13.sp, color: Colors.grey.shade600, ), ), ], ), ), IconButton( icon: const Icon(Icons.close), onPressed: () => Get.back(), ), ], ), ), // Scrollable Content Flexible( child: SingleChildScrollView( padding: EdgeInsets.all(24.w), child: Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Member Number & ID Section Container( padding: EdgeInsets.all(16.w), decoration: BoxDecoration( color: Colors.purple.shade50, borderRadius: BorderRadius.circular(12.r), border: Border.all(color: Colors.purple.shade200), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon(Icons.badge, color: Colors.purple.shade700, size: 22.w), SizedBox(width: 8.w), Text( 'Member Number (Readable)', style: TextStyle( fontSize: 15.sp, fontWeight: FontWeight.w600, color: Colors.purple.shade900, ), ), ], ), SizedBox(height: 12.h), Container( padding: EdgeInsets.all(16.w), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(8.r), border: Border.all(color: Colors.purple.shade300, width: 2), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 'Member #${widget.member.memberNumber}', style: TextStyle( fontSize: 24.sp, fontWeight: FontWeight.bold, color: Colors.purple.shade700, ), ), ], ), ), SizedBox(height: 8.h), Text( 'Use this number to easily reference this member', style: TextStyle( fontSize: 12.sp, color: Colors.purple.shade700, fontStyle: FontStyle.italic, ), ), ], ), ), SizedBox(height: 16.h), // Unique ID Section (Technical) Container( padding: EdgeInsets.all(16.w), decoration: BoxDecoration( color: Colors.grey.shade50, borderRadius: BorderRadius.circular(12.r), border: Border.all(color: Colors.grey.shade300), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon(Icons.fingerprint, color: Colors.grey.shade700, size: 20.w), SizedBox(width: 8.w), Text( 'Unique ID (Technical)', style: TextStyle( fontSize: 14.sp, fontWeight: FontWeight.w600, color: Colors.grey.shade700, ), ), const Spacer(), IconButton( icon: Icon(_showMemberId ? Icons.visibility_off : Icons.visibility, size: 18.w), onPressed: () { setState(() => _showMemberId = !_showMemberId); }, tooltip: _showMemberId ? 'Hide ID' : 'Show ID', ), ], ), if (_showMemberId) ...[ SizedBox(height: 8.h), Row( children: [ Expanded( child: Text( widget.member.userId, style: TextStyle( fontSize: 11.sp, fontFamily: 'monospace', color: Colors.grey.shade800, ), ), ), IconButton( icon: const Icon(Icons.copy, size: 18), onPressed: _copyMemberId, tooltip: 'Copy UUID', ), ], ), ], SizedBox(height: 4.h), Text( 'UUID for database operations', style: TextStyle( fontSize: 11.sp, color: Colors.grey.shade600, fontStyle: FontStyle.italic, ), ), ], ), ), SizedBox(height: 24.h), // Full Name Text( 'Full Name *', style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w600, ), ), SizedBox(height: 8.h), TextFormField( controller: _nameController, decoration: InputDecoration( hintText: 'Full name', prefixIcon: const Icon(Icons.person), border: OutlineInputBorder( borderRadius: BorderRadius.circular(12.r), ), filled: true, fillColor: Colors.grey.shade50, ), validator: (value) { if (value?.isEmpty ?? true) return 'Name is required'; if (value!.length < 2) return 'Name too short'; return null; }, ), SizedBox(height: 20.h), // Mobile Number Text( 'Mobile Number *', style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w600, ), ), SizedBox(height: 8.h), TextFormField( controller: _phoneController, keyboardType: TextInputType.phone, maxLength: 10, decoration: InputDecoration( hintText: '10-digit mobile number', prefixIcon: const Icon(Icons.phone), border: OutlineInputBorder( borderRadius: BorderRadius.circular(12.r), ), filled: true, fillColor: Colors.grey.shade50, counterText: '', ), validator: (value) { if (value?.isEmpty ?? true) return 'Mobile number is required'; if (!RegExp(r'^[0-9]{10}$').hasMatch(value!)) { return 'Must be exactly 10 digits'; } return null; }, ), SizedBox(height: 20.h), // Email (Optional) Text( 'Email (Optional)', style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w600, ), ), SizedBox(height: 8.h), TextFormField( controller: _emailController, keyboardType: TextInputType.emailAddress, decoration: InputDecoration( hintText: 'email@example.com', prefixIcon: const Icon(Icons.email), border: OutlineInputBorder( borderRadius: BorderRadius.circular(12.r), ), filled: true, fillColor: Colors.grey.shade50, ), validator: (value) { if (value != null && value.isNotEmpty) { if (!RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(value)) { return 'Invalid email format'; } } return null; }, ), SizedBox(height: 20.h), // Address (Optional) Text( 'Address (Optional)', style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w600, ), ), SizedBox(height: 8.h), TextFormField( controller: _addressController, maxLines: 3, decoration: InputDecoration( hintText: 'Full address', prefixIcon: const Icon(Icons.location_on), border: OutlineInputBorder( borderRadius: BorderRadius.circular(12.r), ), filled: true, fillColor: Colors.grey.shade50, ), ), SizedBox(height: 20.h), // Emergency Contact (Optional) Text( 'Emergency Contact (Optional)', style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w600, ), ), SizedBox(height: 8.h), TextFormField( controller: _emergencyContactController, keyboardType: TextInputType.phone, maxLength: 10, decoration: InputDecoration( hintText: '10-digit emergency contact', prefixIcon: const Icon(Icons.contacts), border: OutlineInputBorder( borderRadius: BorderRadius.circular(12.r), ), filled: true, fillColor: Colors.grey.shade50, counterText: '', ), validator: (value) { if (value != null && value.isNotEmpty) { if (!RegExp(r'^[0-9]{10}$').hasMatch(value)) { return 'Must be exactly 10 digits'; } } return null; }, ), ], ), ), ), ), // Fixed Footer with Actions Container( padding: EdgeInsets.all(24.w), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.only( bottomLeft: Radius.circular(20.r), bottomRight: Radius.circular(20.r), ), border: Border( top: BorderSide(color: Colors.grey.shade200), ), ), child: Row( children: [ Expanded( child: OutlinedButton( onPressed: _isLoading ? null : () => Get.back(), style: OutlinedButton.styleFrom( padding: EdgeInsets.symmetric(vertical: 14.h), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12.r), ), ), child: Text( 'Cancel', style: TextStyle(fontSize: 16.sp), ), ), ), SizedBox(width: 16.w), Expanded( child: ElevatedButton( onPressed: _isLoading ? null : _handleSubmit, style: ElevatedButton.styleFrom( backgroundColor: Colors.blue.shade600, foregroundColor: Colors.white, padding: EdgeInsets.symmetric(vertical: 14.h), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12.r), ), elevation: 2, ), child: _isLoading ? SizedBox( height: 20.h, width: 20.w, child: const CircularProgressIndicator( strokeWidth: 2, valueColor: AlwaysStoppedAnimation(Colors.white), ), ) : Text( 'Update Member', style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600), ), ), ), ], ), ), ], ), ), ); } }