257 lines
8.5 KiB
Dart
257 lines
8.5 KiB
Dart
/// Dialogue de création de contribution
|
|
library create_contribution_dialog;
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
import 'package:intl/intl.dart';
|
|
import '../../bloc/contributions_bloc.dart';
|
|
import '../../bloc/contributions_event.dart';
|
|
import '../../data/models/contribution_model.dart';
|
|
import '../../../members/bloc/membres_bloc.dart';
|
|
import '../../../members/bloc/membres_event.dart';
|
|
import '../../../members/bloc/membres_state.dart';
|
|
|
|
|
|
class CreateContributionDialog extends StatefulWidget {
|
|
const CreateContributionDialog({super.key});
|
|
|
|
@override
|
|
State<CreateContributionDialog> createState() => _CreateContributionDialogState();
|
|
}
|
|
|
|
class _CreateContributionDialogState extends State<CreateContributionDialog> {
|
|
final _formKey = GlobalKey<FormState>();
|
|
final _montantController = TextEditingController();
|
|
final _descriptionController = TextEditingController();
|
|
|
|
ContributionType _selectedType = ContributionType.mensuelle;
|
|
dynamic _selectedMembre;
|
|
DateTime _dateEcheance = DateTime.now().add(const Duration(days: 30));
|
|
bool _isLoading = false;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
// Charger la liste des membres
|
|
context.read<MembresBloc>().add(const LoadMembres());
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_montantController.dispose();
|
|
_descriptionController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return AlertDialog(
|
|
title: const Text('Nouvelle contribution'),
|
|
content: SizedBox(
|
|
width: MediaQuery.of(context).size.width * 0.8,
|
|
child: Form(
|
|
key: _formKey,
|
|
child: SingleChildScrollView(
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
// Sélection du membre
|
|
BlocBuilder<MembresBloc, MembresState>(
|
|
builder: (context, state) {
|
|
if (state is MembresLoaded) {
|
|
return DropdownButtonFormField<dynamic>(
|
|
value: _selectedMembre,
|
|
decoration: const InputDecoration(
|
|
labelText: 'Membre',
|
|
border: OutlineInputBorder(),
|
|
),
|
|
items: state.membres.map((membre) {
|
|
return DropdownMenuItem(
|
|
value: membre,
|
|
child: Text('${membre.nom} ${membre.prenom}'),
|
|
);
|
|
}).toList(),
|
|
onChanged: (value) {
|
|
setState(() {
|
|
_selectedMembre = value;
|
|
});
|
|
},
|
|
validator: (value) {
|
|
if (value == null) {
|
|
return 'Veuillez sélectionner un membre';
|
|
}
|
|
return null;
|
|
},
|
|
);
|
|
}
|
|
return const CircularProgressIndicator();
|
|
},
|
|
),
|
|
const SizedBox(height: 16),
|
|
|
|
// Type de contribution
|
|
DropdownButtonFormField<ContributionType>(
|
|
value: _selectedType,
|
|
decoration: const InputDecoration(
|
|
labelText: 'Type de contribution',
|
|
border: OutlineInputBorder(),
|
|
),
|
|
items: ContributionType.values.map((type) {
|
|
return DropdownMenuItem(
|
|
value: type,
|
|
child: Text(_getTypeLabel(type)),
|
|
);
|
|
}).toList(),
|
|
onChanged: (value) {
|
|
if (value != null) {
|
|
setState(() {
|
|
_selectedType = value;
|
|
});
|
|
}
|
|
},
|
|
),
|
|
const SizedBox(height: 16),
|
|
|
|
// Montant
|
|
TextFormField(
|
|
controller: _montantController,
|
|
decoration: const InputDecoration(
|
|
labelText: 'Montant (FCFA)',
|
|
border: OutlineInputBorder(),
|
|
prefixIcon: Icon(Icons.attach_money),
|
|
),
|
|
keyboardType: TextInputType.number,
|
|
validator: (value) {
|
|
if (value == null || value.isEmpty) {
|
|
return 'Veuillez saisir un montant';
|
|
}
|
|
if (double.tryParse(value) == null) {
|
|
return 'Montant invalide';
|
|
}
|
|
return null;
|
|
},
|
|
),
|
|
const SizedBox(height: 16),
|
|
|
|
// Date d'échéance
|
|
InkWell(
|
|
onTap: () async {
|
|
final date = await showDatePicker(
|
|
context: context,
|
|
initialDate: _dateEcheance,
|
|
firstDate: DateTime.now(),
|
|
lastDate: DateTime.now().add(const Duration(days: 365)),
|
|
);
|
|
if (date != null) {
|
|
setState(() {
|
|
_dateEcheance = date;
|
|
});
|
|
}
|
|
},
|
|
child: InputDecorator(
|
|
decoration: const InputDecoration(
|
|
labelText: 'Date d\'échéance',
|
|
border: OutlineInputBorder(),
|
|
prefixIcon: Icon(Icons.calendar_today),
|
|
),
|
|
child: Text(
|
|
DateFormat('dd/MM/yyyy').format(_dateEcheance),
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 16),
|
|
|
|
// Description
|
|
TextFormField(
|
|
controller: _descriptionController,
|
|
decoration: const InputDecoration(
|
|
labelText: 'Description (optionnel)',
|
|
border: OutlineInputBorder(),
|
|
prefixIcon: Icon(Icons.description),
|
|
),
|
|
maxLines: 3,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: () => Navigator.pop(context),
|
|
child: const Text('Annuler'),
|
|
),
|
|
ElevatedButton(
|
|
onPressed: _isLoading ? null : _createContribution,
|
|
child: _isLoading
|
|
? const SizedBox(
|
|
width: 16,
|
|
height: 16,
|
|
child: CircularProgressIndicator(strokeWidth: 2),
|
|
)
|
|
: const Text('Créer'),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
String _getTypeLabel(ContributionType type) {
|
|
switch (type) {
|
|
case ContributionType.mensuelle:
|
|
return 'Mensuelle';
|
|
case ContributionType.trimestrielle:
|
|
return 'Trimestrielle';
|
|
case ContributionType.semestrielle:
|
|
return 'Semestrielle';
|
|
case ContributionType.annuelle:
|
|
return 'Annuelle';
|
|
case ContributionType.exceptionnelle:
|
|
return 'Exceptionnelle';
|
|
}
|
|
}
|
|
|
|
void _createContribution() {
|
|
if (!_formKey.currentState!.validate()) {
|
|
return;
|
|
}
|
|
|
|
if (_selectedMembre == null) {
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
const SnackBar(
|
|
content: Text('Veuillez sélectionner un membre'),
|
|
backgroundColor: Colors.red,
|
|
),
|
|
);
|
|
return;
|
|
}
|
|
|
|
setState(() {
|
|
_isLoading = true;
|
|
});
|
|
|
|
final contribution = ContributionModel(
|
|
membreId: _selectedMembre!.id!,
|
|
membreNom: _selectedMembre!.nom,
|
|
membrePrenom: _selectedMembre!.prenom,
|
|
type: _selectedType,
|
|
annee: DateTime.now().year,
|
|
montant: double.parse(_montantController.text),
|
|
dateEcheance: _dateEcheance,
|
|
description: _descriptionController.text.isNotEmpty ? _descriptionController.text : null,
|
|
statut: ContributionStatus.nonPayee,
|
|
dateCreation: DateTime.now(),
|
|
dateModification: DateTime.now(),
|
|
);
|
|
|
|
context.read<ContributionsBloc>().add(CreateContribution(contribution: contribution));
|
|
Navigator.pop(context);
|
|
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
const SnackBar(
|
|
content: Text('Contribution créée avec succès'),
|
|
backgroundColor: Colors.green,
|
|
),
|
|
);
|
|
}
|
|
}
|