import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import '../../../../shared/theme/app_theme.dart'; import '../../../../shared/widgets/cards/sophisticated_card.dart'; import '../../../../shared/widgets/avatars/sophisticated_avatar.dart'; import '../../../../shared/widgets/badges/status_badge.dart'; import '../../../../shared/widgets/badges/count_badge.dart'; import '../../../../shared/widgets/buttons/buttons.dart'; class SophisticatedMemberCard extends StatefulWidget { final Map member; final VoidCallback? onTap; final VoidCallback? onEdit; final VoidCallback? onMessage; final VoidCallback? onCall; final bool showActions; final bool compact; const SophisticatedMemberCard({ super.key, required this.member, this.onTap, this.onEdit, this.onMessage, this.onCall, this.showActions = true, this.compact = false, }); @override State createState() => _SophisticatedMemberCardState(); } class _SophisticatedMemberCardState extends State with TickerProviderStateMixin { late AnimationController _expandController; late AnimationController _actionController; late Animation _expandAnimation; late Animation _actionAnimation; bool _isExpanded = false; @override void initState() { super.initState(); _expandController = AnimationController( duration: const Duration(milliseconds: 300), vsync: this, ); _actionController = AnimationController( duration: const Duration(milliseconds: 200), vsync: this, ); _expandAnimation = CurvedAnimation( parent: _expandController, curve: Curves.easeInOut, ); _actionAnimation = Tween( begin: 0.0, end: 1.0, ).animate(CurvedAnimation( parent: _actionController, curve: Curves.elasticOut, )); _actionController.forward(); } @override void dispose() { _expandController.dispose(); _actionController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return SophisticatedCard( variant: CardVariant.elevated, size: widget.compact ? CardSize.compact : CardSize.standard, onTap: widget.onTap, margin: const EdgeInsets.symmetric(vertical: 6, horizontal: 4), child: Column( children: [ _buildMainContent(), AnimatedBuilder( animation: _expandAnimation, builder: (context, child) { return ClipRect( child: Align( alignment: Alignment.topCenter, heightFactor: _expandAnimation.value, child: child, ), ); }, child: _buildExpandedContent(), ), ], ), ); } Widget _buildMainContent() { return Row( children: [ _buildAvatar(), const SizedBox(width: 16), Expanded(child: _buildMemberInfo()), _buildTrailingActions(), ], ); } Widget _buildAvatar() { final roleColor = _getRoleColor(); final isOnline = widget.member['status'] == 'Actif'; return SophisticatedAvatar( initials: _getInitials(), size: widget.compact ? AvatarSize.medium : AvatarSize.large, variant: AvatarVariant.gradient, backgroundColor: roleColor, showOnlineStatus: true, isOnline: isOnline, badge: _buildRoleBadge(), onTap: () => _toggleExpanded(), ); } Widget _buildRoleBadge() { final role = widget.member['role'] as String; if (role == 'Président' || role == 'Secrétaire' || role == 'Trésorier') { return CountBadge( count: 1, backgroundColor: AppTheme.warningColor, size: 16, suffix: '★', ); } return const SizedBox.shrink(); } Widget _buildMemberInfo() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: Text( '${widget.member['firstName']} ${widget.member['lastName']}', style: const TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: AppTheme.textPrimary, ), overflow: TextOverflow.ellipsis, ), ), const SizedBox(width: 8), _buildStatusBadge(), ], ), const SizedBox(height: 4), _buildRoleChip(), if (!widget.compact) ...[ const SizedBox(height: 8), _buildQuickInfo(), ], ], ); } Widget _buildStatusBadge() { final status = widget.member['status'] as String; final cotisationStatus = widget.member['cotisationStatus'] as String; if (cotisationStatus == 'En retard') { return StatusBadge( text: 'Retard', type: BadgeType.error, size: BadgeSize.small, variant: BadgeVariant.ghost, icon: Icons.warning, ); } return StatusBadge( text: status, type: status == 'Actif' ? BadgeType.success : BadgeType.neutral, size: BadgeSize.small, variant: BadgeVariant.ghost, ); } Widget _buildRoleChip() { final role = widget.member['role'] as String; final roleColor = _getRoleColor(); return Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), decoration: BoxDecoration( color: roleColor.withOpacity(0.1), borderRadius: BorderRadius.circular(12), border: Border.all( color: roleColor.withOpacity(0.3), width: 1, ), ), child: Text( role, style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: roleColor, ), ), ); } Widget _buildQuickInfo() { return Row( children: [ Expanded( child: _buildInfoItem( Icons.email_outlined, widget.member['email'], AppTheme.infoColor, ), ), const SizedBox(width: 16), _buildInfoItem( Icons.phone_outlined, _formatPhone(widget.member['phone']), AppTheme.successColor, ), ], ); } Widget _buildInfoItem(IconData icon, String text, Color color) { return Row( mainAxisSize: MainAxisSize.min, children: [ Icon(icon, size: 14, color: color), const SizedBox(width: 4), Flexible( child: Text( text, style: const TextStyle( fontSize: 12, color: AppTheme.textSecondary, ), overflow: TextOverflow.ellipsis, ), ), ], ); } Widget _buildTrailingActions() { return Column( mainAxisSize: MainAxisSize.min, children: [ AnimatedBuilder( animation: _actionAnimation, builder: (context, child) { return Transform.scale( scale: _actionAnimation.value, child: IconButton( onPressed: _toggleExpanded, icon: AnimatedRotation( turns: _isExpanded ? 0.5 : 0.0, duration: const Duration(milliseconds: 300), child: const Icon(Icons.expand_more), ), iconSize: 20, constraints: const BoxConstraints(minWidth: 32, minHeight: 32), style: IconButton.styleFrom( backgroundColor: AppTheme.backgroundLight, foregroundColor: AppTheme.textSecondary, ), ), ); }, ), if (widget.compact) ...[ const SizedBox(height: 4), _buildQuickActionButton(), ], ], ); } Widget _buildQuickActionButton() { return QuickButtons.iconGhost( icon: Icons.edit, onPressed: widget.onEdit ?? _editMember, size: 32, color: _getRoleColor(), tooltip: 'Modifier', ); } Widget _buildExpandedContent() { return Container( margin: const EdgeInsets.only(top: 16), padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: AppTheme.backgroundLight, borderRadius: BorderRadius.circular(12), ), child: Column( children: [ _buildDetailedInfo(), if (widget.showActions) ...[ const SizedBox(height: 16), _buildActionButtons(), ], ], ), ); } Widget _buildDetailedInfo() { return Column( children: [ _buildDetailRow( 'Adhésion', _formatDate(widget.member['joinDate']), Icons.calendar_today, AppTheme.primaryColor, ), const SizedBox(height: 12), _buildDetailRow( 'Dernière activité', _formatDate(widget.member['lastActivity']), Icons.access_time, AppTheme.infoColor, ), const SizedBox(height: 12), _buildDetailRow( 'Cotisation', widget.member['cotisationStatus'], Icons.payment, _getCotisationColor(), ), ], ); } Widget _buildDetailRow(String label, String value, IconData icon, Color color) { return Row( children: [ Container( width: 32, height: 32, decoration: BoxDecoration( color: color.withOpacity(0.1), borderRadius: BorderRadius.circular(16), ), child: Icon(icon, size: 16, color: color), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( label, style: const TextStyle( fontSize: 12, color: AppTheme.textSecondary, ), ), Text( value, style: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: label == 'Cotisation' ? color : AppTheme.textPrimary, ), ), ], ), ), ], ); } Widget _buildActionButtons() { return Row( children: [ Expanded( child: QuickButtons.outline( text: 'Appeler', icon: Icons.phone, onPressed: widget.onCall ?? _callMember, size: ButtonSize.small, color: AppTheme.successColor, ), ), const SizedBox(width: 8), Expanded( child: QuickButtons.outline( text: 'Message', icon: Icons.message, onPressed: widget.onMessage ?? _messageMember, size: ButtonSize.small, color: AppTheme.infoColor, ), ), const SizedBox(width: 8), Expanded( child: QuickButtons.outline( text: 'Modifier', icon: Icons.edit, onPressed: widget.onEdit ?? _editMember, size: ButtonSize.small, color: AppTheme.warningColor, ), ), ], ); } void _toggleExpanded() { setState(() { _isExpanded = !_isExpanded; if (_isExpanded) { _expandController.forward(); } else { _expandController.reverse(); } }); HapticFeedback.selectionClick(); } String _getInitials() { final firstName = widget.member['firstName'] as String; final lastName = widget.member['lastName'] as String; return '${firstName.isNotEmpty ? firstName[0] : ''}${lastName.isNotEmpty ? lastName[0] : ''}'.toUpperCase(); } Color _getRoleColor() { switch (widget.member['role']) { case 'Président': return AppTheme.primaryColor; case 'Secrétaire': return AppTheme.secondaryColor; case 'Trésorier': return AppTheme.accentColor; case 'Responsable événements': return AppTheme.warningColor; default: return AppTheme.infoColor; } } Color _getCotisationColor() { switch (widget.member['cotisationStatus']) { case 'À jour': return AppTheme.successColor; case 'En retard': return AppTheme.errorColor; case 'Exempt': return AppTheme.infoColor; default: return AppTheme.textSecondary; } } String _formatDate(String dateString) { try { final date = DateTime.parse(dateString); final now = DateTime.now(); final difference = now.difference(date); if (difference.inDays < 1) { return 'Aujourd\'hui'; } else if (difference.inDays < 7) { return 'Il y a ${difference.inDays} jour${difference.inDays > 1 ? 's' : ''}'; } else if (difference.inDays < 30) { final weeks = (difference.inDays / 7).floor(); return 'Il y a $weeks semaine${weeks > 1 ? 's' : ''}'; } else { final months = [ 'Jan', 'Fév', 'Mar', 'Avr', 'Mai', 'Jun', 'Jul', 'Aoû', 'Sep', 'Oct', 'Nov', 'Déc' ]; return '${date.day} ${months[date.month - 1]} ${date.year}'; } } catch (e) { return dateString; } } String _formatPhone(String phone) { if (phone.length >= 10) { return '${phone.substring(0, 3)} ${phone.substring(3, 5)} ${phone.substring(5, 7)} ${phone.substring(7, 9)} ${phone.substring(9)}'; } return phone; } void _callMember() { HapticFeedback.lightImpact(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Appel vers ${widget.member['firstName']} ${widget.member['lastName']}'), backgroundColor: AppTheme.successColor, behavior: SnackBarBehavior.floating, ), ); } void _messageMember() { HapticFeedback.lightImpact(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Message vers ${widget.member['firstName']} ${widget.member['lastName']}'), backgroundColor: AppTheme.infoColor, behavior: SnackBarBehavior.floating, ), ); } void _editMember() { HapticFeedback.lightImpact(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Modification de ${widget.member['firstName']} ${widget.member['lastName']}'), backgroundColor: AppTheme.warningColor, behavior: SnackBarBehavior.floating, ), ); } }