import 'package:flutter/material.dart'; import '../../../../core/widgets/unified_card.dart'; import '../../../../core/theme/app_colors.dart'; import '../../../../core/theme/app_text_styles.dart'; import '../../../../core/utils/date_formatter.dart'; import '../../../../core/utils/currency_formatter.dart'; import '../../domain/entities/demande_aide.dart'; /// Widget de carte pour afficher une demande d'aide /// /// Cette carte affiche les informations essentielles d'une demande d'aide /// avec un design cohérent et des interactions tactiles. class DemandeAideCard extends StatelessWidget { final DemandeAide demande; final bool isSelected; final bool isSelectionMode; final VoidCallback? onTap; final VoidCallback? onLongPress; final ValueChanged? onSelectionChanged; const DemandeAideCard({ super.key, required this.demande, this.isSelected = false, this.isSelectionMode = false, this.onTap, this.onLongPress, this.onSelectionChanged, }); @override Widget build(BuildContext context) { return UnifiedCard( margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: InkWell( onTap: onTap, onLongPress: onLongPress, borderRadius: BorderRadius.circular(12), child: Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), border: isSelected ? Border.all(color: AppColors.primary, width: 2) : null, ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildHeader(), const SizedBox(height: 12), _buildContent(), const SizedBox(height: 12), _buildFooter(), ], ), ), ), ); } Widget _buildHeader() { return Row( children: [ if (isSelectionMode) ...[ Checkbox( value: isSelected, onChanged: onSelectionChanged, activeColor: AppColors.primary, ), const SizedBox(width: 8), ], Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: Text( demande.titre, style: AppTextStyles.titleMedium.copyWith( fontWeight: FontWeight.bold, ), maxLines: 2, overflow: TextOverflow.ellipsis, ), ), const SizedBox(width: 8), _buildStatutChip(), ], ), const SizedBox(height: 4), Row( children: [ Icon( Icons.person, size: 16, color: AppColors.textSecondary, ), const SizedBox(width: 4), Expanded( child: Text( demande.nomDemandeur, style: AppTextStyles.bodySmall.copyWith( color: AppColors.textSecondary, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), ), const SizedBox(width: 8), Text( demande.numeroReference, style: AppTextStyles.bodySmall.copyWith( color: AppColors.textSecondary, fontFamily: 'monospace', ), ), ], ), ], ), ), if (demande.estUrgente) ...[ const SizedBox(width: 8), Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: AppColors.error.withOpacity(0.1), borderRadius: BorderRadius.circular(12), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon( Icons.priority_high, size: 16, color: AppColors.error, ), const SizedBox(width: 4), Text( 'URGENT', style: AppTextStyles.labelSmall.copyWith( color: AppColors.error, fontWeight: FontWeight.bold, ), ), ], ), ), ], ], ); } Widget _buildContent() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( demande.description, style: AppTextStyles.bodyMedium, maxLines: 3, overflow: TextOverflow.ellipsis, ), const SizedBox(height: 8), Row( children: [ _buildTypeAideChip(), const SizedBox(width: 8), _buildPrioriteChip(), const Spacer(), if (demande.montantDemande != null) Text( CurrencyFormatter.formatCFA(demande.montantDemande!), style: AppTextStyles.titleSmall.copyWith( color: AppColors.primary, fontWeight: FontWeight.bold, ), ), ], ), ], ); } Widget _buildFooter() { return Row( children: [ Icon( Icons.access_time, size: 16, color: AppColors.textSecondary, ), const SizedBox(width: 4), Text( 'Créée ${DateFormatter.formatRelative(demande.dateCreation)}', style: AppTextStyles.bodySmall.copyWith( color: AppColors.textSecondary, ), ), if (demande.dateModification != demande.dateCreation) ...[ const SizedBox(width: 8), Text( '• Modifiée ${DateFormatter.formatRelative(demande.dateModification)}', style: AppTextStyles.bodySmall.copyWith( color: AppColors.textSecondary, ), ), ], const Spacer(), _buildProgressIndicator(), ], ); } Widget _buildStatutChip() { final color = _getStatutColor(demande.statut); return Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: color.withOpacity(0.1), borderRadius: BorderRadius.circular(12), ), child: Text( demande.statut.libelle, style: AppTextStyles.labelSmall.copyWith( color: color, fontWeight: FontWeight.w600, ), ), ); } Widget _buildTypeAideChip() { return Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: AppColors.surface, borderRadius: BorderRadius.circular(8), border: Border.all(color: AppColors.outline), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon( _getTypeAideIcon(demande.typeAide), size: 14, color: AppColors.primary, ), const SizedBox(width: 4), Text( demande.typeAide.libelle, style: AppTextStyles.labelSmall.copyWith( color: AppColors.textPrimary, ), ), ], ), ); } Widget _buildPrioriteChip() { final color = _getPrioriteColor(demande.priorite); return Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: color.withOpacity(0.1), borderRadius: BorderRadius.circular(8), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon( _getPrioriteIcon(demande.priorite), size: 14, color: color, ), const SizedBox(width: 4), Text( demande.priorite.libelle, style: AppTextStyles.labelSmall.copyWith( color: color, ), ), ], ), ); } Widget _buildProgressIndicator() { final progress = demande.pourcentageAvancement; final color = _getProgressColor(progress); return Row( mainAxisSize: MainAxisSize.min, children: [ Container( width: 60, height: 4, decoration: BoxDecoration( color: AppColors.outline, borderRadius: BorderRadius.circular(2), ), child: FractionallySizedBox( alignment: Alignment.centerLeft, widthFactor: progress / 100, child: Container( decoration: BoxDecoration( color: color, borderRadius: BorderRadius.circular(2), ), ), ), ), const SizedBox(width: 8), Text( '${progress.toInt()}%', style: AppTextStyles.labelSmall.copyWith( color: color, fontWeight: FontWeight.w600, ), ), ], ); } Color _getStatutColor(StatutAide statut) { switch (statut) { case StatutAide.brouillon: return AppColors.textSecondary; case StatutAide.soumise: return AppColors.warning; case StatutAide.enEvaluation: return AppColors.info; case StatutAide.approuvee: return AppColors.success; case StatutAide.rejetee: return AppColors.error; case StatutAide.enCours: return AppColors.primary; case StatutAide.terminee: return AppColors.success; case StatutAide.versee: return AppColors.success; case StatutAide.livree: return AppColors.success; case StatutAide.annulee: return AppColors.error; } } Color _getPrioriteColor(PrioriteAide priorite) { switch (priorite) { case PrioriteAide.basse: return AppColors.success; case PrioriteAide.normale: return AppColors.info; case PrioriteAide.haute: return AppColors.warning; case PrioriteAide.critique: return AppColors.error; } } Color _getProgressColor(double progress) { if (progress < 25) return AppColors.error; if (progress < 50) return AppColors.warning; if (progress < 75) return AppColors.info; return AppColors.success; } IconData _getTypeAideIcon(TypeAide typeAide) { switch (typeAide) { case TypeAide.aideFinanciereUrgente: return Icons.attach_money; case TypeAide.aideFinanciereMedicale: return Icons.medical_services; case TypeAide.aideFinanciereEducation: return Icons.school; case TypeAide.aideMaterielleVetements: return Icons.checkroom; case TypeAide.aideMaterielleNourriture: return Icons.restaurant; case TypeAide.aideProfessionnelleFormation: return Icons.work; case TypeAide.aideSocialeAccompagnement: return Icons.support; case TypeAide.autre: return Icons.help; } } IconData _getPrioriteIcon(PrioriteAide priorite) { switch (priorite) { case PrioriteAide.basse: return Icons.keyboard_arrow_down; case PrioriteAide.normale: return Icons.remove; case PrioriteAide.haute: return Icons.keyboard_arrow_up; case PrioriteAide.critique: return Icons.priority_high; } } }