177 lines
5.7 KiB
Dart
177 lines
5.7 KiB
Dart
/// 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<CreateAdhesionDialog> createState() => _CreateAdhesionDialogState();
|
|
}
|
|
|
|
class _CreateAdhesionDialogState extends State<CreateAdhesionDialog> {
|
|
final _fraisController = TextEditingController();
|
|
String? _organisationId;
|
|
bool _loading = false;
|
|
bool _isInitLoading = true;
|
|
List<OrganizationModel> _organisations = [];
|
|
MembreCompletModel? _me;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_loadInitialData();
|
|
}
|
|
|
|
Future<void> _loadInitialData() async {
|
|
try {
|
|
final user = await GetIt.instance<IProfileRepository>().getMe();
|
|
final orgRepo = GetIt.instance<IOrganizationRepository>();
|
|
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<AdhesionsBloc>().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<String>(
|
|
value: _organisationId,
|
|
isExpanded: true,
|
|
decoration: const InputDecoration(
|
|
labelText: 'Organisation',
|
|
border: OutlineInputBorder(),
|
|
),
|
|
items: _organisations
|
|
.map((o) => DropdownMenuItem<String>(
|
|
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'),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|