feat(features): refontes explore/feed/finance_workflow/help/logs/members/notifications
- explore + feed : pages de découverte (réseau, fil d'actualité) - finance_workflow : approvals bloc + budgets bloc + dialogs - help : support page avec FAQ + contact - logs : monitoring bloc avec metrics + alerts + searchLogs - members : recherche avancée, bulk actions, bloc complet, import/export - notifications : bloc + page
This commit is contained in:
@@ -63,7 +63,7 @@ class _CreateBudgetDialogState extends State<CreateBudgetDialog> {
|
|||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
const SnackBar(
|
const SnackBar(
|
||||||
content: Text('Veuillez ajouter au moins une ligne budgétaire'),
|
content: Text('Veuillez ajouter au moins une ligne budgétaire'),
|
||||||
backgroundColor: Colors.red,
|
backgroundColor: AppColors.error,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
@@ -112,7 +112,7 @@ class _CreateBudgetDialogState extends State<CreateBudgetDialog> {
|
|||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.all(SpacingTokens.md),
|
padding: const EdgeInsets.all(SpacingTokens.md),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: AppColors.primaryGreen,
|
color: AppColors.primary,
|
||||||
borderRadius: const BorderRadius.only(
|
borderRadius: const BorderRadius.only(
|
||||||
topLeft: Radius.circular(SpacingTokens.radiusMd),
|
topLeft: Radius.circular(SpacingTokens.radiusMd),
|
||||||
topRight: Radius.circular(SpacingTokens.radiusMd),
|
topRight: Radius.circular(SpacingTokens.radiusMd),
|
||||||
@@ -257,8 +257,8 @@ class _CreateBudgetDialogState extends State<CreateBudgetDialog> {
|
|||||||
icon: const Icon(Icons.add, size: 18),
|
icon: const Icon(Icons.add, size: 18),
|
||||||
label: const Text('Ajouter'),
|
label: const Text('Ajouter'),
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: AppColors.primaryGreen,
|
backgroundColor: AppColors.primary,
|
||||||
foregroundColor: Colors.white,
|
foregroundColor: AppColors.onPrimary,
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: SpacingTokens.md,
|
horizontal: SpacingTokens.md,
|
||||||
vertical: SpacingTokens.sm,
|
vertical: SpacingTokens.sm,
|
||||||
@@ -274,16 +274,16 @@ class _CreateBudgetDialogState extends State<CreateBudgetDialog> {
|
|||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.all(SpacingTokens.lg),
|
padding: const EdgeInsets.all(SpacingTokens.lg),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.grey.shade100,
|
color: Theme.of(context).colorScheme.surfaceContainerLow,
|
||||||
borderRadius:
|
borderRadius:
|
||||||
BorderRadius.circular(SpacingTokens.radiusSm),
|
BorderRadius.circular(SpacingTokens.radiusSm),
|
||||||
border: Border.all(color: Colors.grey.shade300),
|
border: Border.all(color: Theme.of(context).colorScheme.outlineVariant),
|
||||||
),
|
),
|
||||||
child: const Center(
|
child: const Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
'Aucune ligne budgétaire.\nCliquez sur "Ajouter" pour commencer.',
|
'Aucune ligne budgétaire.\nCliquez sur "Ajouter" pour commencer.',
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: TextStyle(color: Colors.grey),
|
style: TextStyle(color: AppColors.textTertiary),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -307,9 +307,9 @@ class _CreateBudgetDialogState extends State<CreateBudgetDialog> {
|
|||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.all(SpacingTokens.md),
|
padding: const EdgeInsets.all(SpacingTokens.md),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.grey.shade50,
|
color: Theme.of(context).colorScheme.surfaceContainerLow,
|
||||||
border: Border(
|
border: Border(
|
||||||
top: BorderSide(color: Colors.grey.shade300),
|
top: BorderSide(color: Theme.of(context).colorScheme.outlineVariant),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
@@ -326,7 +326,7 @@ class _CreateBudgetDialogState extends State<CreateBudgetDialog> {
|
|||||||
label: const Text('Créer le budget'),
|
label: const Text('Créer le budget'),
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: AppColors.success,
|
backgroundColor: AppColors.success,
|
||||||
foregroundColor: Colors.white,
|
foregroundColor: AppColors.onPrimary,
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: SpacingTokens.lg,
|
horizontal: SpacingTokens.lg,
|
||||||
vertical: SpacingTokens.md,
|
vertical: SpacingTokens.md,
|
||||||
@@ -419,7 +419,7 @@ class _BudgetLineWidgetState extends State<_BudgetLineWidget> {
|
|||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.receipt_long, color: AppColors.primaryGreen),
|
const Icon(Icons.receipt_long, color: AppColors.primary),
|
||||||
const SizedBox(width: SpacingTokens.sm),
|
const SizedBox(width: SpacingTokens.sm),
|
||||||
const Text(
|
const Text(
|
||||||
'Ligne budgétaire',
|
'Ligne budgétaire',
|
||||||
@@ -427,7 +427,7 @@ class _BudgetLineWidgetState extends State<_BudgetLineWidget> {
|
|||||||
),
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.delete, color: Colors.red),
|
icon: const Icon(Icons.delete, color: AppColors.error),
|
||||||
onPressed: widget.onRemove,
|
onPressed: widget.onRemove,
|
||||||
tooltip: 'Supprimer',
|
tooltip: 'Supprimer',
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ MembreCompletModel _$MembreCompletModelFromJson(Map<String, dynamic> json) =>
|
|||||||
profession: json['profession'] as String?,
|
profession: json['profession'] as String?,
|
||||||
nationalite: json['nationalite'] as String?,
|
nationalite: json['nationalite'] as String?,
|
||||||
photo: json['photo'] as String?,
|
photo: json['photo'] as String?,
|
||||||
statut: $enumDecodeNullable(_$StatutMembreEnumMap, json['statutCompte']) ??
|
statut:
|
||||||
|
$enumDecodeNullable(_$StatutMembreEnumMap, json['statutCompte']) ??
|
||||||
StatutMembre.actif,
|
StatutMembre.actif,
|
||||||
role: json['role'] as String?,
|
role: json['role'] as String?,
|
||||||
organisationId: json['organisationId'] as String?,
|
organisationId: json['organisationId'] as String?,
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import '../../../../core/di/injection_container.dart';
|
import '../../../../core/di/injection_container.dart';
|
||||||
import '../../../../shared/design_system/tokens/app_colors.dart';
|
import '../../../../shared/design_system/tokens/app_colors.dart';
|
||||||
|
import '../../../../shared/design_system/tokens/module_colors.dart';
|
||||||
|
import '../../../../shared/design_system/components/uf_app_bar.dart';
|
||||||
import '../../../../shared/models/membre_search_criteria.dart';
|
import '../../../../shared/models/membre_search_criteria.dart';
|
||||||
import '../../../../shared/models/membre_search_result.dart';
|
import '../../../../shared/models/membre_search_result.dart';
|
||||||
import '../../../organizations/domain/repositories/organization_repository.dart';
|
import '../../../organizations/domain/repositories/organization_repository.dart';
|
||||||
@@ -114,10 +116,9 @@ class _AdvancedSearchPageState extends State<AdvancedSearchPage>
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: UFAppBar(
|
||||||
title: const Text('Recherche Avancée'),
|
title: 'Recherche Avancée',
|
||||||
backgroundColor: AppColors.primaryGreen,
|
moduleGradient: ModuleColors.membresGradient,
|
||||||
foregroundColor: Colors.white,
|
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
bottom: TabBar(
|
bottom: TabBar(
|
||||||
controller: _tabController,
|
controller: _tabController,
|
||||||
@@ -179,7 +180,7 @@ class _AdvancedSearchPageState extends State<AdvancedSearchPage>
|
|||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.flash_on, color: AppColors.primaryGreen),
|
const Icon(Icons.flash_on, color: AppColors.primary),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Text(
|
Text(
|
||||||
'Recherche Rapide',
|
'Recherche Rapide',
|
||||||
@@ -234,7 +235,7 @@ class _AdvancedSearchPageState extends State<AdvancedSearchPage>
|
|||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.tune, color: AppColors.primaryGreen),
|
const Icon(Icons.tune, color: AppColors.primary),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Text(
|
Text(
|
||||||
'Critères Détaillés',
|
'Critères Détaillés',
|
||||||
@@ -325,7 +326,7 @@ class _AdvancedSearchPageState extends State<AdvancedSearchPage>
|
|||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.filter_alt, color: AppColors.primaryGreen),
|
const Icon(Icons.filter_alt, color: AppColors.primary),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Text(
|
Text(
|
||||||
'Filtres Avancés',
|
'Filtres Avancés',
|
||||||
@@ -479,16 +480,16 @@ class _AdvancedSearchPageState extends State<AdvancedSearchPage>
|
|||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.search, size: 64, color: Colors.grey),
|
Icon(Icons.search, size: 64, color: AppColors.textTertiary),
|
||||||
SizedBox(height: 16),
|
SizedBox(height: 16),
|
||||||
Text(
|
Text(
|
||||||
'Aucune recherche effectuée',
|
'Aucune recherche effectuée',
|
||||||
style: TextStyle(fontSize: 18, color: Colors.grey),
|
style: TextStyle(fontSize: 18, color: AppColors.textTertiary),
|
||||||
),
|
),
|
||||||
SizedBox(height: 8),
|
SizedBox(height: 8),
|
||||||
Text(
|
Text(
|
||||||
'Utilisez l\'onglet Critères pour lancer une recherche',
|
'Utilisez l\'onglet Critères pour lancer une recherche',
|
||||||
style: TextStyle(color: Colors.grey),
|
style: TextStyle(color: AppColors.textTertiary),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -535,16 +536,16 @@ class _AdvancedSearchPageState extends State<AdvancedSearchPage>
|
|||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.analytics, size: 64, color: Colors.grey),
|
Icon(Icons.analytics, size: 64, color: AppColors.textTertiary),
|
||||||
SizedBox(height: 16),
|
SizedBox(height: 16),
|
||||||
Text(
|
Text(
|
||||||
'Aucune statistique disponible',
|
'Aucune statistique disponible',
|
||||||
style: TextStyle(fontSize: 18, color: Colors.grey),
|
style: TextStyle(fontSize: 18, color: AppColors.textTertiary),
|
||||||
),
|
),
|
||||||
SizedBox(height: 8),
|
SizedBox(height: 8),
|
||||||
Text(
|
Text(
|
||||||
'Effectuez une recherche pour voir les statistiques',
|
'Effectuez une recherche pour voir les statistiques',
|
||||||
style: TextStyle(color: Colors.grey),
|
style: TextStyle(color: AppColors.textTertiary),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -574,8 +575,8 @@ class _AdvancedSearchPageState extends State<AdvancedSearchPage>
|
|||||||
return ActionChip(
|
return ActionChip(
|
||||||
label: Text(label),
|
label: Text(label),
|
||||||
onPressed: onTap,
|
onPressed: onTap,
|
||||||
backgroundColor: AppColors.primaryGreen.withOpacity(0.1),
|
backgroundColor: AppColors.primary.withOpacity(0.1),
|
||||||
labelStyle: const TextStyle(color: AppColors.primaryGreen),
|
labelStyle: const TextStyle(color: AppColors.primary),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -214,9 +214,9 @@ class _CredentialsDialogState extends State<_CredentialsDialog> {
|
|||||||
Container(
|
Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: const Color(0xFF1E2A1E), // vert ardoise sombre
|
color: const Color(0xFF0D1428), // navy sombre terminal
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
border: Border.all(color: const Color(0xFF2E4A2E)),
|
border: Border.all(color: const Color(0xFF2D3554)),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@@ -225,23 +225,23 @@ class _CredentialsDialogState extends State<_CredentialsDialog> {
|
|||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.fromLTRB(14, 10, 10, 10),
|
padding: const EdgeInsets.fromLTRB(14, 10, 10, 10),
|
||||||
decoration: const BoxDecoration(
|
decoration: const BoxDecoration(
|
||||||
color: Color(0xFF162216),
|
color: Color(0xFF060A14),
|
||||||
borderRadius:
|
borderRadius:
|
||||||
BorderRadius.vertical(top: Radius.circular(11)),
|
BorderRadius.vertical(top: Radius.circular(11)),
|
||||||
border: Border(
|
border: Border(
|
||||||
bottom: BorderSide(color: Color(0xFF2E4A2E))),
|
bottom: BorderSide(color: Color(0xFF2D3554))),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.terminal_rounded,
|
const Icon(Icons.terminal_rounded,
|
||||||
size: 13, color: Color(0xFF4CAF50)),
|
size: 13, color: Color(0xFF297FFF)),
|
||||||
const SizedBox(width: 6),
|
const SizedBox(width: 6),
|
||||||
const Text(
|
const Text(
|
||||||
'credentials.txt',
|
'credentials.txt',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: Color(0xFF90C890),
|
color: Color(0xFF69B7FF),
|
||||||
fontFamily: 'monospace'),
|
fontFamily: 'monospace'),
|
||||||
),
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
@@ -255,12 +255,12 @@ class _CredentialsDialogState extends State<_CredentialsDialog> {
|
|||||||
children: [
|
children: [
|
||||||
Icon(Icons.check_rounded,
|
Icon(Icons.check_rounded,
|
||||||
size: 13,
|
size: 13,
|
||||||
color: Color(0xFF4CAF50)),
|
color: Color(0xFF22C55E)),
|
||||||
SizedBox(width: 4),
|
SizedBox(width: 4),
|
||||||
Text('Copié',
|
Text('Copié',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
color: Color(0xFF4CAF50),
|
color: Color(0xFF22C55E),
|
||||||
fontFamily: 'monospace')),
|
fontFamily: 'monospace')),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@@ -269,12 +269,12 @@ class _CredentialsDialogState extends State<_CredentialsDialog> {
|
|||||||
children: [
|
children: [
|
||||||
Icon(Icons.copy_rounded,
|
Icon(Icons.copy_rounded,
|
||||||
size: 13,
|
size: 13,
|
||||||
color: Color(0xFF90C890)),
|
color: Color(0xFF69B7FF)),
|
||||||
SizedBox(width: 4),
|
SizedBox(width: 4),
|
||||||
Text('Copier tout',
|
Text('Copier tout',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
color: Color(0xFF90C890),
|
color: Color(0xFF69B7FF),
|
||||||
fontFamily: 'monospace')),
|
fontFamily: 'monospace')),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -291,7 +291,7 @@ class _CredentialsDialogState extends State<_CredentialsDialog> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
_credLine('# Identifiants UnionFlow',
|
_credLine('# Identifiants UnionFlow',
|
||||||
color: const Color(0xFF6A9955),
|
color: const Color(0xFF5C8DB5),
|
||||||
isComment: true),
|
isComment: true),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
_credLine('email ',
|
_credLine('email ',
|
||||||
@@ -307,7 +307,7 @@ class _CredentialsDialogState extends State<_CredentialsDialog> {
|
|||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
_credLine(
|
_credLine(
|
||||||
'# Changez le mot de passe à la 1ère connexion',
|
'# Changez le mot de passe à la 1ère connexion',
|
||||||
color: const Color(0xFF6A9955),
|
color: const Color(0xFF5C8DB5),
|
||||||
isComment: true),
|
isComment: true),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -426,7 +426,7 @@ class _CredentialsDialogState extends State<_CredentialsDialog> {
|
|||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontFamily: 'monospace',
|
fontFamily: 'monospace',
|
||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
color: color ?? const Color(0xFF6A9955),
|
color: color ?? const Color(0xFF5C8DB5),
|
||||||
height: 1.4),
|
height: 1.4),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
library edit_member_dialog;
|
library edit_member_dialog;
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import '../../../../shared/design_system/tokens/color_tokens.dart';
|
||||||
|
import '../../../../shared/design_system/tokens/app_colors.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import '../../bloc/membres_bloc.dart';
|
import '../../bloc/membres_bloc.dart';
|
||||||
@@ -325,8 +327,8 @@ class _EditMemberDialogState extends State<EditMemberDialog> {
|
|||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.grey[100],
|
color: Theme.of(context).colorScheme.surfaceContainerHighest,
|
||||||
border: Border(top: BorderSide(color: Colors.grey[300]!)),
|
border: Border(top: BorderSide(color: Theme.of(context).colorScheme.outline)),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
@@ -432,7 +434,7 @@ class _EditMemberDialogState extends State<EditMemberDialog> {
|
|||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
const SnackBar(
|
const SnackBar(
|
||||||
content: Text('Membre modifié avec succès'),
|
content: Text('Membre modifié avec succès'),
|
||||||
backgroundColor: Colors.green,
|
backgroundColor: AppColors.success,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
|
|
||||||
import '../../../../shared/models/membre_search_result.dart' as search_model;
|
import '../../../../shared/models/membre_search_result.dart' as search_model;
|
||||||
import '../../data/models/membre_complete_model.dart';
|
import '../../data/models/membre_complete_model.dart';
|
||||||
|
import '../../../../shared/design_system/tokens/app_colors.dart';
|
||||||
|
|
||||||
/// Widget d'affichage des résultats de recherche de membres
|
/// Widget d'affichage des résultats de recherche de membres
|
||||||
/// Gère la pagination, le tri et l'affichage des membres trouvés
|
/// Gère la pagination, le tri et l'affichage des membres trouvés
|
||||||
@@ -56,20 +57,20 @@ class _MembreSearchResultsState extends State<MembreSearchResults> {
|
|||||||
Icon(
|
Icon(
|
||||||
Icons.search_off,
|
Icons.search_off,
|
||||||
size: 64,
|
size: 64,
|
||||||
color: Colors.grey[400],
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Text(
|
Text(
|
||||||
'Aucun membre trouvé',
|
'Aucun membre trouvé',
|
||||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||||
color: Colors.grey[600],
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Text(
|
Text(
|
||||||
'Essayez de modifier vos critères de recherche',
|
'Essayez de modifier vos critères de recherche',
|
||||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||||
color: Colors.grey[500],
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
@@ -117,9 +118,9 @@ class _MembreSearchResultsState extends State<MembreSearchResults> {
|
|||||||
),
|
),
|
||||||
Chip(
|
Chip(
|
||||||
label: Text('${widget.result.executionTimeMs}ms'),
|
label: Text('${widget.result.executionTimeMs}ms'),
|
||||||
backgroundColor: Colors.green.withOpacity(0.1),
|
backgroundColor: AppColors.success.withOpacity(0.1),
|
||||||
labelStyle: const TextStyle(
|
labelStyle: const TextStyle(
|
||||||
color: Colors.green,
|
color: AppColors.success,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -130,7 +131,7 @@ class _MembreSearchResultsState extends State<MembreSearchResults> {
|
|||||||
Text(
|
Text(
|
||||||
'Critères: ${widget.result.criteria.description}',
|
'Critères: ${widget.result.criteria.description}',
|
||||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||||
color: Colors.grey[600],
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
@@ -162,7 +163,7 @@ class _MembreSearchResultsState extends State<MembreSearchResults> {
|
|||||||
child: Text(
|
child: Text(
|
||||||
_getInitials(membre.nom, membre.prenom),
|
_getInitials(membre.nom, membre.prenom),
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: Colors.white,
|
color: AppColors.onPrimary,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -177,7 +178,7 @@ class _MembreSearchResultsState extends State<MembreSearchResults> {
|
|||||||
if (membre.email.isNotEmpty)
|
if (membre.email.isNotEmpty)
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.email, size: 14, color: Colors.grey),
|
const Icon(Icons.email, size: 14, color: AppColors.textTertiary),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
@@ -191,7 +192,7 @@ class _MembreSearchResultsState extends State<MembreSearchResults> {
|
|||||||
if (membre.telephone?.isNotEmpty == true)
|
if (membre.telephone?.isNotEmpty == true)
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.phone, size: 14, color: Colors.grey),
|
const Icon(Icons.phone, size: 14, color: AppColors.textTertiary),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
Text(
|
Text(
|
||||||
membre.telephone!,
|
membre.telephone!,
|
||||||
@@ -202,7 +203,7 @@ class _MembreSearchResultsState extends State<MembreSearchResults> {
|
|||||||
if (membre.organisationNom?.isNotEmpty == true)
|
if (membre.organisationNom?.isNotEmpty == true)
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.business, size: 14, color: Colors.grey),
|
const Icon(Icons.business, size: 14, color: AppColors.textTertiary),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
@@ -225,7 +226,7 @@ class _MembreSearchResultsState extends State<MembreSearchResults> {
|
|||||||
_formatRoles(membre.role!),
|
_formatRoles(membre.role!),
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
color: Colors.grey,
|
color: AppColors.textTertiary,
|
||||||
),
|
),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
@@ -261,8 +262,8 @@ class _MembreSearchResultsState extends State<MembreSearchResults> {
|
|||||||
icon: const Icon(Icons.chevron_left),
|
icon: const Icon(Icons.chevron_left),
|
||||||
label: const Text('Précédent'),
|
label: const Text('Précédent'),
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Colors.grey[100],
|
backgroundColor: Theme.of(context).colorScheme.surfaceContainerHighest,
|
||||||
foregroundColor: Colors.grey[700],
|
foregroundColor: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
@@ -289,7 +290,7 @@ class _MembreSearchResultsState extends State<MembreSearchResults> {
|
|||||||
label: const Text('Suivant'),
|
label: const Text('Suivant'),
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Theme.of(context).primaryColor,
|
backgroundColor: Theme.of(context).primaryColor,
|
||||||
foregroundColor: Colors.white,
|
foregroundColor: AppColors.onPrimary,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -322,15 +323,15 @@ class _MembreSearchResultsState extends State<MembreSearchResults> {
|
|||||||
Color _getStatusColor(StatutMembre statut) {
|
Color _getStatusColor(StatutMembre statut) {
|
||||||
switch (statut) {
|
switch (statut) {
|
||||||
case StatutMembre.actif:
|
case StatutMembre.actif:
|
||||||
return Colors.green;
|
return AppColors.success;
|
||||||
case StatutMembre.inactif:
|
case StatutMembre.inactif:
|
||||||
return Colors.orange;
|
return AppColors.warning;
|
||||||
case StatutMembre.suspendu:
|
case StatutMembre.suspendu:
|
||||||
return Colors.red;
|
return AppColors.error;
|
||||||
case StatutMembre.enAttente:
|
case StatutMembre.enAttente:
|
||||||
return Colors.grey;
|
return AppColors.textTertiary;
|
||||||
default:
|
default:
|
||||||
return Colors.grey;
|
return AppColors.textTertiary;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:fl_chart/fl_chart.dart';
|
import 'package:fl_chart/fl_chart.dart';
|
||||||
|
|
||||||
import '../../../../shared/models/membre_search_result.dart';
|
import '../../../../shared/models/membre_search_result.dart';
|
||||||
|
import '../../../../shared/design_system/tokens/app_colors.dart';
|
||||||
|
|
||||||
/// Widget d'affichage des statistiques de recherche
|
/// Widget d'affichage des statistiques de recherche
|
||||||
/// Présente les métriques et graphiques des résultats de recherche
|
/// Présente les métriques et graphiques des résultats de recherche
|
||||||
@@ -81,7 +82,7 @@ class SearchStatisticsCard extends StatelessWidget {
|
|||||||
'Total Membres',
|
'Total Membres',
|
||||||
statistics.totalMembres.toString(),
|
statistics.totalMembres.toString(),
|
||||||
Icons.people,
|
Icons.people,
|
||||||
Colors.blue,
|
AppColors.info,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
@@ -91,7 +92,7 @@ class SearchStatisticsCard extends StatelessWidget {
|
|||||||
'Membres Actifs',
|
'Membres Actifs',
|
||||||
statistics.membresActifs.toString(),
|
statistics.membresActifs.toString(),
|
||||||
Icons.person,
|
Icons.person,
|
||||||
Colors.green,
|
AppColors.success,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -105,7 +106,7 @@ class SearchStatisticsCard extends StatelessWidget {
|
|||||||
'Âge Moyen',
|
'Âge Moyen',
|
||||||
'${statistics.ageMoyen.toStringAsFixed(1)} ans',
|
'${statistics.ageMoyen.toStringAsFixed(1)} ans',
|
||||||
Icons.cake,
|
Icons.cake,
|
||||||
Colors.orange,
|
AppColors.warning,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
@@ -155,7 +156,7 @@ class SearchStatisticsCard extends StatelessWidget {
|
|||||||
Text(
|
Text(
|
||||||
title,
|
title,
|
||||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||||
color: Colors.grey[600],
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
@@ -196,7 +197,7 @@ class SearchStatisticsCard extends StatelessWidget {
|
|||||||
PieChartSectionData(
|
PieChartSectionData(
|
||||||
value: statistics.membresActifs.toDouble(),
|
value: statistics.membresActifs.toDouble(),
|
||||||
title: '${statistics.pourcentageActifs.toStringAsFixed(1)}%',
|
title: '${statistics.pourcentageActifs.toStringAsFixed(1)}%',
|
||||||
color: Colors.green,
|
color: AppColors.success,
|
||||||
radius: 60,
|
radius: 60,
|
||||||
titleStyle: const TextStyle(
|
titleStyle: const TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
@@ -208,7 +209,7 @@ class SearchStatisticsCard extends StatelessWidget {
|
|||||||
PieChartSectionData(
|
PieChartSectionData(
|
||||||
value: statistics.membresInactifs.toDouble(),
|
value: statistics.membresInactifs.toDouble(),
|
||||||
title: '${statistics.pourcentageInactifs.toStringAsFixed(1)}%',
|
title: '${statistics.pourcentageInactifs.toStringAsFixed(1)}%',
|
||||||
color: Colors.orange,
|
color: AppColors.warning,
|
||||||
radius: 60,
|
radius: 60,
|
||||||
titleStyle: const TextStyle(
|
titleStyle: const TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
@@ -232,14 +233,14 @@ class SearchStatisticsCard extends StatelessWidget {
|
|||||||
_buildLegendItem(
|
_buildLegendItem(
|
||||||
'Actifs',
|
'Actifs',
|
||||||
statistics.membresActifs,
|
statistics.membresActifs,
|
||||||
Colors.green,
|
AppColors.success,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
if (statistics.membresInactifs > 0)
|
if (statistics.membresInactifs > 0)
|
||||||
_buildLegendItem(
|
_buildLegendItem(
|
||||||
'Inactifs',
|
'Inactifs',
|
||||||
statistics.membresInactifs,
|
statistics.membresInactifs,
|
||||||
Colors.orange,
|
AppColors.warning,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -335,7 +336,7 @@ class SearchStatisticsCard extends StatelessWidget {
|
|||||||
Icon(
|
Icon(
|
||||||
icon,
|
icon,
|
||||||
size: 20,
|
size: 20,
|
||||||
color: Colors.grey[600],
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
Expanded(
|
Expanded(
|
||||||
@@ -382,26 +383,26 @@ class SearchStatisticsCard extends StatelessWidget {
|
|||||||
Text(
|
Text(
|
||||||
statistics.description,
|
statistics.description,
|
||||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||||
color: Colors.grey[700],
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.all(12.0),
|
padding: const EdgeInsets.all(12.0),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.blue.withOpacity(0.1),
|
color: AppColors.infoContainer,
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
border: Border.all(color: Colors.blue.withOpacity(0.3)),
|
border: Border.all(color: AppColors.info),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.lightbulb, color: Colors.blue),
|
const Icon(Icons.lightbulb, color: AppColors.info),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
'Ces statistiques sont calculées en temps réel sur les résultats de votre recherche.',
|
'Ces statistiques sont calculées en temps réel sur les résultats de votre recherche.',
|
||||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||||
color: Colors.blue[700],
|
color: AppColors.primaryDark,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user