Initial commit: unionflow-mobile-apps

Application Flutter complète (sans build artifacts).

Signed-off-by: lions dev Team
This commit is contained in:
dahoud
2026-03-15 16:30:08 +00:00
commit d094d6db9c
1790 changed files with 507435 additions and 0 deletions

View File

@@ -0,0 +1,177 @@
/// Dialog pour approuver une transaction
library approve_dialog;
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:intl/intl.dart';
import '../../../../core/validation/validators.dart';
import '../../../../shared/design_system/unionflow_design_system.dart';
import '../../domain/entities/transaction_approval.dart';
import '../bloc/approval_bloc.dart';
import '../bloc/approval_event.dart';
class ApproveDialog extends StatefulWidget {
final TransactionApproval approval;
const ApproveDialog({
super.key,
required this.approval,
});
@override
State<ApproveDialog> createState() => _ApproveDialogState();
}
class _ApproveDialogState extends State<ApproveDialog> {
final _commentController = TextEditingController();
final _formKey = GlobalKey<FormState>();
@override
void dispose() {
_commentController.dispose();
super.dispose();
}
String _getTransactionTypeLabel(TransactionType type) {
switch (type) {
case TransactionType.contribution:
return 'Cotisation';
case TransactionType.deposit:
return 'Dépôt';
case TransactionType.withdrawal:
return 'Retrait';
case TransactionType.transfer:
return 'Transfert';
case TransactionType.solidarity:
return 'Solidarité';
case TransactionType.event:
return 'Événement';
case TransactionType.other:
return 'Autre';
}
}
@override
Widget build(BuildContext context) {
final currencyFormat = NumberFormat.currency(symbol: widget.approval.currency);
return AlertDialog(
title: const Text('Approuver la transaction'),
content: SingleChildScrollView(
child: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Confirmez-vous l\'approbation de cette transaction ?',
style: AppTypography.bodyTextSmall,
),
const SizedBox(height: SpacingTokens.md),
Container(
padding: const EdgeInsets.all(SpacingTokens.md),
decoration: BoxDecoration(
color: AppColors.lightBackground,
borderRadius: BorderRadius.circular(SpacingTokens.radiusSm),
border: Border.all(color: AppColors.lightBorder),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildInfoRow(
'Type',
_getTransactionTypeLabel(widget.approval.transactionType),
),
const SizedBox(height: SpacingTokens.sm),
_buildInfoRow(
'Montant',
currencyFormat.format(widget.approval.amount),
valueStyle: AppTypography.actionText.copyWith(
color: AppColors.primaryGreen,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: SpacingTokens.sm),
_buildInfoRow(
'Demandeur',
widget.approval.requesterName,
),
const SizedBox(height: SpacingTokens.sm),
_buildInfoRow(
'Date',
DateFormat('dd/MM/yyyy HH:mm').format(widget.approval.createdAt),
),
],
),
),
const SizedBox(height: SpacingTokens.md),
TextFormField(
controller: _commentController,
decoration: const InputDecoration(
labelText: 'Commentaire (optionnel)',
hintText: 'Ajouter un commentaire...',
border: OutlineInputBorder(),
helperText: 'Maximum 500 caractères',
),
maxLines: 3,
maxLength: 500,
validator: FinanceValidators.approvalComment(),
),
],
),
),
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('Annuler'),
),
ElevatedButton.icon(
onPressed: () {
if (_formKey.currentState!.validate()) {
context.read<ApprovalBloc>().add(
ApproveTransactionEvent(
approvalId: widget.approval.id,
comment: _commentController.text.trim().isEmpty
? null
: _commentController.text.trim(),
),
);
Navigator.of(context).pop();
}
},
icon: const Icon(Icons.check),
label: const Text('Approuver'),
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.success,
foregroundColor: Colors.white,
),
),
],
);
}
Widget _buildInfoRow(String label, String value, {TextStyle? valueStyle}) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 90,
child: Text(
'$label :',
style: AppTypography.subtitleSmall.copyWith(
fontWeight: FontWeight.w600,
),
),
),
Expanded(
child: Text(
value,
style: valueStyle ?? AppTypography.bodyTextSmall,
),
),
],
);
}
}