/// Dialog de création d'une demande d'adhésion library create_adhesion_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/adhesions_bloc.dart'; import '../../data/models/adhesion_model.dart'; import '../../../organizations/data/models/organization_model.dart'; import '../../../organizations/domain/repositories/organization_repository.dart'; import '../../../members/data/models/membre_complete_model.dart'; import '../../../profile/domain/repositories/profile_repository.dart'; class CreateAdhesionDialog extends StatefulWidget { final VoidCallback onCreated; const CreateAdhesionDialog({super.key, required this.onCreated}); @override State createState() => _CreateAdhesionDialogState(); } class _CreateAdhesionDialogState extends State { final _fraisController = TextEditingController(); String? _organisationId; bool _loading = false; bool _isInitLoading = true; List _organisations = []; MembreCompletModel? _me; @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('CreateAdhesionDialog: chargement profil/organisations é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() { _fraisController.dispose(); super.dispose(); } void _submit() { if (_me == null) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Profil non chargé, veuillez réessayer')), ); return; } if (_organisationId == null) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Veuillez sélectionner un membre et une organisation')), ); return; } final frais = double.tryParse(_fraisController.text.replaceAll(',', '.')); if (frais == null || frais <= 0) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Frais d\'adhésion invalides')), ); return; } setState(() => _loading = true); final adhesion = AdhesionModel( membreId: _me!.id, organisationId: _organisationId, fraisAdhesion: frais, codeDevise: 'XOF', dateDemande: DateTime.now(), ); context.read().add(CreateAdhesion(adhesion)); widget.onCreated(); if (mounted) { setState(() => _loading = false); Navigator.of(context).pop(); } } @override Widget build(BuildContext context) { return AlertDialog( title: const Text('Nouvelle demande d\'adhésion'), content: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, children: [ if (_isInitLoading) const CircularProgressIndicator() else if (_me != null) TextFormField( initialValue: '${_me!.prenom} ${_me!.nom}', decoration: const InputDecoration( labelText: 'Membre', 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: 16), 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), ), const SizedBox(height: 16), TextField( controller: _fraisController, decoration: const InputDecoration( labelText: 'Frais d\'adhésion (FCFA)', border: OutlineInputBorder(), ), keyboardType: const TextInputType.numberWithOptions(decimal: true), enabled: !_loading, ), ], ), ), 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'), ), ], ); } }