/// Dialog de création d'une demande d'aide library create_demande_aide_dialog; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:get_it/get_it.dart'; import '../../../../core/utils/logger.dart'; import '../../../../shared/design_system/unionflow_design_system.dart'; import '../../bloc/solidarity_bloc.dart'; import '../../data/models/demande_aide_model.dart'; import '../../../organizations/domain/repositories/organization_repository.dart'; import '../../../organizations/data/models/organization_model.dart'; import '../../../members/data/models/membre_complete_model.dart'; import '../../../profile/domain/repositories/profile_repository.dart'; class CreateDemandeAideDialog extends StatefulWidget { final VoidCallback onCreated; const CreateDemandeAideDialog({super.key, required this.onCreated}); @override State createState() => _CreateDemandeAideDialogState(); } class _CreateDemandeAideDialogState extends State { final _formKey = GlobalKey(); final _titreController = TextEditingController(); final _descriptionController = TextEditingController(); final _justificationController = TextEditingController(); final _montantController = TextEditingController(); String? _organisationId; String? _type; List _organisations = []; bool _loading = false; bool _isInitLoading = true; MembreCompletModel? _me; static const List> _types = [ {'value': 'FINANCIERE', 'label': 'Financière'}, {'value': 'MATERIELLE', 'label': 'Matérielle'}, {'value': 'ALIMENTAIRE', 'label': 'Alimentaire'}, {'value': 'MEDICALE', 'label': 'Médicale'}, {'value': 'SCOLAIRE', 'label': 'Scolaire'}, {'value': 'LOGEMENT', 'label': 'Logement'}, {'value': 'AUTRE', 'label': 'Autre'}, ]; @override void initState() { super.initState(); _loadInitialData(); } Future _loadInitialData() async { try { final user = await GetIt.instance().getMe(); final orgRepo = GetIt.instance(); final list = await orgRepo.getOrganizations(page: 0, size: 100); if (mounted) { setState(() { _me = user; _organisations = list; _isInitLoading = false; }); } } catch (e, st) { AppLogger.error('CreateDemandeAideDialog: chargement données initiales échoué', error: e, stackTrace: st); if (mounted) { setState(() { _isInitLoading = false; }); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Impossible de charger le profil ou les organisations. Réessayez.')), ); } } } @override void dispose() { _titreController.dispose(); _descriptionController.dispose(); _justificationController.dispose(); _montantController.dispose(); super.dispose(); } void _submit() { if (_me == null) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Profil non chargé, veuillez réessayer')), ); return; } if (!_formKey.currentState!.validate()) return; final titre = _titreController.text.trim(); final description = _descriptionController.text.trim(); if (titre.isEmpty || description.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Titre et description obligatoires')), ); return; } final montant = double.tryParse(_montantController.text.replaceAll(',', '.')); setState(() => _loading = true); final demande = DemandeAideModel( titre: titre, description: description, justification: _justificationController.text.trim().isEmpty ? null : _justificationController.text.trim(), type: _type, montantDemande: montant, organisationId: _organisationId, demandeurId: _me!.id, dateDemande: DateTime.now(), statut: 'BROUILLON', ); context.read().add(CreateDemandeAide(demande)); widget.onCreated(); if (mounted) { setState(() => _loading = false); Navigator.of(context).pop(); } } @override Widget build(BuildContext context) { return AlertDialog( title: const Text('Nouvelle demande d\'aide'), content: SingleChildScrollView( child: Form( key: _formKey, child: Column( mainAxisSize: MainAxisSize.min, children: [ if (_isInitLoading) const CircularProgressIndicator() else if (_me != null) TextFormField( initialValue: '${_me!.prenom} ${_me!.nom}', decoration: const InputDecoration( labelText: 'Demandeur', border: OutlineInputBorder(), prefixIcon: Icon(Icons.person), ), enabled: false, ) else const Text('Impossible de récupérer votre profil', style: TextStyle(color: AppColors.error)), const SizedBox(height: 12), TextFormField( controller: _titreController, decoration: const InputDecoration( labelText: 'Titre *', border: OutlineInputBorder(), ), validator: (v) => (v == null || v.trim().isEmpty) ? 'Obligatoire' : null, enabled: !_loading, ), const SizedBox(height: 12), TextFormField( controller: _descriptionController, decoration: const InputDecoration( labelText: 'Description *', border: OutlineInputBorder(), ), maxLines: 3, validator: (v) => (v == null || v.trim().isEmpty) ? 'Obligatoire' : null, enabled: !_loading, ), const SizedBox(height: 12), DropdownButtonFormField( value: _type, decoration: const InputDecoration( labelText: 'Type d\'aide', border: OutlineInputBorder(), ), items: _types .map((e) => DropdownMenuItem( value: e['value'], child: Text(e['label']!), )) .toList(), onChanged: _loading ? null : (v) => setState(() => _type = v), ), const SizedBox(height: 12), TextFormField( controller: _montantController, decoration: const InputDecoration( labelText: 'Montant demandé (FCFA, optionnel)', border: OutlineInputBorder(), ), keyboardType: const TextInputType.numberWithOptions(decimal: true), enabled: !_loading, ), const SizedBox(height: 12), TextFormField( controller: _justificationController, decoration: const InputDecoration( labelText: 'Justification', border: OutlineInputBorder(), ), maxLines: 2, enabled: !_loading, ), const SizedBox(height: 12), DropdownButtonFormField( value: _organisationId, isExpanded: true, decoration: const InputDecoration( labelText: 'Organisation', border: OutlineInputBorder(), ), items: _organisations .map((o) => DropdownMenuItem( value: o.id, child: Text(o.nom, overflow: TextOverflow.ellipsis, maxLines: 1), )) .toList(), onChanged: _loading ? null : (v) => setState(() => _organisationId = v), ), ], ), ), ), actions: [ TextButton( onPressed: _loading ? null : () => Navigator.of(context).pop(), child: const Text('Annuler'), ), FilledButton( onPressed: _loading ? null : _submit, child: _loading ? const SizedBox( width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2), ) : const Text('Créer'), ), ], ); } }