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 '../../bloc/solidarity_bloc.dart'; import '../../data/models/demande_aide_model.dart'; import '../../../authentication/presentation/bloc/auth_bloc.dart'; class DemandeAideDetailPage extends StatefulWidget { final String demandeId; const DemandeAideDetailPage({super.key, required this.demandeId}); @override State createState() => _DemandeAideDetailPageState(); } class _DemandeAideDetailPageState extends State { final _currencyFormat = NumberFormat.currency(locale: 'fr_FR', symbol: 'FCFA'); @override void initState() { super.initState(); context.read().add(LoadDemandeAideById(widget.demandeId)); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColors.background, appBar: const UFAppBar( title: 'DÉTAIL DEMANDE', backgroundColor: AppColors.surface, foregroundColor: AppColors.textPrimaryLight, ), body: BlocConsumer( listenWhen: (prev, curr) => prev.status != curr.status, listener: (context, state) { if (state.status == SolidarityStatus.error && state.message != null) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(state.message!), backgroundColor: Colors.red), ); } }, buildWhen: (prev, curr) => prev.demandeDetail != curr.demandeDetail || prev.status != curr.status, builder: (context, state) { if (state.status == SolidarityStatus.loading && state.demandeDetail == null) { return const Center(child: CircularProgressIndicator()); } final d = state.demandeDetail; if (d == null) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.error_outline, size: 64, color: Colors.grey), const SizedBox(height: 16), Text( 'Demande 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: d.numeroReference ?? d.id ?? '—'), _InfoCard(title: 'Statut', value: d.statutLibelle), _InfoCard(title: 'Titre', value: d.titre ?? '—'), if (d.type != null) _InfoCard(title: 'Type', value: d.typeLibelle), if (d.description != null && d.description!.isNotEmpty) _InfoCard(title: 'Description', value: d.description!), if (d.montantDemande != null && d.montantDemande! > 0) _InfoCard( title: 'Montant demandé', value: _currencyFormat.format(d.montantDemande!), ), if (d.montantAccorde != null && d.montantAccorde! > 0) _InfoCard( title: 'Montant accordé', value: _currencyFormat.format(d.montantAccorde!), ), if (d.demandeur != null) _InfoCard(title: 'Demandeur', value: d.demandeur!), if (d.dateDemande != null) _InfoCard( title: 'Date demande', value: DateFormat('dd/MM/yyyy').format(d.dateDemande!), ), if (d.motif != null && d.motif!.isNotEmpty) _InfoCard(title: 'Motif', value: d.motif!), _ActionsSection(demande: d, 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!, ], ), ); } } class _ActionsSection extends StatelessWidget { final DemandeAideModel demande; final bool isGestionnaire; const _ActionsSection({required this.demande, required this.isGestionnaire}); @override Widget build(BuildContext context) { if (!isGestionnaire) return const SizedBox.shrink(); final bloc = context.read(); if (demande.statut != 'EN_ATTENTE' && demande.statut != 'SOUMISE') { return const SizedBox.shrink(); } if (demande.id == null) return const SizedBox.shrink(); 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: () => bloc.add(ApprouverDemandeAide(demande.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: () => _showRejetDialog(context, demande.id!, bloc), 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)), ), ), ], ), ], ); } void _showRejetDialog(BuildContext context, String demandeId, SolidarityBloc bloc) { final motifController = TextEditingController(); showDialog( context: context, builder: (ctx) => AlertDialog( title: const Text('Rejeter la demande'), content: TextField( controller: motifController, decoration: const InputDecoration( labelText: 'Motif du rejet (recommandé pour traçabilité)', hintText: 'Saisir le motif...', border: OutlineInputBorder(), ), maxLines: 3, autofocus: true, ), actions: [ TextButton( onPressed: () => Navigator.pop(ctx), child: const Text('Annuler'), ), FilledButton( onPressed: () { final motif = motifController.text.trim(); Navigator.pop(ctx); bloc.add(RejeterDemandeAide(demandeId, motif: motif.isNotEmpty ? motif : null)); }, style: FilledButton.styleFrom(backgroundColor: AppColors.error), child: const Text('Rejeter'), ), ], ), ); } }