import 'package:flutter/material.dart'; import '../../../../core/theme/app_typography.dart'; import '../../../../core/theme/theme_extensions.dart'; import '../../../../services/clubs/club_models.dart'; import 'club_monogram.dart'; /// Automotive styled card representing a MotorSignal Club in list views, /// discovery grids, and membership directories. class ClubCard extends StatelessWidget { final Club club; final ClubRole? role; final VoidCallback? onTap; final bool inGrid; const ClubCard({ super.key, required this.club, this.role, this.onTap, this.inGrid = false, }); @override Widget build(BuildContext context) { final colors = context.motorColors; final theme = Theme.of(context); return Container( margin: inGrid ? EdgeInsets.zero : const EdgeInsets.symmetric(vertical: 6.0), decoration: BoxDecoration( color: colors.surfaceContainer, borderRadius: BorderRadius.circular(14), border: Border.all(color: colors.outlineVariant, width: 0.8), ), child: Material( color: Colors.transparent, child: InkWell( borderRadius: BorderRadius.circular(14), onTap: onTap, child: Padding( padding: const EdgeInsets.all(14.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Header row: Monogram + Name/Slug + Optional Role Badge Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ ClubMonogram(name: club.name, size: 44), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: Text( club.name, maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle( fontFamily: AppTypography.fontHeadline, fontSize: 15, fontWeight: FontWeight.w700, ), ), ), if (role != null && (role == ClubRole.owner || role == ClubRole.admin)) ...[ const SizedBox(width: 8), _buildRolePill(context, role!, colors), ], ], ), const SizedBox(height: 2), Text( '@${club.slug}', maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( fontFamily: AppTypography.fontTelemetry, fontSize: 12, fontWeight: FontWeight.w600, color: colors.cyberCyan, ), ), ], ), ), const SizedBox(width: 8), Icon( Icons.chevron_right, color: theme.colorScheme.onSurfaceVariant.withValues(alpha: 0.6), size: 20, ), ], ), // Optional description preview if present if (club.description.isNotEmpty) ...[ const SizedBox(height: 10), Text( club.description, maxLines: 2, overflow: TextOverflow.ellipsis, style: TextStyle( fontFamily: AppTypography.fontBody, fontSize: 12.5, color: theme.colorScheme.onSurfaceVariant, height: 1.3, ), ), ], const SizedBox(height: 12), // Badges row: Member count, admission policy, region, focus Wrap( spacing: 8, runSpacing: 6, crossAxisAlignment: WrapCrossAlignment.center, children: [ // Member count badge _buildPill( icon: Icons.people_outline, label: '${club.memberCount} ${club.memberCount == 1 ? 'member' : 'members'}', colors: colors, theme: theme, ), // Admission policy badge if (role == null) _buildAdmissionBadge(context, club.admissionPolicy, colors), // Region badge if available if (club.homeRegion != null && club.homeRegion!.trim().isNotEmpty) _buildPill( icon: Icons.location_on_outlined, label: club.homeRegion!.trim(), colors: colors, theme: theme, ), // Motorcycle focus badge if available if (club.motorcycleFocus != null && club.motorcycleFocus!.trim().isNotEmpty) _buildPill( icon: Icons.two_wheeler_outlined, label: club.motorcycleFocus!.trim(), colors: colors, theme: theme, ), // Non-public visibility badge if (club.visibility != ClubVisibility.public) _buildPill( icon: club.visibility == ClubVisibility.private ? Icons.lock_outline : Icons.visibility_off_outlined, label: club.visibility.label, colors: colors, theme: theme, tintColor: colors.warningAmber, ), ], ), ], ), ), ), ), ); } Widget _buildRolePill(BuildContext context, ClubRole role, MotorSignalThemeColors colors) { Color badgeColor; Color textColor = Colors.black; switch (role) { case ClubRole.owner: badgeColor = colors.warningAmber; break; case ClubRole.admin: badgeColor = colors.cyberCyan; break; case ClubRole.member: badgeColor = colors.outlineVariant; textColor = Theme.of(context).colorScheme.onSurface; break; } return Container( padding: const EdgeInsets.symmetric(horizontal: 7, vertical: 2), decoration: BoxDecoration( color: badgeColor, borderRadius: BorderRadius.circular(6), ), child: Text( role.label.toUpperCase(), style: TextStyle( fontFamily: AppTypography.fontTelemetry, fontSize: 9.5, fontWeight: FontWeight.w800, letterSpacing: 0.4, color: textColor, ), ), ); } Widget _buildAdmissionBadge( BuildContext context, ClubAdmissionPolicy policy, MotorSignalThemeColors colors, ) { Color color; IconData icon; switch (policy) { case ClubAdmissionPolicy.open: color = colors.launchGreen; icon = Icons.group_add_outlined; break; case ClubAdmissionPolicy.request: color = colors.cyberCyan; icon = Icons.how_to_reg_outlined; break; case ClubAdmissionPolicy.inviteOnly: color = colors.outline; icon = Icons.mail_outline; break; } return Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: color.withValues(alpha: 0.12), borderRadius: BorderRadius.circular(8), border: Border.all(color: color.withValues(alpha: 0.35), width: 0.8), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon(icon, size: 12, color: color), const SizedBox(width: 4), Text( policy.label, style: TextStyle( fontFamily: AppTypography.fontHeadline, fontSize: 11, fontWeight: FontWeight.w600, color: color, ), ), ], ), ); } Widget _buildPill({ required IconData icon, required String label, required MotorSignalThemeColors colors, required ThemeData theme, Color? tintColor, }) { final effectiveColor = tintColor ?? theme.colorScheme.onSurfaceVariant; return Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: colors.surfaceContainerHighest.withValues(alpha: 0.5), borderRadius: BorderRadius.circular(8), border: Border.all(color: colors.outlineVariant.withValues(alpha: 0.5), width: 0.6), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon(icon, size: 12, color: effectiveColor), const SizedBox(width: 4), ConstrainedBox( constraints: const BoxConstraints(maxWidth: 160), child: Text( label, maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( fontFamily: AppTypography.fontHeadline, fontSize: 11, fontWeight: FontWeight.w500, color: effectiveColor, ), ), ), ], ), ); } }