Files
unionflow-mobile-apps/lib/features/finance_workflow/presentation/widgets/reject_dialog.dart
dahoud ba779a7a40 feat(ui): dark mode adaptatif sur 15 pages/widgets restants
Pattern AppColors pair (isDark ternaries) appliqué sur :
- login_page : SnackBar error color Color(0xFFDC2626) → AppColors.error
  (gradient brand intentionnel non modifié)
- help_support : barre de recherche + ExpansionTile + chevrons → scheme adaptatif
- system_settings : état 'Accès réservé' + unselectedLabelColor TabBar
- epargne : date/description/boutons OutlinedButton foregroundColor adaptatifs
- conversation_tile, connected_recent_activities, connected_upcoming_events
- dashboard_notifications_widget
- budgets_list_page, pending_approvals_page, approve/reject_dialog
- create_organization_page, edit_organization_page, about_page

Les couleurs sémantiques (error, success, warning, primary) restent inchangées.
Les blancs/gradients intentionnels (AppBars brand, logos payment) préservés.
2026-04-15 20:14:59 +00:00

175 lines
5.6 KiB
Dart

/// Dialog pour rejeter une transaction
library reject_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 RejectDialog extends StatefulWidget {
final TransactionApproval approval;
const RejectDialog({
super.key,
required this.approval,
});
@override
State<RejectDialog> createState() => _RejectDialogState();
}
class _RejectDialogState extends State<RejectDialog> {
final _reasonController = TextEditingController();
final _formKey = GlobalKey<FormState>();
@override
void dispose() {
_reasonController.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 isDark = Theme.of(context).brightness == Brightness.dark;
final currencyFormat = NumberFormat.currency(symbol: widget.approval.currency);
return AlertDialog(
title: const Text('Rejeter la transaction'),
content: SingleChildScrollView(
child: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Vous êtes sur le point de rejeter cette transaction.',
style: AppTypography.bodyTextSmall.copyWith(
color: AppColors.error,
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: SpacingTokens.md),
Container(
padding: const EdgeInsets.all(SpacingTokens.md),
decoration: BoxDecoration(
color: isDark ? AppColors.surfaceDark : AppColors.surface,
borderRadius: BorderRadius.circular(SpacingTokens.radiusSm),
border: Border.all(color: isDark ? AppColors.borderDark : AppColors.border),
),
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.primary,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: SpacingTokens.sm),
_buildInfoRow(
'Demandeur',
widget.approval.requesterName,
),
],
),
),
const SizedBox(height: SpacingTokens.md),
TextFormField(
controller: _reasonController,
decoration: const InputDecoration(
labelText: 'Raison du rejet *',
hintText: 'Expliquez la raison du rejet...',
border: OutlineInputBorder(),
helperText: 'Minimum 10 caractères, maximum 500',
),
maxLines: 4,
maxLength: 500,
validator: FinanceValidators.rejectionReason(),
),
],
),
),
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('Annuler'),
),
ElevatedButton.icon(
onPressed: () {
if (_formKey.currentState!.validate()) {
context.read<ApprovalBloc>().add(
RejectTransactionEvent(
approvalId: widget.approval.id,
reason: _reasonController.text.trim(),
),
);
Navigator.of(context).pop();
}
},
icon: const Icon(Icons.close),
label: const Text('Rejeter'),
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.error,
foregroundColor: AppColors.onError,
),
),
],
);
}
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,
),
),
],
);
}
}