import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:intl/intl.dart'; import '../../../../shared/design_system/unionflow_design_system.dart'; import '../../../../shared/widgets/core_card.dart'; import '../../../../shared/widgets/info_badge.dart'; import '../../bloc/adhesions_bloc.dart'; import '../../data/models/adhesion_model.dart'; import '../widgets/paiement_adhesion_dialog.dart'; import '../widgets/rejet_adhesion_dialog.dart'; import '../../../authentication/presentation/bloc/auth_bloc.dart'; class AdhesionDetailPage extends StatefulWidget { final String adhesionId; const AdhesionDetailPage({super.key, required this.adhesionId}); @override State createState() => _AdhesionDetailPageState(); } class _AdhesionDetailPageState extends State { final _currencyFormat = NumberFormat.currency(locale: 'fr_FR', symbol: 'FCFA'); @override void initState() { super.initState(); context.read().add(LoadAdhesionById(widget.adhesionId)); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColors.background, appBar: const UFAppBar( title: 'DÉTAIL ADHÉSION', backgroundColor: AppColors.surface, foregroundColor: AppColors.textPrimaryLight, ), body: BlocConsumer( listenWhen: (prev, curr) => prev.status != curr.status, listener: (context, state) { if (state.status == AdhesionsStatus.error && state.message != null) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(state.message!), backgroundColor: AppColors.error), ); } }, buildWhen: (prev, curr) => prev.adhesionDetail != curr.adhesionDetail || prev.status != curr.status, builder: (context, state) { if (state.status == AdhesionsStatus.loading && state.adhesionDetail == null) { return const Center(child: CircularProgressIndicator()); } final a = state.adhesionDetail; if (a == null) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.error_outline, size: 64, color: AppColors.textSecondaryLight), const SizedBox(height: 16), Text( 'Adhésion introuvable', style: Theme.of(context).textTheme.titleMedium, ), ], ), ); } return SingleChildScrollView( padding: const EdgeInsets.all(12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _InfoCard( title: 'Référence', value: a.numeroReference ?? a.id ?? '—', ), _InfoCard( title: 'Statut', value: a.statutLibelle, trail: _buildStatutBadge(a.statut), ), _InfoCard( title: 'Organisation', value: a.nomOrganisation ?? a.organisationId ?? '—', ), _InfoCard( title: 'Membre', value: a.nomMembreComplet, ), if (a.emailMembre != null && a.emailMembre!.isNotEmpty) _InfoCard(title: 'Email', value: a.emailMembre!), if (a.dateDemande != null) _InfoCard( title: 'Date demande', value: DateFormat('dd/MM/yyyy').format(a.dateDemande!), ), _InfoCard( title: 'Frais d\'adhésion', value: a.fraisAdhesion != null ? _currencyFormat.format(a.fraisAdhesion) : '—', ), if (a.montantPaye != null && a.montantPaye! > 0) _InfoCard( title: 'Montant payé', value: _currencyFormat.format(a.montantPaye!), ), if (a.montantRestant > 0) _InfoCard( title: 'Montant restant', value: _currencyFormat.format(a.montantRestant), ), if (a.motifRejet != null && a.motifRejet!.isNotEmpty) _InfoCard(title: 'Motif rejet', value: a.motifRejet!), _ActionsSection(adhesion: a, currencyFormat: _currencyFormat, isGestionnaire: _isGestionnaire()), ], ), ); }, ), ); } bool _isGestionnaire() { final state = context.read().state; if (state is AuthAuthenticated) { return state.effectiveRole.level >= 50; } return false; } } class _InfoCard extends StatelessWidget { final String title; final String value; final Widget? trail; const _InfoCard({required this.title, required this.value, this.trail}); @override Widget build(BuildContext context) { return CoreCard( margin: const EdgeInsets.only(bottom: 8), padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10), child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title.toUpperCase(), style: AppTypography.subtitleSmall.copyWith( fontWeight: FontWeight.bold, fontSize: 9, color: AppColors.textSecondaryLight, ), ), const SizedBox(height: 2), Text( value, style: AppTypography.bodyTextSmall.copyWith(fontSize: 12), ), ], ), ), if (trail != null) trail!, ], ), ); } } Widget _buildStatutBadge(String? statut) { Color color; switch (statut) { case 'APPROUVEE': case 'PAYEE': color = AppColors.success; break; case 'REJETEE': case 'ANNULEE': color = AppColors.error; break; case 'EN_ATTENTE': color = AppColors.brandGreenLight; break; case 'EN_PAIEMENT': color = AppColors.warning; break; default: color = AppColors.textSecondaryLight; } return InfoBadge(text: statut ?? 'INCONNU', backgroundColor: color); } class _ActionsSection extends StatelessWidget { final AdhesionModel adhesion; final NumberFormat currencyFormat; final bool isGestionnaire; const _ActionsSection({ required this.adhesion, required this.currencyFormat, required this.isGestionnaire, }); @override Widget build(BuildContext context) { if (!isGestionnaire) return const SizedBox.shrink(); // Normal members cannot approve/pay an adhesion on someone else's behalf (or their own) currently in the UI design. final bloc = context.read(); if (adhesion.statut == 'EN_ATTENTE') { return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: Text( 'ACTIONS ADMINISTRATIVES', style: AppTypography.subtitleSmall.copyWith( fontWeight: FontWeight.bold, letterSpacing: 1.1, ), ), ), const SizedBox(height: 8), Row( children: [ Expanded( child: ElevatedButton( onPressed: () { if (adhesion.id == null) return; bloc.add(ApprouverAdhesion(adhesion.id!)); }, style: ElevatedButton.styleFrom( backgroundColor: AppColors.success, foregroundColor: Colors.white, elevation: 0, padding: const EdgeInsets.symmetric(vertical: 12), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)), ), child: Text('APPROUVER', style: AppTypography.actionText.copyWith(fontSize: 11, color: Colors.white)), ), ), const SizedBox(width: 12), Expanded( child: OutlinedButton( onPressed: () { if (adhesion.id == null) return; showDialog( context: context, builder: (ctx) => BlocProvider.value( value: bloc, child: RejetAdhesionDialog( adhesionId: adhesion.id!, onRejected: () => Navigator.of(ctx).pop(), ), ), ); }, style: OutlinedButton.styleFrom( foregroundColor: AppColors.error, side: const BorderSide(color: AppColors.error), padding: const EdgeInsets.symmetric(vertical: 12), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)), ), child: Text('REJETER', style: AppTypography.actionText.copyWith(fontSize: 11)), ), ), ], ), ], ); } if (adhesion.estEnAttentePaiement && adhesion.id != null) { return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: Text( 'PAIEMENT', style: AppTypography.subtitleSmall.copyWith( fontWeight: FontWeight.bold, letterSpacing: 1.1, ), ), ), const SizedBox(height: 8), ElevatedButton( onPressed: () { showDialog( context: context, builder: (ctx) => BlocProvider.value( value: bloc, child: PaiementAdhesionDialog( adhesionId: adhesion.id!, montantRestant: adhesion.montantRestant, onPaid: () => Navigator.of(ctx).pop(), ), ), ); }, style: ElevatedButton.styleFrom( backgroundColor: AppColors.primaryGreen, foregroundColor: Colors.white, elevation: 0, padding: const EdgeInsets.symmetric(vertical: 12), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)), ), child: Text('ENREGISTRER UN PAIEMENT', style: AppTypography.actionText.copyWith(fontSize: 11, color: Colors.white)), ), ], ); } return const SizedBox.shrink(); } }